8000 T126 — Keep a host-address grant box's minted id across a VM host daemon restart, so its destroy revokes it by minimal-foundry[bot] · Pull Request #3064 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

T126 — Keep a host-address grant box's minted id across a VM host daemon restart, so its destroy revokes it - #3064

Merged
norrietaylor merged 3 commits into
mainfrom
agent/3049-keep-a-host-address-grant-box-s-minted-id-across
Nov 5, 2026
Merged

norrietaylor merged 3 commits into
mainfrom
agent/3049-keep-a-host-address-grant-box-s-minted-id-across

Conversation

@minimal-foundry
Copy link
Copy Markdown
Contributor

T126 — Keep a host-address grant box's minted id across a VM host daemon restart, so its destroy revokes it

slice: S17
kind: task
covers: BEP-043
size: M
est: 100 code, 220 tests
executor: agent
difficulty: needs care
model: standard
diagnostics: min box audit <box> for a host_ip grant box destroyed after a VM host daemon restart shows the revocation of its id, as it does with no restart between; the ids sit in box-host-ip-ids.json beside box-registry.json in the VM host daemon's state dir
observability: the existing bep-revocation thread's warning names the box id and the step that failed; a failed write of the id file is a warn line naming the path, as a failed write of the held names is; the reload logs one info line with the count of minted and credentialed ids it read
layers:
- persist:
- crates/minvmd/src/box_registry.rs: HostIpIds gains credentialed, the minted ids admitted with a credentialed lane, in place of 8000 stopped_credentialed, and a destroy revokes an id in it; ids and credentialed persist to a new HOST_IP_IDS_FILE beside REGISTRY_FILE after each change through write_registry_file, and persisting_to reloads them, so a reloaded id is held for the collision check and revoked at its box's destroy; an unusable file is set aside and reloads no id; reconcile_host_ip_boxes also revokes each id in credentialed whose box the guest list no longer holds, and drops it from the set, so a stopped grant box that the VM destroys with no retire from a client revokes its id
test: cargo nextest run -p minvmd restarted_registry_revokes_a_destroyed_grant_box_id
test: cargo nextest run -p minvmd restarted_registry_never_mints_an_id_it_minted_before
test: cargo nextest run -p minvmd a_stopped_grant_box_the_vm_destroyed_revokes_its_id
produces: none
consumes:
- the revocation of an ended host-address grant box
proof: A host-address grant box destroyed after the VM host daemon restarted has its id revoked at the proxy, and min box audit shows the revocation.
depends on:
- blocked by #3032

Proof

A host-address grant box that a person destroys after the VM host daemon restarts now has its id revoked at the Box Egress Proxy. The id and its credentialed lane are kept in box-host-ip-ids.json beside box-registry.json, so the restarted daemon sends revoke_box for that id. The revocation record that min box audit reads is then written. The tests show the revoke_box and forget_box lines reach the proxy after a reload.

Notes from the agent: HostIpIds.stopped_credentialed is replaced by credentialed, which holds each minted id admitted with a credentialed lane until its box is destroyed. A non-persisted credentialed_admit map holds the admit count of each credentialed id. The reconcile sweep uses it to skip an id that a client admitted after the mark, so a stale guest list cannot revoke a new box. A reloaded id has no entry, so the sweep treats it as older than the mark. The id file grows with each host_ip registration, because ids never shrinks (about 40 bytes for each id in JSON). The proof was checked with a stub control socket, not with a live proxy and min box audit. The reload info line and the warn line on a failed write are added as the observability line says.

Tests

line exit tail
cargo nextest run -p minvmd restarted_registry_revokes_a_destroyed_grant_box_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-8a05... 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 restarted_registry_never_mints_an_id_it_minted_before 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-fe77... 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
cargo nextest run -p minvmd a_stopped_grant_box_the_vm_destroyed_revokes_its_id 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-6b51... 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.

43/718) minvmd net::egress_gate::tests::a_switch_that_hangs_up_takes_the_relay_down_with_it
        PASS [   0.239s] (444/718) minvmd net::egress_gate::tests::a_switch_that_never_answers_releases_the_control_relay_at_the_drain_bound
        PASS [   0.145s] (445/718) minvmd net::egress_gate::tests::a_transient_accept_failure_is_ridden_out_and_keeps_the_gate_serving
        PASS [   0.027s] (446/718) minvmd net::egress_gate::tests::a_waiting_forward_is_dropped_when_its_own_row_is_withdrawn
        PASS [   0.044s] (447/718) minvmd net::egress_gate::tests::a_withdrawn_address_is_held_until_its_forwards_are_unbound
        PASS [   0.047s] (448/718) minvmd net::egress_gate::tests::a_zone_add_of_a_foreign_name_at_a_rows_address_is_refused
        PASS [   0.024s] (449/718) minvmd net::egress_gate::tests::abort_on_drop_ends_the_tasks_it_holds
        PASS [   0.039s] (450/718) minvmd net::egress_gate::tests::accept_failures_split_transient_from_fatal
        PASS [   0.050s] (451/718) minvmd net::egress_gate::tests::admitted_runtime_port_reaches_the_box_through_the_gate
        PASS [   0.031s] (452/718) minvmd net::egress_gate::tests::admitted_runtime_udp_port_does_not_admit_tcp
        PASS [   0.022s] (453/718) minvmd net::egress_gate::tests::an_admitted_probe_round_is_relayed_as_its_canonical_request
        PASS [   0.032s] (454/718) minvmd net::egress_gate::tests::an_expose_on_the_boxs_leased_loopback_publishes_when_the_listener_is_declared
        FAIL [   5.019s] (455/718) minvmd net::egress_gate::tests::a_query_dropped_at_the_queue_is_not_observed
  stdout ───

    running 1 test
    test net::egress_gate::tests::a_query_dropped_at_the_queue_is_not_observed ... FAILED

    failures:

    failures:
        net::egress_gate::tests::a_query_dropped_at_the_queue_is_not_observed

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

  stderr ───

    thread 'net::egress_gate::tests::a_query_dropped_at_the_queue_is_not_observed' (2770) panicked at crates/minvmd/src/net/egress_gate.rs:20369:9:
    the guest side keeps draining; it does not wedge
    note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

  Cancelling due to test failure: 3 tests still running
        PASS [   2.619s] (456/718) minvmd net::egress_gate::tests::a_stalled_relay_leaves_another_relay_flowing
        PASS [   2.232s] (457/718) minvmd net::egress_gate::tests::an_idle_reloaded_box_s_attach_announce_stands_its_row_past_the_bound
        PASS [   4.087s] (458/718) minvmd net::egress_gate::tests::a_stalled_switch_does_not_hold_the_relay_past_a_guest_close
────────────
     Summary [  41.684s] 458/718 tests run: 457 passed (1 leaky), 1 failed, 1 skipped
        FAIL [   5.019s] (455/718) minvmd net::egress_gate::tests::a_query_dropped_at_the_queue_is_not_observed
warning: 260/718 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

Closes #3049

The VM host daemon now persists every minted host_ip box id, and the
ids admitted with a credentialed lane, to box-host-ip-ids.json beside
box-registry.json. A restarted daemon reloads them, so it still refuses
to mint a used id, and the destroy of a grant box still revokes its id
at the Box Egress Proxy (BEP-043). The reconcile also revokes a
credentialed id whose box holds no rules once the VM no longer lists 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: 0ebd85c3-e4be-456f-a098-2df26509967c

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

Approved: every review thread resolved at c52e9d402fd9.

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

Nothing to do.

@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 persisted ids and the destroy revocation after a restart conform to Gatehouse §6.10 line 839. One path does not. The new sweep in reconcile_host_ip_boxes runs only when the reconcile loop runs a pass. The loop skips every pass while holds_host_ip_boxes() is false. So a lone stopped grant box that the VM destroys writes no revocation. Line 839 says the revocation is written when the box is destroyed. Make the change in C1. It widens the gate to the credentialed ids and pins the gate in the two tests.

Ruled at 3015529 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
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — approval withheld

Verdict COMMENT — APPROVE withheld: 2 unresolved threads — minimal-arch[bot] crates/minvmd/src/box_registry.rs:6796, minimal-arch[bot] crates/minvmd/src/box_registry.rs:14238. No findings.

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

@norrietaylor
Copy link
Copy Markdown
Member

/revise Arch CONDITIONS at 3015529 (arch_rulings 991), condition C1. The reconcile loop in crates/minvmd/src/control.rs (spawn_host_ip_reconcile_with) skips every pass while boxes.holds_host_ip_boxes() is false, and that predicate counts only resident and dormant rules. So the new sweep in reconcile_host_ip_boxes never runs when the only host_ip box is a client-stopped grant box, or when a restarted daemon holds only reloaded ids. A destroy in the VM then writes no revocation (Gatehouse §6.10 line 839). Do these two things:

  1. In crates/minvmd/src/box_registry.rs, make BoxRegistry::holds_host_ip_boxes() also return true when HostIpIds::credentialed is not empty. Take the ids' lock after the resident set's read lock, as on the register path. Update its doc line.
  2. Pin the gate in the tests:
    • In a_stopped_grant_box_the_vm_destroyed_revokes_its_id, after the HostIpBoxEnd::Stopped retire, add assert!(registry.holds_host_ip_boxes()).
    • In restarted_registry_revokes_a_destroyed_grant_box_id, after the reload, add assert!(after.holds_host_ip_boxes()).

Change nothing else. Keep each commit message line at 100 characters or fewer. Run the three T126 test lines.

holds_host_ip_boxes now also returns true while a credentialed id waits
for its box's destroy. The reconcile loop then sweeps a lone stopped grant
box, or a restarted daemon's reloaded ids, and revokes the id when the VM
destroys the box. The tests pin the gate.
@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 makes holds_host_ip_boxes() return true while a credentialed id waits for its destroy. The reconcile loop now runs the sweep for a stopped grant box and for ids reloaded after a restart. The persisted ids keep the destroy-written revocation against an id that never returns, as Gatehouse §6.10 line 839 requires. The change conforms, and no condition is open.

Ruled at c52e9d4 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: 2 unresolved threads — minimal-arch[bot] crates/minvmd/src/box_registry.rs:6796, minimal-arch[bot] crates/minvmd/src/box_registry.rs:14244. No findings.

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

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

line exit tail
cargo nextest run -p minvmd restarted_registry_revokes_a_destroyed_grant_box_id 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-de99... 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 restarted_registry_never_mints_an_id_it_minted_before 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-d910... 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
cargo nextest run -p minvmd a_stopped_grant_box_the_vm_destroyed_revokes_its_id 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-646e... 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 — crates/minvmd/src/box_registry.rs:6796: holds_host_ip_boxes() now also returns true while HostIpIds::credentialed is not empty, so the reconcile loop runs the sweep for a lone stopped grant box or reloaded ids.
  • 👍 valid — crates/minvmd/src/box_registry.rs:14244: Added assert!(registry.holds_host_ip_boxes()) after the Stopped retire, and assert!(after.holds_host_ip_boxes()) after the reload in restarted_registry_revokes_a_destroyed_grant_box_id.

A host-address grant box destroyed after the VM host daemon restarted has its id revoked at the proxy, and min box audit shows the revocation. The reconcile gate now also opens while a credentialed id waits for its destroy, so this holds when the daemon holds only reloaded ids or a lone stopped grant box.

Notes from the agent: Revise round 1: BoxRegistry::holds_host_ip_boxes() also returns true when HostIpIds::credentialed is not empty. It takes the ids' lock after the resident set's read lock, as on the register path. No code path takes the resident lock while it holds the ids lock. Both test assertions are added. Nothing else changed.

@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 c52e9d402fd9 withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.

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

Gate passed at c52e9d4 under the standing gate-4 rule.

@norrietaylor
norrietaylor added this pull request to the merge queue Nov 5, 2026
Merged via the queue into main with commit 2e3da1d Nov 5, 2026
36 checks passed
@norrietaylor
norrietaylor deleted the agent/3049-keep-a-host-address-grant-box-s-minted-id-across branch November 5, 2026 21:57
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.

T126 — Keep a host-address grant box's minted id across a VM host daemon restart, so its destroy revokes it

1 participant

0