8000 feat(minimald): put the proxy's root certificate in a grant box's trust store by minimal-foundry[bot] · Pull Request #2495 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(minimald): put the proxy's root certificate in a grant box's trust store - #2495

Merged
norrietaylor merged 9 commits into
mainfrom
agent/2274-put-the-interception-root-in-the-box-s-trust-sto
Oct 23, 2026
Merged

norrietaylor merged 9 commits into
mainfrom
agent/2274-put-the-interception-root-in-the-box-s-trust-sto

Conversation

@minimal-foundry
@minimal-foundry minimal-foundry Bot commented Oct 23, 2026 •
Copy link
Copy Markdown
Contributor

T16 — Put the interception root in the box's trust store

slice: S0
kind: task
covers: BEP-011
size: L
est: 330 code, 420 tests
executor: agent
difficulty: needs care
model: standard
diagnostics: a box spec that sets one of the three trust variables itself keeps its value and activation prints "This box sets itself, so tools that read it will not trust the proxy's certificate." on stderr, pinned by spec_trust_env_shadows_platform_with_warning
observability: one debug log line per box naming whether the root was injected
layers:
- carry:
- crates/boxes/src/lib.rs: Record.root_certificate, the proxy's root certificate PEM beside sealed_deliveries, so every host launch of the box reads it, after a daemon restart included (stale layers found by the coder on 2026-10-22; the record fixtures are struct-literal additions)
- crates/minimald/src/box_manager.rs: the record build copies config.root_certificate from the create request
- crates/minimald/src/box_manager/tests.rs: the record test
- crates/minimald/src/box_runtime/launcher.rs: the launch hands the record's root certificate to EnvArgs, so Env::build writes the box's bundle copy and hashed directory
test: cargo nextest run -p minimald record_carries_the_root_certificate_to_the_launch
- trust:
- crates/minimald/src/env.rs: the root in the box's own bundle copy and hashed directory, per BEP-011, never the package store's copy
- crates/minimald/src/box_runtime.rs: the trust variables of BEP-011
- crates/minimald/src/box_runtime/tests.rs: the trust-variable tests
- scripts/session-e2e.sh: adds three cases
test: ./scripts/session-e2e.sh bep_root_ca_present_in_box_trust_store
test: ./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream
test: ./scripts/session-e2e.sh bep_trust_env_points_at_bundle_and_root
- spec:
- crates/boxes/src/core/bep.rs: the warning for a spec that sets a trust variable
test: cargo nextest run -p boxes spec_trust_env_shadows_platform_with_warning
produces: none
consumes:
- crates/minimald-rpc/src/lib.rs
- crates/boxes/src/core/bep.rs
proof: A grant box has the root in both trust-store forms, and a box with no grant has none.
depends on:
- blocked by #2264
- blocked by #2273
- blocked by #2488

Layer exception

Nine files outside T16's layers: carry changes the task cannot avoid, accepted under the epic's layer-exception rule of 2026-10-19; the babysitter undrafted the PR on them.

  • crates/boxes/src/store.rs, crates/minimal-client/src/box_registration.rs, crates/minimal/src/cmd/boxes/vm_host.rs, crates/minimal/src/dash/render.rs, crates/minimal/src/dash/rpc.rs, crates/minimal/tests/dash_snapshots.rs, crates/minimald/src/exec/tests.rs, crates/minimald/src/store.rs: one root_certificate: None line each in a Record struct literal, the fixtures the plan's carry layer anticipates.
  • crates/minimald/src/box_actor/launcher.rs: two lines that hand the record's root to the launcher, where the launcher literal is built.
  • crates/minimal/src/cmd/boxes/create.rs (round 1): the call to warn_spec_trust_env with the spec's own variable names, where the activation plan is projected, so min prints the BEP-011 warning the plan's diagnostics line requires; the arch review's C1 asked for it there.

Evidence from CI

The Linux native lane at 0753734d (run 39877721856, job native-daemon-e2e 120167546161) ran the no-grant leg of bep_root_ca_absent_from_box_without_credentialed_upstream on a target with no proxy and it passed:

::group::box with no grant: no proxy root in its trust store (BEP-011)
box with no grant: no proxy root in its trust store
session e2e OK

The exit 1 in the Tests table below is the coder's sandbox, where min session exec in the plain box failed before the check ran. Recorded by the babysitter for the arch review's C2.

Residuals

  • The three grant legs (bep_root_ca_present_in_box_trust_store, the grant half of bep_root_ca_absent_from_box_without_credentialed_upstream, bep_trust_env_points_at_bundle_and_root) record NOT RUN until a live proxy runs beside gvproxy on the macOS lane. Filed on T18 #2275, whose e2e layer now names them (arch C2 at 947ab1f9).

Proof

A box created with a GitHub grant now launches with the proxy's root certificate at /etc/ssl/certs/minimal-box-egress-proxy-root.pem, appended to its own copy of /etc/ssl/certs/ca-certificates.crt, and linked as /etc/ssl/certs/.N. Its SSL_CERT_FILE and REQUESTS_CA_BUNDLE name the bundle, and NODE_EXTRA_CA_CERTS names the root. A box with no grant gets no root file, no link and no trust variables. The unit tests show this. The e2e cases that show it inside a real box did not run on this Linux box.

Notes from the agent: Out-of-layer files: crates/minimald/src/box_actor/launcher.rs sets SandboxLauncher.root_certificate from the record (the launcher literal is built there). Adding Record.root_certificate needed root_certificate: None in struct-literal fixtures in crates/boxes/src/store.rs, crates/minimal-client/src/box_registration.rs, crates/minimal/src/cmd/boxes/vm_host.rs, crates/minimal/src/dash/rpc.rs, crates/minimal/src/dash/render.rs, crates/minimal/tests/dash_snapshots.rs, crates/minimald/src/store.rs and crates/minimald/src/exec/tests.rs. The task's layer note for lib.rs anticipates these fixtures.
Not done: BepWarning::TrustEnvSetBySpec and ActivationPlan::warn_spec_trust_env exist and are tested in crates/boxes/src/core/bep.rs, but no caller passes the spec's variable names yet. The call belongs in crates/minimal/src/cmd/boxes/create.rs (where the activation plan is projected), which is outside the layers. So min does not print the warning yet. The warning fires only when the plan injects the root (inject_ca).
The spec value wins over the platform trust variables because they go on the launcher's baseline env layer, below the composition (tested by trust_env_keeps_a_spec_value).
The root is injected only when the record carries a root, the policy has a credentialed upstream, and steering is not Off. env.rs logs one debug line per box saying whether it was injected.
env.rs writes the bundle at /etc/ssl/certs/ca-certificates.crt. …[truncated]

Tests

line exit tail
cargo nextest run -p minimald record_carries_the_root_certificate_to_the_launch 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-eaa2... Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling stdlib v0.0.22 (/workbenc
./scripts/session-e2e.sh bep_root_ca_present_in_box_trust_store 0 the 'min' and 'minimald' under /work/build-cache/target/debug report different versions; rebuilding the pair no usable 'min' and 'minimald' pair on PATH or under target/; building the pair this run drives (cargo build --locked -p minimal --bin min -p minimald --bin minimald) built the pair: /work/bu
./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream 1 ::group::box with no grant: no proxy root in its trust store (BEP-011) bep_root_ca_absent_from_box_without_credentialed_upstream_beside_a_grant_box: NOT RUN (the Box Egress Proxy runs on macOS only) ::error::'min session exec' in the plain box for bep_root_ca_absent_from_box_without_credentialed_ups
./scripts/session-e2e.sh bep_trust_env_points_at_bundle_and_root 0 ::group::GitHub grant box: SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS (BEP-011) bep_trust_env_points_at_bundle_and_root: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_trust_env_points_at_bundle_and_root session e2e OK Applying loado
cargo nextest run -p boxes spec_trust_env_shadows_platform_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-2bca... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench

Verify

min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

the sandbox ran rustc (1.98.1), the repository pins 1.97.0 in rust-toolchain.toml; a failure here may be the newer toolchain's, not this change's
Applying loadouts: default
Running task runtime-implement-verify in session task-runtime-implement-verify-5769...
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking args v0.0.1 (/workbench/crates/args)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking common v0.0.1 (/workbench/crates/common)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking graph v0.0.1 (/workbench/crates/graph)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Out of scope

These files are outside the task's layers:, so this PR is a draft:

  • crates/boxes/src/store.rs
  • crates/minimal-client/src/box_registration.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/dash/render.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimal/tests/dash_snapshots.rs
  • crates/minimald/src/box_actor/launcher.rs
  • crates/minimald/src/exec/tests.rs
  • crates/minimald/src/store.rs

Closes #2274


Generated by Claude Code

BEP-011: the box record carries the root certificate the create requ
8000
est
handed it, so every host launch reads it, after a daemon restart included.
A launch of a box with a credentialed upstream and steering other than
off writes the root into the box's own copy of the CA bundle and links it
in /etc/ssl/certs under its OpenSSL subject hash. Each file is a new file,
never a write through the package store's hardlink. SSL_CERT_FILE,
REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS sit below the composition, so a
spec value stays. One debug line per box says whether the root went in.
BEP-011: ActivationPlan::warn_spec_trust_env adds a warning that names
each of SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS the
spec's environment sets, for a box that gets the proxy's root.
@coderabbitai
coderabbitai Bot commented Oct 23, 2026 •
Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 348ff500-b0ab-4360-b0c0-26d77b08c3f5

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

Adds three session-e2e cases: the root in both trust-store forms, no
root in a box with no grant, and the trust variables.
A target dir can hold a min and a minimald from two builds, one from a
dirty tree. The CLI then refuses the daemon at the first activate. The
script now rebuilds such a pair, and reruns the version build script so
both halves get one version.
@norrietaylor
norrietaylor force-pushed the agent/2274-put-the-interception-root-in-the-box-s-trust-sto branch from ba36c5d to 0753734 Compare October 23, 2026 00:22
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter review of T16 against its plan block, at 0753734d.

Layer carry. Record.root_certificate sits beside sealed_deliveries with the same serde shape, the record build in box_manager.rs copies it from the create request, and record_carries_the_root_certificate_to_the_launch pins the copy, the JSON round trip, the off-steering refusal and the no-grant case. box_runtime/launcher.rs moves the root into the env build and the trust variables onto the baseline layer. Present as the amended plan asks.

Layer trust. env.rs writes the root into the box's own trust store in both forms: the root alone, the box's own bundle copy with the root appended, and the <subject hash>.N link in the hashed directory. Each file is written as a new file after the old name is removed, so a hardlink to the package store keeps its target, and a link resolves inside the rootfs. Three unit tests pin the copy-never-the-store rule, the in-rootfs link rule and the refusal of a non-certificate. box_runtime.rs sets SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS only when the root is injected, below the composition, so a spec's own value wins; two tests pin that. The root is injected only for a box with a credentialed upstream whose steering is not off, which matches BEP-010. scripts/session-e2e.sh adds the three cases the plan names, wired into the full run, the dispatcher and the usage text; they record NOT RUN on every CI lane today, because they need a running proxy, which T18 #2275 brings.

Layer spec. BepWarning::TrustEnvSetBySpec and ActivationPlan::warn_spec_trust_env exist with the plan's exact text, pinned by spec_trust_env_shadows_platform_with_warning. Nothing calls them yet: the agent's notes say the call belongs in crates/minimal/src/cmd/boxes/create.rs, outside the layers, so min does not print the warning the plan's diagnostics line requires. The babysitter asks for that one-line call in a /revise and accepts the file under the layer-exception rule.

Out of the layers. Eight files gain root_certificate: None in record struct literals, which the plan's carry layer anticipates; crates/minimald/src/box_actor/launcher.rs gains two lines that hand the record's root to the launcher. Accepted under the epic's layer-exception rule; the body's "Layer exception" section records them, and the babysitter undrafts the PR.

For the reviewers. env.rs carries its own SHA-1, base64 decoder and X.509 subject canonicaliser (about 400 lines with tests) to compute OpenSSL's subject hash for the link name, because minimald holds no X.509 or digest crate. The hash is checked against two openssl-issued fixtures. A sha1 crate would drop the digest; the canonicaliser would stay. Whether that trade is right is the reviewers' call.

Commits. Two commit bodies had lines over 100 columns, which commitlint refuses. Under the epic's commitlint rule the babysitter reworded them in place (4ab8fa85 to fa732d3c, ba36c5d7 to 0753734d), content and author unchanged, and force-pushed with lease. Every commit now passes commitlint.

No blocking findings of my own.


Generated by Claude Code

@norrietaylor
norrietaylor marked this pull request as ready for review October 23, 2026 00:24
@norrietaylor
norrietaylor requested a review from a team as a code owner October 23, 2026 00:24
Copy link
Copy Markdown
Member

/revise Wire the BEP-011 warning the plan's diagnostics line requires. ActivationPlan::warn_spec_trust_env and BepWarning::TrustEnvSetBySpec exist in crates/boxes/src/core/bep.rs, but nothing calls them, so min never prints "This box sets itself, so tools that read it will not trust the proxy's certificate." Add the one call in crates/minimal/src/cmd/boxes/create.rs, where the activation plan is projected: pass the names of the variables the box spec's own environment sets, so the warning joins the plan's warnings and prints on stderr the way the other BepWarnings do. That file is outside the layers; the babysitter accepts the call under the epic's layer-exception rule, so make it and nothing else there. Pin it with a test in crates/minimal/src/tests.rs or the create module's tests: a spec with SSL_CERT_FILE in its environment and a GitHub grant prints the warning, a spec without it prints none. Change nothing else.


Generated by Claude Code

@minimal-foundry
minimal-foundry Bot commented Oct 23, 2026 •
Copy link
Copy Markdown
Contributor Author

Approved: no findings at d5be6688bab2.

Nothing to do.

Verdict APPROVE, posted as a comment: the App cannot review its own pull request; the check and the label carry it.

Clobber: none seen.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 2 findings, 2 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread crates/boxes/src/core/bep.rs Resolved
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: CONDITIONS · 3 conditions · the full ruling

The trust-store write is in the right place and follows the iff of Gatehouse §6.10. Three items remain. First, the shadow warning that §6.10 line 821 requires is never printed, because warn_spec_trust_env has no caller. Make the change in C1. Second, the no-grant e2e leg exited 1 on Linux. Make it pass, as C2 says. Third, a box with no CA bundle in its packages gets trust variables that name a root-only file, which breaks the additive rule. Make the change in C3.

Ruled at 0753734 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread crates/boxes/src/core/bep.rs Resolved
Comment thread scripts/session-e2e.sh Resolved
Comment thread crates/minimald/src/env.rs Resolved
The activation passes the names of the variables the project's
minimal.toml sets to warn_spec_trust_env, so a grant box that sets
SSL_CERT_FILE, REQUESTS_CA_BUNDLE or NODE_EXTRA_CA_CERTS itself prints
the BEP-011 warning on stderr with the other activation warnings.
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter review of T16 at 947ab1f9 (round 1).

The round changes crates/minimal/src/cmd/boxes/create.rs alone, the one-line layer exception the /revise named plus its plumbing: project_bep_and_grants now also returns the names of the variables the box spec's own environment sets, refuse_unhonourable_grants calls warn_spec_trust_env with them before it prints the plan's warnings, and the function returns the warnings so a test can read them. spec_trust_env_warns_at_activation pins the exact text for a spec that sets SSL_CERT_FILE with a GitHub grant, and no warning without it. That is the arch review's C1 and both of the code reviewer's MEDIUM findings. The existing callers are updated and nothing else moves.

Open from the ruling at 0753734d: C2, the no-grant e2e leg on Linux, and C3, the root-only bundle when the packages ship none. Both go in the next round.

No blocking findings of my own.


Generated by Claude Code

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — approval withheld

Verdict COMMENT — APPROVE withheld: 5 unresolved threads — minimal-foundry[bot] crates/boxes/src/core/bep.rs:722, minimal-foundry[bot] crates/boxes/src/core/bep.rs:723, minimal-arch[bot] crates/boxes/src/core/bep.rs:707, minimal-arch[bot] scripts/session-e2e.sh:11834, minimal-arch[bot] crates/minimald/src/env.rs:922. No findings.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: CONDITIONS · 2 conditions · the full ruling

The trust-store code conforms to Gatehouse §6.10 lines 819 and 821. The node writes the root in both forms, additive, and only for a grant box with steering on. The compare wires the shadowing warning at activation, as line 821 requires. The proof is open. The no-grant leg exited 1 on Linux, and C1 fixes that. The grant legs are NOT RUN, and C2 runs them on the macOS lane.

Ruled at 947ab1f against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread scripts/session-e2e.sh Resolved
Comment thread scripts/session-e2e.sh Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 1 of 10 on a /revise note, pushed as 947ab1f90cb2.

line exit tail
cargo nextest run -p minimald record_carries_the_root_certificate_to_the_launch 0 s v0.1.1 Compiling google-cloud-auth v1.17.0 Compiling xattr v1.6.1 Compiling tonic-prost v0.14.6 Compiling jaq-all v0.3.0 Compiling tar v0.4.46 Compiling google-cloud-gax-internal v0.7.20 Compiling ot v0.0.1 (/workbench/crates/ot) Compiling aead v0.6.1 Compiling aes-gcm v
./scripts/session-e2e.sh bep_root_ca_present_in_box_trust_store 0 the 'min' and 'minimald' under /work/build-cache/target/debug report different versions; rebuilding the pair no usable 'min' and 'minimald' pair on PATH or under target/; building the pair this run drives (cargo build --locked -p minimal --bin min -p minimald --bin minimald) built the pair: /work/bu
./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream 1 ::group::box with no grant: no proxy root in its trust store (BEP-011) bep_root_ca_absent_from_box_without_credentialed_upstream_beside_a_grant_box: NOT RUN (the Box Egress Proxy runs on macOS only) ::error::'min session exec' in the plain box for bep_root_ca_absent_from_box_without_credentialed_ups
./scripts/session-e2e.sh bep_trust_env_points_at_bundle_and_root 0 ::group::GitHub grant box: SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS (BEP-011) bep_trust_env_points_at_bundle_and_root: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_trust_env_points_at_bundle_and_root session e2e OK Applying loado
cargo nextest run -p boxes spec_trust_env_shadows_platform_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-f027... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

nning task runtime-implement-verify in session task-runtime-implement-verify-6618...
    Checking opentelemetry v0.33.1
    Checking args v0.0.1 (/workbench/crates/args)
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking paths v0.0.1 (/workbench/crates/paths)
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking opentelemetry_sdk v0.33.1
    Checking tracing-opentelemetry v0.34.0
    Checking opentelemetry-http v0.33.1
    Checking opentelemetry-appender-tracing v0.33.1
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking wait-timeout v0.2.1
    Checking google-cloud-gax-internal v0.7.20
    Checking opentelemetry-proto v0.33.0
    Checking bit-vec v0.10.1
    Checking quick-error v1.2.3
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking rusty-fork v0.3.1
    Checking bit-set v0.11.1
    Checking opentelemetry-otlp v0.33.0
    Checking rand_xorshift v0.5.0
    Checking google-cloud-longrunning v1.14.0
    Checking google-cloud-iam-v1 v1.13.0
    Checking core_detect v1.0.0
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking unarray v0.1.4
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking proptest v1.12.0
    Checking google-cloud-lro v1.11.0
   Compiling serial_test_derive v4.0.1
    Checking google-cloud-storage v1.20.0
    Checking serial_test v4.0.1
    Checking common v0.0.1 (/workbench/crates/common)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking rcache v0.0.1 (/workbench/crates/rcache)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Outside the task's layers::

  • crates/boxes/src/store.rs
  • crates/minimal-client/src/box_registration.rs
  • crates/minimal/src/cmd/boxes/create.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/dash/render.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimal/tests/dash_snapshots.rs
  • crates/minimald/src/box_actor/launcher.rs
  • crates/minimald/src/exec/tests.rs
  • crates/minimald/src/store.rs

Converted to a draft: something above needs a person before review.

A grant box has the root in both trust-store forms, and a box with no grant has none. This round adds one more fact: min now prints "warning: This box sets SSL_CERT_FILE itself, so tools that read it will not trust the proxy's certificate." on stderr when the start begins for a grant box whose minimal.toml sets that variable. A spec that does not set a trust variable prints no such warning.

Notes from the agent: Revise round 1: I did what the /revise note asked, in crates/minimal/src/cmd/boxes/create.rs only. That file is outside the layers, and the note accepts it as a layer exception. project_bep_and_grants also returns the names from [session] vars and vars_lenient. refuse_unhonourable_grants takes those names, calls ActivationPlan::warn_spec_trust_env, prints each warning with the same warning: prefix as before, and returns the warnings so the test can pin the text. The three existing tests of these functions needed only the new argument. The new test is spec_trust_env_warns_at_activation, in the create module's tests. It checks the returned warnings, which are the lines the function prints. It does not capture stderr itself. In this round I did not run the minimald line or the session-e2e lines again, because this change does not touch those paths. cargo clippy -p minimal --all-targets reports nothing in create.rs. I did not run just clippy-strict.

Copy link
Copy Markdown
Member

/revise Act on the arch review's C3 at 0753734d (thread 4354938597, crates/minimald/src/env.rs): when the box's packages ship no CA bundle, install_root_certificate writes a bundle that holds the root alone, and the launch then points SSL_CERT_FILE and REQUESTS_CA_BUNDLE at it, so a stack that reads those loses the public roots. In that case keep the root-only file and the hashed-directory link, write no bundle, set NODE_EXTRA_CA_CERTS alone, and say so on the debug line env.rs already writes. Have the install report whether a bundle exists, and have launch_trust_env set the two bundle variables only when it does. Pin both cases in trust_env_points_at_bundle_and_root and in the env.rs test that builds a rootfs with no system bundle. Change nothing else.


Generated by Claude Code

@norrietaylor
norrietaylor marked this pull request as ready for review October 23, 2026 00:45
When a grant box's packages ship no CA bundle, the root no longer
becomes a bundle of its own. The box keeps the root file and its
hashed-directory link, and only NODE_EXTRA_CA_CERTS names the root.
SSL_CERT_FILE and REQUESTS_CA_BUNDLE are set only when the box has a
bundle, so a tool that reads them keeps its public roots.

The env build sets the trust variables now, below the composed ones,
because it is where the bundle is known before the rootfs is built.
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling

The compare stops writing a root-only bundle when the packages ship no CA bundle. Gatehouse §6.10 line 821 makes the anchor additive and never anchor-only, so this is the correct behaviour. The box keeps the root file and the hashed link. Only NODE_EXTRA_CA_CERTS names the root, because no merged bundle exists. BEP-011 conforms. C1 is open: the three grant e2e legs must pass under #2275 before BEP-011 is proved in a real box.

Ruled at 848cf43 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread scripts/session-e2e.sh Resolved
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — advisory review

Verdict COMMENT — 1 finding, 1 inline.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

Comment thread crates/minimald/src/env.rs Resolved
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter review of T16 at 848cf437 (round 2).

The round answers the arch review's C3. install_root_certificate now writes the box's bundle only when the packages ship one, and reports whether it did; a box with no bundle keeps the root file and its hashed-directory link and gets NODE_EXTRA_CA_CERTS alone, so a tool that reads the bundle variables keeps its public roots. The trust variables moved from the launcher's baseline layer into the env build, which knows the package layers and so whether a bundle exists, and they are added below every variable the box already holds, so a spec's own value still wins; trust_env_keeps_a_spec_value and trust_env_points_at_bundle_and_root are updated for both shapes, and the no-bundle rootfs test now asserts no bundle is written. The arch review ruled PASS_WITH_CONDITIONS at this head; its one condition is the three grant legs passing under T18 #2275, which is the residual already filed there.

Open: the code reviewer's security finding that the daemon writes the whole PEM string into the trust store and the bundle while it checks only the first certificate block, so a record PEM with extra blocks would add extra anchors. The client refuses such a PEM, but the daemon does not repeat the check. The next round makes the daemon write the first block alone or refuse more than one.

No blocking findings of my own.


Generated by Claude Code

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 2 of 10 on a /revise note, pushed as 848cf437b3bb.

line exit tail
cargo nextest run -p minimald record_carries_the_root_certificate_to_the_launch 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-c2d2... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling stdlib v0.0.22 (/workbenc
./scripts/session-e2e.sh bep_root_ca_present_in_box_trust_store 0 the 'min' and 'minimald' under /work/build-cache/target/debug report different versions; rebuilding the pair no usable 'min' and 'minimald' pair on PATH or under target/; building the pair this run drives (cargo build --locked -p minimal --bin min -p minimald --bin minimald) built the pair: /work/bu
./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream 1 ::group::box with no grant: no proxy root in its trust store (BEP-011) bep_root_ca_absent_from_box_without_credentialed_upstream_beside_a_grant_box: NOT RUN (the Box Egress Proxy runs on macOS only) ::error::'min session exec' in the plain box for bep_root_ca_absent_from_box_without_credentialed_ups
./scripts/session-e2e.sh bep_trust_env_points_at_bundle_and_root 0 ::group::GitHub grant box: SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS (BEP-011) bep_trust_env_points_at_bundle_and_root: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_trust_env_points_at_bundle_and_root session e2e OK Applying loado
cargo nextest run -p boxes spec_trust_env_shadows_platform_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-aa75... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

bitflags v1.3.2
    Checking managed v0.8.0
    Checking moka v0.12.16
    Checking is_executable v1.0.6
    Checking smoltcp v0.14.0
    Checking clap_complete v4.6.11
    Checking args v0.0.1 (/workbench/crates/args)
    Checking hickory-proto v0.26.3
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking common v0.0.1 (/workbench/crates/common)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking dashmap v6.2.1
    Checking vsock v0.5.4
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking tokio-vsock v0.7.2
    Checking russh-sftp v2.4.0
    Checking castaway v0.2.4
    Checking strum v0.28.0
    Checking signal-hook v0.3.18
    Checking compact_str v0.9.1
    Checking unicode-truncate v2.0.1
    Checking kasuari v0.4.12
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking lru v0.18.2
    Checking signal-hook-mio v0.2.5
    Checking ratatui-core v0.1.2
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking derive_more v2.1.1
    Checking line-clipping v0.3.8
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking crossterm v0.29.0
    Checking getrandom v0.2.17
    Checking ring v0.17.14
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking ratatui-widgets v0.3.2
    Checking yasna v0.6.0
    Checking pem v4.0.0
    Checking rcache v0.0.1 (/workbench/crates/rcache)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking rcgen v0.14.10
    Checking rusty-fork v0.3.1
    Checking ratatui-macros v0.7.2
    Checking op v0.0.1 (/workbench/crates/op)
    Checking ratatui-crossterm v0.1.2
    Checking fuzzy-matcher v0.3.7
    Checking proptest v1.12.0
    Checking inquire v0.9.4
    Checking ratatui v0.30.2
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking similar v2.7.0
    Checking insta v1.49.0
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Outside the task's layers::

  • crates/boxes/src/store.rs
  • crates/minimal-client/src/box_registration.rs
  • crates/minimal/src/cmd/boxes/create.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/dash/render.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimal/tests/dash_snapshots.rs
  • crates/minimald/src/box_actor/launcher.rs
  • crates/minimald/src/exec/tests.rs
  • crates/minimald/src/store.rs

Converted to a draft: something above needs a person before review.

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM6vbiig: With no package bundle, install_root_certificate now writes no bundle and reports bundle: false. The box gets only NODE_EXTRA_CA_CERTS, and SSL_CERT_FILE and REQUESTS_CA_BUNDLE stay unset. The debug line says so. Pinned in trust_env_points_at_bundle_and_root and root_certificate_follows_links_inside (not posted on the thread: not an open thread on the pull request)

A grant box whose packages ship a CA bundle has the root in both trust-store forms. It also has SSL_CERT_FILE and REQUESTS_CA_BUNDLE at its own bundle copy and NODE_EXTRA_CA_CERTS at the root. A grant box whose packages ship no bundle keeps the root file and the hashed-directory link. It gets no bundle and only NODE_EXTRA_CA_CERTS, so a tool that reads the bundle variables keeps its public roots. A box with no grant gets none of these. The unit tests trust_env_points_at_bundle_and_root and root_certificate_follows_links_inside_the_rootfs pin both cases.

Notes from the agent: C3 (revise note). install_root_certificate now returns RootInstall { link, bundle }. When the packages ship no bundle, it writes no bundle. launch_trust_env(root_injected, bundle) sets the two bundle variables only when bundle is true. The sandbox fixes a box's variables in its config before the rootfs exists, and the sandbox crate has no way to unset a variable later. For that reason Env::build now sets the trust variables, not the launcher. Before the sandbox build, it checks the package layers for the bundle (layers_ship_ca_bundle), and it adds the variables with or_insert below the composed ones (layer_trust_env), so a box spec value still wins. The launcher line that put them on the baseline layer is removed, and trust_env_keeps_a_spec_value now exercises layer_trust_env. After the install, the debug line says when the packages ship no bundle, and it records bundle_variables (the result of the layer check). The two checks can disagree only when a bundle link crosses from one package layer into another. That rare case leaves the bundle variables unset. scripts/session-e2e.sh is not changed: its trust-env case uses a box with a bundle, and that case is NOT RUN on Linux. The e2e no-grant case fails on this machine because boxes cannot start here (mount remount EPERM). It is not a result of this change.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft October 23, 2026 01:07
@norrietaylor
norrietaylor marked this pull request as ready for review October 23, 2026 01:07
Copy link
Copy Markdown
Member

/revise Act on the review's security finding at 848cf437 on crates/minimald/src/env.rs (install_root_certificate, thread 4355119851): the daemon writes the whole trimmed PEM string into the box's root file and appends it to the bundle, while its checks read only the first certificate block, so a record PEM with extra blocks would add extra trust anchors to the box. The client refuses such a PEM, but the daemon must not rely on that. Refuse a PEM that holds more than one -----BEGIN CERTIFICATE----- block with the same InvalidData error the non-certificate case uses, and write the one block re-encoded from its DER (or the one block's own text, trimmed) so nothing outside it reaches the store. Pin it beside root_certificate_that_is_not_a_certificate_is_refused with a two-block PEM. Change nothing else.


Generated by Claude Code

The daemon checked the first certificate block of the record PEM but
wrote the whole string. A PEM with more blocks added trust anchors.
Refuse such a PEM and write the one block's own text.
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling

The compare conforms to Gatehouse §6.10. Only the one root certificate block now reaches the box trust store. A PEM with no block or with two blocks fails the launch, and that is fail closed. One anchor per box matches line 839, because an un-enrolled root replacement re-creates the box. The three grant e2e legs are still NOT RUN. C1 keeps them open on #2275 until they pass on the macOS lane.

Ruled at 6f065b6 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread scripts/session-e2e.sh Resolved
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — approval withheld

Verdict COMMENT — APPROVE withheld: 2 unresolved threads — minimal-foundry[bot] crates/minimald/src/env.rs, minimal-arch[bot] scripts/session-e2e.sh:11862. No findings.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter review of T16 at 6f065b65 (round 3).

The round changes crates/minimald/src/env.rs alone: install_root_certificate now takes the one certificate block out of the record's PEM, refuses a PEM with no block or more than one with the same InvalidData error as a non-certificate, and writes that block alone into the root file and the bundle, so text around it or a second block never reaches the box's trust store. Two tests pin the refusal of a two-block PEM and the dropping of surrounding text. That is the code reviewer's security finding, and the arch review's ruling at this head records the behaviour as fail-closed and conforming. Its one condition is the three grant legs under T18 #2275, the residual already filed there.

No blocking findings of my own. Ready for the merge gate once CI and the code reviewer finish at this head.


Generated by Claude Code

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minimal-review — approved

Verdict APPROVE — every review thread is resolved; @norrietaylor closed the last one. The review of 6f065b6514fe withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.

@minimal-foundry minimal-foundry Bot added the review:approved minimal-review approved the current head label Oct 23, 2026
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 3 of 10 on a /revise note, pushed as 6f065b6514fe.

line exit tail
cargo nextest run -p minimald record_carries_the_root_certificate_to_the_launch 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-e3e4... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling stdlib v0.0.22 (/workbenc
./scripts/session-e2e.sh bep_root_ca_present_in_box_trust_store 0 no usable 'min' and 'minimald' pair on PATH or under target/; building the pair this run drives (cargo build --locked -p minimal --bin min -p minimald --bin minimald) built the pair: /work/build-cache/target/debug/min and /work/build-cache/target/debug/minimald ::group::GitHub grant box: the proxy's
./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream 1 ::group::box with no grant: no proxy root in its trust store (BEP-011) bep_root_ca_absent_from_box_without_credentialed_upstream_beside_a_grant_box: NOT RUN (the Box Egress Proxy runs on macOS only) ::error::'min session exec' in the plain box for bep_root_ca_absent_from_box_without_credentialed_ups
./scripts/session-e2e.sh bep_trust_env_points_at_bundle_and_root 0 ::group::GitHub grant box: SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS (BEP-011) bep_trust_env_points_at_bundle_and_root: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_trust_env_points_at_bundle_and_root session e2e OK Applying loado
cargo nextest run -p boxes spec_trust_env_shadows_platform_with_warning 0 rray v0.4.14 Compiling regex-automata v0.4.18 Compiling tokio v1.53.3 Compiling icu_normalizer v2.2.0 Compiling idna_adapter v1.2.2 Compiling rustls v0.23.46 Compiling ctutils v0.4.2 Compiling idna v1.1.0 Compiling block-buffer v0.12.1 Compiling rustls-webpki v0.103.16

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

mplete v4.6.11
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking dashmap v6.2.1
    Checking vsock v0.5.4
    Checking async-dialog v0.0.1 (/workbench/crates/async-dialog)
    Checking russh-sftp v2.4.0
    Checking args v0.0.1 (/workbench/crates/args)
    Checking tokio-vsock v0.7.2
    Checking castaway v0.2.4
    Checking strum v0.28.0
    Checking compact_str v0.9.1
    Checking signal-hook v0.3.18
    Checking unicode-truncate v2.0.1
    Checking common v0.0.1 (/workbench/crates/common)
    Checking kasuari v0.4.12
    Checking lru v0.18.2
    Checking signal-hook-mio v0.2.5
    Checking derive_more v2.1.1
    Checking ratatui-core v0.1.2
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking crossterm v0.29.0
    Checking line-clipping v0.3.8
    Checking getrandom v0.2.17
    Checking ring v0.17.14
    Checking yasna v0.6.0
    Checking ratatui-widgets v0.3.2
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking pem v4.0.0
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking rcgen v0.14.10
    Checking rusty-fork v0.3.1
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking ratatui-macros v0.7.2
    Checking ratatui-crossterm v0.1.2
    Checking fuzzy-matcher v0.3.7
    Checking proptest v1.12.0
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking inquire v0.9.4
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking ratatui v0.30.2
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking similar v2.7.0
    Checking rcache v0.0.1 (/workbench/crates/rcache)
    Checking insta v1.49.0
   Compiling serial_test_derive v4.0.1
    Checking op v0.0.1 (/workbench/crates/op)
    Checking serial_test v4.0.1
    Checking orchestrator v0.0.1 (/workbench/crates/orchestrator)
    Checking check v0.0.1 (/workbench/crates/check)
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Outside the task's layers::

  • crates/boxes/src/store.rs
  • crates/minimal-client/src/box_registration.rs
  • crates/minimal/src/cmd/boxes/create.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/dash/render.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimal/tests/dash_snapshots.rs
  • crates/minimald/src/box_actor/launcher.rs
  • crates/minimald/src/exec/tests.rs
  • crates/minimald/src/store.rs

Converted to a draft: something above needs a person before review.

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM6vb9LU: install_root_certificate refuses a PEM with more than one certificate block (InvalidData) and writes only the one block's text; pinned by root_certificate_with_two_blocks_is_refused. (not posted on the thread: not an open thread on the pull request)

A grant box has the proxy's root in both trust-store forms, and a box with no grant has none. The daemon now refuses a root PEM with more than one certificate block, and it writes only the one block's own text, so no other trust anchor reaches the box.

Notes from the agent: Revise round 3: install_root_certificate now takes the one certificate block through a new certificate_block helper. A PEM with no block or with more than one block gets the same InvalidData error as before. Only the block text, from BEGIN through END, goes into the root file and the bundle. New tests: root_certificate_with_two_blocks_is_refused (the pin the directive asked for) and root_certificate_text_outside_the_block_is_dropped. I did not run the three session-e2e.sh lines or the boxes test in this round. This round did not change their code paths, and the e2e lines need a KVM host. cargo clippy -p minimald --all-targets shows only warnings in files this round did not touch (box_runtime/handle.rs, net/switch.rs, minimald-rpc/src/trace.rs).

@minimal-foundry
minimal-foundry Bot marked this pull request as draft October 23, 2026 01:22
@norrietaylor
norrietaylor marked this pull request as ready for review October 23, 2026 01:30
Copy link
Copy Markdown
Member

/revise CI's Linux KVM lane fails at 6f065b65 in bep_root_ca_absent_from_box_without_credentialed_upstream (job test-kvm 120186533584): bep_trust_box_files activates the plain box with --allow-dns-hosts github.com ... and no --network flag, and on that lane the default network mode refuses it: "with --network host_ip this machine can only block all network access; it cannot apply these rules: allow_dns_hosts". The plain box declares no grant and needs no egress rule, so pass the --allow-dns-hosts flags only when $2 is grant, and activate the plain box with no egress flags at all, so it takes the lane's default. Keep the grant box's flags as they are. Change nothing else, and run ./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream on your target to confirm the plain leg still exits 0 there.


Generated by Claude Code

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

That /revise is held, not dropped. A coder is already running on #2274. Your note is kept and goes into the next round here, which starts when that coder finishes.

Nothing to type again: the command gets a rocket when its round starts, or a refusal that names the reason. No round was counted for it yet.

The plain box in bep_root_ca_absent_from_box_without_credentialed_upstream
passed the GitHub --allow-dns-hosts flags. On the KVM lane a host_ip box
refuses hostname rules at the start, so its activate failed. Only the
grant box declares those hosts now.
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will 10BC8 be displayed to describe this comment to others. Learn more.

minimal-review — approved

Verdict APPROVE — No findings.

Panel: 3 of 3 personas ran (correctness, security, supply-chain).

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling

The new commit removes the GitHub egress flags from the no-grant box in the BEP-011 e2e. Section 6.10 line 819 keys injection on credentialed upstreams, not on egress hosts. So the absence proof stays as hard as before. The code still conforms to the Trust-store injection paragraph (line 821). The three grant legs still record NOT RUN. C1 keeps them open on #2275 until the macOS lane runs them with a live proxy.

Ruled at d5be668 against gominimal/arch@109541a48c31 by claude-opus-5-5.

Comment thread scripts/session-e2e.sh Resolved
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Babysitter review of T16 at d5be6688 (round 4).

The round changes scripts/session-e2e.sh alone: bep_trust_box_files passes the four GitHub --allow-dns-hosts rules only for the grant box, and starts the no-grant box with no egress rule, which is what the KVM lane's default network mode refused at 6f065b65. The rest of the compare is main merged in: the listing host-slot change from #2231, no PR content. The code reviewer approved at this head with no findings, and no thread is open.

No blocking findings of my own. The KVM and macOS lanes decide the proof; ready for the merge gate when they are green.


Generated by Claude Code

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 4 of 10 on a failed check suite, pushed as d5be6688bab2.

line exit tail
cargo nextest run -p minimald record_carries_the_root_certificate_to_the_launch 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-5786... Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling stdlib v0.0.22 (/workbenc
./scripts/session-e2e.sh bep_root_ca_present_in_box_trust_store 0 the 'min' and 'minimald' under /work/build-cache/target/debug report different versions; rebuilding the pair no usable 'min' and 'minimald' pair on PATH or under target/; building the pair this run drives (cargo build --locked -p minimal --bin min -p minimald --bin minimald) built the pair: /work/bu
./scripts/session-e2e.sh bep_root_ca_absent_from_box_without_credentialed_upstream 1 ::group::box with no grant: no proxy root in its trust store (BEP-011) bep_root_ca_absent_from_box_without_credentialed_upstream_beside_a_grant_box: NOT RUN (the Box Egress Proxy runs on macOS only) ::error::'min session exec' in the plain box for bep_root_ca_absent_from_box_without_credentialed_ups
./scripts/session-e2e.sh bep_trust_env_points_at_bundle_and_root 0 ::group::GitHub grant box: SSL_CERT_FILE, REQUESTS_CA_BUNDLE and NODE_EXTRA_CA_CERTS (BEP-011) bep_trust_env_points_at_bundle_and_root: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_trust_env_points_at_bundle_and_root session e2e OK Applying loado
cargo nextest run -p boxes spec_trust_env_shadows_platform_with_warning 0 Applying loadouts: default Running task runtime-implement-test-4 in session task-runtime-implement-test-4-e568... Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling paths v0.0.1 (/workbench/crates/paths) Compiling common v0.0.1 (/workbench

Verify min task run agent-verify exited 101 under rustc 1.98.1, which the repository does not pin (1.97.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.

-dalek v3.0.0
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking generic-array v0.14.7
    Checking sha3 v0.11.0
    Checking p384 v0.14.0
    Checking p521 v0.14.0
    Checking opentelemetry-proto v0.33.0
    Checking opentelemetry-http v0.33.1
    Checking module-lattice v0.2.3
    Checking tracing-serde v0.2.0
    Checking kem v0.3.0
    Checking data-encoding v2.11.1
    Checking sponge-cursor v0.1.0
    Checking symlink v0.1.0
    Checking compression-core v0.4.33
    Checking httpdate v1.0.3
    Checking sha3 v0.12.0
    Checking tracing-appender v0.2.5
    Checking compression-codecs v0.4.45
    Checking opentelemetry-otlp v0.33.0
    Checking json-subscriber v0.3.1
    Checking ml-kem v0.3.2
    Checking ssh-key v0.7.0-rc.11
    Checking generic-array v1.4.4
    Checking rcache v0.0.1 (/workbench/crates/rcache)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking russh-cryptovec v0.62.0
    Checking num-bigint v0.5.1
    Checking opentelemetry-appender-tracing v0.33.1
    Checking hash32 v0.3.1
    Checking russh-util v0.52.0
    Checking constcat v0.6.1
    Checking hex-literal v1.1.0
    Checking size v0.5.0
    Checking heapless v0.9.3
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking russh v0.64.1
    Checking op v0.0.1 (/workbench/crates/op)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking async-compression v0.4.50
    Checking async-tar v0.6.1
    Checking tagptr v0.2.0
    Checking bitflags v1.3.2
    Checking tinyvec_macros v0.1.1
    Checking managed v0.8.0
    Checking tinyvec v1.12.0
    Checking smoltcp v0.14.0
    Checking moka v0.12.16
    Checking object v0.40.0
    Checking is_executable v1.0.6
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking clap_complete v4.6.11
    Checking hickory-proto v0.26.3
    Checking check v0.0.1 (/workbench/crates/check)
    Checking orchestrator v0.0.1 (/workbench/crates/orchestrator)
    Checking sysinfo v0.39.6
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking hashbrown v0.14.5
error: using `chunks_exact` with a constant chunk size
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    |
help: consider using `as_chunks::<2>()` instead
   --> crates/minimald-rpc/src/trace.rs:199:46
    |
199 |     for (byte, pair) in out.iter_mut().zip(s.chunks_exact(2)) {
    |                                              ^^^^^^^^^^^^^^^
    = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.98.0/index.html#chunks_exact_to_as_chunks
    = note: `-D clippy::chunks-exact-to-as-chunks` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::chunks_exact_to_as_chunks)]`

error: could not compile `minimald-rpc` (lib) due to 1 previous error
warning: build failed, waiting for other jobs to finish...

Outside the task's layers::

  • crates/boxes/src/store.rs
  • crates/minimal-client/src/box_registration.rs
  • crates/minimal/src/cmd/boxes/create.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/dash/render.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimal/tests/dash_snapshots.rs
  • crates/minimald/src/box_actor/launcher.rs
  • crates/minimald/src/exec/tests.rs
  • crates/minimald/src/store.rs

Converted to a draft: something above needs a person before review.

A grant box has the root in both trust-store forms, and a box with no grant has none. This round, the no-grant case starts its box on the KVM lane again, so that lane can show that a box with no grant has no root.

Notes from the agent: Round 4 cause: the public check-run annotations for test-kvm name the failure as "'min session activate' of the plain box for bep_root_ca_absent_from_box_without_credentialed_upstream failed". That case runs on every lane with no gate. Its plain box passed the four GitHub --allow-dns-hosts flags without --network own_ip. On a VM host, a host_ip box with hostname rules is refused at the start (minimald net/classifier.rs unenforceable_declaration_words). Now only the grant box passes those flags. The empty array expands with the ${a[@]+...} form so bash 3.2 on macOS with set -u accepts it. The stderr of the CI activate was not readable (job logs need admin rights), so this cause is inferred from the annotation and the code. On this box the activate now succeeds, but the exec step fails. The baseline ./scripts/session-e2e.sh session_exec fails here with the same 'sandbox supervisor ... has no child process' error, so this box cannot run box execs. The KVM lane is the record for the e2e cases. The two grant cases report NOT RUN here because the Box Egress Proxy is not running on this lane.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft October 23, 2026 01:55
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 5 of 10 on a /revise note: the coder changed nothing. noop: the branch head d5be668 already does what the note asks. bep_trust_box_files passes the four --allow-dns-hosts flags only when $2 is grant. It activates the plain box with no egress flags, and the grant box flags are unchanged. No new commit is needed. Confirmation on this box is partial. The plain box activate now succeeds, and the KVM lane failed at that step. The next step, 'min session exec', fails here. The baseline session_exec e2e case fails at the same step, so this sandbox cannot run box execs. This box has no /dev/kvm, so it cannot reproduce the KVM lane. The test-kvm lane must re-run at d5be668 to confirm the plain leg exits 0.

@norrietaylor
norrietaylor marked this pull request as ready for review October 23, 2026 02:05
@norrietaylor norrietaylor changed the title T16 — Put the interception root in the box's trust store feat(minimald): put the proxy's root certificate in a grant box's trust store Oct 23, 2026
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved by the babysitter at d5be6688 after the merge gate passed on every point: own reviews at every head, arch-review PASS_WITH_CONDITIONS at d5be6688 whose one condition is the residual filed on T18 #2275, the code reviewer's approval, every review thread resolved, every CI lane green including KVM and macOS, and the squash subject lint-clean. Layer exceptions and CI evidence are recorded in the body. Enqueued for a squash merge.


Generated by Claude Code

@norrietaylor
norrietaylor added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 197a96b Oct 23, 2026
37 checks passed
@norrietaylor
norrietaylor deleted the agent/2274-put-the-interception-root-in-the-box-s-trust-sto branch October 23, 2026 03:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:approved minimal-review approved the current head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

T16 — Put the interception root in the box's trust store

1 participant

0