Repository navigation
Conversation
Adds the runtime operation that builds one Compose-style image inside the native VM's engine with the pinned host BuildKit client, and the isolated build network it needs. Native up does not call it yet. - Egress pools give dockerd a fixed default bridge (10.213.255.0/24, icc=false) instead of --bridge=none; isolated pools keep none. guest-build-network.sh isolates it after the engine starts (drops build traffic to the guest, the host gateway and link-local metadata; allows DNS to the guest resolvers) and writes a boot-bound readiness marker. The engine client now refuses any container create that does not name an owned network, none or a container namespace, and any connect to the default bridge, so only BuildKit RUN steps can use it. - runtime build-image --request <private 0600 file> --json: paths resolve inside the project without symlinks; the Dockerfile is read (never run) and scanned; every base image resolves to a digest-pinned manifest and is handed to BuildKit as a named build context; base images with stored ONBUILD triggers refuse. The build key covers namespace (project root + branch), paths, Dockerfile and .dockerignore bytes, target, salted argument hashes and builder/engine versions; context contents are not hashed (Compose parity). - Argument values reach the client only through its environment (--build-arg NAME); names that would change the client's own environment refuse. Labels carry a digest of the pool incarnation, never the token. - The provider lease is held only for admission and adoption, never while BuildKit runs. A shared build fence makes runtime down refuse instead of stopping the engine under a build. A per-key lock serializes builds; a building receipt found under it is a dead attempt and is recorded indeterminate before building again. - Adoption requires the same incarnation, boot and engine as admission, the metadata's config digest, linux/arm64, exactly the owned labels, no other reserved ownership labels and no image VOLUMEs. Reuse requires a verified receipt from the same checkout, incarnation and engine whose image still inspects that way. - SIGINT/SIGTERM/SIGHUP and the time budget (default 30 min, max 2 h) stop the client's whole process group (SIGTERM, then SIGKILL after 10 s). Refs HACK-1270 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The fake client now publishes its child PID atomically, cancellation waits for that published PID, and the timeout case checks the child only when the client forked it within the one-second budget. Refs HACK-1270 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
Security findingsAdvisory findings (1)ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e5eb57778f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…builds Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The default-bridge guard refuses a container create that names no network before admission is consulted, so the dispatch-level admission controls (built only with environment-launcher) now send NetworkMode none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The build client now reads a private copy of the Dockerfile bytes that were scanned and hashed, with the effective ignore rules written beside it, instead of reopening the project paths while bases resolve. Its stderr is piped through a filter that redacts every build-argument value, strips terminal control characters, cuts long lines and bounds total output before it reaches the caller, and stops writing before the operation returns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a0c58c89b5
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…esolution Closing the output forwarder no longer waits on the sink lock: it marks the sink closed, waits at most one second for a write in progress, and returns, so a caller stream that stops draining cannot hold the operation or its build fence. The time budget now starts before base-image resolution: each resolution gets the operation deadline, runs on its own thread so Ctrl-C, SIGTERM and the deadline interrupt it, and the client gets only what remains. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1ea5f339e4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…den redaction The build client now runs buildx bake with a private mode-0600 definition file that carries the argument values, the context, the pinned base contexts, labels and tag. It is removed after the run, so values never enter the client's command line or environment, which stays a fixed allowlist. Every string in the definition is escaped so bake never interpolates project text. Argument names must be plain identifiers; only names BuildKit or buildx interpret themselves (BUILDKIT_*, BUILDX_*, SOURCE_DATE_EPOCH) refuse. The output filter also redacts each value's Go-quoted, JSON-escaped and bake encoded forms. On a cut line it trims a trailing partial value from the sanitized bytes that are forwarded, not the raw ones. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f26acd9d2e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Build arguments follow Docker: an image records their values in its history, and resolved base references an argument selects are reported in receipts and results. The guide now says never to pass secrets as build arguments and points to BuildKit build secrets, which native builds do not support yet. Output redaction stays as defense in depth. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🛡️ Codex Security Review · Automatically triggered
Here are some automated security review suggestions for this pull request.
Reviewed commit: f26acd9d2e
ℹ️ About Codex security reviews in GitHub
This is an experimental Codex feature. Security reviews are triggered when:
- You comment "@codex security review"
- A regular code review gets triggered (for example, "@codex review" or when a PR is opened), and you’re opted in so security review runs alongside code review
Once complete, Codex will leave suggestions, or a comment if no findings are found.
…builds Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bake client now receives EXPERIMENTAL_BUILDKIT_SOURCE_POLICY naming a private mode-0600 policy file written beside the definition and removed with it on every path. The policy comes from build_policy::document for exactly the pinned base references the definition names as contexts. It allows those images and denies every other image and network source, including sources a base image's stored ONBUILD triggers add. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
The receipt read bound is now 64 KiB, which covers a receipt with the most base pins the scanner accepts at their longest, so a receipt a build writes can always be read again. A new end-to-end test also shows that remote ADD sources (URLs, git refs, variables, ONBUILD forms) refuse at prepare, before any build effect. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8c39b609e7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
… lock state::write publishes a receipt through <key>.pending and a rename. A process that died between the two left that file, and every later write for the key failed with AlreadyExists. Under the per-key lock, which proves no writer is live, the build now discards the leftover before writing; the committed receipt, if any, is unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3b42fdd93c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
|
Codex Review: Didn't find any major issues. 🚀 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…lled The build client now inherits the build fence and the per-key lock. A flock belongs to the open file description, so if hack-native is SIGKILLed while the client runs, both stay held until the client and anything it left running exit. runtime down keeps refusing, and a later attempt of the same key refuses with native_build_busy instead of sharing the surviving client's attempt files. An orderly return still releases both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
@codex review |
|
Codex Review: Didn't find any major issues. What shall we delve into next? Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
…overage The native-build-retention coverage row and model README said the fence is released with its holder when the coordinator dies. Since #606 the build client inherits the fence and per-key lock, so both stay held until an orphaned client exits; the model still does not cover that case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
, #612, #628, #629, #630) (#639) ## What this is Merge train batch 6 into `next`: the native image builds stack and its fixes, as one batch. Builds stay off by default: they run only with `HACK_NATIVE_BUILDS=1`, which native `up`, restart and doctor all check. Each component's reviewed head is merged with `git merge --no-ff`, in stack order. Integration conflicts are resolved in the batch's merge commits, described below. Hosted CI on this branch is the full-suite gate for the combined result. | PR | Title | Linear | Head included | Review | | --- | --- | --- | --- | --- | | #583 | feat(native): pin a BuildKit client and scan Dockerfile image references | HACK-1270 | `f21d5a04` | Codex code + security: no findings; 0 open threads | | #606 | feat(native): build Compose images in the guest engine (runtime build-image) | HACK-1270 | `460ddff2` | Codex code + security: no findings; 0 open threads | | #607 | feat(native): admit build storage, budget build cache and reclaim superseded build images | HACK-1270 | `9f33a1d0` | Codex code + security: no findings; 0 open threads | | #612 | feat(native): build Compose build services in native up behind HACK_NATIVE_BUILDS | HACK-1270 | `7f42e328` | Codex clean at `8ec7460e`; `7f42e328` adds #628's squash (re-review requested) | | #628 | fix(native): admit native build fields and name services in build refusals | HACK-1925 | `f07ea583` | Codex code + security clean; already squashed into #612's branch | | #629 | fix(native): keep the VM responsive during image builds and stop a silent guest | HACK-1924 | `a0e3e797` | Codex code + security: no findings; 0 open threads | | #630 | fix(native): restore a sourceless graph after its project files were touched | HACK-1914 | `a93db842` | Codex clean at `009989c7`; `a93db842` only merges #629 into it (re-review requested) | ## Security properties in the merged code - **Build arguments:** they reach the BuildKit client only through a private 0600 bake definition, never its environment. The client environment is cleared to an allowlist. Names must be plain identifiers, and BuildKit-interpreted names such as `BUILDKIT_*`, `BUILDX_*` and `SOURCE_DATE_EPOCH` are refused. A build argument equal to a managed secret value is refused without echoing the value. Build arguments are not secrets, matching Docker. - **Source policy:** a source policy from `build_policy::document`, set through `EXPERIMENTAL_BUILDKIT_SOURCE_POLICY` in a private file, applies to every build. It allows only the scanner's digest-pinned base images and denies other images, `oci-layout`, `http`, `https`, `git` and blob sources. Pinned bases whose config has `OnBuild` triggers are refused. - **Dockerfile scanner:** - remote `ADD` sources are refused, including the JSON form, multiple sources and variables; - JSON-form arguments are read as BuildKit reads them, and a lenient-decode differential fails closed; - heredocs are recognized as BuildKit's lexer does, including whitespace after `<<`; - a stage named `scratch` is refused; - `ARG` names must be plain identifiers; - platform arguments must resolve to `linux/arm64`; - expanded values are size-bounded. - **Build output:** forwarded output is sanitized and then redacted, including Go-quoted and JSON-escaped forms and values split across a line cut. It is bounded by size. ## Integration changes - **#606 with #605 / #609:** `resolve_build_base` runs on #605's guarded registry client, so the resolver and address policy, origin-bound authentication and the realm rules apply. It uses #609's native platform selection, so builds stay Docker Hub and linux/arm64 only. The older Docker Hub-only fetch helpers are dropped. - **#606 / #607 with #605 / #609 / #615:** the `build-image` and `reclaim-build-images` commands sit beside the image-policy and emulation options. The build error helpers take `impl Into<ErrorMessage>`. - **#607:** the native-build-retention TLA+ contract is registered beside the restart-policy, pool-emulation and multi-root contracts. Its model-coverage row now says an orphaned build client keeps the fence and per-key lock until it exits (`9f33a1d0`). - **#612 with batch 5:** - The builds-enabled classification flows through `classifyAdapted`, the Compose-backend refusal and doctor. - With the gate off, native `up` refuses a build with a message that names `HACK_NATIVE_BUILDS`, so doctor's basic-build advice names it too; one test expectation changed to match. - Startup and restart keep the dependency-file selection, host aliases, emulation policy and the inactive-profile skip alongside the build services. - **New (#609 x #612):** a build service whose adaptation selects amd64 emulation is refused before any effect, because native builds are linux/arm64 only. `prefer-native` passes, and a test covers it. - **#629:** the socket cleanup after a clean stop is kept inside #629's new guest stop. #629's two flaky relay tests are fixed on its branch (`a0e3e797`): each test gets its own fixture root, and EINVAL from `set_read_timeout` after the peer closes is accepted. - **`next` merge:** the last merge brings in Kit's CI shard and SIGKILL harness changes (#624, #627). The commit hook formatted `tests/native-compose-generation.test.ts` with Biome, a whitespace-only change to that Kit file. ## Validation on this branch (`6337e0ed`) - Clean CLI typecheck: pass. Biome on the 20 changed files: no errors. - `RUSTUP_TOOLCHAIN=1.97.1 bun run check:local`: pass. All-features clippy `-D warnings` (Zig 0.15.2): pass. - Cargo `--lib`: 1346 pass. `--features native-config-plan` `provider::graph`: 673 pass. Contracts: `project_contract` 66, `compose_fields_contract` 10, `interpolation_budget_contract` 1, `local_contract` 14. - `bun run test:models` (TLA+ 1.7.4): exit 0, 172 controls verified. - Focused bun tests, bounded runner, the changed test files: 242 pass, 0 fail. - `docs:prepare` + `docs:check`, `privacy:check`, gitleaks over `origin/next..HEAD`: pass. Host evidence: 11 of 11 builds passed on an M5 host with the relay (#629). Still open: the source-policy host check (a pinned build succeeds, and a base trigger that pulls an unpinned image or fetches https fails with "denied by policy") and the bake `--allow fs.read` / metadata shape on the pinned buildx 0.34.1. Both are listed in #606. After this merges, each component PR is closed with a link to the merge commit. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- codesmith:footer --> --- <a href="https://backend.blacksmith.sh/track/run-proof?expires=1796625833&installation_model_id=17053&pr_number=639&ref=codesmith_pr_footer&repository=hack-dance%2Fhack&return_to=https%3A%2F%2Fgithub.com%2Fhack-dance%2Fhack%2Fpull%2F639&variant=see_it_in_action&signature=c3ba624f6f34813ba26773c5b4c3caf941bd59515e8c3016c92df8f0e2a6048f"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-see-it-in-action-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/proof-see-it-in-action-light.svg"><img alt="See it in action" src="https://pr-comments-assets.blacksmith.sh/codesmith/proof-see-it-in-action-dark-3x.png" width="132" height="28"></picture></a> <sup><a href="https://app.blacksmith.sh/hack-dance/codesmith/hack/pr/639?autoLogin=true&ref=codesmith_pr_footer">Open in [code]smith</a> · Need help on this PR? Tag <code>@codesmith-bot</code> with what you need.</sup> <!-- codesmith:autofix:disabled --> <!-- /codesmith:footer --> --------- Co-authored-by: Dimitri Kennedy <344842+roodboi@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged into 🤖 Addressed by Claude Code |
Summary
Stacked on #583 (
claude/native-build-groundwork); review only the top two commits. Covers units NB2 (build network) and NB4 (runtime build-image) of native Composebuild:support. Nativeupdoes not call the new operation yet, so no user-visibleupbehavior changes. The frontend wiring comes in a later PR of this stack.Build network (NB2)
Egress pools (
internet,approved-hosts,host-gateway) now start dockerd with a fixed default bridge,--bip=10.213.255.1/24 --icc=false, instead of--bridge=none. The range is outside Docker's default address pools, so owned project networks keep their allocations. Isolated pools keep--bridge=none, and builds refuse on them.guest-build-network.shruns after the engine is ready. It isolatesdocker0:100.96.0.1and to169.254.0.0/16;Docker's own isolation chains already drop default-bridge to project-bridge traffic. A failure here does not fail pool startup, because graph containers never use the bridge; builds then refuse on that pool.
The engine client now refuses, before dispatch, any container create whose
HostConfig.NetworkModeis unset,default,bridgeorhost, and any connect to the default bridge. Only BuildKitRUNsteps can therefore use that bridge.runtime build-image --request <private file> --json(NB4)0600JSON file owned by the user. The context and Dockerfile resolve inside the project without symlinks (the existingsource::resolve). The Dockerfile and.dockerignorefiles must be bounded, singly linked regular files.registry_image::resolve_build_base, digest refs must match their pin). Each one is handed to BuildKit as a named context<name>=docker-image://docker.io/<repo>@<digest>in the private bake definition. A base image whose stored configuration hasONBUILDtriggers refuses. That closes the gap feat(native): pin a BuildKit client and scan Dockerfile image references #583 listed..dockerignorebytes, target, salted argument hashes, platform, and the buildx and engine versions. Other files in the context are not hashed, matching Compose: an existing image is reused until an explicitrebuild. Base-image tags resolve only when a build runs. Each project root and worktree gets its own namespace, so one shared pool can host many of them.buildx bakewith a private mode-0600definition file. The file carries the context, a private copy of the scanned Dockerfile and ignore rules, the pinned base contexts, labels, tag and argument values, and it is removed after the run on every path. Argv carries only paths and fixed flags. The client environment is a fixed allowlist: an empty privateDOCKER_CONFIGandBUILDX_CONFIG(no contexts, credential helpers or proxies), the verified forwarded engine socket and the source policy path. Every string in the definition is escaped so bake never interpolates project text. Names must be plain identifiers;BUILDKIT_*,BUILDX_*andSOURCE_DATE_EPOCHrefuse. Image labels carry a digest of the pool incarnation, never the token itself.base_pinsin the receipt and the result. The guide says to use BuildKit build secrets for secrets (not yet supported natively). Forwarded client output still redacts argument values, including their Go-quoted, JSON-escaped and bake-encoded forms, and strips terminal controls within fixed bounds (16 KiB lines, 4 MiB total), as defense in depth. Nativeup(feat(native): build Compose build services in native up behind HACK_NATIVE_BUILDS #612) refuses a build arg equal to a managedhack envsecret.EXPERIMENTAL_BUILDKIT_SOURCE_POLICYnaming a private mode-0600file. It holdsbuild_policy::document(feat(native): pin a BuildKit client and scan Dockerfile image references #583) for exactly the pinned base references, sits beside the definition and is removed with it. The policy deniesdocker-image://*andoci-layout://*except the exact pinned references, and denieshttp,https,gitanddocker-image+blobsources. It is applied here, and it covers sources a base image's storedONBUILDtriggers add (such bases already refuse during resolution).flockfence is taken under the lease and held for the whole operation.runtime downchecks that fence under its own lease and refuses withprovider_busyinstead of stopping the engine under a build. A per-key lock serializes builds of one key.run/image-builds/<namespace>/<key>.json. Abuildingreceipt found under the key lock belongs to a dead attempt. It is recordedindeterminateand the image is built again; no operator action is needed.containerimage.config.digest, and the image must belinux/arm64. It must carry exactly the owned labels, no other reserved ownership labels (com.docker.compose.*,io.hack-local.*,io.hack.native-config.*,io.hack.native-file.*,io.hack.storage-witness.*), and no imageVOLUMEs.Validation
RUSTUP_TOOLCHAIN=1.97.1 bun run check:local: pass. All-features Clippy with-D warnings(Zig 0.15.2): pass.Focused tests:
cargo test --lib -- image_build engine::tests registry_image build_scan: 65 passed, after rebasing onto the current feat(native): pin a BuildKit client and scan Dockerfile image references #583 head. They cover:/bin/shreading a script from the client's private directory), with argv and environment inspected: values never reach argv or receipts;rebuild, incarnation change, a missing image and relabeled images;guest-daemon.shargument matrix per network mode, and the network script syntax and modes;ONBUILDdetection.The image-build tests were repeated 5 times under load.
Full
cargo testfrom a short-path checkout of this diff before the rebase: 21 binaries, 1300 passed, 1 failed, 109 ignored. The one failure was this PR's own cancellation test reading the child PID before it was written. It is fixed in the second commit: the PID is now published atomically. The rebase brought in only the two scanner commits from feat(native): pin a BuildKit client and scan Dockerfile image references #583. In an earlier run from a/tmpsymlinked path,resources::tests::explicit_root_binding_requires_exact_executablealso failed. That is a symlinked-path artifact of where the run started; it passes from the canonical path.bun run --cwd packages/cli typecheck: pass.bun run docs:prepare && bun run docs:check: pass.tests/prerelease-plan.test.tsandtests/native-candidate-authored-artifact.test.ts, which read the native candidate guide: 64 pass. This PR changes no TypeScript.I did not run the full Bun suite locally because the host is loaded; hosted CI runs it.
gitleaks (staged and
origin/next..HEAD): no leaks.Remaining gaps and host evidence still needed
None of these were faked; each needs a prepared private candidate home on Apple Silicon:
H1. The host buildx (docker driver) must work over the smolvm-forwarded engine socket, including BuildKit's
/sessionand/grpcupgrade. If it does not, the client moves into the guest, as the feat(native): pin a BuildKit client and scan Dockerfile image references #583 notes describe.H2. BuildKit
RUNwith network must work on the newdocker0under--internetand--allow-host. The negative controls must hold: a buildRUNcannot reach a running project container's IP, the guest relays, or100.96.0.1. DNS must work through the guest resolvers. Existing graphs must be unaffected after a pool restart.H3. Named build contexts must match the scanner's short names for
FROM, ARG-substitutedFROMandCOPY --from=<image>.H5 (required for the stack): source policy on a real build. With the pinned buildx and engine:
ONBUILDtrigger pulls an unpinned image, or runsADD https://…, fails with "denied by policy";docker-image://docker.io/<repo>@<digest>identifier the policy allows.Not run here.
H6.
buildx bakespecifics on the pinned client (0.34.1).--allow fs.read=<context>and--allow fs.read=<private Dockerfile dir>must satisfy bake's filesystem entitlements. The metadata file must be keyed by the target ({"build": {"containerimage.config.digest": …}}). HCL escaping of definition strings was checked withbake --printon buildx 0.37.2 only.H4. The built image
Idmust equal the metadata'scontainerimage.config.digestwith the overlay2 store, and the labels must be present.Behaviors on a real VM.
/v1.53/infomust expose a stableID.--build-arg NAMEmust read the value from the environment. A cold and a warm build of a small public-image fixture, cancellation mid-RUN, and a VM stop mid-build (thenindeterminate, then success) must all behave as described.Base images are anonymous Docker Hub only. Any-registry base images (Nov 5 decision) depend on the registry generalization in flight elsewhere.
resolve_build_baseand the scanner's reference check are the seams to widen, and private registries would also need the client'sDOCKER_CONFIGto read the host's credential helpers read-only. Not done here.amd64 and Rosetta.
platform: linux/amd64builds (Rosetta, opt-in) are not supported; builds arelinux/arm64only.Orphaned client. If
hack-nativeitself is killed (SIGKILL), the client can outlive it. The client inherits the build fence and the per-key lock, so both stay held until it exits.runtime downkeeps refusing and the same key refusesnative_build_busy; a test covers this with a SIGKILLed coordinator process. The receipt staysbuilding, and the next run after the client exits recovers.Refs HACK-1270
🤖 Generated with Claude Code
Open in [code]smith · Need help on this PR? Tag
@codesmith-botwith what you need.