Repository navigation
feat(stack-kms): ZeroKMS as a vitaminc key provider (CIP-3965) - #1084
Draft
freshtonic wants to merge 7 commits into
Draft
freshtonic wants to merge 7 commits into
freshtonic wants to merge 7 commits into
Conversation
|
Contributor
Contributor
Mutation testing (cargo-mutants,
|
`ZeroKmsKeyset` resolves one keyset over a shared `Arc<StackKms>` and implements vitaminc-kms's `KeyProvider` and `IndexKeyProvider`, so a client library can be generic over those traits and run on ZeroKMS or on a vendor data key source without knowing which. The keyset is resolved once, at construction, and every call carries it. That is not a restriction the traits impose: ZeroKMS itself carries the keyset id once per *request*, and the server resolves it to a single authority key for the whole batch. Binding at construction is what the wire protocol already does. At the trait level ZeroKMS is `ClientAndServer` reconstruction, `PerValue` isolation, and `Bound` — the binding is the descriptor, which ZeroKMS binds into the key server-side and logs on every retrieval. The `KeyId` is the IV followed by the tag. Nothing is removed. `DataKeySource` and `IndexKeySource` stay exactly as they are, so this adds a second shape beside the first rather than switching anything over; consumers move in a later change. The test fixtures move out of `client.rs`'s test module into `test_connection.rs` so both it and `provider.rs` can drive the same stub. `vitaminc-kms` is pinned to a git rev because these traits are not published yet, with `default-features = false` to keep every vendor SDK out of this crate's graph.
`ZeroKmsKeyset` added two error variants — a binding that is not UTF-8 and a key id too short to hold an IV — and `stack_kms::Error` is not `#[non_exhaustive]`, so the guest's exhaustive match stopped compiling. Both are the provider refusing its own input before any request is sent, never a ZeroKMS verdict, so both are `STATUS_ENCODING`: something the host can fix, rather than something it can only log. The test pins the classification rather than the compile. A variant added upstream already fails the build; one reclassified here would not, and the difference between "fix your input" and "log this" is what the status word is for.
`split_key_id` refuses a key id shorter than the IV, and a test covers `IV_LEN - 1`. Nothing covered `IV_LEN` itself, so tightening the guard to `<=` — rejecting a key id the format permits — passed the whole suite. A key id of exactly the IV length splits into that IV and an empty tag, which is a shape the split accepts. The test asserts the request ZeroKMS receives carries the whole id as the IV and an empty tag. Found by running the mutation gate locally over `stack-kms`, which the CI gate does not cover — its crate list is stack-auth and stack-encrypt.
… onto vitaminc 0.5.1 cipherstash/vitaminc#352 is now on vitaminc main, which carries the 0.5.1 release that the workspace takes from crates.io. Pin b3bc6eb, the tip of claude/cip-3965-key-provider. The suite PR pinned c6009a2 and then 9cb1965; neither is on the branch now. Every lockfile that builds stack-kms by path moves with it: the root, the stackencrypt Go guest, the stack-kms and stack-encrypt fuzz crates and packages/eql. Only the seven git-sourced vitaminc packages are added.
…rning stack-kms now pins vitaminc-kms to a git rev, because vitaminc has not released the key-provider traits yet (cipherstash/vitaminc#352). cargo refuses to package a crate with a git dependency, so the dry run failed on stack-kms although nothing in this PR publishes it. A `version` beside the `git` would not help: the packaged crate would then build against vitaminc-kms 0.5.1 from crates.io, which does not have the traits. The step now finds the crates in its list that have a non-dev git dependency, skips each with a warning, and verifies the rest. This is the same shape test-eql.yml uses for a stack-encrypt not yet on crates.io. When vitaminc releases and the pin becomes a version, the skip stops applying by itself.
stack-kms had no CHANGELOG.md. It is published from 0.1.0 in its own version group, so it gets one in the format stack-encrypt's uses, with the entries for this change under Unreleased.
Move the vitaminc-kms and vitaminc-protected git pins from b3bc6eb to 5b8a9c7, the head of the vitaminc PR stack ending at claude/cip-5029-aws-request-shape-tests. That stack removes KeyProvider::ISOLATION and ::BINDING, because every source now mints one key per value and binds it. It adds KeyProvider::CUSTODY. ZeroKmsKeyset declares BackendHeld: its key id names a key that ZeroKMS rebuilds, not a wrapped copy of the key. Main added a diagnostic code to every stack-kms error variant and an ErrorPayload impl. Give BindingNotUtf8 and MalformedKeyId their codes, payload arms and rows in the every-variant test.
freshtonic
force-pushed
the
claude/cip-3965-key-provider
branch
from
October 21, 2026 10:52
c5bcba9 to
e4df2d6
Compare
freshtonic
marked this pull request as draft
October 21, 2026 11:02
tobyhede
approved these changes
Oct 22, 2026
This branch has not been deployed
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.
Summary
This ports cipherstash/cipherstash-suite#2247 (https://github.com/cipherstash/cipherstash-suite/pull/2247) to this repository. The stack-* crates moved here in #1001 and #1003, so the suite PR cannot merge there.
It adds one thing to
stack-kmsand removes nothing.ZeroKmsKeysetresolves one keyset over a sharedArc<StackKms>and implements thevitaminc-kmstraitsKeyProvider<32>andIndexKeyProvider<32>. A client library can then be generic over those traits, and run on ZeroKMS or on another data key source without knowing which.At the trait level, ZeroKMS is
RECONSTRUCTION = ClientAndServerandCUSTODY = BackendHeld: the key id names a key that ZeroKMS rebuilds, not a wrapped copy of the key. Each value gets its own key. The binding is the descriptor, which ZeroKMS binds into the data key on the server and logs on every retrieval. TheKeyIdis the IV followed by the tag.DataKeySource,IndexKeySourceandFakeDataKeySourcedo not change. The next PR (the port of cipherstash-suite#2257) movesstack-encryptonto the new shape.Why the keyset is bound at construction
The vitaminc traits do not force this. ZeroKMS carries
keyset_idonce per request, not once per payload, and the server resolves it to one authority key for the whole batch. So a provider bound at construction models the wire protocol. See cipherstash/vitaminc ADR 0004.What changed in the port
git format-patchandgit am -3, with the original author. The source applied with no conflicts. Paths moved frombindings/go/...tolanguages/golang/....Cargo.lockchanges were left out. Each lockfile that buildsstack-kmsby path was updated withcargo update -w: the root, the stackencrypt Go guest, the stack-kms and stack-encrypt fuzz crates, andpackages/eql. Only the seven git-sourced vitaminc packages are added.c6009a2, then9cb1965. feat(kms): key-provider traits Stack Encrypt is generic over (CIP-3965) vitaminc#352 is now rebased onto vitaminc main, which holds the 0.5.1 release that this workspace takes from crates.io. Both pins (vitaminc-kmsand itsvitaminc-protected) were thenb3bc6eb, the tip ofclaude/cip-3965-key-provider. The suite's own repin commit (9b9e4a889) was dropped in favour of this one.5b8a9c7, the tip ofclaude/cip-5029-aws-request-shape-tests(vitaminc 0.8.0 in git). That stack removesKeyProvider::ISOLATIONand::BINDING, because every source now mints one key per value and binds it, and addsKeyProvider::CUSTODY.ZeroKmsKeysetdeclaresBackendHeld. The branch is also rebased onto main, which gave every stack-kms error variant a diagnostic code and anErrorPayloadimpl.BindingNotUtf8andMalformedKeyIdnow have codes (stack_kms::binding_not_utf8,stack_kms::malformed_key_id) and empty payloads.stack-kmsis published from this repository, andtests-crates.ymldry-runscargo publishfor it. cargo will not package a crate that has a git dependency, and aversionbeside thegitwould make the packaged crate build against vitaminc-kms 0.5.1 from crates.io, which does not have the traits. The step now skips such a crate with a warning and still verifies the others, astest-eql.ymldoes for a stack-encrypt version that is not on crates.io yet. When vitaminc releases and the pin becomes a version, the skip stops by itself.stack-kmshad noCHANGELOG.md. It now has one, in the stack-encrypt format, with this change under Unreleased.Before this can ship
stack-kmscannot be published while it pins vitaminc-kms to a git rev. The pin becomes a version once cipherstash/vitaminc#352 is released.Test plan
Run locally on Rust 1.94.1 (mise):
cargo fmt --all --check,cargo clippy --locked --workspace --all-targets --all-features -D warningscargo nextest run --locked --workspace --all-features. The trybuilduibinary fails only with the localkacherustc wrapper on; with the wrapper off it passes, unchanged.mise run test:doc,mise run doc,cargo build -p stack-encrypt --examplesmise run wasm:wasi-check,wasm:no-http-test,wasm:guest:test,wasm:guest:build,wasm:auth-guest:buildmise run go:test,scripts/go-binding-test.sh languages/golangclient-key,sealed-value,term-decode,check-record,plan-build(-runs=0)🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation