8000 T123 — Revoke a host-address grant box's minted id at the proxy when the box ends by minimal-foundry[bot] · Pull Request #3034 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

T123 — Revoke a host-address grant box's minted id at the proxy when the box ends - #3034

Merged
norrietaylor merged 14 commits into
mainfrom
agent/3032-revoke-a-host-address-grant-box-s-minted-id-at-t
Nov 5, 2026
Merged

norrietaylor merged 14 commits into
mainfrom
agent/3032-revoke-a-host-address-grant-box-s-minted-id-at-t

Conversation

@minimal-foundry
@minimal-foundry minimal-foundry Bot commented Nov 5, 2026 •
Copy link
Copy Markdown
Contributor

T123 — Revoke a host-address grant box's minted id at the proxy when the box ends

slice: S17
kind: task
covers: BEP-043
size: S
est: 60 code, 120 tests
executor: agent
difficulty: routine
model: standard
diagnostics: min box audit <box> for an ended host_ip grant box shows the revocation of its id, as it does for an ended own-address box
observability: the existing bep-revocation thread's warning names the box id and the step that failed, for a host_ip box as for an own-address box
layers:
- revoke:
- crates/minvmd/src/box_registry.rs: retire_host_ip_box sends spawn_revocation for the box's minted id when the retired box declared a credentialed upstream and the id is one HostIpIds minted, as the own-address destroy does (BEP-043); the id stays in the id set so it never returns
test: cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id
test: cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation
produces:
- the revocation of an ended host-address grant box
consumes: none
proof: After a host-address grant box ends, the proxy refuses a sealed value under its id, and min box audit shows the revocation.
depends on:
- blocked by #2854

Proof

When a host_ip box that declared a credentialed upstream ends, retire_host_ip_box sends the proxy's control socket a revoke_box line and then a forget_box line for the box's minted id. This is the same path the own-address destroy uses. The proxy then records the revocation, which min box audit reads, and refuses sealed values under that id. The tests show the two lines at a stub control socket and show that the id stays in the minted set. The proxy-side refusal and the audit row come from the existing revoke_box handling. No test in this task runs them end to end.

Notes from the agent: The revocation goes only when three things are true: the retired rules declared a credentialed upstream, HostIpIds minted the id, and the registry has a proxy control socket. A box with no grant, or one under an id this registry did not mint, sends nothing. The second test covers both of those cases. The existing bep-revocation thread logs failures with the box id and the failed step. Its warning text says 'the destroy completed', and that wording now also covers a host_ip box end. A stop retires the box's rules with end: stopped and revokes nothing. Only a destroy revokes the box's id. This is safe because the retire already withdraws the registration name, so a later box under that name gets a new id. cargo clippy -p minvmd --all-targets and cargo fmt --check are clean.

Tests

line exit tail
cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-2a94... Compiling paths v0.0.1 (/workbench/crates/paths) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling client-config v0.0.1 (/wo
8000 cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-738a... Compiling version v0.8.0 (/workbench/crates/version) Compiling mlog v0.0.1 (/workbench/crates/mlog) Compiling minvmd v0.8.0 (/workbench/crates/minvmd) Finished 'test' profil

Verify

min task run agent-verify passed ([tasks.verify]).

Closes #3032

Residuals

retire_host_ip_box now sends the Box Egress Proxy a revocation of the
box's minted id when the box declared a credentialed upstream, as the
destroy of an own-address box does (BEP-043). The id stays in the id set,
so no later mint takes it.
@coderabbitai
coderabbitai Bot commented Nov 5, 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: ec4071e2-a585-4316-805b-b9951fa93e93

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

@minimal-foundry
minimal-foundry Bot commented Nov 5, 2026 •
Copy link
Copy Markdown
Contributor Author

Reviewed: 1 finding, none blocking at c9719cb471df.

Address the comments on the diff.

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 — 1 finding, 1 inline.

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

Comment thread crates/minvmd/src/box_registry.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 · 1 condition · the full ruling

The revocation itself conforms to BEP-043: it goes on destroy, uses the right gate, and keeps the id in the set. But retire_host_ip_box also runs when min session rename renames a live host_ip box (crates/minimal/src/cmd/session.rs:739). After this change, that rename permanently revokes the id of a running box. Gatehouse §6.10 line 839 says destroy is the one revocation event. architecture.md lines 486 and 499 say rename changes only the alias. Make the revocation a field of the retire request, default true, and send false from rename. C1 gives the edits.

Ruled at dea5244 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

Comment thread crates/minvmd/src/box_registry.rs Resolved
A retired host_ip box now logs that the box ended, not that a destroy
completed. The own-address destroy keeps its text, which the session
e2e matches.
@minimal-foundry minimal-foundry Bot left a comment
Copy link
8000 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/minvmd/src/box_registry.rs Resolved
Comment thread crates/minvmd/src/box_registry.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

line exit tail
cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-866c... Compiling paths v0.0.1 (/workbench/crates/paths) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling client-config v0.0.1 (/wo
cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-c22c... Compiling version v0.8.0 (/workbench/crates/version) Compiling mlog v0.0.1 (/workbench/crates/mlog) Compiling minvmd v0.8.0 (/workbench/crates/minvmd) Finished 'test' profil

Verify min task run agent-verify passed.

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM6z5V6I: spawn_revocation takes a BoxEnd now. A host_ip retire logs 'the box ended ...'. The destroy keeps its text, which scripts/session-e2e.sh matches. The info line says 'the ended box's revocation'. (not posted on the thread: not an open thread on the pull request)

After a host-address grant box ends, minvmd sends the proxy a revocation of its minted id, so the proxy refuses a sealed value under that id and min box audit shows the revocation. If the revocation fails, the bep-revocation warning now says the box ended, not that a destroy completed.

Notes from the agent: Revise round 1: spawn_revocation now takes a BoxEnd value. The own-address destroy keeps the text 'the destroy completed without a revocation from the Box Egress Proxy', because scripts/session-e2e.sh matches it and that script is outside this task's layers. The host_ip retire says 'the box ended ...'. The info line and the forget warning now say 'the ended box's revocation' for both callers. No test or script matches those lines. clippy -p minvmd --all-targets and cargo fmt --check are clean. just clippy-strict was not run.

@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 destroy of a credentialed host_ip box now revokes its id, and that part conforms. But retire_host_ip_box also runs on min box stop and on a rename. So a stop revokes the id of a box that restart brings back, and a rename revokes the id of a live box. Gatehouse §6.10 line 839 says destroy is the one revocation event. architecture.md lines 486 and 499 say that a rename and a restart keep the id. Make C1 to revoke only on a destroy, and C2 to take the rename off the retire. Add the tests in C3.

Outside the diff

  • crates/minimal/src/cmd/boxes/lifecycle.rs:600: C1 · The stop sends RetireHostIpBox. With this PR, that retire revokes the box id. Send end: stopped here, so that the stop drops the egress rules and does not revoke.
  • crates/minimal/src/cmd/boxes/lifecycle.rs:835: C2 · release_held_box_name retires the box, so with this PR a rename revokes a live box id. Architecture.md line 486 says a rename leaves the id untouched. Release only the old name's hold with hold_box_name_with_vm_host(.., false).

Ruled at fda1689 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

Comment thread crates/minvmd/src/box_registry.rs Resolved
Comment thread crates/minvmd/src/box_registry.rs Resolved
@norrietaylor
Copy link
Copy Markdown
Member

/revise Arch CONDITIONS at fda1689 (BEP-043, Gatehouse §6.10 line 839: destroy is the one revocation event). retire_host_ip_box has callers that are not a destroy. min box stop (crates/minimal/src/cmd/boxes/lifecycle.rs:600) sends RetireHostIpBox, and every rename calls release_held_box_name, which retires (lifecycle.rs:835, crates/minimal/src/cmd/session.rs:739). So this PR revokes the id of a stopped box that restart brings back, and the id of a live box that was renamed (architecture line 486: a rename leaves the id untouched). The owner accepts these files outside the layers: crates/minimald-rpc/src/lib.rs, crates/minimal-client/src/attach.rs, crates/minimal/src/cmd/boxes/vm_host.rs, crates/minimal/src/cmd/boxes/lifecycle.rs, crates/minimal/src/cmd/session.rs, crates/minimal/src/dash/rpc.rs, crates/minvmd/src/control.rs. Do these three things:

  1. Revoke only on a destroy (C1). Add a required field end: HostIpBoxEnd (stopped | destroyed, no serde default) to RetireHostIpBoxRequest in crates/minimald-rpc/src/lib.rs, so a request that does not say how the box ended is refused at decode.
    • Carry end through minimal_client::attach::host_ip_box_at and the retire_host_ip_box* helpers in vm_host.rs.
    • BoxRegistry::retire_host_ip_box takes end, and the RetireHostIpBox arm in control.rs passes request.end.
    • Run spawn_revocation(.., BoxEnd::HostIpRetire) only when the box was destroyed, declared a credentialed upstream, and has an id that HostIpIds minted.
    • cmd_box_stop sends stopped. These paths send destroyed: destroy, rm, prune, the attach that finds the box gone, the re-admit undo (vm_host.rs ~379, dash/rpc.rs ~355), settle_destroyed_box, withdraw_interrupted_box and the HostIpResidency drop.
    • Fix the BoxEnd::HostIpRetire and retire_host_ip_box doc comments to say that only a destroy revokes.
  2. A rename does not retir 8000 e the box (C2). In cmd_box_rename (lifecycle.rs) and the rename arm in session.rs (~739), replace the release_held_box_name(..) call. Release only the old name's hold: hold_box_name_with_vm_host(control_sock.clone(), old_name, Some(record.id), false) when record.name is Some. A rename then neither drops the live box's egress rules nor revokes its id.
  3. Tests (C3).
    • In crates/minvmd/src/box_registry.rs tests, add retiring_a_stopped_host_ip_grant_box_sends_no_revocation: a credentialed, minted box retired with end: stopped sends nothing to the stub control socket, and its id stays in the id set.
    • Keep retiring_a_host_ip_grant_box_revokes_its_minted_id for end: destroyed.
    • In vm_host.rs or lifecycle.rs tests, use the recording stub control socket to show that a rename of a host_ip box sends no RetireHostIpBox, and that the stop path sends RetireHostIpBox with end: stopped.

Run both T123 test lines and the new tests.

RetireHostIpBoxRequest now carries a required `end` (stopped or
destroyed), with no serde default. The registry revokes a credentialed,
minted id only on a destroy. A stop keeps the id, because a restart
brings the box back. The id set remembers a stopped grant box, so its
later destroy still revokes. `min box stop` retires as stopped, and the
destroy paths retire as destroyed.

A rename no longer retires the box. It releases the old name's hold and
holds the new name, so a live box keeps its egress rules and its id.

The no-grant test reads a synchronous record of spawned revocations in
place of a 200 ms sleep. The label-only warning test is removed.
@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/minvmd/src/box_registry.rs Resolved
Comment thread crates/minimald-rpc/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: PASS · the full ruling

This head conforms. A host_ip grant box now has its id revoked only when the box is destroyed, as Gatehouse §6.10 line 839 says. A stop and a rename keep the id, as architecture.md lines 486 and 499 require. The prior conditions on this PR are met. Update the PR body: it still says that a stop sends a revocation.

Ruled at d1a555b against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

10000
line exittail
cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-454c... Compiling paths v0.0.1 (/workbench/crates/paths) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling client-config v0.0.1 (/wo
cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-1bdf... Compiling version v0.8.0 (/workbench/crates/version) Compiling mlog v0.0.1 (/workbench/crates/mlog) Compiling minvmd v0.8.0 (/workbench/crates/minvmd) Finished 'test' profil

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

82/1800) minimal task::tests::unknown_task_message_lists_declared_tasks_sorted
        PASS [   0.011s] ( 583/1800) minimal tests::a_name_resolves_case_insensitively
        PASS [   0.013s] ( 584/1800) minimal task::tests::untrimmed_task_names_are_rejected
        PASS [   0.012s] ( 585/1800) minimal tests::a_non_hex_or_short_input_is_not_an_id_prefix
        PASS [   0.012s] ( 586/1800) minimal tests::a_unique_id_prefix_resolves_to_its_session
        PASS [   0.017s] ( 587/1800) minimal tests::activate_help_shows_network_flags
        PASS [   0.013s] ( 588/1800) minimal tests::activate_prints_routing_cause_once
        PASS [   0.015s] ( 589/1800) minimal tests::ambiguous_name_across_hosts_exit2_lists_candidates
        PASS [   0.627s] ( 590/1800) minimal resolver::tests::the_lists_two_queries_run_under_one_deadline
        PASS [   0.014s] ( 591/1800) minimal tests::an_ambiguous_id_prefix_cuts_at_the_first_differing_digit
        PASS [   0.018s] ( 592/1800) minimal tests::an_ambiguous_id_prefix_names_the_candidates
        PASS [   0.011s] ( 593/1800) minimal tests::an_exact_name_wins_and_an_ambiguous_fold_resolves_to_none
        PASS [   0.011s] ( 594/1800) minimal tests::an_exact_name_wins_over_an_id_prefix
        PASS [   0.012s] ( 595/1800) minimal tests::assess_at_risk_classifies_clean_dirty_and_unknowable
        PASS [   0.012s] ( 596/1800) minimal tests::attach_error_printed_after_terminal_restore
        PASS [   0.872s] ( 597/1800) minimal tests::ambiguous_name_across_hosts_exit2_lists_candidates_for_stop_and_rm
        PASS [   0.822s] ( 598/1800) minimal tests::attach_fall_through_hands_off_the_owning_vm
        FAIL [   1.514s] ( 599/1800) minimal tests::a_stopped_vm_does_not_hold_a_listing
  stdout ───

    running 1 test
    test tests::a_stopped_vm_does_not_hold_a_listing ... FAILED

    failures:

    failures:
        tests::a_stopped_vm_does_not_hold_a_listing

    test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 750 filtered out; finished in 1.50s

  stderr ───

    thread 'tests::a_stopped_vm_does_not_hold_a_listing' (4674) panicked at crates/minimal/src/tests.rs:3596:5:
    a stopped VM's stale socket must not charge the listing its connect-retry window (1.221450721s)
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 3 tests still running
        PASS [   0.288s] ( 600/1800) minimal tests::bare_status_counts_elsewhere_sessions
        PASS [   1.603s] ( 601/1800) minimal tests::a_stopped_vm_does_not_hold_a_box_name_resolution
        PASS [   1.019s] ( 602/1800) minimal tests::attach_refuses_a_box_name_two_vms_know
────────────
     Summary [  14.694s] 602/1800 tests run: 601 passed, 1 failed, 2 skipped
        FAIL [   1.514s] ( 599/1800) minimal tests::a_stopped_vm_does_not_hold_a_listing
warning: 1198/1800 tests were not run due to test failure (run with --no-fail-fast to run all tests, or run with --max-fail)
error: test run failed

Outside the task's layers::

  • crates/minimal-client/src/attach.rs
  • crates/minimal/src/cmd/boxes/lifecycle.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/cmd/mod.rs
  • crates/minimal/src/cmd/session.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimald-rpc/src/lib.rs
  • crates/minvmd/src/control.rs
  • crates/minvmd/src/net/answerer.rs
  • crates/minvmd/src/net/dns_pins.rs
  • crates/minvmd/src/net/egress_gate.rs
  • crates/minvmd/tests/vm_escape_integration.rs

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

Review threads the coder judged:

  • 👍 valid — crates/minvmd/src/box_registry.rs: Rename no longer retires: cmd_rename and cmd_box_rename call move_held_box_name, which releases only the old name's hold. The retire request carries a required end (stopped|destroyed) in place of a revoke bool, per the later directive.
  • 👍 valid — PRRT_kwDOPdfcxM6z5eJO: Deleted the constant-comparison test. capture_log is thread-local and the warning is logged on the bep-revocation thread, so the log text cannot be captured from the test. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — PRRT_kwDOPdfcxM6z5eJS: Removed the 200 ms sleep. spawn_revocation now records each id in a cfg(test) list before it spawns, and the test asserts the ids are absent, with no wait. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — crates/minvmd/src/box_registry.rs:6474: retire_host_ip_box takes the request's end and spawns the revocation only for destroyed. min box stop sends stopped, and a stopped grant box is revoked when it is destroyed later.
  • 👍 valid — crates/minvmd/src/box_registry.rs: BoxEnd::HostIpRetire and retire_host_ip_box doc comments now say only a destroy revokes, and a stopped box keeps its id.

After a host-address grant box is destroyed, the VM host daemon sends revoke_box and forget_box for its minted id to the Box Egress Proxy, so the proxy refuses a sealed value under that id and the revocation is in the audit log that min box audit reads. A stop or a rename of the box revokes nothing, and a box that was stopped first still has its id revoked when it is destroyed.

Notes from the agent: Files outside the layers: the directive's owner-accepted list (minimald-rpc lib.rs, minimal-client attach.rs, vm_host.rs, lifecycle.rs, session.rs, dash/rpc.rs, minvmd control.rs). Four more files changed only because the new required field and the new retire_host_ip_box argument must compile: crates/minimal/src/cmd/mod.rs (withdraw_interrupted_box sends destroyed), and test-only call sites in minvmd net/answerer.rs, net/dns_pins.rs, net/egress_gate.rs and tests/vm_escape_integration.rs (all pass destroyed). Design: host_ip_box_at's resident: bool became HostIpBoxChange { Admit, Retire(HostIpBoxEnd) }, so a retire cannot be sent without an end. One addition the directive did not name: a stop drops the box's rules, so a later destroy saw no credentialed lane and revoked nothing. HostIpIds now keeps a stopped_credentialed set, and the destroy of a stopped grant box still revokes (covered in retiring_a_stopped_host_ip_grant_box_sends_no_revocation). The rename and stop paths go through two new helpers in vm_host.rs (move_held_box_name, retire_stopped_box_with_vm_host), so the recording stub can test them without a daemon. The HostIpRetire warning prefix now says 'the box was destroyed'. That text is a log line, not printed output. minimald only pattern-matches RetireHostIpBox(_), so I did not lint it. just clippy-strict was not run.

@norrietaylor
Copy link
Copy Markdown
Member

/revise Arch CONDITIONS at d1a555b (BEP-082; architecture line 499: "ids, never names, key every record"; Gatehouse §6.10 line 839). Round 2 took the retire out of the rename. That retire was also what removed the old name from minvmd's registration-name map (HostIpIds.by_name; only retire_host_ip_box ~6447 and withdraw_host_ip_name ~4775 remove a name). After min box rename web api of a host_ip grant box, web still points at the live box's id. The box is admitted, so HOST_IP_UNADMITTED_NAME_BOUND never frees it, and a new grant box named web is refused with NameAlreadyHeld in register_host_ip_box_as. The owner's earlier acceptance of the files outside the layers still holds. Do these three things:

  1. Withdraw the old registration name on a rename (C1). In move_held_box_name (crates/minimal/src/cmd/boxes/vm_host.rs ~235), before the new hold, withdraw minvmd's registration name for the old name by the box's id. Use the existing no-address withdraw: withdraw_box_row(control_sock.clone(), Some(old_name), None, Some(minimald_rpc::BoxId::from_bytes(id.to_bytes()))). minvmd serves it through withdraw_host_ip_name, and it retires and revokes nothing.
  2. Tests.
    • Update a_rename_retires_nothing_and_a_stop_retires_as_stopped to expect three requests on a rename: the withdraw carrying the id, the release of the old hold and the new hold. Still no RetireHostIpBox.
    • Add a minvmd test in crates/minvmd/src/box_registry.rs or control.rs. Register a grant box under web and admit it. Withdraw the name by its id, as the rename does. Then show that a new registration under web gets a fresh id, and that the first id stays in the minted set.
  3. PR body.
    • In the agent notes, replace "The retire also runs when a host_ip box stops, and a stop sends a revocation too." with a sentence that says a stop retires the box's rules with end: stopped and revokes nothing, and only a destroy revokes.
    • Under Residuals, list Revoke a host_ip grant box's id on destroy across a minvmd restart #3041: a destroy after a minvmd restart sends no revocation, because HostIpIds is held in memory only.

Run both T123 test lines and the new tests.

A rename withdraws the old registration name by the box's id. The test
shows the name is free for a new grant box and the first id stays minted.
A rename now withdraws minvmd's registration name for the old name by
the box's id, so a new grant box under that name is not refused. The
withdraw retires and revokes nothing.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

line exit tail
cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-e1e3... Compiling paths v0.0.1 (/workbench/crates/paths) Compiling args v0.0.1 (/workbench/crates/args) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling client-config v0.0.1 (/wo
cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-629a... Compiling version v0.8.0 (/workbench/crates/version) Compiling mlog v0.0.1 (/workbench/crates/mlog) Compiling m 10BC8 invmd v0.8.0 (/workbench/crates/minvmd) Finished 'test' profil

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

     "span_id": "7f7606af41539ed2",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "GetPaths",
                "parent_span_id": "2b1e619696004cc9",
                "span_id": "6ac165e7bb53392a",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "2b1e619696004cc9",
                "queued_behind": "0",
                "span_id": "dce6e35f7481b4f6",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "2b1e619696004cc9",
                "queued_behind": "0",
                "span_id": "64eff867b0a73762",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "64eff867b0a73762",
                "span_id": "6a92b37ff8be2544",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "64eff867b0a73762",
                "queued_behind": "0",
                "span_id": "8ca472edb87e115a",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 3 tests still running
        PASS [   5.011s] (1019/1817) minimal-client box_registration::tests::resume_timeout_goes_on_and_an_absent_host_fails_closed
        PASS [   4.385s] (1020/1817) minimal-client tty_relay::tests::resume_after_drop_prints_line_and_nudges_winsize
        PASS [   6.094s] (1021/1817) minimal-client box_registration::tests::a_silent_daemon_does_not_hold_the_exit_past_the_deadline
────────────
     Summary [  57.979s] 1021/1817 tests run: 1020 passed, 1 failed, 2 skipped
        FAIL [   3.174s] (1018/1817) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
warning: 796/1817 tests were not run due to test failure (run with --no-fail-fast to run all tests, or run with --max-fail)
error: test run failed

Outside the task's layers::

  • crates/minimal-client/src/attach.rs
  • crates/minimal/src/cmd/boxes/lifecycle.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/cmd/mod.rs
  • crates/minimal/src/cmd/session.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimald-rpc/src/lib.rs
  • crates/minvmd/src/control.rs
  • crates/minvmd/src/net/answerer.rs
  • crates/minvmd/src/net/dns_pins.rs
  • crates/minvmd/src/net/egress_gate.rs
  • crates/minvmd/tests/vm_escape_integration.rs

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

Review threads the coder judged:

  • 👎 invalid — crates/minvmd/src/box_registry.rs:6464: The restart gap is wider than this flag: all of HostIpIds (the minted set too) is in memory only, so after a restart minted is false and no destroy revokes. That is tracked as Revoke a host_ip grant box's id on destroy across a minvmd restart #3041 and stays out of this PR, per the owner's note. Keeping the flag on re-admit is deliberate: a restarted box keeps
  • 👎 invalid — crates/minimald-rpc/src/lib.rs:1000: Deliberate. A default of destroyed makes an old client's stop revoke a live id. A default of stopped makes an old client's destroy never revoke. Both break BEP-043, so a retire that does not say how the box ended is refused, as the field's doc says.

After a host-address grant box is destroyed, minvmd sends the proxy a revoke_box line for its minted id, so the proxy refuses a sealed value under that id and min box audit shows the revocation. A stop or a rename revokes nothing. After min box rename web api, a new grant box named web registers under a fresh id.

Notes from the agent: Round 3. move_held_box_name (crates/minimal/src/cmd/boxes/vm_host.rs) now withdraws minvmd's registration name for the old name by the box's id before it releases the old hold and takes the new one. minvmd serves that withdraw through withdraw_host_ip_name, which retires and revokes nothing. The owner accepted this file outside the layers in an earlier round. The rename test now expects three requests: the withdraw with the id, the release and the hold, and still no RetireHostIpBox. New minvmd test: a_renamed_host_ip_grant_box_frees_its_old_name_for_a_fresh_id.

For the PR body, agent notes: a stop retires the box's rules with end: stopped and revokes nothing. Only a destroy revokes the box's id. (This replaces the sentence "The retire also runs when a host_ip box stops, and a stop sends a revocation too.")

Residuals: #3041. A destroy after a minvmd restart sends no revocation, because HostIpIds is held in memory only.

just clippy-strict was not run.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 4 of 10 on a failed check suite: the coder changed nothing. noop: this round changed nothing. The directive lists two failed checks and no new thread. ci-macos-success is the lane aggregator: its job runs only exit 1 because a gated job failed. The gated job is the macOS e2e job. It ended with exit code 100, which is the cargo-nextest code for a failed test run, so a test in the 'VM integration harnesses' step failed. The excerpt does not name the test or show its output, and I have no access to the run log. The only VM harness that this branch changes is crates/minvmd/tests/vm_escape_integration.rs, and its only change adds end: HostIpBoxEnd::Destroyed to the retire request. That harness admits its box with credentialed_upstream: false, so retire_host_ip_box sends no revocation for it and acts as it did before this branch. The excerpt also quotes the runner's reap step ('port ... is still held after the reap'), which points to leftover processes on the self-hosted runner. This box has no /dev/kvm, so I cannot run the VM har…[truncated]

@norrietaylor
norrietaylor marked this pull request as ready for review November 5, 2026 15:31
@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 at bda81e1, against the T123 plan block in #3032, BEP-043 and BEP-082.

  • Destroy is the one revocation event (Gatehouse §6.10 line 839).
    • RetireHostIpBoxRequest carries a required end: HostIpBoxEnd (stopped | destroyed). minvmd passes it to retire_host_ip_box, which spawns revoke_box only for a destroyed, credentialed box whose id HostIpIds minted.
    • min box stop sends stopped, and every destroy path sends destroyed: destroy, rm, prune, the attach that finds the box gone, the re-admit undo, settle_destroyed_box, withdraw_interrupted_box and the HostIpResidency drop.
    • A stopped box keeps its id, and a later rm or prune still revokes it.
  • A rename keeps the id (architecture lines 486 and 499). min box rename and min session rename no longer retire. move_held_box_name withdraws the old registration name by id (bda81e1), then moves the zone hold. So a new grant box under the old name gets a fresh id, and the renamed box keeps its rules and its id. A minvmd test pins the fresh id.
  • Wire. A retire with no end is refused at decode, so nothing is retired or revoked (fail closed).
  • PR body. The stop sentence is corrected, and #3041 is listed under Residuals.

Residual: #3041 (a destroy after a minvmd restart sends no revocation; HostIpIds is in memory only).

Lanes: the macOS e2e vm_escape_bounded_to_resident_union failure on the first run was a flake (#1845 class). The rerun passed.

@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 · the full ruling

This head adds one change to the PASS on d1a555b. A rename now withdraws the old host_ip name by the box id. minvmd serves that withdraw in withdraw_host_ip_name, which removes the name only. It does not retire the box or revoke the id. The id stays minted, so a later destroy still revokes it (gatehouse-spec.md line 839). The rename keeps the id, as architecture.md line 486 requires, and a new box under the old name gets a fresh id. Residual #3041 stays open.

Ruled at bda81e1 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

@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-rpc/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: PASS · the full ruling

The compare from 4104bdc9 changes one test call in crates/minvmd/src/box_registry.rs. It passes HostIpBoxEnd::Destroyed to retire_host_ip_box, so the test that the merge of #3014 brought matches the new signature. No other caller uses the old form. The revoke path is not changed, so the earlier ruling on BEP-043 and Gatehouse §6.10 line 839 stands. Residual #3041 stays open.

Ruled at ef92a66 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

@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/minvmd/src/box_registry.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 5 of 10 on the runtime's review findings, pushed as ef92a66e21f9.

Resolved conflicts in: crates/minvmd/src/box_registry.rs

line exit tail
cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-a0a3... Compiling paths v0.0.1 (/workbench/crates/paths) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling client-config v0.0.1 (/wo
cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-896b... Compiling version v0.8.0 (/workbench/crates/version) Compiling mlog v0.0.1 (/workbench/crates/mlog) Compiling minvmd v0.8.0 (/workbench/crates/minvmd) Finished 'test' profil

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

     "span_id": "4d3e346ed4a57fa0",
                "trace_id": "0af7651916cd43dd8448eb211c8
10BC8
03111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "GetPaths",
                "parent_span_id": "04e900d905a9b924",
                "span_id": "8e4254f711b2aa4b",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "04e900d905a9b924",
                "queued_behind": "0",
                "span_id": "0f0c079c6c9e4ed7",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "04e900d905a9b924",
                "queued_behind": "0",
                "span_id": "7e4294f915aaf791",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "7e4294f915aaf791",
                "span_id": "fcb5e9ac6c5b7e1c",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "7e4294f915aaf791",
                "queued_behind": "0",
                "span_id": "57ff96814a98aba9",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 3 tests still running
        PASS [   5.018s] (1031/1837) minimal-client box_registration::tests::resume_timeout_goes_on_and_an_absent_host_fails_closed
        PASS [   6.078s] (1032/1837) minimal-client box_registration::tests::a_silent_daemon_does_not_hold_the_exit_past_the_deadline
        PASS [   4.998s] (1033/1837) minimal-client tty_relay::tests::resume_after_drop_prints_line_and_nudges_winsize
────────────
     Summary [  76.224s] 1033/1837 tests run: 1032 passed, 1 failed, 2 skipped
        FAIL [   4.475s] (1030/1837) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
warning: 804/1837 tests were not run due to test failure (run with --no-fail-fast to run all tests, or run with --max-fail)
error: test run failed

Outside the task's layers::

  • crates/minimal-client/src/attach.rs
  • crates/minimal/src/cmd/boxes/lifecycle.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/cmd/mod.rs
  • crates/minimal/src/cmd/session.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimald-rpc/src/lib.rs
  • crates/minimald-rpc/src/tests.rs
  • crates/minvmd/src/control.rs
  • crates/minvmd/src/net/answerer.rs
  • crates/minvmd/src/net/dns_pins.rs
  • crates/minvmd/src/net/egress_gate.rs
  • crates/minvmd/tests/vm_escape_integration.rs

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

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM60I_Mp: Added #[serde(default)] on RetireHostIpBoxRequest::end, with HostIpBoxEnd::Destroyed as the default. No version gate covers the min-to-minvmd control socket, and old clients retired only on destroy. A minimald-rpc test pins the decode. (not posted on the thread: not an open thread on the pull request)

After a host-address grant box is destroyed, minvmd sends the revocation of its minted id to the proxy, so the proxy refuses a sealed value under that id, and min box audit shows the revocation. A retire from an older min that does not say how the box ended now counts as a destroy, so it is no longer refused.

Notes from the agent: This round changed only crates/minimald-rpc/src/lib.rs and its tests.rs. An earlier round already touched both files to add HostIpBoxEnd, and neither file is in the task's layers. RetireHostIpBoxRequest::end now has a serde default of Destroyed. Before this pull request, a client sent a retire only on its destroy paths. The stop retire is new in this pull request. So the default keeps the old meaning, and an old client never revokes the id of a box that it only stopped.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft November 5, 2026 16:02
@minimal-foundry minimal-foundry Bot added the needs-human An agent handed off; a human must act, then clear this label. Set by defer and handoffs. label Nov 5, 2026
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

The runtime will not revise this pull request again on its own: the diff is +496/-69 (565 lines), past 3x the plan's estimate of 180 lines (est: 60 code, 120 tests, as #3032 reads now), at round 5 (the last trigger was the runtime's review findings). A person decides now. Remove needs-human from this pull request to let /revise <note> or the automatic rounds resume, or finish #3032 by hand.

minimal-foundry Bot and others added 2 commits November 5, 2026 09:18
A test from main called retire_host_ip_box with one argument. A
client retire ends the box as destroyed, so the call passes
HostIpBoxEnd::Destroyed.
A min built before the end field also sends a retire on min box stop.
A default of destroyed read that stop as a destroy and revoked the id
of a box that min box restart brings back. The end field is required
again, so a retire that does not say how the box ended is refused at
decode, and nothing is retired or revoked.
@norrietaylor
norrietaylor force-pushed the agent/3032-revoke-a-host-address-grant-box-s-minted-id-at-t branch from ef92a66 to 626f5d6 Compare November 5, 2026 16:23
@norrietaylor norrietaylor removed the needs-human An agent handed off; a human must act, then clear this label. Set by defer and handoffs. label Nov 5, 2026
@norrietaylor
norrietaylor marked this pull request as ready for review November 5, 2026 17:08
@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 · the full ruling

This head conforms. A retire must now say how the box ended, and the control door refuses a retire with no end. An older min also sends a retire on min box stop and on rename. Under the old default, those retires revoked an id that restart brings back. Gatehouse §6.10 line 839 allows a revocation only on destroy. The refusal revokes nothing, and the NET-085 reconcile still clears the box's rules. Residual #3041 stays open.

Ruled at 626f5d6 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

@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: 3 unresolved threads — minimal-foundry[bot] crates/minvmd/src/box_registry.rs:6434, minimal-arch[bot] crates/minvmd/src/box_registry.rs:6432, minimal-foundry[bot] crates/minvmd/src/box_registry.rs:6432. No findings.

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

A reconcile sets aside the rules of a host_ip box the guest lists but
does not run. The retire then dropped those dormant rules unread, so a
credentialed grant box the guest stopped revoked nothing at its
destroy, and its stop never recorded it for a later destroy. BEP-043
says a destroy writes the revocation. The retire now reads whether the
box was credentialed from its dormant rules when the resident set holds
none.
@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 · 1 condition · the full ruling

The compare is correct: a destroy of a box with dormant rules now revokes its id. One path still loses the revocation. reconcile_host_ip_boxes drops the rules of a box that the guest no longer lists and keeps no record of the grant. If that pass runs before the client's retire_host_ip_box(.., Destroyed), the destroy revokes nothing. Section 6.10 line 839 says that the destroy writes the box revocation. Make the change in C1. Then the change conforms.

Ruled at d698066 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

Comment thread crates/minvmd/src/box_registry.rs 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/minvmd/src/box_registry.rs Resolved
A reconcile drops the rules of a host_ip box the in-VM daemon no longer
lists: the guest destroyed it with no retire from a client. That pass
withdrew the box's name but sent no revocation, and left the id in the
stopped set. BEP-043 says the end of a grant box revokes its minted id.
The reconcile now revokes the id of each such box that declared a
credentialed upstream, from resident or set-aside rules or the stopped
set, and clears it from the stopped set.
@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: 2 of 3 personas ran (correctness, security); did not complete: supply-chain.

Comment thread crates/minvmd/src/box_registry.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: PASS · the full ruling

This head closes the gap from the ruling on d6980668. A grant box that the VM destroys with no client retire now has its minted id revoked at the Box Egress Proxy. Gatehouse §6.10 line 839 and BEP-043 require that revocation. The id stays in the minted set, so it never returns. A failed list read changes nothing, so the path fails closed. No conditions.

Ruled at c9719cb against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

line exit tail
cargo nextest run -p minvmd retiring_a_host_ip_grant_box_revokes_its_minted_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-50d3... Compiling paths v0.0.1 (/workbench/crates/paths) Compiling ot v0.0.1 (/workbench/crates/ot) Compiling args v0.0.1 (/workbench/crates/args) Compiling client-config v0.0.1 (/wo
cargo nextest run -p minvmd retiring_a_host_ip_box_with_no_grant_sends_no_revocation 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-775d... Compiling version v0.8.0 (/workbench/crates/version) Compiling mlog v0.0.1 (/workbench/crates/mlog) Compiling minvmd v0.8.0 (/workbench/crates/minvmd) Finished 'test' profil

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

     "span_id": "d948bcdadf823218",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "GetPaths",
                "parent_span_id": "dea860172f61f4d1",
                "span_id": "510c32fa9c4fb415",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "GetRecord",
                "parent_span_id": "dea860172f61f4d1",
                "queued_behind": "0",
                "span_id": "14962bfef020b53c",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "DeleteSession",
                "parent_span_id": "dea860172f61f4d1",
                "queued_behind": "0",
                "span_id": "b1a39d639d5d3a94",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "session.message",
            fields: {
                "kind": "Destroy",
                "parent_span_id": "b1a39d639d5d3a94",
                "span_id": "7f3a404dfecaf9e0",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
        LoggedSpan {
            name: "sessions.manager.message",
            fields: {
                "kind": "HandOverName",
                "parent_span_id": "b1a39d639d5d3a94",
                "queued_behind": "0",
                "span_id": "1721ec2882e542ba",
                "trace_id": "0af7651916cd43dd8448eb211c803111",
            },
            parent: None,
            closed: true,
        },
    ]
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 3 tests still running
        PASS [   5.013s] (1031/1841) minimal-client box_registration::tests::resume_timeout_goes_on_and_an_absent_host_fails_closed
        PASS [   6.070s] (1032/1841) minimal-client box_registration::tests::a_silent_daemon_does_not_hold_the_exit_past_the_deadline
        PASS [   4.614s] (1033/1841) minimal-client tty_relay::tests::resume_after_drop_prints_line_and_nudges_winsize
────────────
     Summary [  65.720s] 1033/1841 tests run: 1032 passed, 1 failed, 2 skipped
        FAIL [   3.296s] (1030/1841) minimal::otel_cli exec_run_attach_and_task_run_share_the_commands_trace
warning: 808/1841 tests were not run due to test failure (run with --no-fail-fast to run all tests, or run with --max-fail)
error: test run failed

Outside the task's layers::

  • crates/minimal-client/src/attach.rs
  • crates/minimal/src/cmd/boxes/lifecycle.rs
  • crates/minimal/src/cmd/boxes/vm_host.rs
  • crates/minimal/src/cmd/mod.rs
  • crates/minimal/src/cmd/session.rs
  • crates/minimal/src/dash/rpc.rs
  • crates/minimald-rpc/src/lib.rs
  • crates/minimald-rpc/src/tests.rs
  • crates/minvmd/src/control.rs
  • crates/minvmd/src/net/answerer.rs
  • crates/minvmd/src/net/dns_pins.rs
  • crates/minvmd/src/net/egress_gate.rs
  • crates/minvmd/tests/vm_escape_integration.rs

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

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM60JYnl: Fixed in d698066: retire_host_ip_box reads declares_credentialed_upstream from the dormant rules when the resident set holds none, for a destroy and for a stop. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — PRRT_kwDOPdfcxM60JY1C: Fixed in d698066: when removed_rules is None, the credentialed flag comes from the dormant rules. Tests a_destroyed_dormant_grant_box_revokes_its_id and a_stopped_dormant_grant_box_revokes_at_its_destroy cover it. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — PRRT_kwDOPdfcxM60Jimk: Fixed in d698066: the retire reads the dormant rules before it drops them, so a destroy of a box the guest stopped revokes its id. (not posted on the thread: not an open thread on the pull request)
  • 👍 valid — crates/minvmd/src/box_registry.rs:6440: reconcile_host_ip_boxes now keeps the credentialed flag of each box the guest no longer lists, from resident or set-aside rules, and revokes its minted id. It does not wait for a later client destroy. Test: a_grant_box_the_vm_destroyed_revokes_its_id.
  • 👍 valid — crates/minvmd/src/box_registry.rs:7813: The reconcile now revokes the id of a credentialed box the VM destroyed and removes it from stopped_credentialed. The in-memory set across a minvmd restart is not changed. That needs persistence, which is beyond this task.

After a host-address grant box ends, by a client's destroy or by the VM destroying it, minvmd sends revoke_box and then forget_box for its minted id. The proxy then refuses a sealed value under that id, and min box audit shows the revocation. A stop still revokes nothing.

Notes from the agent: Revise round 1. Threads 1-3 (dormant rules on a destroy) were already fixed on this branch by d698066. This round fixes threads 4-5: reconcile_host_ip_boxes now revokes the minted id of a credentialed box the guest no longer lists, and clears it from stopped_credentialed. The new BoxEnd::HostIpGuestDestroy names that step in the bep-revocation warnings ("the VM destroyed the box"). Not done: the HostIpIds set is still in memory only, so a minvmd restart between a stop and a destroy loses the stopped-credentialed record. Persistence is a design change beyond this task. A box a client stopped and the VM later destroyed, with no destroy retire, is also not revoked, because the reconcile thread runs only while minvmd holds host_ip rules. just clippy-strict was not run.

@minimal-foundry
minimal-foundry Bot marked this pull request as draft November 5, 2026 17:39
@minimal-foundry minimal-foundry Bot added the needs-human An agent handed off; a human must act, then clear this label. Set by defer and handoffs. label Nov 5, 2026
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

The runtime will not revise this pull request again on its own: the diff is +719/-82 (801 lines), past 3x the plan's estimate of 180 lines (est: 60 code, 120 tests, as #3032 reads now), at round 1 (the last trigger was the runtime's review findings). A person decides now. Remove needs-human from this pull request to let /revise <note> or the automatic rounds resume, or finish #3032 by hand.

@norrietaylor norrietaylor removed the needs-human An agent handed off; a human must act, then clear this label. Set by defer and handoffs. label Nov 5, 2026
8
@norrietaylor
norrietaylor marked this pull request as ready for review November 5, 2026 18:30
@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.

Gate passed at c9719cb.

@norrietaylor
norrietaylor added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit b5233b0 Nov 5, 2026
36 checks passed
@norrietaylor
norrietaylor deleted the agent/3032-revoke-a-host-address-grant-box-s-minted-id-at-t branch November 5, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

T123 — Revoke a host-address grant box's minted id at the proxy when the box ends

1 participant

0