ci: delegate gate-attestation to the fleet reusable - #9
Merged
Merged
Conversation
Replace the inline copy (which lacked any release-please waiver, failing every release PR with 'No Gate-Passed trailer found') with a thin caller of the canonical reusable, pinned past the branch-shaped release-please waiver (forkwright/.github#10). One fact, one place. Gate-Passed: kanon 0.1.6 +stages:fmt,check,clippy,nextest,lint sha:f37359ad8909afc24d679265586d080fd00a793d
4 tasks
forkwright
added a commit
that referenced
this pull request
Aug 15, 2026
… the adapter seam (#32) ## Summary sphragis#23 asks Sphragis to earn authority as a versioned, multi-recipient content-key envelope — not as a generic X-Wing/KEM primitive library — by hiding `HybridKem`, `EncapsulationKey`, `DecapsulationKey`, `SharedSecret`, and `derive_wrap_key` from the normal public API, and by defining the seam for an eventual upstream-X-Wing adapter. **What this PR does:** - Adds a `hazmat` feature (the RustCrypto/rustls convention for exactly this shape of surface) that gates the generic hybrid-KEM primitive: `HybridKem`, direct `EncapsulationKey::encapsulate`/`DecapsulationKey::decapsulate`, and `derive_wrap_key`. Off by default; carries no stability promise; exists only so this crate's own known-answer/conformance tests can reach the primitive directly. - Adds `generate_recipient_keypair()` — the new stable, profile-level entry point for device-key creation, replacing `HybridKem::generate()` for a normal consumer. - Keeps `EncapsulationKey`/`DecapsulationKey` and their key-management operations (`to_bytes`/`from_bytes`, `from_seed`/`to_seed`, `encapsulation_key`) public — `seal_for`/`unseal` require them in their own signatures, and publishing/persisting a device key is a profile-level operation, not a primitive one. - `DECISION.md` #9 documents the module boundary (`src/hybrid.rs` is now the *only* place that performs a raw KEM operation) as the adapter seam a future migration would use, and is explicit that this PR does **not** perform that migration: upstream `x-wing` is still a release-candidate stack (`DECISION.md` #6), so the local X-Wing transcription remains the implementation until a stable, audited release meets the existing migration gate. Building the seam now and gating the migration on upstream stabilizing is the honest scope here, per the task brief. - New `tests/profile_api.rs`: a normal-consumer round-trip (`generate_recipient_keypair` → `seal_for` → `unseal`) compiled with `preview-pq` alone, `hazmat` off — the proof that narrowing the API did not also narrow what a normal consumer can *do*. - A `compile_fail` doctest on `HybridKem`'s non-hazmat declaration proves the hiding: it fails to compile under `--features preview-pq` (pre-fix behaviour: `HybridKem::generate()` was reachable and this snippet would have compiled) and is entirely absent — so never even attempted — under `--features preview-pq,hazmat`, since that cfg arm doesn't exist there. - CI (`ci.yml`) and the local gate (`.kanon-ci.toml`) both gain a `preview-pq,hazmat` check/clippy/test lane so `tests/known_answer_vectors.rs` keeps compiling and running unmodified (see below) instead of silently going unbuilt. ## Sequencing (sphragis#17, sphragis#18) Per the task brief, this rebases onto current `origin/main` and stays off files those two sibling lanes are actively editing: - **`src/lib.rs` / `src/envelope.rs`**: zero overlap — neither #17 nor #18 touches these files. - **`src/hybrid.rs`**: #17 (unmerged, no PR yet) touches two disjoint regions — the `EncapsulationKey` doc comment and `encapsulate_deterministic`'s signature/body, appending an inline KAT test at EOF. This PR's edits (`SharedSecret`'s doc, `HybridKem`, `HybridKem::generate`, `EncapsulationKey::encapsulate`, `DecapsulationKey::decapsulate`) sit outside those hunks. **Deferred**: `encapsulate_deterministic`'s own visibility is left exactly as on `main` (`#[doc(hidden)] pub fn`) — #17 is already privatizing it directly; touching the same lines here would be fighting for the same file for no benefit, since #17 lands a strictly tighter result (fully private, not hazmat-gated). - **`tests/known_answer_vectors.rs`**: #17 removes/relocates one test there; #18 (PR #27, mid-rebase) rewrites ~270 lines of it (ACVP vectors, provenance-lock helpers). This PR does not touch that file at all — instead, `Cargo.toml` gains a `[[test]] required-features = ["preview-pq", "hazmat"]` entry for it, so it silently skips under `--features preview-pq` (no hazmat) instead of failing to compile, and keeps compiling/running byte-for-byte unmodified under `--features preview-pq,hazmat` — its existing calls to `HybridKem::generate()`, `.encapsulate()`, `.decapsulate()`, `derive_wrap_key()` all still resolve because those items are genuinely `pub` in that feature combination. - **`DECISION.md`**: #18 edits section 7 (lines ~185-199, inside its own hunk). This PR's new section 9 is appended after section 8, at the file's end — disjoint from that hunk. - **`Cargo.toml`**: #18 appends two `[dev-dependencies]` (`serde_json`, `hex`) after `proptest = "1"`. This PR's `hazmat` feature line sits in the `[features]` block near the top, and the new `[[test]]` block sits right before `[lints.rust]` — both disjoint from #18's dev-dependency hunk. - **`README.md`**: #18 inserts a paragraph after the "Testing" code block (~line 56+). This PR edits the earlier "Usage" example and the "Features" list (~lines 31-51) — disjoint. - **Deferred, not touched**: `AGENTS.md`, `llms.txt` — both list `tests/` contents in a region #18 is actively rewriting for its own new files (`provenance_lock.rs`, `vectors/`, `crypto-provenance.toml`). Left for a follow-up doc-sync pass once #17/#18/#23 have all landed, rather than risk a three-way collision on the same lines. ## Deliberate scope limit: `SharedSecret`'s alias name `SharedSecret`'s type-alias visibility stays exactly as it is today (public, reachable at `sphragis::hybrid::SharedSecret`) rather than being hazmat-gated like `HybridKem`/`derive_wrap_key`/direct encaps-decaps. Reason: `EncapsulationKey::encapsulate_deterministic` (pre-existing, `#[doc(hidden)]`, unrelated to this issue and explicitly left untouched per the sequencing above) returns `SharedSecret` **unconditionally** — narrowing the alias's own visibility would leak a private type through that method's still-fully-public signature (`private_interfaces`, denied under `-D warnings` in CI), without ever touching the method causing it. This is inert: no operation reachable without `hazmat` (`HybridKem::generate`, direct `encapsulate`/`decapsulate`, `derive_wrap_key`) can produce a real X-Wing-derived value of it, and `Zeroizing<[u8; 32]>` — the concrete type this aliases — carries no capability a consumer couldn't already construct directly from the public `zeroize` crate. Documented inline in `src/hybrid.rs` at the declaration site. ## Blast radius Verified zero: akroasis pins `sphragis` via `tag = "v0.1.1"` in `[workspace.dependencies]`, but no member crate depends on it (`grep -rln sphragis --include Cargo.toml` finds only the root pin) and no `.rs` file references it. ## Test plan - [x] `cargo fmt --all -- --check` — clean. - [ ] CI: `cargo check`/`clippy`/`test` × {default, preview-pq, preview-pq+hazmat} — this box's local `vgate` admission is under heavy contention from concurrent sessions and did not complete a full local pass before push; per this repo's build-reality guidance, CI is the reliable verifier here and a prior agent on this exact repo correctly withheld a PR rather than ship unverified crypto without it — this PR relies on the GitHub Actions run rather than a claimed-clean local build. - [x] New `tests/profile_api.rs` proves the narrowed API is still fully usable end-to-end without `hazmat`. - [x] New `compile_fail` doctest proves `HybridKem` is unreachable without `hazmat` (fails pre-fix behaviour, passes post-fix). Closes #23 --------- Co-authored-by: forkwright <cody@forkwright.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces the inline gate-attestation (no release-please waiver — every release PR failed with "No Gate-Passed trailer found") with a thin caller of the canonical reusable, pinned past the branch-shaped RP waiver (forkwright/.github#10). Note: the check context becomes
gate / gate-attestation; branch protection (where present) is updated in lockstep.