Skip to content

Commit 3048893

Browse files
authored
Merge branch 'main' into PM-33500
2 parents fe0f808 + 753c8c8 commit 3048893

124 files changed

Lines changed: 5455 additions & 3526 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/bump-rust-sdk/SKILL.md

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ description: This skill should be used when the user asks to "bump the Rust SDK"
77

88
## Overview
99

10-
The server's `util/RustSdk/rust/Cargo.toml` pins three crates from the `bitwarden/sdk-internal`
11-
repository by git rev: `bitwarden-core`, `bitwarden-crypto`, and `bitwarden-vault`. These must
12-
be periodically bumped to stay aligned with the Bitwarden client applications.
10+
The server's `util/RustSdk/rust/Cargo.toml` pins `bitwarden-crypto` from the
11+
`bitwarden/sdk-internal` repository by git rev. This must be periodically bumped to stay
12+
aligned with the Bitwarden client applications.
1313

1414
The RustSdk is used by the Seeder to produce cryptographically correct Protected Data for
15-
integration testing. It is NOT part of the production server runtime.
15+
integration testing. It is NOT part of the production server runtime. The Rust layer provides
16+
generic field-level encryption (`encrypt_string`, `decrypt_string`, `encrypt_fields`) and
17+
key generation — the C# Seeder drives which fields to encrypt via `EncryptPropertyAttribute`.
1618

1719
## Key Challenge: NPM-to-Git-Rev Mapping
1820

@@ -60,19 +62,19 @@ Query the GitHub Actions API to find the commit that produced that NPM build. Se
6062

6163
### Step 3: Analyze Breaking Changes
6264

63-
Compare the current pinned rev against the target rev, focusing on the three crates:
65+
Compare the current pinned rev against the target rev, focusing on `bitwarden-crypto`:
6466

6567
```bash
6668
cd /path/to/sdk-internal
67-
git log --oneline <old-rev>..<new-rev> -- crates/bitwarden-core crates/bitwarden-crypto crates/bitwarden-vault
69+
git log --oneline <old-rev>..<new-rev> -- crates/bitwarden-crypto
6870
```
6971

7072
Cross-reference each commit against the API surface documented in `references/api-surface.md`.
7173

7274
### Step 4: Apply Changes
7375

74-
1. Update `Cargo.toml` — bump all three rev pins to the same SHA
75-
2. Fix any compilation errors from breaking changes (type renames, new struct fields, etc.)
76+
1. Update `Cargo.toml` — bump the `bitwarden-crypto` rev pin to the new SHA
77+
2. Fix any compilation errors from breaking changes (type renames, new parameters, etc.)
7678
3. Add `#[allow(deprecated)]` for any newly-deprecated APIs (with a comment explaining why)
7779

7880
### Step 5: Build and Verify (Claude)
@@ -119,7 +121,7 @@ Two mechanisms enforce this:
119121
modified but `api-surface.md` was not updated in the same session.
120122

121123
To regenerate: read all `.rs` files in `util/RustSdk/rust/src/`, extract every `use` statement
122-
from the three bitwarden crates, and rewrite `references/api-surface.md` to match.
124+
from `bitwarden_crypto`, and rewrite `references/api-surface.md` to match.
123125

124126
## Additional Resources
125127

@@ -129,13 +131,13 @@ from the three bitwarden crates, and rewrite `references/api-surface.md` to matc
129131
queries, breaking change analysis checklist, human verification commands, and a worked example
130132
from the Feb 2026 bump
131133
- **`references/api-surface.md`** — Complete inventory of types, traits, and functions the RustSdk
132-
imports from each crate, used to assess breaking change impact
134+
imports from `bitwarden-crypto`, used to assess breaking change impact
133135

134136
## Files Modified in a Typical Bump
135137

136-
| File | Change |
137-
| --------------------------------- | -------------------------------------------------- |
138-
| `util/RustSdk/rust/Cargo.toml` | Rev pin update |
139-
| `util/RustSdk/rust/src/*.rs` | Type renames, new struct fields, deprecation fixes |
140-
| `util/RustSdk/rust/Cargo.lock` | Auto-regenerated (commit alongside) |
141-
| `util/RustSdk/NativeMethods.g.cs` | Should NOT change (verify) |
138+
| File | Change |
139+
| --------------------------------- | ----------------------------------------------- |
140+
| `util/RustSdk/rust/Cargo.toml` | `bitwarden-crypto` rev pin update |
141+
| `util/RustSdk/rust/src/*.rs` | Type renames, new parameters, deprecation fixes |
142+
| `util/RustSdk/rust/Cargo.lock` | Auto-regenerated (commit alongside) |
143+
| `util/RustSdk/NativeMethods.g.cs` | Should NOT change (verify) |

.claude/skills/bump-rust-sdk/references/api-surface.md

Lines changed: 43 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -3,72 +3,58 @@
33
> **Auto-generated from actual source files.** Last updated: 2026-02-25
44
> Pinned rev: `abba7fdab687753268b63248ec22639dff35d07c`
55
6-
This documents every type, trait, and function the server's RustSdk imports from the three
7-
sdk-internal crates. Use this to assess breaking change impact when bumping revs.
6+
This documents every type, trait, and function the server's RustSdk imports from
7+
`bitwarden-crypto`. Use this to assess breaking change impact when bumping revs.
88

99
**Location:** `util/RustSdk/rust/src/`
1010

11-
## bitwarden-crypto (primary dependency)
12-
13-
### Types Used
14-
15-
| Type | File | Usage |
16-
| ------------------------- | ----------------- | -------------------------------------------------------------------------------------------- |
17-
| `BitwardenLegacyKeyBytes` | lib.rs, cipher.rs | `BitwardenLegacyKeyBytes::from()` — wraps raw key bytes for `SymmetricCryptoKey::try_from()` |
18-
| `HashPurpose` | lib.rs | `HashPurpose::ServerAuthorization` enum variant |
19-
| `Kdf` | lib.rs | `Kdf::PBKDF2 { iterations }` enum variant with `NonZeroU32` |
20-
| `KeyStore` | cipher.rs | `KeyStore::<KeyIds>::default()`, `.context_mut()`, `.add_local_symmetric_key()` |
21-
| `MasterKey` | lib.rs | `MasterKey::derive()`, `.derive_master_key_hash()`, `.make_user_key()` |
22-
| `PrivateKey` | lib.rs | `PrivateKey::from_pem()`, `.to_public_key()`, `.to_der()` |
23-
| `PublicKey` | lib.rs | `PublicKey::from_der()` |
24-
| `RsaKeyPair` | lib.rs | Struct literal: `RsaKeyPair { private, public }` |
25-
| `SpkiPublicKeyBytes` | lib.rs | `SpkiPublicKeyBytes::from()` — wraps public key DER bytes |
26-
| `SymmetricCryptoKey` | lib.rs, cipher.rs | `.make_aes256_cbc_hmac_key()`, `::try_from()`, `.to_base64()` |
27-
| `UnsignedSharedKey` | lib.rs | `::encapsulate_key_unsigned()` (deprecated — wrapped with `#[allow(deprecated)]`) |
28-
| `UserKey` | lib.rs | `UserKey::new()`, `.make_key_pair()`, `.0` field access |
11+
## bitwarden-crypto
2912

30-
### Traits Used
31-
32-
| Trait | File | Methods Called |
33-
| ---------------------- | ----------------- | -------------------------------------------------------------------------- |
34-
| `KeyEncryptable` | lib.rs, cipher.rs | `.encrypt_with_key(&key)` — encrypts DER bytes and strings |
35-
| `CompositeEncryptable` | cipher.rs | `.encrypt_composite(&mut ctx, key_id)` — encrypts `CipherView` -> `Cipher` |
36-
| `Decryptable` | cipher.rs | `.decrypt(&mut ctx, key_id)` — decrypts `Cipher` -> `CipherView` |
37-
38-
## bitwarden-core (minimal dependency)
39-
40-
| Type | File | Usage |
41-
| ------------------------ | --------- | -------------------------------------------- |
42-
| `key_management::KeyIds` | cipher.rs | Generic type parameter: `KeyStore::<KeyIds>` |
43-
44-
## bitwarden-vault (data model dependency)
13+
### Types Used — lib.rs (key generation and management)
4514

46-
### Production Code
15+
| Type | Usage |
16+
| ------------------------- | -------------------------------------------------------------------------------------------- |
17+
| `BitwardenLegacyKeyBytes` | `BitwardenLegacyKeyBytes::from()` — wraps raw key bytes for `SymmetricCryptoKey::try_from()` |
18+
| `HashPurpose` | `HashPurpose::ServerAuthorization` enum variant |
19+
| `Kdf` | `Kdf::PBKDF2 { iterations }` enum variant with `NonZeroU32` |
20+
| `MasterKey` | `MasterKey::derive()`, `.derive_master_key_hash()`, `.make_user_key()` |
21+
| `PrivateKey` | `PrivateKey::from_pem()`, `.to_public_key()`, `.to_der()` |
22+
| `PublicKey` | `PublicKey::from_der()` |
23+
| `RsaKeyPair` | Struct literal: `RsaKeyPair { private, public }` |
24+
| `SpkiPublicKeyBytes` | `SpkiPublicKeyBytes::from()` — wraps public key DER bytes |
25+
| `SymmetricCryptoKey` | `.make_aes256_cbc_hmac_key()`, `::try_from()`, `.to_base64()` |
26+
| `UnsignedSharedKey` | `::encapsulate_key_unsigned()` (deprecated — wrapped with `#[allow(deprecated)]`) |
27+
| `UserKey` | `UserKey::new()`, `.make_key_pair()`, `.0` field access |
4728

48-
| Type | File | Usage |
49-
| ------------ | --------- | ----------------------------------------------------- |
50-
| `Cipher` | cipher.rs | Protected Data container (encrypted), deserialized from JSON via serde |
51-
| `CipherView` | cipher.rs | Vault Data in Use (decrypted view), serialized to/from JSON via serde |
29+
### Types Used — cipher.rs (field-level encryption)
5230

53-
### Test-Only Types
31+
| Type | Usage |
32+
| ------------------------- | ----------------------------------------------------------------------------------------------- |
33+
| `BitwardenLegacyKeyBytes` | `BitwardenLegacyKeyBytes::from()` — wraps raw key bytes for `SymmetricCryptoKey::try_from()` |
34+
| `EncString` | `enc_str.parse::<EncString>()`, `.to_string()` — parsed from and serialized to EncString format |
35+
| `SymmetricCryptoKey` | `::try_from()`, `.make_aes256_cbc_hmac_key()`, `.to_base64()` — key construction and testing |
5436

55-
| Type | File | Usage |
56-
| -------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
57-
| `CipherRepromptType` | cipher.rs tests | `CipherRepromptType::None` enum variant |
58-
| `CipherType` | cipher.rs tests | `CipherType::Login` enum variant |
59-
| `LoginView` | cipher.rs tests | Struct literal with fields: `username`, `password`, `password_revision_date`, `uris`, `totp`, `autofill_on_page_load`, `fido2_credentials` |
37+
### Traits Used
6038

61-
### CipherView Fields (used in test struct literal)
39+
| Trait | File | Methods Called |
40+
| ---------------- | --------- | -------------------------------------------------------------------- |
41+
| `KeyEncryptable` | lib.rs | `.encrypt_with_key(&key)` — encrypts DER bytes and strings |
42+
| `KeyEncryptable` | cipher.rs | `.encrypt_with_key(&key)` — encrypts plaintext strings to EncStrings |
43+
| `KeyDecryptable` | cipher.rs | `.decrypt_with_key(&key)` — decrypts EncString back to plaintext |
6244

63-
The test helper `create_test_cipher_view()` constructs a `CipherView` with these fields:
45+
## FFI Functions Exposed
6446

65-
`id`, `organization_id`, `folder_id`, `collection_ids`, `key`, `name`, `notes`, `type`,
66-
`login`, `identity`, `card`, `secure_note`, `ssh_key`, `favorite`, `reprompt`,
67-
`organization_use_totp`, `edit`, `permissions`, `view_password`, `local_data`, `attachments`,
68-
`attachment_decryption_failures`, `fields`, `password_history`, `creation_date`, `deleted_date`,
69-
`revision_date`, `archived_date`
47+
The Rust layer exposes these functions to C# via csbindgen:
7048

71-
Any new required field added to `CipherView` upstream will break this struct literal.
49+
| Function | File | Purpose |
50+
| -------------------------------- | --------- | --------------------------------------------------------- |
51+
| `generate_user_keys` | lib.rs | Derive master key, user key, key pair from email/password |
52+
| `generate_organization_keys` | lib.rs | Generate org symmetric key + RSA key pair |
53+
| `generate_user_organization_key` | lib.rs | Encapsulate org key with user's public key (unsigned) |
54+
| `encrypt_string` | cipher.rs | Encrypt a single plaintext string with a symmetric key |
55+
| `decrypt_string` | cipher.rs | Decrypt an EncString with a symmetric key |
56+
| `encrypt_fields` | cipher.rs | Encrypt specified fields in a JSON object by dot-path |
57+
| `free_c_string` | lib.rs | Free a C string returned by any of the above functions |
7258

7359
## Breaking Change Risk Matrix
7460

@@ -77,9 +63,9 @@ When reviewing upstream commits, prioritize checking for changes to:
7763
**Critical (compilation failure):**
7864

7965
- Any type rename or removal listed above
80-
- New required fields on `CipherView`, `Cipher`, or `LoginView`
81-
- Changes to `KeyStore` generic parameters or `context_mut()` method
82-
- Changes to encryption/decryption trait method signatures
66+
- Changes to `EncString` parsing or serialization format
67+
- Changes to `KeyEncryptable` or `KeyDecryptable` trait method signatures
68+
- Changes to `SymmetricCryptoKey::try_from()` or `BitwardenLegacyKeyBytes`
8369

8470
**High (runtime failure):**
8571

@@ -96,21 +82,12 @@ When reviewing upstream commits, prioritize checking for changes to:
9682
**Low (transparent):**
9783

9884
- Internal implementation changes that don't affect the public API
99-
- New optional fields on structs (serde defaults to `None` for `Option<T>`)
10085
- New methods added to existing types (additive, non-breaking)
10186

10287
## How to Check for Changes
10388

104-
For each crate, check the public API exports:
105-
10689
```bash
10790
cd /path/to/sdk-internal
10891
# bitwarden-crypto public API
10992
git diff <old>..<new> -- crates/bitwarden-crypto/src/lib.rs crates/bitwarden-crypto/src/keys/mod.rs
110-
111-
# bitwarden-vault Cipher/CipherView changes
112-
git diff <old>..<new> -- crates/bitwarden-vault/src/cipher/cipher.rs crates/bitwarden-vault/src/cipher/login.rs
113-
114-
# bitwarden-core KeyIds
115-
git diff <old>..<new> -- crates/bitwarden-core/src/key_management/mod.rs
11693
```

.claude/skills/bump-rust-sdk/references/methodology.md

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,6 @@
88
grep 'rev = ' util/RustSdk/rust/Cargo.toml
99
```
1010

11-
All three crates (`bitwarden-core`, `bitwarden-crypto`, `bitwarden-vault`) must always pin to
12-
the **same rev**. If they don't, something is wrong.
13-
1411
### 2. Identify the Target Version from Clients
1512

1613
Determine the latest production release tag from the clients repo:
@@ -62,35 +59,32 @@ This shows when the current pin was made and what commit it corresponds to.
6259

6360
### 5. Analyze Breaking Changes
6461

65-
List all commits touching the three crates between the old and new revs:
62+
List all commits touching `bitwarden-crypto` between the old and new revs:
6663

6764
```bash
6865
cd /path/to/sdk-internal
69-
git log --oneline <old-rev>..<new-rev> -- \
70-
crates/bitwarden-core crates/bitwarden-crypto crates/bitwarden-vault
66+
git log --oneline <old-rev>..<new-rev> -- crates/bitwarden-crypto
7167
```
7268

7369
For each commit, check for:
7470

7571
- **Type renames** (e.g., `AsymmetricCryptoKey` -> `PrivateKey`)
76-
- **New required struct fields** (e.g., new `Option<T>` fields on `CipherView`)
7772
- **Removed or deprecated functions** (look for `#[deprecated]` annotations)
7873
- **Changed function signatures** (parameter types, return types)
7974
- **Trait changes** (new required methods, changed generic bounds)
8075

81-
To check the public API diff for a specific crate:
76+
To check the public API diff:
8277

8378
```bash
8479
git diff <old-rev>..<new-rev> -- crates/bitwarden-crypto/src/keys/mod.rs
8580
git diff <old-rev>..<new-rev> -- crates/bitwarden-crypto/src/lib.rs
86-
git diff <old-rev>..<new-rev> -- crates/bitwarden-vault/src/cipher/cipher.rs
8781
```
8882

8983
Cross-reference findings against `references/api-surface.md` to assess impact.
9084

9185
### 6. Apply Code Changes
9286

93-
1. **Cargo.toml** — Update all three `rev = "..."` to the new SHA
87+
1. **Cargo.toml** — Update the `bitwarden-crypto` `rev = "..."` to the new SHA
9488
2. **Rust source files** — Fix compilation errors from breaking changes
9589
3. **Deprecation warnings** — Add `#[allow(deprecated)]` with a comment explaining why
9690
4. Do NOT make unrelated formatting or style changes
@@ -119,8 +113,8 @@ dotnet test test/SeederApi.IntegrationTest/
119113
cargo fmt --check
120114
```
121115

122-
**Key validation:** The `encrypt_decrypt_roundtrip_preserves_plaintext` test proves the new SDK
123-
version correctly encrypts and decrypts Vault Data. If this passes, the crypto is working.
116+
**Key validation:** The `encrypt_string_decrypt_string_roundtrip` test proves the new SDK
117+
version correctly encrypts and decrypts data. If this passes, the crypto is working.
124118

125119
### 8. Human Verification (HUMAN ONLY — Claude does NOT run these)
126120

@@ -183,13 +177,12 @@ This section documents the actual bump performed in Feb 2026 as a reference.
183177

184178
### Breaking Changes Found
185179

186-
| Change | Impact | Fix |
187-
| --------------------------------------------------------- | ---------------------------------------- | ------------------------------------------ |
188-
| `AsymmetricCryptoKey` renamed to `PrivateKey` | Import + usage in lib.rs | Rename type |
189-
| `AsymmetricPublicCryptoKey` renamed to `PublicKey` | Import + usage in lib.rs | Rename type |
190-
| `CipherView` added `attachment_decryption_failures` field | Test struct literal in cipher.rs | Add `attachment_decryption_failures: None` |
191-
| `PrivateKey::to_der()` returns `Pkcs8PrivateKeyBytes` | Low risk — auto-refs to `KeyEncryptable` | No code change needed |
192-
| `encapsulate_key_unsigned` deprecated | Deprecation warning | `#[allow(deprecated)]` + comment |
180+
| Change | Impact | Fix |
181+
| ----------------------------------------------------- | -------------------------------- | ---------------------------------------- |
182+
| `AsymmetricCryptoKey` renamed to `PrivateKey` | Import + usage in lib.rs | Rename type |
183+
| `AsymmetricPublicCryptoKey` renamed to `PublicKey` | Import + usage in lib.rs | Rename type |
184+
| `PrivateKey::to_der()` returns `Pkcs8PrivateKeyBytes` | Low risk — auto-refs | No code change needed |
185+
| `encapsulate_key_unsigned` deprecated | Deprecation warning | `#[allow(deprecated)]` + comment |
193186

194187
### Cargo.lock Review
195188

@@ -200,7 +193,7 @@ This section documents the actual bump performed in Feb 2026 as a reference.
200193

201194
### Results
202195

203-
- 7/7 Rust unit tests passed
204-
- 65/65 C# integration tests passed
196+
- All Rust unit tests passed
197+
- All C# integration tests passed
205198
- NativeMethods.g.cs unchanged
206199
- Human verification: login, vault decryption, seeding all confirmed working

0 commit comments

Comments
 (0)