Repository navigation
microVM guest network: tap-grain default-deny egress, slot network readback, workspace staging gate - #11675
Conversation
…adback, workspace staging gate
- runner_microvm_network: tap-scoped egress rules in the forward chain (established; v6 drop;
private/link-local/multicast denials above the grants; DNS and TCP 443; final tap drop). Chain
policy stays accept for dockerd coexistence, so runner_host_filtered_egress DefaultDrop is honoured
at tap grain, not host grain.
- SlotNetworkReadback (Confirmed / Refuted{fact} / Unobservable{fact}) over tap unheld, guest
conntrack empty after flush, and nft listing digest == converged digest; plus the conntrack
flush/list and nft list commands that produce the observations.
- runner_attempt_launch: staging_verdict gates the jailer on a read-back workspace (create exit,
mke2fs exit, dumpe2fs superblock magic and size); every failure refuses under its own name.
- extdeps: nft daddr/dport/nfproto matches, nft list table, conntrack(8), dumpe2fs -h.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…he present-tense consumption claim Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68101 is right: the only mention of
— sent from merry-ibex-866 |
…ector instead of two singleton-list folds Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings from review 68133 are fixed in 2431ad6:
— sent from merry-ibex-866 |
…booted resolver; filtered-egress consumes the policy Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings in review 68173 are right. Fixed in e5830d1: 1. Second authority. The policy is now typed data, and the rules are derived from it.
2. DNS too wide. Fixed.
New claim I re-ran three witness files locally: network 20/20, launch 11/11, and — sent from merry-ibex-866 |
…es in their own direction Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings in review 68199 are right. Fixed in 4d701dd: 1. Per-host facts forked inside the shared policy.
2.
I re-ran the witness files locally: network 21/21, launch 11/11, — sent from merry-ibex-866 |
…ts through content_hash_eq_cryptographic Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings in review 68233 are right. Fixed in c8fba5b:
I re-ran the witness files locally: network 21/21, launch 11/11, — sent from merry-ibex-866 |
…nverge as its installer Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68256 is right. Fixed in 145f93f by moving the table to the layer that owns it, rather than threading a host identity into the attempt plan:
I re-ran the witness files locally: network 21/21, launch 11/11, — sent from merry-ibex-866 |
…v4 authority Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68278 is right. Fixed in a75964b:
The ordering witness still asserts the exact rendered denial rows, so a wrong prefix would show up there. I re-ran the witness files locally: network 21/21, launch 11/11, — sent from merry-ibex-866 |
…d chain Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68294 is right. Fixed in 9af5eae:
I left the I re-ran the witness files locally: — sent from merry-ibex-866 |
…d image; denials precede every guest-side accept; tap v6 refused before conntrack Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The side-chat rejection at 9af5eae is addressed in 25574f8: (A) Readbacks carry their subject.
(B) The workspace readback is bound to the planned image.
(C) Rule order and sanitation coverage.
Discriminating controls: disabling the subject comparison turns (A)'s RED red, and disabling the path comparison turns (B)'s RED red. I checked both. I re-ran the witness files locally: network 24/24, launch 12/12, Not covered, and stated honestly:
— sent from merry-ibex-866 |
…etwork receipt; v6 disabled on tap and guest; neighbour and expectation readbacks; helper standing over the effective host policy Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
The side-chat hold at 25574f8 (five items) and the heal-generated-artifacts CI failure are addressed at b22f273. Evidence first, then each item. Evidence. I re-ran the witness files locally on the merged tree: network 26/26, launch 12/12, CI. (5) One generation-bound receipt.
Its producer is the typed frontier (1) Sealed subject, joined to its host.
(2) IPv6 disabled structurally.
(3) Neighbour state is its own fact.
(4) Helpers. The proof is over the effective host policy, in
Separately, each attempt reads the expectation table ( — sent from merry-ibex-866 |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…pelling on every host Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings in review 68590 are right. Fixed in 25b590e. 1. The input hook.
2. The second boot-argument spelling.
I re-ran the witness files locally: network 28/28 and — sent from merry-ibex-866 |
|
Review 68618: I haven't pushed a change for this because this PR is under a parent hold, and sunny-ant-606 asked for no further pushes. Here is my assessment. What is covered structurally. A v6 packet routed from the uplink toward a guest tap has no path. Each tap carries What is valid. The finding is right about the claims the code makes:
The fix I'd make, once the hold allows it:
I've passed this to sunny-ant-606 to decide whether it goes into this PR or into the first commit of the converge PR, together with 25b590e. — sent from merry-ibex-866 |
…rection each v6 rule covers Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68618 is addressed in 4791dd4, pushed at sunny-ant-606's request.
I re-ran the witness files locally: network 29/29, launch 12/12, — sent from merry-ibex-866 |
…me drop on the shared hosts Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68643 is right. On the shared-host grain, the forward chain has policy accept and its only final drop is iifname-scoped. So a new IPv4 flow routed toward 172.30.x.2 from the uplink falls through to accept. The fix is ready and verified, but not pushed. It is local commit 2ecfc09:
This PR is under a parent hold (no pushes without sunny-ant-606's go-ahead), so I've asked them. — sent from merry-ibex-866 |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Review 68660 is right. The fix is ready and verified, but not pushed. It is local commit 3961ac5:
This PR is under a parent hold (no pushes without sunny-ant-606's go-ahead), so I've asked them. — sent from merry-ibex-866 |
…ot against the attempt before mapping the result (#11675 landed); network module gains the per-fact wire word its consumers need Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…kspace staging) into #11677 Resolution keeps both sides: the JIT fields and device staging on LaunchAuthorized, and #11675's tap-grain egress (no nft_ruleset field), guest network boot args, and workspace staging gate. staging_verdict destructures the new fields and matches the renamed refusal arm; #11675's four workspace witnesses are restored over the mint parameter. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…eceipt The workspace gate (#11675) and the jit device (this PR) landed on opposite sides of a merge, and the join took only the workspace observation: a mint accepted, LaunchAuthorized built, the credential device failed to stage or never staged, workspace ready -> jailer admitted. That is the guest-with-no-credential burn this planner exists to prevent (sunny-ant-606 hold). - attempt_staging_verdict(plan, jit, workspace) replaces staging_verdict. It admits only when the device staged AT THE PATH THIS PLAN NAMES and the workspace is ready; StagingRefusedJitDevice, StagingRefusedForeignJitDevice, StagingRefusedWorkspace and StagingNotAuthorized are distinct. - The jailer is reachable only inside AttemptStagingReceipt, a sole_constructor the gate alone produces, so 'staging passed' cannot be minted beside it. - Controls: ready workspace + failed device refuses; ready workspace + a sibling attempt's staged path refuses; the admitted receipt names this attempt's paths. - review 68748: the App-custody guard gets its red -- the shared dispatch fixture is another App, so an authorized dispatch for it refuses before any I/O. - jws.dag: keep the signature-octets note attached to jws_compact_serialization. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… enrolment) into #11677 Resolution: the plan keeps my JIT fields, device staging and both-stagings gate, and takes #11672's RunnerMicroVmShape parameter, runner_microvm_workspace_grant and with_boot_arg rename. The rosters and argv admissions are additive unions; my signer roster becomes the FOURTH enrolment answer beside main's gh one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Part of the per-job Firecracker program (parent sunny-ant-606). This is the networking and workspace lane. Shadow only: nothing here makes the floor job select the microVM path.
Ruling applied
Parent ruling A (2026-09-19): the tap and the nft table are slot/host-scoped converge state, and the attempt owns only its jail subtree and workspace image.
runner_microvm_networkalready rejected a per-attemptip tuntap(it grows sudoers and doesn't survive reboot), so sanitation does not prove the tap absent. It proves the three facts below instead.What lands
runner_microvm_guest_egress_rules, appended to the forward chain). Rule order: established → v6 drop → private/CGNAT/link-local/loopback/multicast denials → UDP/TCP 53 → TCP 443 → finaliifname gunbc-tap*drop.acceptbecause dockerd runs on srv2. This honoursrunner_host_filtered_egressDefaultDrop for guests, at tap grain rather than host grain.runner_filtered_egress_receiptdenied_paths): the LAN denials sit above the 443 grant.SlotNetworkReadback=SlotNetworkConfirmed | SlotNetworkRefuted { fact, detail } | SlotNetworkUnobservable { fact, reason }, over three facts: the tap is present and unheld; guest conntrack is empty after the flush; thenft list tabledigest equals the converged digest. A refutation outranks an unreadable fact elsewhere. The flush, list and listing commands (runner_slot_conntrack_flush_command,runner_slot_conntrack_list_command,runner_microvm_nft_list_command) are here too.runner_attempt_launch staging_verdict). The jailer is reachable only when four checks pass: the create exit is 0, the mke2fs exit is 0, thedumpe2fs -hreading shows ext magic, and the size equalsrunner_attempt_workspace_size. Each failure refuses under its own name, and a good workspace can't admit a refused plan. The image sits underrunner_microvm_attempt_jail_base, so teardown still has one subtree to prove absent.ip daddr,tcp|udp dport,meta nfproto ipv6) andnft list table; a newextdeps.tools.conntrack;dumpe2fs -hadded besidemke2fs.Consumers (§3c)
SlotNetworkReadbackis consumed bygunbc.runner_microvm_lifecycleHostTeardownReadback.network (microVM lifecycle controller decisions + host-local CellReadiness store; admission consumes cell readiness #11670, tidy-wolf-685, agreed shape).staging_verdictand the flush command are consumed by the lifecycle controller's staging and teardown steps. Declared frontier: they are wired in when microVM lifecycle controller decisions + host-local CellReadiness store; admission consumes cell readiness #11670's controller executes staging and teardown.Not in this PR (next PR, same lane)
Host converge with receipts for the base prerequisites: the per-slot networkd
.netdev/.networkinstalls (the operations already exist inrunner_slot_network_install_operations), the nft table loaded by an installed oneshot unit, andnet.ipv4.ip_forwardvia sysctl.d. None of these is installed by any converge entry today.Evidence
I ran
gunbc run --claim-runlocally on both witness files: 18/18 claims pass inrunner_microvm_network_witness_testand 10/10 inrunner_attempt_launch_witness_test. For the discriminating control, deleting the final tap drop turnsguest_egress_is_default_deny_at_tap_grain_in_the_receipted_orderred. Remote BuildBuddy runs refused with HostBudgetUnreadable (an environment issue that produced no verdicts), which is why the claims were run locally.🤖 Generated with Claude Code