Repository navigation
T134 — Expose decisions for a box with no switch, and answered asks, reach the host's audit log - #2969
Conversation
ExposeDecisionReport now carries an optional box id beside an optional switch address, both serde-defaulted, so an older guest's report still reads. The host names a report with no switch address from what it holds under the box id: a row, a held name, or a resident host_ip box. It logs at debug which key found the box. A yes answer to a pending ask now appends the same admission record an allow-decided expose writes, with source "ask" (NET-046). The guest still sends no report for a box with no switch: the report path has no box id to send. The two struct literals in minimald follow the new field shape.
…isions-for-a-box-with-no-switch-and-an
|
Important Review skippedBot user detected. To trigger a single review, invoke the
|
|
Approved: every review thread resolved at @norrietaylor resolved the last thread, which releases the approval this review had withheld. Nothing to do. |
There was a problem hiding this comment.
arch-review: CONDITIONS · 2 conditions · the full ruling
The host can now record an expose decision for a box with no switch, but no guest sends one. So the task's proof is not met, and the PR must not close #2929. Section 7.1 line 265 requires that the result is audited locally. C1 files the guest half as a residual with an issue. C2 gives each no-switch box its own audit cap, so one box cannot suppress the records of another. The escalation asks if a host_ip refusal is a NET-046 decision.
Ruled at f4c131d against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
…isions-for-a-box-with-no-switch-and-an
Every box with no switch shares the node's own address, so a cap window keyed by that address let one box spend the cap of all of them. The window is now keyed by the row's switch address or, for a box with no switch, by its box id. The audit_suppressed line names the box id for such a box and carries no switch address.
There was a problem hiding this comment.
arch-review: CONDITIONS · 2 conditions · the full ruling
The host half of NET-046 conforms. The new cap key per box fixes the shared-address cap from the last head. The guest half is missing. report_expose_decision still returns early for a box with no switch, and it always sends box_id: None. So the host gets no record for that box, and §7.1 line 265 requires one. C1 delivers the guest half and its test. C2 keeps #2929 open until then. The host_ip case in the proof goes to a person as an escalation.
Ruled at 6d4b0c6 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 1 of 10 on the runtime's review findings, pushed as
Verify Converted to a draft: something above needs a person before review. Review threads the coder judged:
Partial. A yes answer in the ask dialog now writes an admission record to the audit log on the host. The host also records an expose decision report that names a box with no switch by its box id, and each such box has its own cap window. But the guest still sends no report for a refused Notes from the agent: The guest half cannot be done inside this task's layers. The expose path that knows the box id is crates/minimald/src/box_actor/ports.rs (answer_expose_because). The record it hands to crates/minimald/src/audit.rs carries only the box name, and report_to_host in audit.rs calls report_expose_decision in listeners.rs with that name only. Nothing in listeners.rs maps a box with no switch to its box id or to a host channel: HOST_AUDIT_ROUTES is filled only by the listen watcher, which runs only for boxes with a switch. A fix needs a box id passed from ports.rs through audit.rs (or a route registered from box_manager.rs at the mint_box_id call), so a follow-up task must name those files. The PR must say Refs, not Closes, for the issue, and the guest half needs its own issue. This round: the host cap window is keyed by switch address or by box id (GuestAuditKey), and the audit_suppressed line names box_id and omits switch_address for a box with no switch. A no-switch box's window is not flushed on withdrawal, because no withdrawal names it by id; it ends by the window timeout or the tracked-box pruning. cargo clippy -p minvmd --all-targets and cargo fmt are clean. |
|
/revise Design decision on the arch ruling: a host-address box's |
…isions-for-a-box-with-no-switch-and-an
A box with no switch has no audit route by switch address, so its refused or published expose decision never reached the VM host daemon. The box actor now hands the audit its box id and control channel when the box has no switch, and the report goes to the host door keyed by the box id. A host-address box's needs-no-exposing answer stays unaudited, because it decides nothing.
…isions-for-a-box-with-no-switch-and-an
|
Round 2 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
An ask box on a VM host with no switch address is refused as not attached. The in-VM daemon now sends that decision to the VM host daemon keyed by the box id, and the host writes a record for it in its audit log. A yes answer in the ask dialog writes an admission record in the host audit log, as an allow-decided expose does. The guest test shows the report with switch_address None and the box id, and the two minvmd tests show the host records. Notes from the agent: Round 2 delivers arch C1, the guest half. The box id and control channel do not go into DecisionRecord as fields. A new field breaks the struct literal in crates/minimald/src/diag.rs, which is outside the layers. They travel as a separate audit::HostReportKey argument to audit::append, audit::try_append and report_to_host. answer_expose and answer_expose_because keep their signatures, because crates/minimald/src/box_actor/host.rs (outside the layers) calls answer_expose. answer_expose_because reads the box record and sends the box id only when the record has no box_addresses. A box with a switch still reports by its route, so its report is unchanged. The listen watcher passes an empty key, because it always holds a route. A host-address box's NeedsNoExposing refusal stays unaudited, as the note directs. Arch C2 is not applied, as the note directs. The failed ci-linux-kvm-success and test-kvm checks show only runner setup lines in the excerpt and no test failure. I did not change anything for them. Extra check: cargo nextest run -p minimald expose ask report audit unaudited ran 160 tests, all passed. I did not run just clippy-strict. |
…isions-for-a-box-with-no-switch-and-an
There was a problem hiding this comment.
arch-review: CONDITIONS · 3 conditions · the full ruling
The guest now sends a no-switch box's decision by box id, but the host cannot name the box that sends it. On a VM host only a none box sends a report by id. no_switch_box_name finds ids only for host_ip boxes, so the host answers Error and writes no record. §7.1 line 265 says the helper audits the decision locally. C1 gives the host a record for a none box. C2 makes both tests use a box a VM host can create. C3 corrects the task proof and the PR body.
Ruled at 291c81d against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
A box with no switch files its audit window by box id. Its hold release and its host-address retire now remove that window and write the count of the records it suppressed, as a row withdrawal does for its switch.
…isions-for-a-box-with-no-switch-and-an
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The change conforms to §7.1 lines 244 and 265. A box with no switch reports its expose decisions by box id. The host names the box only from records it holds. A yes answer to an ask writes an admission record on the host. Commit 928f2de9 flushes the audit window of a box with no switch when its name hold is released or it retires. Only the host door serves those verbs. The host_ip record in the proof is not a design requirement. Amend the proof line in #2929.
Ruled at 0991384 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 3 of 10 on the runtime's review findings, pushed as
Verify Review threads the coder judged:
After an ask box on a VM host with no switch address is refused as not attached, and after a yes answer in the ask dialog, the audit log on the host holds a record for each. When such a box ends, the log also holds the count of the records its cap suppressed. Notes from the agent: Revise round 3. A box with no switch never sends Withdraw. It ends through ReleaseBoxName (with its session id) or RetireHostIpBox. Both arms now flush the box-id audit window: they write the audit_suppressed line when the count is above zero, and they remove the window from GUEST_AUDIT_WINDOWS. flush_guest_audit now takes a GuestAuditKey. A ReleaseBoxName with no session id cannot name the box id, so it flushes nothing. cargo clippy -p minvmd --all-targets is clean. I did not run just clippy-strict. |
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 7 unresolved threads — minimal-arch[bot] crates/minvmd/src/control.rs, minimal-arch[bot] crates/minimald/src/net/listeners.rs, minimal-arch[bot] crates/minimald/src/net/listeners.rs, minimal-foundry[bot] crates/minvmd/src/control.rs:2733, minimal-arch[bot] crates/minvmd/src/control.rs:2845, …. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The compare conforms to §7.1. min holds a none box's name over the host door at create, as a host_ip box does. So the host knows the box id from its own record (line 244, line 255). The guest still sends one key, and the switch route wins. A report for an unknown id is refused. The PASS on 8da17e83 stands for the rest of the change.
Ruled at f1e89da against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 5 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
On a VM host, Notes from the agent: create.rs: a |
|
/revise Round 6 lost its container, so this replaces it. The |
…isions-for-a-box-with-no-switch-and-an
A box with a switch address reports only by its route again. When the box record cannot be read, the reported switch address decides.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
The compare from f1e89da6 changes only the guest's choice of host report key, plus a doc comment move in a test. A box with a switch address reports by its route again. A box with no switch address reports by box id. When the box record cannot be read, the reported switch address decides. NET-046 conforms to §7.1 lines 244 and 265, as it did at the PASS on f1e89da6. No conditions.
Ruled at 42590fe against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 7 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
After an Notes from the agent: The CI failure came from commit ae01543. It gave every box the box-id key, so a switch box with no registered route took the by-id path. answer_expose_because now gives the box-id key only when the box record has no box_addresses. When the record cannot be read, the key follows self.reported_switch_address. The five failing minimald tests pass unchanged, in the same run as the minimald test line. I also ran the two create.rs tests (cargo nextest run -p minimal none_box_holds_its_name_with_the_vm_host dns_steering_is_admitted_where_the_switch_resolves_boxes, exit 0), and cargo clippy -p minimald --all-targets is clean. |
…isions-for-a-box-with-no-switch-and-an
The dashboard destroy and min session rename test holds_name, which covers only a host_ip box, so they do not release or move a none box's name hold. The comment claimed every destroy releases it.
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 2 conditions · the full ruling
The code is the same as at the PASS on 42590fed. The new comment is accurate. It states that the dashboard's destroy and min session rename do not release or move a none box's name hold. Section 7.1 line 255 says an unknown name answers NXDOMAIN, and line 265 says the host audits the decision. C1 makes vm_host::holds_name cover none boxes. C2 makes the re-hold before an attach cover them, so a report after a VM host daemon restart still gets an audit record. File each as an issue and name it in the PR body, or make the edits.
Ruled at 15cf459 against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
|
Round 8 of 10 on a failed check suite, pushed as
Verify Review threads the coder judged:
On a VM host, a Notes from the agent: Revise round 8. The failed check is test-kvm, which runs scripts/session-e2e.sh against a VM (ci-linux-kvm.yml). The log excerpt in the directive holds only script source lines and job cleanup, and names no failing step. This box has no /dev/kvm, so I could not run the VM lane. I read the e2e legs that this PR touches: the ask legs (yes, no, nobody attached), the deny box's expose_decision count, and the allow box's admission line. I found no assertion that the new records break. So this round makes no change for the failed check, and a person must read the full test-kvm log to find the failing step. A rerun can show if the failure is flaky. The three test: lines pass on the merged head (3e3ac08 plus this commit). The one commit this round corrects the comment in create.rs, which said that every destroy releases a none box's name hold. The thread's code fix is outside the layers: it needs |
|
/revise Deliver arch C1 and C2 of the ruling at |
|
That What the platform saidcould not start the coder: Error: there is no container instance that can be provided to this durable object Nothing to type again: the command gets a rocket when its round starts, or a refusal that names the reason. No round was counted for it yet. |
holds_name is now true for a named none box with no row, as for a host_ip box, so the dashboard's destroy releases its hold and a rename moves it. An attach or exec re-holds a none box's name after a VM host daemon restart. The egress re-admit stays for host_ip boxes only.
There was a problem hiding this comment.
arch-review: PASS · the full ruling
This head closes the open item from the ruling on 15cf4598. A none box's name hold is the host's record of its box id. The dashboard's destroy now releases that hold, a rename moves it, and an attach or exec re-holds it after a VM host daemon restart. Egress stays for host_ip boxes only. Section 7.1 line 265 requires the host to audit each decision locally, and the host now keeps the record that the audit needs. NET-046 conforms. There are no conditions.
Ruled at e38a0bc against gominimal/arch@7a86ec7bb3c0 by claude-opus-5-5.
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 11 unresolved threads — minimal-arch[bot] crates/minvmd/src/control.rs, minimal-arch[bot] crates/minimald/src/net/listeners.rs, minimal-arch[bot] crates/minimald/src/net/listeners.rs, minimal-arch[bot] crates/minvmd/src/control.rs:2845, minimal-arch[bot] crates/minvmd/src/control.rs, …. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
|
Round 9 of 10 on a /revise note, pushed as
Verify Review threads the coder judged:
After an Notes from the agent: C1: |
There was a problem hiding this comment.
minimal-review — approved
Verdict APPROVE — every review thread is resolved; @norrietaylor closed the last one. The review of e38a0bc0b79a 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.
There was a problem hiding this comment.
Read at e38a0bc. The disputed threads are met at this head: a none box holds its name, holds_name and the re-hold cover it, and report_expose_decision falls back to the box id. Arch passes.
T134 — Expose decisions for a box with no switch, and answered asks, reach the host's audit log
slice: S16
kind: task
covers: NET-046
size: M
est: 150 code, 250 tests
executor: agent
difficulty: needs care
model: standard
diagnostics: a person reads the audit log the VM host daemon keeps on the host, which now holds a record for a refused
min net exposefrom a box with no switch, and an admission record when a person answers yes to the ask dialogobservability: the VM host daemon appends one audit record per reported decision, now including boxes with no switch and yes-answered asks, and logs at debug which key, switch address or box id, found the row
layers:
- guest:
- crates/minimald/src/net/listeners.rs:
report_expose_decisionsends a box with no switch address its report by box id over the box control channel, instead of returning without a report- crates/minimald-rpc/src/lib.rs:
ExposeDecisionReportcarries the box id beside an optional switch address, both serde-defaulted, so an older guest's report still readstest: cargo nextest run -p minimald no_switch_box_reports_expose_decision_by_id
- host:
- crates/minvmd/src/control.rs:
audit_expose_decisionfinds the row by box id when the report has no switch address;record_ask_answerappends the admission record for a yes answer, as an allow-decided expose doestest: cargo nextest run -p minvmd expose_decision_recorded_for_no_switch_box
test: cargo nextest run -p minvmd ask_yes_writes_admission_line
produces: none
consumes: none
proof: After a refused
min net exposefrom ahost_ipbox and a yes answer in the ask dialog, the audit log on the host holds a record for each.Proof
Partly delivered. A yes answer in the ask dialog now writes an admission record (source "ask") to the host audit log at audit/box-admissions.log. The VM host daemon also records an expose decision report that names a box with no switch by its box id. But a refused
min net exposefrom a host_ip box still leaves no record on the host. The guest never sends that report: see notes.Notes from the agent: Guest half not done. The task cannot be done inside its layers. (1)
report_expose_decisionin listeners.rs gets only the box name, fromaudit::report_to_hostand theDecisionRecord. Nothing in listeners.rs maps a name to a box id or a control channel for a box with no switch. The host audit routes exist only for boxes with a listen watcher, and a listen watcher needs a lease. To send the box id, the id must pass frombox_actor/ports.rs(answer_expose/answer_expose_because) throughaudit::DecisionRecordoraudit::report_to_hostintoreport_expose_decision. Those files are not in the layers. (2) A host_ip (HostNet) box never reaches the audit path.box_actor/ports.rsanswers its expose withNeedsNoExposingbefore any decision, and its comment says nothing is audited on purpose. So the proof's host_ip case also needs a change in ports.rs, and a decision on whether that refusal counts as a NET-046 decision. Today the only no-switch box that reachesreport_expose_decisionis anaskbox on a VM host with nobox_addresses, which is refusedNotAttached. The minimald testno_switch_box_reports_expose_decision_by_idis not written, and its test line exits 4 (no tests to run).Outside the layers:
crates/minimald/src/box_runtime/tests.rshas twoExposeDecisionReportstruct literals inexpose_unenrolled_decision_audited. The newbox_idfield and theOptionswitch address forced me to change them (Some(row),box_id: None). That test passes. In listeners.rs the only change is the same literal shape.Host details: a repo…[truncated]
Tests 8000
cargo nextest run -p minimald no_switch_box_reports_expose_decision_by_idcargo nextest run -p minvmd expose_decision_recorded_for_no_switch_boxcargo nextest run -p minvmd ask_yes_writes_admission_lineVerify
min task run agent-verifypassed ([tasks.verify]).Base
The base branch moved while the coder worked; it was merged in before the tests ran.
Out of scope
These files are outside the task's
layers:, so this PR is a draft:crates/minimald/src/box_runtime/tests.rsCloses #2929