Bump sdk-internal Rust crate dependencies
Overview
util/RustSdk/rust/Cargo.toml pins bitwarden-crypto from bitwarden/sdk-internal by git rev; bump
it periodically to track a bitwarden/clients release. RustSdk is Seeder test infrastructure
(util/, not src/ production): it gives the C# Seeder field-level encryption
(encrypt_string/decrypt_string/encrypt_fields) to produce cryptographically correct Protected
Data for integration tests. EncryptPropertyAttribute drives which fields get encrypted.
NPM → git-rev mapping
Clients consume sdk-internal as npm (@bitwarden/sdk-internal, e.g. 0.2.0-main.841); the server
pins a git rev. The .NNN suffix is an opaque counter from a private Azure publish task — not a
GitHub Actions run_number, and it does not track main commits 1:1. Do not infer the SHA from a run
number or timestamp; both pick the wrong commit (verified: 841→c5d5bba, 842→c9f9dba, 840→1e45444
— no time correlation). Read the commit the build bakes into the published WASM instead:
# <VERSION> is the npm version from the clients release tag (Step 1), e.g. 0.2.0-main.841
cd "$(mktemp -d)"
curl -sSL "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-<VERSION>.tgz" -o pkg.tgz
tar xzf pkg.tgz
grep -ao "main ([0-9a-f]\{7\})" package/bitwarden_wasm_internal_bg.wasm | sort -u # -> main (c5d5bba)
cd /path/to/sdk-internal && git rev-parse c5d5bba # -> full rev to pin in Cargo.toml
That full SHA is the exact source the production client runs. @bitwarden/commercial-sdk-internal
ships the same commit, so the open-source tarball's embedded SHA is authoritative for both.
Process
- Identify target — latest
web-v* release tag from clients, then its npm version:gh release list --repo bitwarden/clients --limit 5 | grep web-v
git -C /path/to/clients show <tag>:package.json | grep sdk-internal # -> 0.2.0-main.841
- Map npm → git SHA — the mapping section above.
- Analyze breaking changes — cross-ref each commit against
references/api-surface.md; watch for
type renames, removed/deprecated functions, changed signatures, and trait changes:cd /path/to/sdk-internal
git log --oneline <old-rev>..<new-rev> -- crates/bitwarden-crypto
git diff <old-rev>..<new-rev> -- crates/bitwarden-crypto/src/keys/mod.rs crates/bitwarden-crypto/src/lib.rs
- Apply —
- Update the
bitwarden-crypto rev in Cargo.toml.
- MSRV check: compare the target's workspace
rust-version against util/RustSdk/rust-toolchain.toml;
if the MSRV rose above our channel, bump the channel to the MSRV (not sdk-internal's dev
toolchain), else the build fails "requires rustc X or newer".
cargo update -p bitwarden-crypto (targeted — re-resolves only what the new rev needs; a bare
cargo update churns the lockfile).
- Fix compile errors; add
#[allow(deprecated)] + a why-comment for newly-deprecated APIs.
- Build & verify (Claude) —
cd util/RustSdk/rust
cargo build && cargo test # roundtrip test is the gate: encrypt_string_decrypt_string_roundtrip
cargo fmt --check
git diff ../NativeMethods.g.cs # must be unchanged
dotnet test test/SeederApi.IntegrationTest/
Review the Cargo.lock diff for unexpected transitive crypto crates (rsa, aes, sha2).
- Human verification (human only — present these, do not run them) — the human seeds and confirms
Protected Data is decryptable in the web client:
cd util/SeederUtility
dotnet run -- organization -n SdkBumpTest -d sdk-bump-test.example -u 3 -c 10 -g 5 -o Traditional -m
# or a preset: dotnet run -- seed --preset dunder-mifflin-enterprise-full --mangle
# SeederApi HTTP alternative — start `dotnet run` in util/SeederApi, then:
curl -X POST localhost:5000/seed -H 'X-Play-Id: sdk-bump-test' -H 'Content-Type: application/json' \
-d '{"template":"SingleUserScene","arguments":{"email":"test@example.com","password":"<8+ char pwd>"}}'
curl -X DELETE localhost:5000/seed/sdk-bump-test # cleanup
Pass = seeded users log in with the fake master password (see util/SeederUtility/README.md),
ciphers are decryptable in the web vault, no Seeder errors, and cleanup deletes all tracked entities.
Security notes
- RustSdk is
util/ test infrastructure, not src/ production; the server never decrypts Vault Data,
so the zero-knowledge invariant is unaffected.
- Matching the production client release makes the Seeder produce Protected Data with the same
cryptographic primitives real clients use.
Keeping api-surface.md current
references/api-surface.md must mirror the actual code. After a bump, regenerate it: read every .rs
in util/RustSdk/rust/src/, extract the bitwarden_crypto use statements, and rewrite the file.
A Stop hook (.claude/hooks/rust-sdk-surface-check.sh) blocks if Cargo.toml changed but
api-surface.md did not.
Files typically modified
| File |
Change |
util/RustSdk/rust/Cargo.toml |
bitwarden-crypto rev pin |
util/RustSdk/rust-toolchain.toml |
bump channel only if the MSRV rose |
util/RustSdk/rust/src/*.rs |
breaking-change fixes |
util/RustSdk/rust/Cargo.lock |
re-resolved (cargo update -p bitwarden-crypto) |
util/RustSdk/NativeMethods.g.cs |
should NOT change — verify |
References
references/api-surface.md — types, traits, and functions imported from bitwarden-crypto.
references/examples/2026-06-bump.md — the June 2026 bump, worked end-to-end.
1---2name: bump-rust-sdk3description: Bump the server's util/RustSdk `bitwarden-crypto` git-rev pin to a bitwarden/clients release — map the client's sdk-internal version to a commit, fix breaking changes, then verify.4---56# Bump sdk-internal Rust crate dependencies78## Overview910`util/RustSdk/rust/Cargo.toml` pins `bitwarden-crypto` from `bitwarden/sdk-internal` by git rev; bump11it periodically to track a `bitwarden/clients` release. RustSdk is Seeder **test** infrastructure12(`util/`, not `src/` production): it gives the C# Seeder field-level encryption13(`encrypt_string`/`decrypt_string`/`encrypt_fields`) to produce cryptographically correct Protected14Data for integration tests. `EncryptPropertyAttribute` drives which fields get encrypted.1516## NPM → git-rev mapping1718Clients consume sdk-internal as npm (`@bitwarden/sdk-internal`, e.g. `0.2.0-main.841`); the server19pins a git rev. The `.NNN` suffix is an opaque counter from a private Azure publish task — **not** a20GitHub Actions `run_number`, and it does not track `main` commits 1:1. Do not infer the SHA from a run21number or timestamp; both pick the wrong commit (verified: `841→c5d5bba`, `842→c9f9dba`, `840→1e45444`22— no time correlation). Read the commit the build bakes into the published WASM instead:2324```bash25# <VERSION> is the npm version from the clients release tag (Step 1), e.g. 0.2.0-main.84126cd "$(mktemp -d)"27curl -sSL "https://registry.npmjs.org/@bitwarden/sdk-internal/-/sdk-internal-<VERSION>.tgz" -o pkg.tgz28tar xzf pkg.tgz29grep -ao "main ([0-9a-f]\{7\})" package/bitwarden_wasm_internal_bg.wasm | sort -u # -> main (c5d5bba)30cd /path/to/sdk-internal && git rev-parse c5d5bba # -> full rev to pin in Cargo.toml31```3233That full SHA is the exact source the production client runs. `@bitwarden/commercial-sdk-internal`34ships the same commit, so the open-source tarball's embedded SHA is authoritative for both.3536## Process37381. **Identify target** — latest `web-v*` release tag from clients, then its npm version:39 ```bash40 gh release list --repo bitwarden/clients --limit 5 | grep web-v41 git -C /path/to/clients show <tag>:package.json | grep sdk-internal # -> 0.2.0-main.84142 ```432. **Map npm → git SHA** — the mapping section above.443. **Analyze breaking changes** — cross-ref each commit against `references/api-surface.md`; watch for45 type renames, removed/deprecated functions, changed signatures, and trait changes:46 ```bash47 cd /path/to/sdk-internal48 git log --oneline <old-rev>..<new-rev> -- crates/bitwarden-crypto49 git diff <old-rev>..<new-rev> -- crates/bitwarden-crypto/src/keys/mod.rs crates/bitwarden-crypto/src/lib.rs50 ```514. **Apply** —52 - Update the `bitwarden-crypto` `rev` in `Cargo.toml`.53 - **MSRV check:** compare the target's workspace `rust-version` against `util/RustSdk/rust-toolchain.toml`;54 if the MSRV rose above our channel, bump the channel to the **MSRV** (not sdk-internal's dev55 toolchain), else the build fails "requires rustc X or newer".56 - `cargo update -p bitwarden-crypto` (targeted — re-resolves only what the new rev needs; a bare57 `cargo update` churns the lockfile).58 - Fix compile errors; add `#[allow(deprecated)]` + a why-comment for newly-deprecated APIs.595. **Build & verify (Claude)** —60 ```bash61 cd util/RustSdk/rust62 cargo build && cargo test # roundtrip test is the gate: encrypt_string_decrypt_string_roundtrip63 cargo fmt --check64 git diff ../NativeMethods.g.cs # must be unchanged65 dotnet test test/SeederApi.IntegrationTest/66 ```67 Review the `Cargo.lock` diff for unexpected transitive crypto crates (`rsa`, `aes`, `sha2`).686. **Human verification (human only — present these, do not run them)** — the human seeds and confirms69 Protected Data is decryptable in the web client:70 ```bash71 cd util/SeederUtility72 dotnet run -- organization -n SdkBumpTest -d sdk-bump-test.example -u 3 -c 10 -g 5 -o Traditional -m73 # or a preset: dotnet run -- seed --preset dunder-mifflin-enterprise-full --mangle7475 # SeederApi HTTP alternative — start `dotnet run` in util/SeederApi, then:76 curl -X POST localhost:5000/seed -H 'X-Play-Id: sdk-bump-test' -H 'Content-Type: application/json' \77 -d '{"template":"SingleUserScene","arguments":{"email":"test@example.com","password":"<8+ char pwd>"}}'78 curl -X DELETE localhost:5000/seed/sdk-bump-test # cleanup79 ```80 Pass = seeded users log in with the fake master password (see `util/SeederUtility/README.md`),81 ciphers are decryptable in the web vault, no Seeder errors, and cleanup deletes all tracked entities.8283## Security notes8485- RustSdk is `util/` test infrastructure, not `src/` production; the server never decrypts Vault Data,86 so the zero-knowledge invariant is unaffected.87- Matching the production client release makes the Seeder produce Protected Data with the same88 cryptographic primitives real clients use.8990## Keeping api-surface.md current9192`references/api-surface.md` must mirror the actual code. After a bump, regenerate it: read every `.rs`93in `util/RustSdk/rust/src/`, extract the `bitwarden_crypto` `use` statements, and rewrite the file.94A Stop hook (`.claude/hooks/rust-sdk-surface-check.sh`) blocks if `Cargo.toml` changed but95`api-surface.md` did not.9697## Files typically modified9899| File | Change |100| --- | --- |101| `util/RustSdk/rust/Cargo.toml` | `bitwarden-crypto` rev pin |102| `util/RustSdk/rust-toolchain.toml` | bump `channel` only if the MSRV rose |103| `util/RustSdk/rust/src/*.rs` | breaking-change fixes |104| `util/RustSdk/rust/Cargo.lock` | re-resolved (`cargo update -p bitwarden-crypto`) |105| `util/RustSdk/NativeMethods.g.cs` | should NOT change — verify |106107## References108109- `references/api-surface.md` — types, traits, and functions imported from `bitwarden-crypto`.110- `references/examples/2026-06-bump.md` — the June 2026 bump, worked end-to-end.