8000 feat(minimald): deliver each GitHub grant's sealed value into its variable in the box by minimal-foundry[bot] · Pull Request #2491 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(minimald): deliver each GitHub grant's sealed value into its variable in the box - #2491

Merged
norrietaylor merged 9 commits into
mainfrom
agent/2488-deliver-each-sealed-value-into-its-grant-s-envir
Oct 22, 2026
Merged

norrietaylor merged 9 commits into
mainfrom
agent/2488-deliver-each-sealed-value-into-its-grant-s-envir

Conversation

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

T42 — Deliver each sealed value into its grant's environment variable in the box

slice: S0
kind: task
covers: BEP-007
size: L
est: 260 code, 260 tests
executor: agent
difficulty: needs care
model: strongest
diagnostics: min box spec <box> shows each grant's variable name and never its value; a box whose create request carries no sealed value for a declared grant is refused at creation with exit 3 naming the grant
observability: one debug log line per delivered variable naming the box id and the variable, never the value
layers:
- carry:
- crates/minimald-rpc/src/lib.rs: BoxConfig carries the sealed deliveries and the root certificate, and the shared create-request constructor takes them
- crates/minimal/src/cmd/boxes/create.rs: the MintGrants step hands each Minted.sealed to the create request as its grant's delivery in place of drop(minted) (arch C2 on #2490, residual filed here)
- crates/minimald-rpc/src/tests.rs: the new fields in its full literals
- crates/minimald/src/box_manager.rs: record_from_config copies the deliveries into the box record
- crates/boxes/src/lib.rs: Record holds the deliveries
- crates/minimald/src/box_manager/tests.rs: the new fields in its full literals
test: cargo nextest run -p minimald sealed_deliveries_ride_the_record_to_the_host_params
- place:
- crates/minimald/src/box_actor/host.rs: builds HostParams with the deliveries
- crates/minimald/src/box_runtime.rs: places each sealed value in its grant's environment variable and no plaintext
- crates/minimald/src/box_runtime/tests.rs: the placement test
test: cargo nextest run -p minimald sealed_value_is_placed_in_its_grant_variable_only
- e2e:
- scripts/session-e2e.sh: adds the case
test: ./scripts/session-e2e.sh bep_box_env_holds_sealed_value_only
produces: none
consumes:
- crates/minimal/src/mint.rs
- crates/minimald-rpc/src/lib.rs
proof: A second grant box starts with no prompt and holds only a sealed value in its grant's variable.
depends on:
- blocked by T14

Proof

On a macOS host with a GitHub sign-in and bep serve running, min session activate of a box that declares [session.secrets.GH_TOKEN] source = "broker" starts with no prompt. min session exec <box> printenv GH_TOKEN prints a sealed value for that box and no plaintext token. A second grant box does the same with a value of its own. The new e2e case checks this, but it did not run here: this box is Linux, and the case records NOT RUN. The unit tests show the daemon half: the value rides the create request into the box record, and every host launch places it in the grant's variable over any older value.

Notes from the agent: Files outside the layers: adding sealed_deliveries to boxes::Record breaks every full Record literal. Each of these files gets one line, sealed_deliveries: Vec::new(),: 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 (two literals), crates/minimal/tests/dash_snapshots.rs, crates/minimald/src/exec/tests.rs, crates/minimald/src/store.rs. The plan did not list them.

Design: the mint needs the box id, and the daemon reads deliveries from the create request. So the MintGrants step now runs before CreateSession, and ActivationStep::ORDER changes to match. An autogen-name collision re-registers under a new box id. In that case the retry mints again for the new id, and the replaced proxy registration drops and forgets the old id. A mint failure now only withdraws the row, because no box exists yet to destroy.

Placement: the host puts the sealed values into its connection-env layer. That layer goes over every command the host runs in the box (exec and hooks). It is also published to the per-attach env files, which the shell re-reads before every command. The shell's first environ does not hold the value: the launcher (box_runtime/launcher.rs) is outside the layers. The re-read before every co…[truncated]

Tests

line exit tail
cargo nextest run -p minimald sealed_deliveries_ride_the_record_to_the_host_params 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-7664... 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
cargo nextest run -p minimald sealed_value_is_placed_in_its_grant_variable_only 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-d42e... Compiling stdlib v0.0.22 (/workbench/crates/stdlib) Compiling version v0.8.0 (/workbench/crates/version) Compiling decode v0.0.1 (/workbench/crates/decode) Compiling mlog v0.
./scripts/session-e2e.sh bep_box_env_holds_sealed_value_only 0 ::group::GitHub grant boxes: the grant's variable holds a sealed value only bep_box_env_holds_sealed_value_only: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_box_env_holds_sealed_value_only session e2e OK Applying loadouts: default Running task r

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-de63...
    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 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 common v0.0.1 (/workbench/crates/common)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    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 decode v0.0.1 (/workbench/crates/decode)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
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 test) due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `minimald-rpc` (lib) due to 1 previous error

Layer exception

Accepted by the epic owner on 2026-10-19 under the rule recorded for #2361, #2363 and #2365 (required one-line changes outside the planned layers), applied by the babysitter on 2026-10-22: boxes::Record gains sealed_deliveries, so every full Record literal needs the one line sealed_deliveries: Vec::new(),. The eight files are 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 (two literals), crates/minimal/tests/dash_snapshots.rs, crates/minimald/src/exec/tests.rs and crates/minimald/src/store.rs, each test or fixture code with that one line and nothing else. Also crates/minimal/src/mint.rs: arch-review condition C2 at 8c381bc deletes the interim doc text and the allow(dead_code) attribute on Minted::sealed, since this PR delivers the value (round 2, 73877d2).

Residuals

Filed by the babysitter from the arch rulings on this PR; it may stay open at merge.

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/exec/tests.rs
  • crates/minimald/src/store.rs

Closes #2488


Generated by Claude Code

BEP-007: `min` now mints the GitHub grants before `CreateSession`, and
the create request carries each sealed value. The daemon copies them
into the box record. Every host launch places each value in its
grant's environment variable, over any value already there. A grant
that the mint gives no sealed value is refused by name.

`BoxConfig` also gets an empty `root_certificate` field. The proxy
does not publish the certificate yet (#2437).

The new `Record` field also needs one line 
8000
in each `Record` literal
outside the task's files.
BEP-007: two GitHub grant boxes start headless. Each box's GH_TOKEN is a
value of its own, and no plaintext GitHub token is in its environment.
The case is NOT RUN on a lane with no Box Egress Proxy.
@coderabbitai
coderabbitai Bot commented Oct 22, 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: 15873458-d58e-4529-84d8-f527b676efd5

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.

@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 T42 at 8c381bc, against the plan block on #2488.

Plan coverage. Every layer line is in the diff. Carry: BoxConfig in crates/minimald-rpc/src/lib.rs gains sealed_deliveries and root_certificate (the latter None until #2437 publishes a certificate, and read by nothing yet, as the plan allows), the constructor and the round-trip tests take them, build_record in box_manager.rs copies the deliveries into boxes::Record, which holds them under #[serde(default)] so older records read back empty. Place: HostParams carries the deliveries from the record and Host::build puts each sealed value into the connection-env layer over any earlier value, so the per-attach env files the shell re-reads, every exec and every hook see it and nothing else. The create.rs line from arch C2 on #2490 is done by moving MintGrants before CreateSession so the create request carries the sealed values; a missing value for a declared grant refuses the start by name. The e2e case starts two grant boxes headless on macOS, reads each box's GH_TOKEN, refuses any GitHub-shaped plaintext in the environment and requires the two values to differ, with the same NOT RUN gates as T14's proof. The plan's three test lines ran green in the round table; CI is in progress at this head.

Design points for arch. (1) The mint now runs before the create, so a mint failure withdraws only the row (no session exists yet), and an autogen-name collision re-mints for the new id while the replaced registration forgets the old one at the proxy. (2) The sealed value now rides the box record on disk so every relaunch places it; it is sealed to the proxy key, and Debug redacts it. (3) The shell's first environment does not hold the value, because the launcher is outside the layers; the value arrives on the per-attach re-read before the first command, and every exec and hook has it from the start.

Commits. Two, both Conventional Commits clean.

Layer exception. Eight files outside the layers, each one line sealed_deliveries: Vec::new(), in a full Record literal that stopped compiling: the same shape as the ::default() updates accepted on #2365 under the epic owner's 2026-10-19 rule. Recorded in the body; the PR is undrafted under that rule.

Size. +491/-69 against an estimate of 520 lines: at estimate.

Verdict: on track; waiting on CI, the arch ruling and the runtime review at this head.


Generated by Claude Code

@norrietaylor
norrietaylor marked this pull request as ready for review October 22, 2026 17:27
@norrietaylor
norrietaylor requested a review from a team as a code owner October 22, 2026 17:27
@minimal-foundry
minimal-foundry Bot commented Oct 22, 2026 •
Copy link
Copy Markdown
Contributor Author

Approved: every review thread resolved at 7d41640e17c3.

@norrietaylor resolved the last thread, which releases the approval this review had withheld.

Nothing to do.

@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 — 3 findings, 3 inline.

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

Comment thread crates/minimald/src/box_runtime.rs Resolved
Comment thread crates/minimal/src/cmd/boxes/create.rs Resolved
Comment thread crates/boxes/src/lib.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 · 4 conditions · the full ruling

The change carries each sealed value to the box and places it for exec, hooks and the per-attach env files. The value is not in the shell's launch environment, and Gatehouse §6.3 line 637 requires env values before the entrypoint runs. C1 adds the deliveries to attach_env.connection in BoxActor::launch_host. C2 removes the stale #2488 interim from mint.rs. C3 makes the e2e check the compact JWE form. C4 runs the e2e leg, which is NOT RUN at this head.

Outside the diff

  • crates/minimal/src/mint.rs:400: C2 · This PR is the flip that this interim names, and it closes #2488. Delete the interim text and the allow(dead_code) attribute on Minted::sealed.

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

Comment thread crates/minimald/src/box_actor/host.rs Resolved
Comment thread scripts/session-e2e.sh Resolved
Comment thread scripts/session-e2e.sh Resolved
A sealed delivery's variable is written unquoted into the file the
box's shell sources. The create now refuses a name that is not a
POSIX variable name, and the placement skips one as well.
A grant whose name is not a POSIX variable name is refused before
anything is created, and a grant the mint left with no sealed value
is refused by name. Both end the run with exit 3.
@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/boxes/src/lib.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 · 2 conditions · the full ruling

The change carries each sealed value to the box with no plaintext, and the compare closes the name injection. One gap stays. The host adds the sealed values after the launcher builds the shell's environment, so the box's shell starts without its grant's variable. Gatehouse §6.3 line 637 says env values must exist before the entrypoint runs. C1 moves the placement into host.rs before the launch. C2 adds a test that reads the launch environment.

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

Comment thread crates/minimald/src/box_actor/host.rs Resolved
Comment thread crates/minimald/src/box_runtime.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 1 of 10 on the runtime's review findings, pushed as f00a7f09207a.

line exit tail
cargo nextest run -p minimald sealed_deliveries_ride_the_record_to_the_host_params 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-113f... Downloading crates ... Downloaded wnaf v0.14.1 Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling paths v0.0.1 (/workbench/cr
cargo nextest run -p minimald sealed_value_is_placed_in_its_grant_variable_only 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-be2d... Compiling stdlib v0.0.22 (/workbench/crates/stdlib) Compiling version v0.8.0 (/workbench/crates/version) Compiling decode v0.0.1 (/workbench/crates/decode) Compiling mlog v0.
./scripts/session-e2e.sh bep_box_env_holds_sealed_value_only 0 ::group::GitHub grant boxes: the grant's variable holds a sealed value only bep_box_env_holds_sealed_value_only: NOT RUN (the Box Egress Proxy runs on macOS only) ::endgroup:: session e2e: 1 case(s) NOT RUN: bep_box_env_holds_sealed_value_only session e2e OK Applying loadouts: default Running task r

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-1e19...
    Checking ot v0.0.1 (/workbench/crates/ot)
    Checking args v0.0.1 (/workbench/crates/args)
    Checking paths v0.0.1 (/workbench/crates/paths)
    Checking wnaf v0.14.1
   Compiling stdlib v0.0.22 (/workbench/crates/stdlib)
    Checking common v0.0.1 (/workbench/crates/common)
   Compiling version v0.8.0 (/workbench/crates/version)
    Checking switch v0.0.1 (/workbench/crates/switch)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
    Checking primeorder v0.14.0
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking diagnostics v0.0.1 (/workbench/crates/diagnostics)
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking p256 v0.14.0
    Checking p521 v0.14.0
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking p384 v0.14.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)
10000
]`

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/vm_host.rs
  • crates/minimal/src/dash/render.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimal/src/main.rs
  • crates/minimal/tests/dash_snapshots.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_kwDOPdfcxM6vTdI6: Grant names are now checked against StrictVarName: check_github_grants refuses one before anything is created (exit 3), build_record refuses one with InvalidInput, and place_sealed_deliveries skips one. LD_PRELOAD-style names stay allowed, because loadout vars can already set them. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — PRRT_kwDOPdfcxM6vTdJG: sealed_deliveries now returns GrantNotDelivered::NotSealed, and failure_exit_code maps GrantNotDelivered to exit 3. The message states the situation and stops, because no command is proven to fix it. (not posted on the thread: not an open thread on the pull request)
  • 👎 invalid — crates/boxes/src/lib.rs:1288: GetSessionRecord answers only the daemon's authenticated user, who owns the box and can read the same sealed value in the box's environment. That value is sealed to this host's proxy key and is meant to sit in the box (BEP-007). Stripping it means changing the RPC handlers in minimald, which are out

A grant box starts with no prompt, and its grant's variable holds only the sealed value. A grant whose name is not a variable name is refused with exit 3 before anything is created. A grant the mint gives no sealed value is also refused with exit 3, and the message names the grant.

Notes from the agent: Revise round 1. I touched crates/minimal/src/main.rs outside the layers. It is a 3-line downcast in failure_exit_code, plus one test, that maps the new GrantNotDelivered error to exit 3. Without it, the exit 3 that the task's diagnostics line requires was not reachable without a new BepRefusal variant in crates/boxes/src/core/bep.rs, which is also outside the layers. I did not run ./scripts/session-e2e.sh bep_box_env_holds_sealed_value_only: this box has no /dev/kvm. The NotSealed message has no next step because no command is proven to fix it, so it states the situation and stops. The client checks the names of GitHub grants only, not of every [session.secrets] key. The other keys deliver nothing in this task. A project can still set names such as LD_PRELOAD or BASH_ENV. A project can already set those through its loadout vars, so this change does not refuse them.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft October 22, 2026 17:48
Copy link
Copy Markdown
Member

/revise

Carry the arch-review conditions at f00a7f0 (ruling 119988501499), the one condition from the ruling at 8c381bc that no round has touched, and the review finding at f00a7f0, in one round.

  1. Arch C1 (threads 4351635991 and 4351635997). The shell's launch environment does not hold the sealed values: launch_host in crates/minimald/src/box_actor/host.rs reads attach_env.connection_env() at line 425 and hands attach_env to session_launcher, and place_sealed_deliveries runs only later in Host::new. Gatehouse §6.3 line 637 says the values exist before the entrypoint runs. In launch_host, before line 425 and before the session_launcher call: take connection_env, call box_runtime::place_sealed_deliveries(&mut connection_env, <session id>, &box_runtime::launch_deliveries(&record)), and set attach_env.connection from it, so layer_session_env folds each value into the shell's launch environ and the republished layer still holds it. Remove the second place_sealed_deliveries call in Host::new (box_runtime.rs line 594) and the HostParams::sealed_deliveries field, so each launch logs one debug line per variable. Both files are in the layers; the launcher file does not change.

  2. Arch C2 (thread 4351636004). Add a test that the AttachEnv the launch hands to session_launcher holds GH_TOKEN = the sealed value, and that layer_session_env over it yields that value above a composition GH_TOKEN. The existing sealed_value_is_placed_in_its_grant_variable_only test and the e2e case read only the connection layer, so they pass with the shell's launch environ empty.

  3. Arch C2 at 8c381bc (outside the diff). crates/minimal/src/mint.rs lines 400 to 403, Minted::sealed: delete the interim text ("Interim: nothing delivers it into the box until BEP-007 places it in the grant's environment variable. The flip is T42 …") and the #[cfg_attr(not(test), allow(dead_code))] attribute, since create.rs sealed_deliveries now reads the field and this PR closes T42 — Deliver each sealed value into its grant's environment variable in the box #2488. Say in the doc comment that the create request carries the value to the grant's variable. The file is outside the layers; it is a doc and attribute deletion, which the epic owner's layer-exception rule covers, and the babysitter records it in the body.

  4. Arch C3 at 8c381bc (thread 4351507088). In proof_bep_box_env_holds_sealed_value_only, after bep_value is read, fail the case with an ::error:: line unless the value matches the compact JWE form bep::seal returns (header..iv.ciphertext.tag), for example [[ "$bep_value" =~ ^[A-Za-z0-9_-]+\.\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$ ]]. Today the case passes for any non-empty value that differs per box.

  5. Review HIGH (thread 4351628305, crates/boxes/src/lib.rs 1288, confidence 0.50). serve_get_session_record in crates/minimald/src/rpc.rs returns the whole Record, so every daemon client reads every box's sealed values. They are sealed to the proxy key and bound to their box, so the gain is small, but the fix is too: clear sealed_deliveries on the Record in every RPC response that carries one (GetSessionRecordResponse, and any list or lookup response with a boxes::Record in it) while the store keeps the field, and pin it with a test that a GetSessionRecord reply for a grant box carries no deliveries. Do not use #[serde(skip)] on the field: the store serialises the same type.

Arch C4 at 8c381bc (the e2e leg NOT RUN until #2275 starts bep serve) is filed as a residual on #2275 and needs nothing here. Do not change the leg's gates.

Keep every commit message Conventional Commits compliant (type(scope): subject, subject at most 92 characters, body lines at most 100), as the commitlint check requires.


Generated by Claude Code

The launch now places each grant's sealed value in attach_env.connection
before session_launcher builds the shell, so the values exist before the
entrypoint runs. HostParams no longer carries the deliveries, and each
launch logs one debug line per variable.
The store keeps them. Only the daemon's own launch reads them.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 2 of 10 on a /revise note, pushed as 7d41640e17c3.

line exit tail
cargo nextest run -p minimald sealed_deliveries_ride_the_record_to_the_host_params 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-1a0e... 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
cargo nextest run -p minimald sealed_value_is_placed_in_its_grant_variable_only 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-da5f... Compiling stdlib v0.0.22 (/workbench/crates/stdlib) Compiling version v0.8.0 (/workbench/crates/version) Compiling decode v0.0.1 (/workbench/crates/decode) Compiling mlog v0.
./scripts/session-e2e.sh bep_box_env_holds_sealed_value_only 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 boxes: the grant

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-370c...
    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)
    Checking boxes v0.0.1 (/workbench/crates/boxes)
    Checking sandbox v0.0.1 (/workbench/crates/sandbox)
   Compiling minvmd v0.8.0 (/workbench/crates/minvmd)
    Checking bep v0.0.1 (/workbench/crates/bep)
    Checking mlog v0.0.1 (/workbench/crates/mlog)
    Checking mfile v0.0.1 (/workbench/crates/mfile)
    Checking decode v0.0.1 (/workbench/crates/decode)
    Checking checkouts v0.0.1 (/workbench/crates/checkouts)
    Checking graph v0.0.1 (/workbench/crates/graph)
    Checking minimald-rpc v0.0.1 (/workbench/crates/minimald-rpc)
    Checking lcache v0.0.1 (/workbench/crates/lcache)
    Checking rcache v0.0.1 (/workbench/crates/rcache)
    Checking op v0.0.1 (/workbench/crates/op)
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...
error: could not compile `minimald-rpc` (lib test) due to 1 previous error

Outside the task's layers::

  • 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/src/main.rs
  • crates/minimal/src/mint.rs
  • crates/minimal/tests/dash_snapshots.rs
  • crates/minimald/src/exec/tests.rs
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/store.rs

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

Review threads the coder judged:

  • 👍 valid — crates/minimald/src/box_actor/host.rs: launch_host now calls box_runtime::place_launch_deliveries before session_launcher, so attach_env.connection holds the sealed values when the shell's environ is built.
  • 👍 valid — scripts/session-e2e.sh:11623: The case now fails with an ::error:: line unless bep_value matches the compact JWE form header..iv.ciphertext.tag.
  • 👎 invalid — scripts/session-e2e.sh:11574: This branch cannot produce that run. The leg needs a macOS host with bep serve running, and nothing starts bep serve until T18 — Run the proxy beside gvproxy so git and gh reach GitHub from a box #2275 lands. It is filed as a residual on T18 — Run the proxy beside gvproxy so git and gh reach GitHub from a box #2275, and the leg's gates are unchanged.
  • 👍 valid — crates/boxes/src/lib.rs:1288: serve_get_session_record replies through session_record_response, which clears sealed_deliveries. The store keeps them. A test pins a grant box's reply, on the wire too.
  • 👍 valid — crates/minimald/src/box_actor/host.rs: The deliveries go into attach_env.connection before the session_launcher call, and the HostParams::sealed_deliveries field is removed.
  • 👍 valid — crates/minimald/src/box_runtime.rs: Removed the place_sealed_deliveries call in Host::new. Placement happens once per launch in launch_host, so each launch logs one line per variable.
  • 👍 valid — crates/minimald/src/box_runtime/tests.rs:6958: Added sealed_value_reaches_the_shell_launch_environment: the launch AttachEnv holds GH_TOKEN, and layer_session_env over it yields the sealed value above a composition GH_TOKEN.

A second grant box starts with no prompt. Its shell's launch environment holds the grant's sealed value in GH_TOKEN before the entrypoint runs, and holds no plaintext token. The GetSessionRecord reply no longer carries any box's sealed values.

Notes from the agent: Two files outside the layers, both named by the directive. (1) crates/minimald/src/rpc.rs: serve_get_session_record now builds its reply through a new session_record_response, which clears Record.sealed_deliveries. GetSessionRecordResponse is the only RPC response that carries a boxes::Record. The store keeps the field, and no #[serde(skip)] is used. (2) crates/minimal/src/mint.rs: deleted the interim doc text and the cfg_attr(dead_code) attribute on Minted::sealed. The doc now says the create request carries the value to the grant's variable. Placement now happens in launch_host through a new box_runtime::place_launch_deliveries. It sets attach_env.connection from the placed map before session_launcher runs. The HostParams::sealed_deliveries field and the second placement in Host::new are gone, so each launch logs one debug line per variable. The launcher file is not changed. I did not run ./scripts/session-e2e.sh bep_box_env_holds_sealed_value_only. The script runs the whole VM e2e and does not filter by case. On Linux the case records NOT RUN (macOS only, and it needs bep serve, see #2275). I checked only bash -n on the edited script. cargo clippy -p minimald -p minimal --all-targets shows only warnings that were there before. I did not run just clippy-strict.

@norrietaylor
norrietaylor marked this pull request as ready for review October 22, 2026 18:10
@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.

APPROVE withheld: 8 unresolved threads — minimal-foundry[bot] crates/boxes/src/lib.rs:1288, minimal-arch[bot] crates/minimald/src/box_actor/host.rs, minimal-arch[bot] scripts/session-e2e.sh:11623, minimal-arch[bot] scripts/session-e2e.sh:11574, minimal-foundry[bot] crates/boxes/src/lib.rs:1288, ….

minimal-review — advisory review

Verdict COMMENT — No findings.

Panel: 2 of 3 personas ran (correctness, security); did not complete: 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 sealed value is now in the shell's launch environment before the entrypoint runs, as Gatehouse §6.3 line 637 requires. GetSessionRecord no longer returns the values. BEP-007 conforms on this head. One leg is open. The e2e case records NOT RUN on every lane until #2275 starts the Box Egress Proxy on the macOS lane. Section 6.10 line 857 says sealed delivery lands with its e2e. C1 keeps that leg open as a filed residual. The change can merge with C1 open.

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

Comment thread scripts/session-e2e.sh Resolved
@norrietaylor norrietaylor changed the title T42 — Deliver each sealed value into its grant's environment variable in the box feat(minimald): deliver each GitHub grant's sealed value into its variable in the box Oct 22, 2026
@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 7d41640e17c3 withheld this approval on the threads open then. Posted as a comment, as the review itself was; the check and the label carry it.

@minimal-foundry minimal-foundry Bot added the review:approved minimal-review approved the current head label Oct 22, 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.

Babysitter review of T42 at 7d41640, against the plan block on #2488 and the two rounds since my review at 8c381bc.

Plan coverage. Unchanged from 8c381bc: carry (BoxConfig and Record hold the deliveries, the daemon copies them at create, older records read back empty), place (now at launch time: place_launch_deliveries puts each sealed value into the launch's connection layer before the launcher builds the shell, so the shell's launch environment, every exec, every hook and the per-attach files hold it above any earlier value), the create.rs reorder of the mint before the create, and the e2e case with its NOT RUN gates, JWE-form and plaintext checks. The plan's three test lines ran green in every round table.

Rounds verified. Round 1 (f00a7f0): a grant name that is not a POSIX variable name is refused at the client before any create, at the daemon before the store, and skipped at placement, each with a test including a shell-text name; the undeliverable-grant refusal is its own error type with exit 3. Round 2 (7d41640): launch-time placement with a test through layer_session_env, the session-record reply cleared of the values with a wire test, the stale mint interim and dead-code attribute removed, the JWE-form check added. Six commits, all Conventional Commits clean.

Arch. PASS_WITH_CONDITIONS at 7d41640 with C1 only: the e2e leg NOT RUN until #2275 starts the proxy, filed as a residual on #2275 as a test line on T18's e2e layer. The review at this head has no findings.

Layer exception. Eight one-line Record literal updates and the mint.rs doc and attribute deletion arch asked for, under the recorded rule.

Size. +771/-85 against an estimate of 520 lines: 1.6x, under the 3x cap.

Verdict: ready to merge once the KVM, Kani and macOS lanes finish at this head.


Generated by Claude Code

@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 at 7d41640 by the babysitter under the epic owner's merge-on-green delegation for #1501. All twelve gates pass at this head: own review, arch pass (C1 filed on #2275), review concluded with no findings, no open threads, every bot resolution re-verified, five lane aggregators green, not a draft, no needs-human, no round in flight, and Closes #2488. The squash message is Conventional Commits compliant (feat(minimald): deliver each GitHub grant's sealed value into its variable in the box).


Generated by Claude Code

@norrietaylor
norrietaylor added this pull request to the merge queue Oct 22, 2026
Merged via the queue into main with commit 3eb782b Oct 22, 2026
37 checks passed
@norrietaylor
norrietaylor deleted the agent/2488-deliver-each-sealed-value-into-its-grant-s-envir branch October 22, 2026 19:50
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.

T42 — Deliver each sealed value into its grant's environment variable in the box

1 participant

0