Repository navigation
test(minimald): prove on a real kernel that a blocked cohort refuses pre-flip UDP 443 (T87) - #2648
Conversation
The leg loads the installer's classifier table over a scratch cgroup2 tree. It opens a UDP socket to 127.0.0.1:443 in a host_ip member's own allow leaf. Then it flips the cohort the way the daemon does: the process moves into boxes/quic443-blocked, and the helper adds the own leaf to quic443_blocked_leaves. The pre-flip socket then reports ECONNREFUSED. After the helper removes the leaf, the same socket sends again. A root-bound listener on port 443 confirms each delivery. The leg prints NOT RUN with its gate where the host has no nft or the process is outside the root network namespace. (BEP-018, #2606)
…-real-kernel-that-a-blocked-cohort-rej
|
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: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The leg proves BEP-018 against the installer's real reject rule. It goes through the quic443_blocked_leaves set, the only rule that covers a socket made before the flip. It needs ECONNREFUSED, so a silent drop fails it. This matches §5.3 line 150: "an active reject, never a silent drop". The PR says nobody saw the leg run on a real kernel, and the leg exits green on NOT RUN. C1: read the minimald-root-integration job on this head and confirm step 8 printed, with no NOT RUN line, before merge.
Ruled at 9322713 against gominimal/arch@109541a48c31 by claude-opus-5-5.
|
/revise Round 1 of #2648, on arch condition C1 at Why. C1 asks the
Generated by Claude Code |
…-real-kernel-that-a-blocked-cohort-rej
The arch review reads this leg's steps from the CI log (BEP-018), and nextest captures a passing test's output by default.
There was a problem hiding this comment.
arch-review: PASS_WITH_CONDITIONS · 1 condition · the full ruling
The leg proves the design's active reject on a pre-flip host_ip socket, against the real installed table. The test file is the same as on the earlier head, and the new nextest override only prints the leg's steps in the ci profile. The leg is still not observed on a real kernel. Section 5.3 line 150 requires an active reject, and a NOT RUN leg does not prove it. Link the lane run on this head as C1 says.
Ruled at fca73a8 against gominimal/arch@109541a48c31 by claude-opus-5-5.
There was a problem hiding this comment.
minimal-review — approval withheld
Verdict COMMENT — APPROVE withheld: 2 unresolved threads — minimal-arch[bot] crates/minimald/tests/netns_root_integration.rs:2487, minimal-arch[bot] .config/nextest.toml:31. No findings.
Panel: 3 of 3 personas ran (correctness, security, supply-chain).
|
Round 1 of 10 on a /revise note, pushed as
Verify Outside the task's
Converted to a draft: something above needs a person before review. Review threads the coder judged:
On a real kernel, a host_ip member's UDP 443 socket opened before the cohort turns blocked is rejected after the flip and sends again after the block lifts. With this round, the minimald-root-integration CI log prints the leg's steps, step 8 included, or its NOT RUN line, so a reviewer can read which one happened. Notes from the agent: Layer exception: .config/nextest.toml is outside T87's layers. The epic owner accepted it for arch condition C1, and the PR body needs a 'Layer exception' section that names it. This box has no root and no MINIMALD_NETNS_TEST, so the leg did not run its steps here. The output check proved only that the ci profile now shows a passing test's output. The C1 condition (step 8 present, no NOT RUN line) can be checked only on the CI log of the next head. The local branch also carried a merge of origin/main (7c353cf) from before this round, and I did not change it. |
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 fca73a8efa58 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.
Own review at fca73a8. The new root-integration leg opens a UDP 443 socket in a host_ip member's own leaf, blocks the cohort, sees ECONNREFUSED, and sends again after the block lifts, on the runner's real kernel. The ci profile override prints its steps. The linked run shows step 1 through step 9 and no NOT RUN line.
Generated by Claude Code
There was a problem hiding this comment.
Babysitter approval at fca73a8: every merge gate passes at this head (arch PASS at fca73a8, zero open threads, every lane aggregator green). Squash title test(minimald): prove on a real kernel that a blocked cohort refuses pre-flip UDP 443 (T87) and the squashed message pass commitlint. Queued for squash merge.
Generated by Claude Code
T87 — Prove on a real kernel that a blocked cohort rejects a pre-flip UDP 443 socket
slice: S12
kind: task
covers: BEP-018
size: M
est: 40 code, 160 tests
executor: agent
difficulty: unknown ground
model: strongest
diagnostics: the leg records NOT RUN with its gate where the host has no root netns or no nft
observability: one line per step of the leg
layers:
- kernel:
- crates/minimald/tests/netns_root_integration.rs: a leg that opens a UDP 443 socket in a host_ip member's leaf before the cohort flips to blocked, expects ECONNREFUSED on the next datagram after the flip, and a send again after the block lifts, against the loaded classifier table (#2606)
test: cargo nextest run -p minimald --run-ignored only a_blocked_cohort_rejects_a_pre_flip_udp_443_socket
produces: none
consumes: none
proof: On a real kernel, a host_ip member's UDP 443 socket opened before the cohort turns blocked is rejected after the flip and sends again after the block lifts.
depends on:
- blocked by #2558
Proof
The native lane's minimald-root-integration job now has a leg, a_blocked_cohort_rejects_a_pre_flip_udp_443_socket. It loads the installer's real classifier table on a real kernel and opens a UDP socket to 127.0.0.1:443 in a host_ip member's own allow leaf. It flips the cohort to blocked: the process moves into boxes/quic443-blocked and the installed helper adds the own leaf to quic443_blocked_leaves. The pre-flip socket then gets ECONNREFUSED, and the listener gets nothing. After the helper removes the leaf, the same socket sends again and the listener receives the datagram. The leg was NOT observed passing on a real kernel in this session, because this box has no sudo and no nft.
Notes from the agent: The real-kernel leg did not run here. This box has no sudo, no nft and no root reach, so only the gate path ran: the skip, and NOT RUN for the missing nft. The CI lane holds the first real evidence. Read its run before you trust the proof.
Design choices that the lane run must confirm:
(1) Port 443 is privileged, so the leg runs a UDP listener as
sudo -n python3. A listener is necessary because without one, the kernel itself answers port unreachable before the flip. python3 is a declared system dependency in AGENTS.md. If the runner has no python3, the leg fails loudly.(2) I expect the first datagram after the flip to return EPERM, because NF_DROP in the output hook gives EPERM. I expect the next datagram to report ECONNREFUSED from the reject's ICMP. The leg accepts EPERM, success or ECONNREFUSED on the first datagram, and it requires ECONNREFUSED by the next one at the latest.
(3) The install puts the helper and its sudoers rule in a root-owned
mktemp -d /run/minimald-quic443-proof.XXXXXX, through the MINIMAL_OVERRIDE_QUIC443_HELPER and MINIMAL_OVERRIDE_QUIC443_SUDOERS knobs. Nothing goes to /usr/local/lib or /etc/sudoers.d on the host. Cleanup runs the installer's own --uninstall with the same knobs, then removes the directory.(4) The leg takes …[truncated]
Real-kernel run (arch C1): the
minimald-root-integrationjob onfca73a8e(https://github.com/gominimal/minimal/actions/runs/40429271408/job/121942764926) passed the leg in 6.5 s. Its log showsstep 1throughstep 9, ending withstep 8: the pre-flip socket sends again after the block liftsandstep 9: the table, the helper and the scratch tree are removed. No line in the log containsNOT RUN.Layer exception
The epic owner accepted this file outside T87's layers on 2026-10-27, for arch condition C1 (round 1):
.config/nextest.toml: a[[profile.ci.overrides]]entry withsuccess-output = "immediate"fora_blocked_cohort_rejects_a_pre_flip_udp_443_socket, so the CI log shows the leg's steps.Tests
cargo nextest run -p minimald --run-ignored only a_blocked_cohort_rejects_a_pre_flip_udp_443_socketVerify
min task run agent-verifyexited 101 under rustc 1.98.1, which the repository does not pin (1.99.0 in rust-toolchain.toml); the PR is not a draft on that alone — CI, which honours the pin, is the gate.Base
The base branch moved while the coder worked; it was merged in before the tests ran.
Closes #2606
Generated by Claude Code