8000 feat(bep): refuse undeclared egress and host mismatches, admit only when every check passes by minimal-foundry[bot] · Pull Request #2450 · gominimal/minimal · GitHub
[go: up one dir, main page]

Skip to content

feat(bep): refuse undeclared egress and host mismatches, admit only when every check passes - #2450

Merged
norrietaylor merged 3 commits into
mainfrom
agent/2268-pin-the-request-authority-re-check-the-box-s-egr
Oct 20, 2026
Merged

norrietaylor merged 3 commits into
mainfrom
agent/2268-pin-the-request-authority-re-check-the-box-s-egr

Conversation

@minimal-foundry
Copy link
Copy Markdown
Contributor

T6 — Pin the request authority, re-check the box's egress, and admit only when every check passes

slice: S0
kind: task
covers: BEP-022, BEP-023, BEP-025
size: L
est: 150 code, 360 tests
executor: agent
difficulty: needs care
model: strongest
diagnostics: every refusal names its first failing check in the audit record's marker, which min box audit <box> shows
observability: the connection span and the audit marker name a refusal's first failing check
layers:
- decide:
- crates/bep/src/redeem.rs: the BEP-022 and BEP-023 checks, and Admit iff every check passes, else Refuse naming the first failing one
- scripts/kani.sh: the added harnesses' count
test: cargo nextest run -p bep prop_undeclared_egress_authority_is_refused
test: cargo nextest run -p bep prop_host_header_mismatch_is_refused
test: cargo nextest run -p bep prop_admit_iff_every_check_passes
test (deferred: kani): cargo nextest run -p bep kani_redeem_requires_egress_admission
test (deferred: kani): cargo nextest run -p bep kani_redeem_pins_request_authority
test (deferred: kani): cargo nextest run -p bep kani_redeem_admits_iff_all_checks_pass
produces: none
consumes: none
proof: A mismatched Host or an egress-denied authority is refused, and the decision admits only when every check passes.
depends on:
- blocked by #2266

Proof

In crates/bep/src/redeem.rs, decide refuses a request to an authority outside the box's declared egress as outside_declared_egress. It refuses a request whose Host header or absolute-form target differs from the connection authority as host_mismatch. decide_plain makes the same two checks for a request with no sealed value. A property test and a Kani harness show that decide admits exactly when every check passes, and otherwise names the first failing check.

Notes from the agent: Deferred (lane: kani): kani_redeem_requires_egress_admission, kani_redeem_pins_request_authority and kani_redeem_admits_iff_all_checks_pass are written in the #[cfg(kani)] module, and scripts/kani.sh now expects 9 bep harnesses. I ran none of them. The new checks run last, as checks 9 (egress) and 10 (request authority). That order leaves the existing Kani harnesses unchanged. The decision gets the declared egress as a list of authorities that the shell resolves (Redemption::egress, Plain::egress). bep does not depend on boxes, and its Cargo.toml is outside the layers, so wildcard matching of an egress declaration is a job for the shell. A missing Host header (RequestAuthority::host = None) is refused as host_mismatch. The new audit markers are outside_declared_egress and host_mismatch. The spec fixes no wording for them. The task's observability line asks for the connection span to name the check. No TLS or socket shell exists in bep yet, so no span records it. The shell task needs to put Check::marker on its span. BEP-025's property also names BEP-064 (store-handle checks). BEP-064 is not built in this module and is not in this task's covers, so the oracle in prop_admit_iff_every_check_passes leaves it out.

Tests

line exit tail
cargo nextest run -p bep prop_undeclared_egress_authority_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-ee69... Compiling bep v0.0.1 (/workbench/crates/bep) Finished 'test' profile [unoptimized] target(s) in 8.23s ──────────── Nextest run ID 8a917a45-c5a2-46ef-84aa-de5b354dc6a3 with nextes
cargo nextest run -p bep prop_host_header_mismatch_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-42b2... Finished 'test' profile [unoptimized] target(s) in 0.38s â 8000 ”€─────────── Nextest run ID ce0fedaf-75a3-4b8a-a6e6-a11651f514c5 with nextest profile: default Starting 1 test across 2
cargo nextest run -p bep prop_admit_iff_every_check_passes 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-9651... Finished 'test' profile [unoptimized] target(s) in 0.41s ──────────── Nextest run ID fad91360-55e4-4e53-98f9-27ce1383831b with nextest profile: default Starting 1 test across 2

Verify

min task run agent-verify passed ([tasks.verify]).

Deferred

The plan marked these test lines deferred: the executor lacks the lane, so nothing here ran them and they still owe evidence.

line lane
cargo nextest run -p bep kani_redeem_requires_egress_admission kani
cargo nextest run -p bep kani_redeem_pins_request_authority kani
cargo nextest run -p bep kani_redeem_admits_iff_all_checks_pass kani

Closes #2268

decide now checks the box's declared egress (BEP-022) and pins the Host
header and absolute-form target to the connection authority (BEP-023),
and admits only when every check passes (BEP-025). decide_plain applies
both checks to a request with no sealed value. Three Kani harnesses
cover the new checks, so scripts/kani.sh expects nine for bep.
@coderabbitai
coderabbitai Bot commented Oct 20, 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: fc418f2e-81cd-494f-b285-b722b18e7a96

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

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

Approved: no findings at eb3e7f69b1ee.

Nothing to do.

Clobber: none seen: the diff only adds checks to decide.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — approved

Verdict APPROVE — No findings.

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

@minimal-foundry minimal-foundry Bot added the review:approved minimal-review approved the current head label Oct 20, 2026
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Own review of a8e49e0 against the T6 plan block (BEP-022, BEP-023, BEP-025).

  • BEP-022 (prop_undeclared_egress_authority_is_refused): request_check refuses as outside_declared_egress when the resolved egress list lacks the connection authority, in decide and in decide_plain, so the check holds with and without a sealed value, as the spec's property says. The third arm (any other facts, an admission has a declared authority) is the harness property in test form. Wildcard matching of the egress declaration is left to the shell, which the agent note records; bep does not depend on boxes.
  • BEP-023 (prop_host_header_mismatch_is_refused): RequestAuthority::pins requires Host (or :authority) equal to the connection authority and an absolute-form target, when present, equal too; a missing Host never pins. That is the spec's "all three are equal", origin-form counting as the connection authority. Refusal host_mismatch before substitution, in both decide and decide_plain.
  • BEP-025 (prop_admit_iff_every_check_passes): the oracle failures() lists the checks of BEP-019 to BEP-024, BEP-031 and BEP-058 in decide's order, independently of decide, and the test asserts Admit exactly when none fails and Refuse naming the first otherwise, over a full any_redemption() plus the two "reaching" variants that drive the earlier checks. kani_redeem_admits_iff_all_checks_pass states the same iff. BEP-064 (store-handle checks) is named by the spec property but is outside this task's covers and not built in this module; the oracle omits it and the agent note says so. The task that builds BEP-064 extends the oracle and the harness; no new issue, it is already a task in this epic's slice plan.
  • Order and purity: checks 9 and 10 run after the host-set checks, the earlier harnesses are unchanged, decide and decide_plain stay pure over owned values, and the markers test carries outside_declared_egress and host_mismatch.
  • Layers: crates/bep/src/redeem.rs and scripts/kani.sh (bep harness count 6 to 9) only, as planned. The connection span is still not wired (no TLS/socket shell), the same interim as T5.

Approval follows the arch ruling, the runtime review and the lanes (Kani lane supplies the deferred harness evidence).


Generated by Claude Code

@norrietaylor norrietaylor changed the title T6 — Pin the request authority, re-check the box's egress, and admit only when every check passes feat(bep): refuse undeclared egress and host mismatches, admit only when every check passes Oct 20, 2026
@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

arch-review: CONDITIONS · 1 condition · the full ruling

The new egress and Host checks are in the right place, and they fail closed. The order is wrong. decide runs the egress check after the bound-set, current-set, expiry and revocation checks. Gatehouse §6.10 line 823 orders egress declaration as step 3, before the step 4 invariants. So a request outside both egress and the current set gets the audit marker outside_current_set, not outside_declared_egress. Move the egress check to directly after attribution, as C1 says.

Ruled at a8e49e0 against gominimal/arch@3dab1097cda1 by claude-opus-5-5.

8000

Comment thread crates/bep/src/redeem.rs Resolved
Comment thread crates/bep/src/redeem.rs Resolved
Comment thread crates/bep/src/redeem.rs Resolved
Copy link
Copy Markdown
Member

/revise minimal-arch ruled CONDITIONS on a8e49e0 (arch_rulings 81): one condition, C1, on the order of the egress check. Take it and nothing else:

  1. crates/bep/src/redeem.rs decide(): move the BEP-022 egress check so that it runs immediately after the BEP-020 attribution match and before the BEP-024 expiry check (Gatehouse §6.10 line 823 makes egress declaration step 3, before the step 4 checks). It refuses Check::OutsideDeclaredEgress when !redemption.egress.contains(&redemption.authority). In the Unsealed::Expired arm, refuse Check::OutsideDeclaredEgress before Check::Expired once the attribution passes; the NoLiveBox and CrossBox outcomes stay as they are. Keep the BEP-023 HostMismatch check last, after OutsideCurrentSet. decide_plain() does not change.
  2. Renumber the module-doc list so that egress is check 4 (after attribution) and request authority stays last as check 10.
  3. In the test oracle failures(), move the (Check::OutsideDeclaredEgress, ...) entry to directly after the Check::CrossBox entry, keeping HostMismatch last, so prop_admit_iff_every_check_passes follows the new order. Re-run the three task test lines. The Kani harnesses state admit-iff and membership facts only, so they need no change.

The runtime review approved with no findings; arch accepted the placement, the fail-closed Host handling and the reached() test helper. Reply on the three arch threads with the commit.


Generated by Claude Code

Gatehouse makes egress declaration step 3, before the expiry, revocation,
port and host-set checks. decide() now refuses OutsideDeclaredEgress after
the BEP-020 attribution, and before Expired for a value open refused as
expired. HostMismatch stays last. The module doc and the test oracle follow
the new order.
@minimal-foundry
Copy link
Copy Markdown
Contributor Author

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

line exit tail
cargo nextest run -p bep prop_undeclared_egress_authority_is_refused 0 Applying loadouts: default Running task runtime-implement-test-0 in session task-runtime-implement-test-0-dff6... Compiling bep v0.0.1 (/workbench/crates/bep) Finished 'test' profile [unoptimized] target(s) in 5.07s ──────────── Nextest run ID 0d4f7495-8f20-4d24-8031-78988185541b with nextes
cargo nextest run -p bep prop_host_header_mismatch_is_refused 0 Applying loadouts: default Running task runtime-implement-test-1 in session task-runtime-implement-test-1-e873... Finished 'test' profile [unoptimized] target(s) in 0.24s ──────────── Nextest run ID d36244e2-20d2-4bf3-acf9-f80742927388 with nextest profile: default Starting 1 test across 2
cargo nextest run -p bep prop_admit_iff_every_check_passes 0 Applying loadouts: default Running task runtime-implement-test-2 in session task-runtime-implement-test-2-f01b... Finished 'test' profile [unoptimized] target(s) in 0.23s ──────────── Nextest run ID 81c5d366-3cde-41e1-b303-addbc282745c with nextest profile: default Starting 1 test across 2

Verify min task run agent-verify passed.

Review threads the coder judged:

  • 👍 valid — crates/bep/src/redeem.rs: ede2b5f: decide() refuses OutsideDeclaredEgress directly after the attribution match (and before Expired in the Unsealed::Expired arm). HostMismatch stays last.
  • 👍 valid — crates/bep/src/redeem.rs: ede2b5f: module-doc list renumbered. Egress is check 4 after attribution, request authority stays check 10.
  • 👍 valid — crates/bep/src/redeem.rs: ede2b5f: the oracle's OutsideDeclaredEgress entry now follows CrossBox, and HostMismatch stays last.

A redemption whose authority is outside the box's declared egress is refused as outside_declared_egress right after attribution, before the expiry, revocation, port and host-set checks. A mismatched Host is still refused last. decide() admits only when every check passes, in the order the module doc lists.

Notes from the agent: Revise round 1 (arch C1) in commit ede2b5f. decide() refuses Check::OutsideDeclaredEgress directly after the BEP-020 attribution match. In the Unsealed::Expired arm it refuses OutsideDeclaredEgress before Expired once attribution passes. NoLiveBox and CrossBox stay as they were. HostMismatch is now a direct request.pins() check after OutsideCurrentSet. decide_plain() and request_check() do not change. The module-doc list is renumbered: egress is check 4, request authority stays check 10, and the OffPort note now points to check 9. The Unsealed::from_open doc now says Expired applies once the attribution and the declared egress pass. The oracle failures() moves the egress entry to after CrossBox. The whole bep suite passes (67 tests). Kani harnesses are unchanged. kani_redeem_requires_egress_admission, kani_redeem_pins_request_authority and kani_redeem_admits_iff_all_checks_pass are deferred to the kani lane and were not run. scripts/kani.sh did not change this round.

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

arch-review: PASS · the full ruling

The compare fixes the step order. decide now checks the declared egress right after attribution, before expiry and the host sets. Section 6.10 gives this order. The pinning check is the last check before substitution, and a missing Host is refused. BEP-022, BEP-023 and BEP-025 conform, and no condition stays open. The new Kani harnesses are deferred to the advisory Kani lane and did not run.

Ruled at ede2b5f against gominimal/arch@3dab1097cda1 by claude-opus-5-5.

@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — approval withheld

Verdict COMMENT — APPROVE withheld: 3 unresolved threads — minimal-arch[bot] crates/bep/src/redeem.rs, minimal-arch[bot] crates/bep/src/redeem.rs, minimal-arch[bot] crates/bep/src/redeem.rs. No findings.

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

@minimal-foundry minimal-foundry Bot removed the review:approved minimal-review approved the current head label Oct 20, 2026
@minimal-foundry minimal-foundry Bot left a comment
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

minimal-review — approved

Verdict APPROVE — every review thread is resolved; @norrietaylor closed the last one. The review of ede2b5f65aa3 withheld this approval on the threads open then. Posted as a comment: the App cannot approve its own pull request; the check and the label carry it.

@minimal-foundry minimal-foundry Bot added the review:approved minimal-review approved the current head label Oct 20, 2026
@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Own review of ede2b5f (round 1 on arch C1). The one commit moves the BEP-022 egress refusal to directly after attribution, in the opened path and in the Unsealed::Expired arm, renumbers the module-doc list (egress 4, request authority 10) and moves the oracle entry to match. Nothing else changed: decide_plain, the three property tests' bodies and the Kani harnesses are as reviewed at a8e49e0, and the admit-iff property now follows the design's order. minimal-arch ruled PASS on this head. The three arch threads are resolved with the verification above. Approval follows the lanes.


Generated by Claude Code

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

Approving for merge: T6 on ede2b5f (arch PASS 118521752109, review approved with no findings, three arch threads verified). Gate passes on ede2b5f (arch PASS, review concluded with no open threads, lanes green, squash subject lint-clean).


Generated by Claude Code

@minimal-arch minimal-arch Bot left a comment
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

arch-review: PASS · the full ruling

The new head is a merge of main. It does not change crates/bep/src/redeem.rs or scripts/kani.sh. Their diff against the base is the same as at ede2b5f6, which had a PASS. The new bep::http parser checks that Host is well-formed. It does not pin the request authority, so check 10 still owns the §6.10 pin. The ruling stays PASS.

Ruled at eb3e7f6 against gominimal/arch@109541a48c31 by claude-opus-5-5.

@minimal-foundry
Copy link
Copy Markdown
Contributor Author

Round 2 of 10 on a failed check suite: the coder changed nothing. every commit this round put on the branch above eb3e7f6 is a merge of the base branch, so it carries no work of its own

Copy link
Copy Markdown
Member

The red e2e lane on eb3e7f6 is the macOS runner's, not this change's. Job 118808857864 fails in minvmd::guest_classifier_integration::guest_classifier_table_present with:

hostname proxy port 7654 held by pid 94417 (gvproxy); bind refused; configured ports never redraw

The same leaked gvproxy fails main's own run (39464338657) and #2457's, and 32 of the 39 harnesses never ran. This head is a merge of main over a diff in crates/bep and scripts/kani.sh, which do not touch minvmd, gvproxy or the port assignment. Nothing to fix here; the epic owner is asked to reap the runner, after which the lane is re-run once on this head and the armed auto-merge takes it.


Generated by Claude Code

@norrietaylor
norrietaylor added this pull request to the merge queue Oct 20, 2026
Merged via the queue into main with commit 4fcfa9c Oct 20, 2026
42 of 44 checks passed
@norrietaylor
norrietaylor deleted the agent/2268-pin-the-request-authority-re-check-the-box-s-egr branch October 20, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:approved minimal-review approved the current head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

T6 — Pin the request authority, re-check the box's egress, and admit only when every check passes

1 participant

0