8000 T66 — Register a box on the host and hand it its addresses by minimal-foundry[bot] · Pull Request #1789 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

T66 — Register a box on the host and hand it its addresses - #1789

Merged
norrietaylor merged 22 commits into
mainfrom
agent/1711-register-a-box-on-the-host-and-hand-it-its-addre
Oct 1, 2026
Merged

norrietaylor merged 22 commits into
mainfrom
agent/1711-register-a-box-on-the-host-and-hand-it-its-addre

Conversation

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

T66 — Register a box on the host and hand it its addresses

slice: S9
kind: task
covers: NET-138
size: M
est: 280 code, 140 tests
executor: agent
difficulty: needs care
model: strongest
diagnostics: the bundle's VM host daemon log names each registration with the box id and the addresses allocated; the daemon log names the handed address at attach
observability: one info log line per registration with the box id and its two addresses; one debug line per attach naming the handed address
layers:
- vmhost:
- crates/minvmd/src/control.rs (new): the host-side control socket the client registers a box on and reads its addresses from
- crates/minvmd/src/box_registry.rs: a registration fills the box's row from the client's expanded spec and allocates its switch and loopback addresses from the helper's slice
- crates/minvmd/src/lib.rs: declares the control module
test: cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon
- cli:
- crates/minimal/src/cmd/session.rs: on a VM-backed host, activate registers the new box (id, name, ingress rules, egress rules) with the VM host daemon over its control socket, receives the box's switch and loopback addresses, and passes them in the session create request
test: cargo nextest run -p minimal activate_registers_box_with_vm_host
- daemon:
- crates/minimald-rpc/src/lib.rs: the session create request carries the handed switch and loopback addresses
- crates/minimald/src/net/gvproxy_network.rs: an own-address attach configures the tap with the handed address and selects none
test: cargo nextest run -p minimald own_ip_attach_uses_handed_address
produces:
- crates/minvmd/src/control.rs
consumes:
- crates/minvmd/src/box_registry.rs
proof: On a VM-backed host, activate registers the new box with the VM host daemon on the host, the VM host daemon allocates the box's switch and loopback addresses into its table and hands them back, and the in-VM daemon attaches the box with the handed switch address and selects none.
depends on:
- blocked by #1640

Proof

On a VM-backed host, min session activate --network own-ip register 8000 s the new box (name, expanded ingress ports, declared egress policy) with the VM host daemon over a same-uid 0600 control socket beside the ssh socket. The host daemon allocates the box's switch and loopback addresses from the upper half of the plan's PTask run with a monotone cursor, fills the row from the client's expanded spec, and hands the pair back; the create request carries it, and the in-VM daemon attaches the tap at the handed address (IpAllocator::hand) and selects none. The lower half of the run is the in-VM daemon's self-allocation reserve (task sandboxes and unregistered boxes), so a handed address can never collide with a drawn one; a handed address an attach still holds is refused, never shared.

Withdrawal. The creator withdraws the row it registered: min session destroy, and every activate path that fails after registration, sends the withdraw verb with the box's name and handed pair, and the host daemon removes the row only when the pair matches the creator's row (WithdrawError otherwise). Addresses are not reused (the cursor never regresses); withdrawal ends the row's admissions. The daemon-side lease ends with its attach, handed or drawn alike, so the static-lease table holds only live taps; the host row is untouched by detach.

Interim, stated in the code. Control-socket trust is the socket's 0600 mode with no peer-credential check, served serially with a 30 s read timeout. An absent socket degrades an own-ip activate to unregistered with a warning rather than failing it. The gate's UNREGISTERED_SOURCE_PHASE is not flipped here: the flip belongs to the task that lands the last row source, and the host-address cohort row is not yet planned. The host-row check by box id lands with T44 (#1660, NET-133).

Design review: ARCH-EXPERT ruled on the two-cursor split, the control-socket posture and the withdraw ownership (creator withdraws its own row; T66, not T44); every condition landed by round 5.

Out of layer, justified

The create request's new box_addresses field forced the SessionConfig / Record constructor literals across the CLI, TUI, daemon store and test harness to name it (None everywhere but the own-ip activate path and the store samples). The withdraw verb added crates/minimal/src/cmd/mod.rs (the control-socket client helper) beside the plan's session.rs.

Tests

line exit
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0
cargo nextest run -p minimal activate_registers_box_with_vm_host 0
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0
cargo nextest run -p minvmd host_row_withdrawn_on_destroy 0 (CI lanes)

Verify

min task run agent-verify passed. Every lane is green at the head.

Closes #1711

The host-side box table (NET-138) had no way to be filled from a
creator: the activating client had no door to minvmd, so an own-address
box's row never landed in the registry the egress gate decides by, and
its addresses were left to the daemon to draw itself.

Add the VM host daemon's box-registration control socket, beside the
ssh socket in the provider-instance dir, speaking one JSON line each
way over the wire types in minimald-rpc (RegisterBoxRequest /
RegisterBoxReply). A registration allocates the box's switch address
from the plan's lease run and its loopback address from the slice the
host switch publishes at — shared cursors across registry clones, so
no address is ever handed twice — fills the row from the client's
expanded spec, and answers with the addresses; one info line per
registration names the box and both of them. run.rs binds the socket
at boot and degrades to a warn, not a failed boot, when it cannot.
An own-address activation on a minvmd-backed host had no way to put its
box into the host-side table the egress gate decides by: it created the
session without telling the VM host daemon anything, so the box drew its
own switch address and its declared rules reached no host-side gate.

Before the create, activate registers the box over the VM host daemon's
control socket — the box's name, its expanded ingress ports, its egress
policy — and carries the addresses the daemon hands back in the create
request, so the in-VM daemon attaches with the handed switch address. A
host-ip box shares the node's own row, a none box has no switch address,
and a native daemon has no box table: all three register nothing. A
registration that cannot be made degrades to a warning, never a failed
activation, the same way a supervisor predating the socket behaves.

Carries the wire groundwork with it: sessions::BoxAddresses (the pair
handed together) rides the SessionConfig and the session Record, and the
struct literals across the workspace gain the new field.
An own-address session now attaches at the switch and loopback addresses
the VM host daemon allocated for its box registration and handed back in
the create request, instead of drawing one from the switch allocator
itself. The handed address still lands in the lease table, so the
never-reuse rule and every downstream consumer of that table see it the
same way as a self-allocated one.

- Record carries the handed pair from the create request into the
  session launcher, and the task path passes none deliberately: a task
  sandbox is not the box the registration named.
- SwitchClient::attach_handed validates the handed address against the
  plan's PTask run and records the lease without a draw; a handed
  address outside the plan is NetError::HandedAddressOutsidePlan.
- The one debug line per attach names the handed address and whether it
  was honored from the host.

The switch allocator's next draw skips past a handed lease, so an
interim self-allocating session cannot take the box's address.
cargo fmt across the three box-registration commits; no code-meaning
change.
- read_request_line carries the slice invariant as an expect with a
  reason, matching the header-parts precedent.
- the test register helper maps a serialization failure into its
  io::Result instead of expecting.
- complete_own_ip_attach switches its too_many_arguments allow to an
  expect with a reason.
- the socketpair's second descriptor gets its own SAFETY comment.
- the fake VM host's reply writes propagate a client that is already
  gone instead of discarding the must-use result.
@coderabbitai
coderabbitai Bot commented Oct 1, 2026 •
Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

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

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 99a9a606-3844-420f-a79a-7f7e1d9dc9ab

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
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


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.

Review at 5cb14db against the T66 plan block and NET-138 (the requirement text lives in spec PR #1707, not yet on main).

Every layer obligation is implemented: the control socket (control.rs), host-side registration and allocation (box_registry.rs register_client_box / take_next), the CLI registering before create and carrying the pair in the request, and the daemon attaching with the handed address through attach_handed / IpAllocator::hand. The daemon half lives in net/mod.rs and net/provider.rs rather than the gvproxy_network.rs the plan named; that is the right home. The three plan tests are non-vacuous. The 17 out-of-layer files are 12 mechanical box_addresses: None literals and 5 pieces of wiring the plan omitted (starting the control server in run.rs, the shared BoxAddresses type and Record field, and the launcher threading). Justified; the draft is un-drafted once the blocking thread below is fixed.

One blocking defect (two allocators over one address run) and one design note, inline. Not asks for this PR: no withdraw verb exists yet, so destroyed boxes and failed creates leave live rows (T63 #1788 carries row withdrawal); UNREGISTERED_SOURCE_PHASE stays Announced although the gate doc says T66 flips it (not in this plan's layers; follow-up); the request carries the box name but no box id, which NET-133 will need. Size: plan est 280 code + 140 tests, PR is +1469; most of that is the literal fallout and tests.

Comment thread crates/minimald/src/net/mod.rs Resolved
Comment thread crates/minimald/src/exec.rs Resolved
@norrietaylor
Copy link
Copy Markdown
Member

/revise

Round 1, bounded to two items from review 5379008672. Nothing else is in scope for this round.

  1. crates/minimald/src/net/mod.rs:244-246 (IpAllocator::hand): an existing lease at the handed address may only be returned when that lease was itself handed (the daemon-restart re-attach). A self-drawn lease at that address is a collision: record whether each lease was handed and return a new NetError::HandedAddressCollision { address, holder } for it, surfaced as a failed launch like HandedAddressOutsidePlan. Add a test that self-allocates an address, hands the same address, and asserts the error; keep own_ip_attach_uses_handed_address passing.
  2. crates/minimald/src/exec.rs:188-192: extend the comment to state the interim plainly: task sandboxes self-allocate from the same run the host hands box addresses from, and a collision is refused daemon-side by item 1. No behaviour change here this round.

Re-run the three plan test lines at the new head.

…0s ran out

the coder's uncommitted work as it stood when its 7200s ran out

The coder was stopped at the end of its time with these changes
not committed. The runtime committed its working tree as it stood so
the work is kept: this commit is a snapshot, not a finished step, and
may not build or pass its tests.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 1 of 10 on a review requesting changes, pushed as fc3341a6d78c.

The coder ran out of its 7200s before it finished. If it left work uncommitted, its last commit is the runtime's snapshot of that work as it stood — the commit message says so — and not a finished step: it may not build or pass its tests.

line exit tail
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0 .36 Compiling rustls v0.23.45 Compiling rustix v1.1.4 Compiling tracing v0.1.44 Compiling parking_lot_core v0.9.12 Compiling icu_normalizer v2.2.0 Compiling parking_lot v0.12.5 Compiling tokio v1.53.1 Compiling tracing-log v0.2.0 Compiling idna_adapter v1.2.2 Compiling
cargo nextest run -p minimal activate_registers_box_with_vm_host 0 r v0.9.1 Compiling ssh-cipher v0.3.0 Compiling hakoniwa v1.7.2 (https://github.com/souk4711/hakoniwa.git?rev=0810ffa37620ef5c57de263c8eaa1f4d7633c14a#0810ffa3) Compiling signal-hook v0.3.18 Compiling kasuari v0.4.12 Compiling unicode-truncate v2.0.1 Compiling lru v0.18.2 Compili
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-0a76... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/d6c34/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/d6c34/tree/crates/args) C

Verify min task run agent-verify passed.

Outside the task's layers::

  • crates/minimal-tui/src/rpc.rs
  • crates/minimal-tui/tests/snapshots.rs
  • crates/minimal/src/task.rs
  • crates/minimal/tests/cli.rs
  • crates/minimald/src/exec.rs
  • crates/minimald/src/net/mod.rs
  • crates/minimald/src/net/provider.rs
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/session.rs
  • crates/minimald/src/session/tests.rs
  • crates/minimald/src/session_host.rs
  • crates/minimald/src/sessions.rs
  • crates/minimald/src/store.rs
  • crates/minimald/src/test_harness.rs
  • crates/minvmd/examples/exec.rs
  • crates/minvmd/src/cmd/run.rs
  • crates/minvmd/tests/minimald_session_integration.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs

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

On a VM-backed host, activate registers the new box with the VM host daemon on the host, the VM host daemon allocates the box's switch and loopback addresses into its table and hands them back, and the in-VM daemon attaches the box with the handed switch address and selects none.

Commit headers reworded by the runtime to fit commitlint. The header the coder wrote is the first paragraph of each of these commits' bodies:

  • feat(minimald): the coder's uncommitted work as it stood when its 7200s ran out

@norrietaylor
Copy link
Copy Markdown
Member

/revise

Round 2, from the ARCH-EXPERT design ruling on round 1 (PASS-with-conditions). Bounded to five items; nothing else is in scope for this round.

  1. crates/minimald/src/net/mod.rs (IpAllocator): reserve a disjoint sub-run of the plan's PTask run for daemon self-allocation (task sandboxes, unregistered boxes) and draw self-allocations only from it; the host hands addresses only from the remainder, so the two allocators cannot meet. Mirror the split in crates/minvmd/src/box_registry.rs take_next bounds (hand from the remainder only) and keep exhaustion an explicit error with no wrap or reuse on either side.
  2. IpAllocator::hand (round 1 added HandedAddressCollision for locally-drawn leases and a handed list that lets a handed address be re-handed): the design wants any existing lease refused, whatever its origin, since a box attaches once per daemon life and a restart starts from an empty allocator. Drop the re-hand allowance and the handed list unless a real same-daemon re-attach path is named in the doc; also refuse an address inside the self-allocation sub-run. Keep hand_refuses_an_address_a_local_lease_holds and add one for the sub-run refusal.
  3. crates/minimald/src/exec.rs:188-192 and the IpAllocator doc: state the interim plainly: task sandboxes self-allocate from the reserved sub-run until the task registering them host-side (NET-138's "every live box") retires self-allocation, after which no daemon-side draw happens once a control socket exists.
  4. crates/minimal/src/cmd/session.rs (activate's registration failure path): the warn names the missing registration and says the box runs unattributed until the gate is in force (#1790 carries fail-closed).
  5. crates/minvmd/src/control.rs module doc: state that same-uid 0600 on the UDS is the trust (no peer-cred check), that requests are served serially with the 30 s read timeout, and that this is the v1 posture.

Re-run the three plan test lines at the new head.

The plan's PTask run is now two disjoint sub-runs: the daemon
self-allocates task sandboxes and unregistered boxes from the lower
half (net::self_allocation_run), and the VM host daemon hands
registered boxes only from the upper half (box_registry::hand_out_run,
the mirrored midpoint rule). Each side's tests pin the default plan's
split literally, so the two statements cannot drift silently.

IpAllocator::hand now refuses any recorded lease whatever drew it (a
box attaches once per daemon life; a restart starts from an empty
allocator, so the re-hand allowance and its handed list are gone) and
refuses an address inside the reserve, where a host that disagrees
about the split would put a box beside the daemon's own draws.

Exhaustion stays an explicit error with no wrap or reuse on either
side; the interim is stated in the IpAllocator and task_network docs —
task sandboxes self-allocate from the reserve until the task
registering every live box host-side retires daemon-side allocation —
and the control socket's module doc states its v1 posture: the
same-uid 0600 socket is the trust, requests are served serially with
the 30 s read timeout.
A box whose VM host registration cannot be made runs with no host-side
row: its frames are unattributed under the egress gate's announced
interim, and the gate's per-box default fails closed for it when it
binds (#1790). The warnings on the registration failure path — an
unresolvable provider dir, a refusal, the deadline — now name the
missing registration and that posture instead of the old
egress-not-enforced phrasing.
clippy's manual_div_ceil flags (last - first + 1) / 2 in both mirrored
split functions; (last - first).div_ceil(2) is the same number, since a
PTask run's address span is always even. Doc: state that the hand-out
run keeps one address more than the reserve.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

line exit tail
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-6eaa... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/1dcf7/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/1dcf7/tree/crates/args) C
cargo nextest run -p minimal activate_registers_box_with_vm_host 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-b10d... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/c3a76/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/c3a76/tree/crates/ot) C
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-b2cd... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/3fd22/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/3fd22/tree/crates/ot) C

Verify min task run agent-verify passed.

Outside the task's layers::

  • crates/minimal-tui/src/rpc.rs
  • crates/minimal-tui/tests/snapshots.rs
  • crates/minimal/src/task.rs
  • crates/minimal/tests/cli.rs
  • crates/minimald/src/exec.rs
  • crates/minimald/src/net/mod.rs
  • crates/minimald/src/net/provider.rs
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/session.rs
  • crates/minimald/src/session/tests.rs
  • crates/minimald/src/session_host.rs
  • crates/minimald/src/sessions.rs
  • crates/minimald/src/store.rs
  • crates/minimald/src/test_harness.rs
  • crates/minvmd/examples/exec.rs
  • crates/minvmd/src/cmd/run.rs
  • crates/minvmd/tests/minimald_session_integration.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs

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

Review threads the coder judged:

  • 👍 valid — crates/minimald/src/net/mod.rs: The shared run is gone: the daemon self-allocates the PTask run's lower half, the host hands only from the run above it, and hand() refuses a reserve address or any existing lease; split, refusals and exhaustion are pinned by new tests in both daemons.
  • 👍 valid — crates/minimald/src/exec.rs:192: The interim is now stated in exec.rs's task_network and the IpAllocator/self_allocation_run docs: task sandboxes draw from the reserved sub-run until host-side registration covers every live box (NET-138), after which a daemon with a control socket draws nothing.

On a VM-backed host, min session activate registers the new box with the VM host daemon over the control socket: the daemon allocates the box's switch and loopback addresses into its host-side table, hands them back, and the in-VM daemon attaches the box at the handed switch address and selects none. This round makes the hand-over collision-free by construction: the plan's PTask run is split into disjoint sub-runs — the daemon self-allocates task sandboxes and unregistered boxes only from the run's lower half (reserve 100.64.0.2..100.64.127.254 on the default plan), the VM host hands registered boxes only from the run above it (from 100.64.127.255) — with explicit exhaustion and no wrap or reuse on either side; a hand into the reserve or onto any existing lease is refused with a named error. The round also states the interim plainly (task sandboxes self-allocate until host-side registration covers every live box, per NET-138), makes activate's failure warns say the box runs unattributed until #1790's fail-closed egress default, and records minvmd's v1 socket-trust posture in the control module doc.

Notes from the agent: Revise round 2 of 10; commits c797826, d662268, a0e0f96. All five directive items addressed: (1) split via mirrored self_allocation_run/hand_out_run with IpAllocator bounded at the reserve and take_next bounded at the hand-out run; (2) hand() now refuses any existing lease whatever its origin (handed list and re-hand allowance dropped) and refuses reserve addresses via the new HandedAddressInReserve; (3) interim stated in exec.rs's task_network and the IpAllocator/self_allocation_run docs; (4) all four activate failure warns name the unattributed interim and the #1790 fail-closed gate; (5) control.rs states the v1 posture (same-uid 0600 UDS, serial serving, 30 s read timeout). The split is deliberately mirrored, not centralized: crates/switch is outside this round's layers, so the rule lives once per daemon and each side's tests pin…[truncated]

@norrietaylor
norrietaylor marked this pull request as ready for review October 1, 2026 15:53
@norrietaylor
norrietaylor requested a review from a team as a code owner October 1, 2026 15:53
@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.

Round 2 at a0e0f96 meets every ask and the ARCH-EXPERT conditions: disjoint self-allocation reserve and hand-out run on both sides, hand() refuses reserve and held addresses, interim and v1 control-socket posture stated, unattributed-box warn with #1790. Body rewritten by hand; the out-of-layer literal fixes are justified in it.

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

Reviewed: 1 finding, none blocking at dbc7482b1dce.

Address the comments on the diff.

Clobber: none: git log --oneline -5 shows the change stacked on its own prior rounds (withdraw verb, register verb, daemon wiring), no recent unrelated fix reverted.

@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.

Comment thread crates/minimald/src/net/mod.rs Resolved
Re-attaching a handed (own-ip VM) box after its in-process host was
rebuilt met HandedAddressCollision: hand() records the handed address
into the allocator's table, detach() never removed a lease, so the
lease outlived the teardown and the re-attach looked like a live
attach. The session launcher threads the persisted box addresses into
the respawn, so the box stayed unreachable until daemon restart.

Key the collision to a live attach instead: detach now releases the
handed lease it is given (a drawn lease is never released), and the
OwnIp guard and abandon path pass their lease through. The same box
re-attaching re-hands its address; a genuinely colliding attach is
still refused.

Addresses the review finding on IpAllocator::hand.
clippy-strict flags unwrap_used on changed lines; the lock is the one
the abandon rewrite touched, so give it the same poisoned-mutex expect
the rest of the strict-gated lines carry.
@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.

Comment thread crates/sessions/src/lib.rs Resolved
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 3 of 10 on the runtime's review findings, pushed as 7a0a1326ce8e.

line exit tail
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-4746... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/40cc0/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/40cc0/tree/crates/args) C
cargo nextest run -p minimal activate_registers_box_with_vm_host 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-483a... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/732ac/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/732ac/tree/crates/ot) C
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-b85a... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/f4053/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/f4053/tree/crates/args) C

Verify min task run agent-verify passed.

Outside the task's layers::

  • crates/minimal-tui/src/rpc.rs
  • crates/minimal-tui/tests/snapshots.rs
  • crates/minimal/src/task.rs
  • crates/minimal/tests/cli.rs
  • crates/minimald/src/exec.rs
  • crates/minimald/src/net/mod.rs
  • crates/minimald/src/net/provider.rs
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/session.rs
  • crates/minimald/src/session/tests.rs
  • crates/minimald/src/session_host.rs
  • crates/minimald/src/sessions.rs
  • crates/minimald/src/store.rs
  • crates/minimald/src/test_harness.rs
  • crates/minvmd/examples/exec.rs
  • crates/minvmd/src/cmd/run.rs
  • crates/minvmd/tests/minimald_session_integration.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs

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

Review threads the coder judged:

  • 👍 valid — PRRT_kwDOPdfcxM6oBxkQ: Released the handed lease when its attach ends (detach -> release_handed; guard and abandon pass the lease), so the same box's re-attach after a host rebuild re-hands its address instead of meeting HandedAddressCollision. (not posted on the thread: not an open thread on the pull request)

On a VM-backed host, activate registers the new box with the VM host daemon on the host, the daemon allocates the box's switch and loopback addresses into its table and hands them back, and the in-VM daemon attaches the box with the handed switch address and selects none — and now the same box re-attaching after its in-process host is torn down and rebuilt re-hands its address instead of meeting HandedAddressCollision, so the box is reachable again without a daemon restart.

Notes from the agent: The review finding (PRRT_kwDOPdfcxM6oBxkQ) is valid and fixed by its first suggested framing: hand() still records the handed lease (so a live attach is refused), but detach() now releases the handed lease it is given via release_handed(); a drawn lease is never released. The OwnIp guard (gvproxy_network.rs) and the abandon path (provider.rs) pass their lease through to detach, so both production detach sites release. Two files are outside this task's layers: crates/minimald/src/net/mod.rs and crates/minimald/src/net/provider.rs — the finding points at the allocator in mod.rs itself, and the layer list predates the daemon-side allocator split from earlier rounds; gvproxy_network.rs is in-layer. Known residual: the rare wedged-host path (kill_and_stop_loop aborts the loop without NetGuard teardown) still holds the lease and refuses, by design — the collision guard stays meaningful for a live attach. Exec/task launches pass box_addresses: None, so they never hand and are unaffected. Round 3, thread judged: see threads.

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

/revise

Round 4, bounded to the items below; everything round 3 did stands.

  1. crates/minvmd/tests/vm_escape_integration.rs:379: the SessionConfig initializer lacks the box_addresses field this branch adds (merge of T41 — Bound a root-in-VM spoofer to the resident union #1792), so the macOS unit lane fails to compile the test target (E0063). Add box_addresses: None as the other initializers in the tree do.
  2. crates/minimald/src/net/mod.rs (IpAllocator::release_handed, SwitchClient::detach): per the ARCH-EXPERT ruling the lease's life is the attachment's for every attachment, handed or drawn alike: a task sandbox's self-drawn address ends with the sandbox. Withdraw the lease on every detach; the cursor (next) never regresses, so a withdrawn drawn address is never re-drawn, and the never-reuse rule (R1.6) is carried by the cursor, not by a lease the static-lease table keeps for a tap that is gone. Rename release_handed accordingly (the handed set is then unneeded), and adjust handed_lease_releases_on_detach_and_the_box_rehands: after a drawn lease is withdrawn, the next allocate() returns a higher address, never the withdrawn one; a handed address held by a live attach still refuses with HandedAddressCollision.
  3. attach_handed doc: the re-handed address comes from the host's persisted row and detach never touches that row; state that the host-row check by box id (same address for the same box, refusal on mismatch) lands with the box id in the registration (T44, NET-133), and name it there as the gap.

Re-run the three plan test lines at the new head and refresh the Tests table.

The merge of #1792 added the field to SessionConfig and every other
initializer in the tree carries it; this one did not, so the macOS unit
lane failed to compile the minvmd test target (E0063).
Per the ARCH-EXPERT ruling the lease's life is the attachment's for
every attachment, handed or drawn alike: a task sandbox's self-drawn
address ends with the sandbox the way a registered box's handed one
ends with the box's attach. SwitchClient::detach withdraws the lease on
every detach and IpAllocator::release_handed is renamed release; the
handed set is unneeded and goes.

The never-reuse rule (R1.6) is carried by the draw cursor, not by a
lease the static-lease table keeps for a tap that is gone: the cursor
never regresses, so a withdrawn drawn address is never re-drawn, and it
is never handed either (the reserve hand refuses).
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 4 of 10 on a /revise note, pushed as 688b0bc37a38.

line exit tail
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-a644... Updating crates.io index Downloading crates ... Downloaded hash32 v0.3.1 Downloaded heapless v0.9.3 Downloaded managed v0.8.0 Downloaded smoltcp v0.14.0 Compiling ot v0.0
cargo nextest run -p minimal activate_registers_box_with_vm_host 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-5c98... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/6a40c/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/6a40c/tree/crates/args) C
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-163f... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/67694/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/67694/tree/crates/args) C

Verify min task run agent-verify passed.

Outside the task's layers::

  • crates/minimal-tui/src/rpc.rs
  • crates/minimal-tui/tests/snapshots.rs
  • crates/minimal/src/task.rs
  • crates/minimal/tests/cli.rs
  • crates/minimald/src/exec.rs
  • crates/minimald/src/net/mod.rs
  • crates/minimald/src/net/provider.rs
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/session.rs
  • crates/minimald/src/session/tests.rs
  • crates/minimald/src/session_host.rs
  • crates/minimald/src/sessions.rs
  • crates/minimald/src/store.rs
  • crates/minimald/src/test_harness.rs
  • crates/minvmd/examples/exec.rs
  • crates/minvmd/src/cmd/run.rs
  • crates/minvmd/tests/minimald_session_integration.rs
  • crates/minvmd/tests/vm_escape_integration.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs

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

On a VM-backed host, activate registers the new box with the VM host daemon on the host, the VM host daemon allocates the box's switch and loopback addresses into its table and hands them back, and the in-VM daemon attaches the box with the handed switch address and selects none — and now every lease ends with its attach, handed or drawn alike, so the same box re-attaching re-hands its own address from the host's persisted row while a self-drawn address is never re-drawn, and the macOS unit lane compiles the minvmd test target again.

Notes from the agent: Round-4 items: (1) added box_addresses: None to the SessionConfig initializer in vm_escape_integration.rs — the failing macOS unit lane's E0063; the minvmd test-line build compiles that target here. (2) IpAllocator::release_handed renamed release, the handed set removed, and SwitchClient::detach now withdraws the lease on every detach, handed or drawn alike, per the ARCH-EXPERT ruling; R1.6 now carried by the draw cursor (never regresses; a withdrawn drawn address is also refused by the reserve on hand). The adjusted handed_lease_releases_on_detach_and_the_box_rehands pins the drawn withdrawal (next draw is a higher address), the live-attach HandedAddressCollision refusal, and the re-hand. (3) attach_handed's doc now states the re-handed address comes from the host's persisted row, that detach never touches that row, and that the host-row check by box id (same address for the same box, refusal on mismatch) lands with the box id in the registration (T44, #1660, NET-133), which names it as the gap — that doc statement went into the item-2 commit, since both items rewrite the same attach_handed paragraph. gvproxy_network.rs (OwnIpGuard/lease_ip docs) and provider.rs (abandon doc) got doc-only consistency touches describing the new release rule: gvproxy_network.rs is a task-layer file, provider.rs is outside this task's layers but inside this PR's changed set; no code there changed. First run of the adjust…[truncated]

@norrietaylor
Copy link
Copy Markdown
Member

/revise

Round 4 landed every earlier ask; lanes are green at 688b0bc. One design condition from the ARCH review of T63 (#1788) lands on this task, because it is the creator-side half of the same rule: the host-side row's creator is its withdrawer (deployment-and-egress-gateway.md v0.9 §5.5, §7.1 "withdrawn at box end", §4.2 "withdrawal precedes reuse").

  1. Withdraw the host row at destroy, in this PR (crates/minvmd/src/control.rs, crates/minvmd/src/box_registry.rs, crates/minimal/src/cmd/session.rs). Add a withdraw verb to the control socket beside register: the client that registered the box on activate withdraws its row when the session is destroyed (and on every activate path that fails after registration), and the VM host daemon removes the row from its table, so the handed switch and loopback addresses no longer admit anything. Until this exists, a destroyed box's row keeps admitting its declared egress for whatever later sources its address. Do NOT close this from inside the VM: the guest daemon must never assert or withdraw address→box facts (§7.1 line 240); the row is the host-side creator's alone. Addresses are not reused by this PR (the host cursor never regresses); withdrawal only ends the row's admissions.

  2. Document the gap this PR still leaves on register_client_box and the control module: the UNREGISTERED_SOURCE_PHASE flip (the gate's announced interim, egress_gate.rs) is carried by the task that lands the last row source; with the host-address cohort row unplanned, that is this task's follow-up, not this PR. One sentence, no code change to the phase.

  3. Test: cargo nextest run -p minvmd host_row_withdrawn_on_destroy — register a box over the control socket, withdraw it, and assert the table no longer holds a row at either address and the gate refuses a publish at the withdrawn switch address. Extend activate_registers_box_with_vm_host (or a sibling in the same file) so a destroy sends the withdraw.

Re-run the plan's lines after the change:

  • cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon
  • cargo nextest run -p minimal activate_registers_box_with_vm_host
  • cargo nextest run -p minimald own_ip_attach_uses_handed_address
  • cargo nextest run -p minvmd host_row_withdrawn_on_destroy

The destroyed or failed activation's client withdraws the row its
registration bought: a tagged request envelope (register | withdraw),
a withdrawal answered with the pair echoed back, and the pair-proven
removal in the registry — lookup, proof, and removal under one write
of the row lock, no row at the address answered as the success it is.
The withdrawn addresses are not returned to the cursors; what their
frames do next stays the gate phase's to say, both arms pinned at
relay level through the phase parameter in
host_row_withdrawn_on_destroy.

The unregistered-source phase flip is not this change: it lands with
the last row source (T66's follow-up), and the docs on
register_client_box and the control module say so.
The session's creator now speaks the withdraw verb everywhere the
registration bought a row it no longer holds: at destroy (single and
--all, whose per-session record fetch carries the pair), at every
activation failure after registering — create transport and daemon
refusals, the autogen retry's abandoned row, the version-skew bail,
compose and verdict failures, the finalize teardown, the Ctrl-C guard —
and the registration itself moved to just before the create, the last
fallible client-side step, so the checks between config and create can
no longer strand a row.

Withdrawals are best-effort and quiet when nothing is owed; the Ctrl-C
guard fetches the record before aborting, which may take the pair with
the session. cmd/mod.rs and task.rs are outside this task's layers;
the guard's withdrawal required the former (the signature is
unchanged, so task sessions need no edit) — noted in result.json.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 5 of 10 on a /revise note, pushed as dbc7482b1dce.

line exit tail
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-c681... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/bfe76/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/bfe76/tree/crates/ot) C
cargo nextest run -p minimal activate_registers_box_with_vm_host 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-3f36... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/092c5/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/092c5/tree/crates/ot) C
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-b067... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/33303/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/33303/tree/crates/ot) C

Verify min task run agent-verify passed.

Outside the task's layers::

  • crates/minimal-tui/src/rpc.rs
  • crates/minimal-tui/tests/snapshots.rs
  • crates/minimal/src/cmd/mod.rs
  • crates/minimal/src/task.rs
  • crates/minimal/tests/cli.rs
  • crates/minimald/src/exec.rs
  • crates/minimald/src/net/mod.rs
  • crates/minimald/src/net/provider.rs
  • crates/minimald/src/rpc.rs
  • crates/minimald/src/session.rs
  • crates/minimald/src/session/tests.rs
  • crates/minimald/src/session_host.rs
  • crates/minimald/src/sessions.rs
  • crates/minimald/src/store.rs
  • crates/minimald/src/test_harness.rs
  • crates/minvmd/examples/exec.rs
  • crates/minvmd/src/cmd/run.rs
  • crates/minvmd/tests/minimald_session_integration.rs
  • crates/minvmd/tests/vm_escape_integration.rs
  • crates/sessions/src/lib.rs
  • crates/sessions/src/store.rs

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

Review threads the coder judged:

  • 👎 invalid — crates/sessions/src/lib.rs:638: The loopback half is not dead: it is the second half of the creator's handed pair, and this round gives it its reader — the destroy-side withdrawal reads it off the session record and presents it to the host daemon, whose withdraw_client_box refuses a row removal unless the presented pair matches th

On a VM-backed host, activate registers the box with the VM host daemon, the daemon allocates its switch and loopback addresses into its table and hands them back, the in-VM daemon attaches with the handed switch address — and now the same client withdraws that row when the session is destroyed or the activation fails after registering: min session destroy (single or --all) sends the withdraw verb presenting the pair the registration handed back, the daemon removes the row at both addresses so the pair admits nothing, a foreign pair is refused, and a row already gone is answered as the success it is. A failed activation's create/compose/verdict/finalize paths and the Ctrl-C guard send the same withdrawal.

Notes from the agent: Directive asks 1-3 done in five commits on the branch. Layer notes: (a) crates/minimal/src/cmd/mod.rs is outside the layers but the Ctrl-C guard's withdrawal required it — arm_activation_interrupt gained an in-task record fetch (before the abort, which may take the pair with the session) plus the withdraw call; its signature is unchanged, so task.rs and the tests.rs connection inventory needed no edit, and both verify (inventory test listed in tests). (b) The registration call moved from pre-config to just before the create loop — the last fallible client-side step — so the config/loadout/hook/daemon-connect failures between them can no longer strand a row; this is a behavior-order change worth a reviewer's eye (the control socket already exists by then: ensure_daemon autospawns at function start). (c) The directive's test wording 'the gate refuses a publish at the withdrawn switch address' is only true under the InForce phase; the shipped Announced interim admits a withdrawn in-plan address with its rate-limited warn, so host_row_withdrawn_on_destroy pins both arms via gate_over_with_phase's phase parameter — the flip the follow-up lands breaks nothing here. (d) just clippy-strict (local-only gate): one hit, unwrap_in_result on…[truncated]

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

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

Choose a reason for hiding this comment

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

Round 5 lands every ask: the withdraw verb with creator and pair checks, the CLI withdrawing on destroy and on both failed-create paths, the phase-flip ownership note, and host_row_withdrawn_on_destroy. ARCH conditions met; minimal-review concluded on this head with one LOW deferred to #1797.

@norrietaylor
norrietaylor merged commit 4f8959b into main Oct 1, 2026
34 checks passed
@norrietaylor
norrietaylor deleted the agent/1711-register-a-box-on-the-host-and-hand-it-its-addre branch October 1, 2026 22:42
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 6 of 10 on the runtime's review findings, pushed as a17325c15e34.

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

line exit tail
cargo nextest run -p minvmd box_addresses_allocated_on_host_and_handed_to_daemon 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-81ea... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/a13b0/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/a13b0/tree/crates/ot) C
cargo nextest run -p minimal activate_registers_box_with_vm_host 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-68a1... Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/129c6/tree/crates/args) Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/129c6/tree/crates/ot) C
cargo nextest run -p minimald own_ip_attach_uses_handed_address 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-d8c3... Compiling ot v0.0.1 (/home/runner/.local/state/minimal/sessions/2d4e8/tree/crates/ot) Compiling args v0.0.1 (/home/runner/.local/state/minimal/sessions/2d4e8/tree/crates/args) C

Verify min task run agent-verify passed.

Outside the task's layers::

  • crates/minimald/src/session/tests.rs
  • crates/minimald/src/session_host/tests.rs

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

On a VM-backed host, activate registers the new box with the VM host daemon on the host, the VM host daemon allocates the box's switch and loopback addresses into its table and hands them back, and the in-VM daemon attaches the box with the handed switch address and selects none — unchanged by this round, which only makes a refused registration stop burning a hand-out address.

Notes from the agent: Round 6 delta: the one open thread, fixed in crates/minvmd/src/box_registry.rs. register_client_box drew the switch address before the loopback address, so a LoopbackExhausted refusal advanced the switch cursor and burned a hand-out address no row was ever published at; the spent-for-good rationale covers only addresses a row held. The draws are swapped (loopback first — the slice is the run a host exhausts, 32 addresses per switch against a hand-out run of at least 126, so an exhausted slice refuses before the switch cursor moves), the spent-for-good doc paragraph is rescoped to published addresses and names the plan-shape dependency (every planned hand-out run outnumbers its slice, which keeps the reverse exhaustion out of reach), and the carved-/24 test pins the refusals leaving the switch cursor exactly where the 32 successes left it. Happy-path behaviour is unchanged, so the proof above still holds. Also ran beyond the test lines: cargo nextest run -p minvmd box_registry:: (3 passed), cargo clippy -p minvmd --all-targets (clean), just clippy-strict (clean, scoped to the branch's changed crates), cargo fmt --all -- --check (clean).

norrietaylor added a commit that referenced this pull request Oct 2, 2026
…ost at merge

T66 (#1789) added box_addresses to SessionConfig and SandboxLauncher; #1768
and #1765 each added an initializer without it on a base that predated the
field, and their green lanes never re-ran against the merged main. The
minimald test targets no longer compile on main; this fills the field the
way every other initializer does. The merge queue this PR enables is what
catches that class of stale green before it lands.
norrietaylor added a commit that referenced this pull request Oct 2, 2026
* ci: trigger the required lanes on merge_group

A merge queue on main needs the five required aggregators to report on
every queue commit. Each lane already gates its jobs on
`github.event_name != 'pull_request' || <changes output>` and runs the
dorny filter only on pull_request, so a queue commit runs the full set,
which is what docs/ci-strategy.md section 5 prescribes for the queue.
No job logic changes.

* fix(minimald): fill box_addresses in the two test initializers main lost at merge

T66 (#1789) added box_addresses to SessionConfig and SandboxLauncher; #1768
and #1765 each added an initializer without it on a base that predated the
field, and their green lanes never re-ran against the merged main. The
minimald test targets no longer compile on main; this fills the field the
way every other initializer does. The merge queue this PR enables is what
catches that class of stale green before it lands.

* ci: pin the merge_group trigger to main and release branches

The sibling push and pull_request triggers in all five lanes pin
branches to main and release/**; the merge_group trigger now matches
them, so a queue opened on any other branch does not run the lanes.
minimal-foundry Bot added a commit that referenced this pull request Oct 2, 2026
Main's box registration (#1789) added a `box_addresses` field to
`SessionConfig`, and the NET-068 harness's `CreateSession` initializer
went without it. The macOS lane is the only one that compiles the
harness (the `minvmd_libkrun` cfg the file is gated on is unset on
stock Linux CI, where the file compiles to nothing), so the Linux
lanes stayed green while the macOS `unit` job failed at clippy with
E0063, reding `ci-macos-success` with it.

Send `None`: no registration happens on this path, the box attaches as
an unregistered one always has, drawing its own switch lease — the
same value every sibling minvmd harness sends.
yermakoffivan pushed a commit to yermakoffivan/minimal that referenced this pull request Oct 3, 2026
…al#1771)

* test(minimald): hostname-only toolchain allowlist admitted by DNS gate (NET-068)

* test(minvmd): hostname-only allowlist toolchain completes inside a VM box (NET-068)

* fix(minvmd): use minvmd::cmd in integration test instead of crate::cmd

The integration test crate cannot resolve crate::cmd::own_ip_requested.

Use the public minvmd::cmd::own_ip_requested path instead.

Review: PRRT_kwDOPdfcxM6ngj6Y

* fix(minvmd): address review threads in NET-068 egress allowlist integration test

- Move the toolchain hostname list into sessions::NET068_TOOLCHAIN_EGRESS_HOSTS so the minimald unit fixture and the minvmd integration test share it.

- Fix integration-test compile issues: use sessions::SessionId, remove private minimald_rpc::SessionId, gate on MINVMD_GVPROXY_BIN instead of MINVMD_VM_OWN_IP, and fix FinalizeSession error typing.

- Upload a minimal.toml with toolchain packages before ConfigureLoadout; replace podman pull with skopeo copy; add per-tool timeouts and small git clone target.

- Read MINVMD_BOOT_LOG (falling back to boot.log) and boot with RUST_LOG=info,minimald::net::dns_gate=debug for diagnostics.

- Document that the DNS gate lives in the guest minimald and that the host gvproxy is the L2 switch.

- In dns_gate.rs, reword the negative assertion to name the design divergence and note that the TCP-only fixture still resolves because of the UDP/53 resolver carve-out.

* docs(sessions): correct EgressPolicy doc comment to say egress

* fix(minvmd): make NET-068 integration harness match the composed box

The composed box has no Debian userland or apt package, so drop the
apt-get leg and document the NET-068 deviation. Use pip3 (the only pip
in the python package) and skopeo --insecure-policy (no containers
policy.json ships). Cap per-tool exec at 60s and make the boot-log tail
robust to invalid UTF-8 while filtering to dns-gate/policy lines so a
chatty tool cannot push the admission evidence out of the cap.

* chore(sessions,build): make NET-068 fixture internal and give test-vm a gvproxy export

Hide the shared NET068_TOOLCHAIN_EGRESS_HOSTS constant from public
docs. Export MINVMD_GVPROXY_BIN in both test-vm recipes so the own-IP
integration tests can run, and add a vm-profile override for
hostname_allowlist_toolchain_completes so the 6-minute default kill
does not cut off a real toolchain run.

* test(minvmd): drop the apt leg from the NET-068 toolchain run

Spec PR gominimal#1707 amended NET-068 to the four-tool toolchain (git clone, npm install,
pip install, a container pull): the composed box has no Debian userland and no
upstream package carries apt, so an apt leg can never exit 0 there.

- Module doc and in-file comments now state the four-tool toolchain and no longer
  claim apt is asserted or recorded as a deviation; the spec matches the test.
- `deb.debian.org` and `security.debian.org` leave
  `sessions::NET068_TOOLCHAIN_EGRESS_HOSTS`; the only other user, the `minimald`
  DNS-gate unit test `toolchain_hosts_admitted_by_gate`, drops the same two rows.
- The boot-log tail no longer keys on the `dns-gate` component string, which the
  guest console need not print; it matches the gate's message text alone
  (`admitted`, `refused`, `rule_matched`) and, when nothing matches, returns the
  last 40 unfiltered lines so the console stays visible.

* test(minvmd): bring the NET-068 harness up through the supervisor path

`minvmd boot --foreground` never spawns the host gvproxy switch (only the `run`
supervisor does), so the shuttle bridge dialled a socket nothing served and the
guest had no egress: the composer could not fetch the upstream packages and every
toolchain leg failed to spawn before the allowlist was exercised.

- `Guest::boot` now runs `minvmd run --detach --timeout 150`, polls
  `status --json` until Running, and stops the VM on drop, bounded like the
  sibling harnesses; boot failures quote the supervisor's `run.log`.
- With the packages composed, `ConfigureLoadout` routes their env wiring back
  as `Pending`; the harness gates it with the `sessions` client handler and an
  approve-all `PolicyHooks`, then `SubmitVerdict`. An `Approved` patch would
  need the patches upload the CLI performs, so it is reported instead.
- `camino` joins minvmd's dev-dependencies: the `PolicyHooks` trait names
  `Utf8Path` in its signatures.

* test(sessions,minvmd): admit Docker Hub's CloudFront blob CDN in the NET-068 run

The container pull stalled under the hostname-only allowlist: Docker Hub's blob
fetch 307-redirects to `production.cloudfront.docker.com` (18.238.0.0/16), which
the list did not name, so the relay refused the flow as `egress-undeclared-subnet`.
Docker Hub has served blobs from either of its CDNs, so the list now carries both
`production.cloudflare.docker.com` and `production.cloudfront.docker.com`, with a
doc comment saying why; the `minimald` DNS-gate unit table mirrors the row.

Also read the status JSON with `.get(..)` in the harness's Running poll instead of
indexing, clearing the strict-lint hit the previous commit introduced.

* docs(minvmd): state the no-apt facts beside the NET-068 four-tool run

Thread PRRT_kwDOPdfcxM6nlsFW asked the PR to name which package would carry apt: none does. gominimal/pkgs@f4de33d0 is not a Debian userland and no upstream package carries apt, so the pre-gominimal#1707 apt leg could never exit 0 in the composed box. The module doc now states those facts; the PR body statement is carried by this round's result.

* test(minvmd): add box_addresses to the NET-068 session create

Main's box registration (gominimal#1789) added a `box_addresses` field to
`SessionConfig`, and the NET-068 harness's `CreateSession` initializer
went without it. The macOS lane is the only one that compiles the
harness (the `minvmd_libkrun` cfg the file is gated on is unset on
stock Linux CI, where the file compiles to nothing), so the Linux
lanes stayed green while the macOS `unit` job failed at clippy with
E0063, reding `ci-macos-success` with it.

Send `None`: no registration happens on this path, the box attaches as
an unregistered one always has, drawing its own switch lease — the
same value every sibling minvmd harness sends.

* test(minvmd): approve only the named pending var and report skips in the NET-068 run

The compose gate now approves exactly NPM_CONFIG_CACHE, the one variable the
node package wires through env_state_wiring, and fails the test naming any
other var, patch, or hook the daemon routes back. A missing precondition
(MINVMD_E2E != 1 or no MINVMD_GVPROXY_BIN) prints one
"SKIPPED: hostname_allowlist_toolchain_completes: ..." stderr line and returns;
under MINVMD_VM_LANE it panics instead, so a VM lane cannot go green without
the host switch.

* test(minimald): hold the gate's toolchain names to the NET-068 constant

The gate test pairs each host with a representative address, so it cannot
read its names off the shared constant. It now asserts its names equal the
constant, so a host added there fails here until the test exercises it.

* test(minvmd): track the boot-log tail offset in raw bytes

The offset was taken from a lossy-decoded copy, where each invalid byte
becomes a three-byte replacement character, so the next read could skip
new bytes or slice inside a character. Slice the raw bytes, then decode.

* test(minvmd): pin the guest READY wait to the cold-boot timeout

The detach timeout bounds only the poll for Running; the VMM parent's
READY wait reads MINVMD_READY_TIMEOUT_SECS (60 s default). Set it in the
harness so a bare nextest run tolerates a 40-70 s cold boot.

---------

Co-authored-by: minimal-foundry[bot] <327719912+minimal-foundry[bot]@users.noreply.github.com>
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.

T66 — Register a box on the host and hand it its addresses

1 participant

0