Refuse a build whose module directory, archive or bundle output leads out of the module through a link, so a repository cannot make build-agent pack files from the build node (issue 1609)
#415
Merged
mesh-toolsmerged 2 commits from fix/1609-archive-symlink into main2026-10-21 10:16:52 +00:00
Issue 1609 (security; build-agent builds every delivered module until R4e). A repository could commit a link and make build-agent pack and publish files the build account can read outside the module:
a symlinked module directory: inside() (internal/builder/builder.go ~947) now resolves the fetched tree and the module directory with filepath.EvalSymlinks and refuses a module directory outside the tree;
a symlinked parent of an archive's from: archiveRoot (~1369), called from the archive case of one, refuses a resolved root outside the resolved module directory;
a committed .mesh-build link: outsideTheModule (~1392, follows links of the deepest existing part) is checked in compile before MkdirAll, in bundled on final, and before pack(compiled) in the bundle case.
pack still gets the unresolved paths, so no digest of a legitimate tree changes; links that stay inside the module still work.
Tests: internal/builder/archive_symlink_test.go (symlinked parent of from, symlinked module dir, .mesh-build link, a link inside the module still packed), each made at run time with t.TempDir/os.Symlink; the refusal tests fail on main. mesh-controller.try passed at fcca6ba9 (7m21s) and at 0caa8c68 (build-1792575972135120157, 8m55s).
Left open from the review: issue 1616 (reads whose content is not shipped), issue 1627 (a launcher written outside the module through a link or .. in an entrypoint).
Issue 1609 (security; build-agent builds every delivered module until R4e). A repository could commit a link and make build-agent pack and publish files the build account can read outside the module:
- a symlinked module directory: `inside()` (internal/builder/builder.go ~947) now resolves the fetched tree and the module directory with filepath.EvalSymlinks and refuses a module directory outside the tree;
- a symlinked parent of an archive's `from`: `archiveRoot` (~1369), called from the archive case of `one`, refuses a resolved root outside the resolved module directory;
- a committed `.mesh-build` link: `outsideTheModule` (~1392, follows links of the deepest existing part) is checked in `compile` before MkdirAll, in `bundled` on `final`, and before `pack(compiled)` in the bundle case.
`pack` still gets the unresolved paths, so no digest of a legitimate tree changes; links that stay inside the module still work.
Tests: internal/builder/archive_symlink_test.go (symlinked parent of from, symlinked module dir, `.mesh-build` link, a link inside the module still packed), each made at run time with t.TempDir/os.Symlink; the refusal tests fail on main. mesh-controller.try passed at fcca6ba9 (7m21s) and at 0caa8c68 (build-1792575972135120157, 8m55s).
Left open from the review: issue 1616 (reads whose content is not shipped), issue 1627 (a launcher written outside the module through a link or `..` in an entrypoint).
Reviewed-by: reviewer-1609@shanks at 0caa8c6844d9a3701f18556d516e3e3b040d89b3
mesh/merge-gate head 0caa8c6844d9 merged into trunk 0205b8f7080a — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
Deliverynovox/mesh-controller@0caa8c6844d9 — delivered since 2026-10-21T10:39:03Z
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before build-agent is judged on its first machine
Machines
mesh-controller on every machine running it: sent
build-agent on every machine running it: sent
Transitions
2026-10-21 09:57 (new) → proposed (announced): novox/mesh-controller#415's head announced
2026-10-21 10:16 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-21 10:16 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-21 10:36 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-21 10:36 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
2026-10-21 10:39 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-controller@0caa8c6844d9` — **delivered** since 2026-10-21T10:39:03Z
**Delivery plan** — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- ace: receives build-agent
- g14: receives build-agent
- novox: receives mesh-controller, build-agent
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before build-agent is judged on its first machine
**Machines**
- mesh-controller on every machine running it: sent
- build-agent on every machine running it: sent
**Transitions**
- 2026-10-21 09:57 (new) → proposed (announced): novox/mesh-controller#415's head announced
- 2026-10-21 10:16 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-21 10:16 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-21 10:36 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-21 10:36 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
- 2026-10-21 10:39 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Merge check at 0caa8c68
Judged: head 0caa8c6844d9 merged into trunk 0205b8f7080a; read beside it: mesh-catalog 0f2cee1bea4e, mesh-controller-main 0205b8f7080a, mesh-host c5c4caa2a4ab, mesh-tools e0fadc43d9dd
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
mesh/repo-check: PASS — its merge-check.sh passed
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before build-agent is judged on its first machine
read by no module's build: internal/builder/archive_symlink_test.go
Run by the build seat on ace as build-1792576657291322114 (builds --log build-1792576657291322114).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Issue 1609 (security; build-agent builds every delivered module until R4e). A repository could commit a link and make build-agent pack and publish files the build account can read outside the module:
inside()(internal/builder/builder.go ~947) now resolves the fetched tree and the module directory with filepath.EvalSymlinks and refuses a module directory outside the tree;from:archiveRoot(~1369), called from the archive case ofone, refuses a resolved root outside the resolved module directory;.mesh-buildlink:outsideTheModule(~1392, follows links of the deepest existing part) is checked incompilebefore MkdirAll, inbundledonfinal, and beforepack(compiled)in the bundle case.packstill gets the unresolved paths, so no digest of a legitimate tree changes; links that stay inside the module still work.Tests: internal/builder/archive_symlink_test.go (symlinked parent of from, symlinked module dir,
.mesh-buildlink, a link inside the module still packed), each made at run time with t.TempDir/os.Symlink; the refusal tests fail on main. mesh-controller.try passed atfcca6ba9(7m21s) and at0caa8c68(build-1792575972135120157, 8m55s).Left open from the review: issue 1616 (reads whose content is not shipped), issue 1627 (a launcher written outside the module through a link or
..in an entrypoint).Reviewed-by: reviewer-1609@shanks at
0caa8c6844Delivery
novox/mesh-controller@0caa8c6844d9— delivered since 2026-10-21T10:39:03ZDelivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
0caa8c68Judged: head
0caa8c6844d9merged into trunk0205b8f7080a; read beside it: mesh-catalog0f2cee1bea4e, mesh-controller-main0205b8f7080a, mesh-hostc5c4caa2a4ab, mesh-toolse0fadc43d9ddmesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1792576657291322114(builds --log build-1792576657291322114).