Skip to content

feat(admin): admit verified zip download tokens - #1534

Draft
overtrue wants to merge 2 commits into
mainfrom
p1/1400-zip-token-latest
Draft

overtrue wants to merge 2 commits into
mainfrom
p1/1400-zip-token-latest

Conversation

@overtrue

@overtrue overtrue commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A minted ZIP download URL cannot currently authenticate at the gateway. This adds the route-bound, opt-in host bearer verifier from ADR-0042 for the two RustFS admin ZIP GET aliases. It carries a request-bound receipt through authorization, strips the token from authorization and handler contexts when the verifier is enabled, and preserves the existing header-signed path when it is not installed. A missing verifier keeps token-only requests denied.

Part of #1400. The gateway fixture does not implement the RustFS host's AEAD verifier or prove a real archive download. That adapter work remains Phase 2; this PR does not resolve R-062.

Verification

$ cargo fmt --all --check
exit 0
$ cargo clippy --workspace --all-targets -- -D warnings
exit 0
$ cargo test --workspace
exit 0; 10472 passed, 3 ignored
$ cargo xtask verify --all
exit 0
verify: workspace test build finished in 0.32s
verify: workspace tests finished in 267.77s
verify: guard self-test finished in 350.83s
verify: workspace tests and build guards passed in 618.92s

The full verifier's two unchanged 480-second stage budgets passed, but 618.92 seconds exceeds the 600-second feedback target. This is recorded separately in #1462; The earlier PR CI completed successfully in 7 minutes 16 seconds. The admin crate verifier first hit its 30-second deadline with Cargo lock waits; a warm rerun exited 0 with 0.52 seconds prebuild and 27.96 seconds reported verification. Earlier runs also recorded intermittent socket failures, one of which reproduced on the unchanged main baseline, a baseline prebuild timeout, and a cross-worktree target-cache path error. No failed run is counted as passing. Detailed receipts and their limits are in the issue Handoffs.

All 69 new explicit assertions and the two receipt compile-fail probes were mapped to individual failing mutations, followed by restored targeted tests. Attacks included token parsing, signed and bearer identities, default refusal, authorization and handler reach, both query redactions, response and Debug leakage, posture, state identity, and cross-admission reuse. Removing only the first duplicate-token check remained green because the decoder independently refused duplicates; removing both made the assertion red. Two observer-disabled controls prove observation availability and do not alone prove authorization execution. Evidence: #1400 (comment).

The follow-up commit adds a concurrent control with two pre-minted receipts from different admissions. Two actual custom-verifier calls overlap, and both requests must be refused before the handler. Removing the rejection guard produced two 200 responses and two handler calls; separate assertion orderings exposed each response and handler assertion. Disabling the overlap observer made its assertion fail, which is an observation control rather than proof of the security boundary. The restored test passed directly and in the workspace suite. It does not establish concurrent host AEAD verification or real archive behavior. The initial command used an exact filter that matched zero tests and is not counted as a pass.

The ordered gate was rerun for the follow-up commit: fmt and workspace clippy exited 0; workspace tests exited 0 with 10473 passed and 3 ignored across 78 summaries; cargo xtask verify --all exited 0 with a 334.09-second workspace stage and 379.40-second guard stage, totaling 713.89 seconds. Both stage budgets passed, while total feedback time again exceeded 600 seconds; the budget issue remains #1462. The PR remains draft pending ADR-0042's native host and archive acceptance.

Role Verdicts

  • simplicity-adversary: attacked receipt ownership, state transport, query filtering, and the file splits needed for existing size guards — no break found
  • security-adversary: attacked credential precedence, cross-admission receipts, token redaction, pre-authentication Debug, and signed-principal binding — no break found
  • test-adversary: attacked denial ordering, both redaction consumers, observer controls, forged receipts, and every added assertion by mutation — no break found

The role review is advisory and limited to the gateway implementation and fixture evidence; it does not establish native RustFS archive, concurrency, or crash-persistence behavior.

Breaking Change

  • BREAKING — this PR changes public authentication contracts.

AuthSchemeRef gains Bearer; downstream exhaustive matches must add an explicit bearer arm and must not treat it as a signed scheme. Gateway, core, signature, and RustFS admin dialect versions are bumped to 0.60.0, 0.57.0, 0.14.0, and 0.13.0 respectively. Hosts opt in by installing BearerTokenVerifier, validate the token and its request-bound resource and expiry, and pass their verified state through BearerGrant; handlers read the same state through RequestContextView::bearer(). Host state with interior mutability must remain consistent with the verified decision. With no verifier, valid header-signed requests retain their previous query and credential path. With one installed, the signed path also requires a token for the same principal.

Checklist

  • The four-command gate passed (fmt, clippy, test, cargo xtask verify)
  • New or changed public API has rustdoc
  • Negative test cases outnumber positive ones
  • Every new assertion was mutated — the implementation was broken on purpose and the assertion
    went red. The PR description names which ones
  • No Protected File touched; if one was, the PR description contains BREAKING and a migration path
  • No unsafe introduced
  • No inventory / linkme introduced
  • No #[non_exhaustive] added to a DTO
  • No s3s code copied; behavioural evidence is URL + self-written summary
  • No credentials, signatures, or expected-signature values reachable from logs or error bodies
  • No plan document, analysis report, or working note committed
  • Commits follow Conventional Commits; PR title ≤72 characters
  • A Handoff comment has been appended to the issue

@overtrue

Copy link
Copy Markdown
Collaborator Author

Advisory role evidence

  • simplicity-adversary: attacked receipt ownership, typed state transport, query filtering, and the file splits needed to retain existing size guards — no break found
  • security-adversary: attacked AWS credential precedence, receipt reuse across admissions, signed-principal binding, pre-authentication Debug, and both authorization and handler query redaction — no break found
  • test-adversary: attacked positive and negative dispatch, refusal ordering, both context consumers, observer controls, receipt construction and cloning, and the added assertions with individual mutations — no break found

The security review includes an independent static pass. Mutation evidence and the observer-control limit are recorded in the PR body and #1400 (comment). These roles do not establish real RustFS AEAD/archive acceptance, host behavior when it explicitly logs raw pre-authentication query data, concurrent execution, or crash persistence.

@overtrue

Copy link
Copy Markdown
Collaborator Author

Role Verdicts

  • simplicity-adversary: attacked the two-request rendezvous, bounded timeout, receipt ownership, and handler counter — no break found
  • security-adversary: attacked reuse of receipts from separate prior admissions across two overlapping custom-verifier calls — no break found
  • test-adversary: attacked each response and handler assertion by disabling the runtime refusal, and disabled the overlap observer — each intended assertion went red

The overlap observer mutation controls observation availability. The test does not establish concurrent RustFS host AEAD or archive behavior.

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.

1 participant