Skip to content

Conversation

@quexten
Copy link
Contributor

@quexten quexten commented Oct 22, 2025

🎟️ Tracking

📔 Objective

Note: Diff will look weird until #274 is merged.

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation
    team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed
    issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

dani-garcia and others added 26 commits May 12, 2025 12:36
# Conflicts:
#	crates/bitwarden-crypto/src/store/context.rs
#	crates/bitwarden-crypto/src/traits/key_id.rs
# Conflicts:
#	crates/bitwarden-crypto/src/store/context.rs
#	crates/bitwarden-vault/src/cipher/attachment.rs
#	crates/bitwarden-wasm-internal/src/pure_crypto.rs
# Conflicts:
#	crates/bitwarden-core/src/key_management/crypto.rs
#	crates/bitwarden-crypto/src/store/context.rs
#	crates/bitwarden-vault/src/cipher/cipher.rs
#	crates/bitwarden-wasm-internal/src/pure_crypto.rs
# Conflicts:
#	crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs
## 🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-22591

## 📔 Objective

Currently, all app crates (wasm, uniffi) need to declare all the client
managed repositories that they allow clients to implement. This means
that all the crates need to be updated when adding more repositories,
which adds more steps to implementations and can lead to things being
out of sync. This PR unifies the declaration of client managed
repositories so that there's only one place where they are defined.

While I was at it, I've changed slightly the way we register the
repositories. Rather than provide one function for each
(`register_cipher_repository`/`register_folder_repository`) I provide a
single function that takes an object that contains all the repos. This
is easier to generate and should make it easier to know if any of the
repos are missing (you should get a compile error). I left the previous
ones for backwards-compat

Sadly both wasm and uniffi have a lot of compile time type shenanigans
and macros which don't make this easy, so this solution contains
multiple parts:
- In `bitwarden_wasm` and `bitwarden_uniffi` we already have a macro
that creates the repository implementations based on a type. This has
been expanded to take multiple types and also create the `Repositories`
struct which is just a grouping of all of them. Now, instead of manually
calling these macros manually for each type, they instead get passed to
the `bitwarden_pm::create_client_managed_repositories!` macro.
- The `bitwarden_pm::create_client_managed_repositories!` macro's only
purpose is to call the passed macro repeatedly with all the types that
need to be created. This is the only way I found to lazily define the
types in `bitwarden-pm` so that they would be usable in macros in the
other crates. The definition is fairly repetitive with the types,
because we don't have easy ways to change the case of identifiers or
merge them together. We could use the `paste` crate to avoid the
repetition but didn't seem worth it at the moment

Note that in the past we placed the sdk-managed definitions in a shared
`bitwarden-state-migrations` crate, but now that we have the new
`bitwarden-pm` crate as a shared crate focused on password manager
functionality I don't think `bitwarden-state-migrations` is needed.
Instead this PR moves the sdk-managed definitions to `bitwarden-pm`
(next to the new client managed repositories macro) and deletes the
`bitwarden-state-migrations` crate.

## ⏰ Reminders before review

- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or
informed the documentation
  team

## 🦮 Reviewer guidelines

<!-- Suggested interactions but feel free to use (or not) as you desire!
-->

- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry
that's not quite a confirmed
  issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or
concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or
indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
## 🎟️ Tracking

<!-- Paste the link to the Jira or GitHub issue or otherwise describe /
point to where this change is coming from. -->

## 📔 Objective

Accidentally renamed the artifact causing npm publishing to break

## ⏰ Reminders before review

- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or
informed the documentation
  team

## 🦮 Reviewer guidelines

<!-- Suggested interactions but feel free to use (or not) as you desire!
-->

- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry
that's not quite a confirmed
  issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or
concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or
indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
## 🎟️ Tracking

<!-- Paste the link to the Jira or GitHub issue or otherwise describe /
point to where this change is coming from. -->

## 📔 Objective

Updates the CODEOWNERS replace platform and architecture with
@bitwarden/team-sdk-sme as the co-owner of
@bitwarden/team-key-management-dev's code. Further, this moves the KM
code in core, and PureCrypto into KM co-ownership.

## ⏰ Reminders before review

- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or
informed the documentation
  team

## 🦮 Reviewer guidelines

<!-- Suggested interactions but feel free to use (or not) as you desire!
-->

- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry
that's not quite a confirmed
  issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or
concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or
indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
Updates the API bindings to `d2577f670e1cf9ca32791135d2197cff1fe12096`

---------

Co-authored-by: bw-ghapp[bot] <178206702+bw-ghapp[bot]@users.noreply.github.com>
Co-authored-by: Daniel García <dani-garcia@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
## 🎟️ Tracking

<!-- Paste the link to the Jira or GitHub issue or otherwise describe /
point to where this change is coming from. -->

## 📔 Objective

Publish a commercial version of the SDK to NPM

## ⏰ Reminders before review

- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or
informed the documentation
  team

## 🦮 Reviewer guidelines

<!-- Suggested interactions but feel free to use (or not) as you desire!
-->

- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry
that's not quite a confirmed
  issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or
concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or
indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
## 🎟️ Tracking

<!-- Paste the link to the Jira or GitHub issue or otherwise describe /
point to where this change is coming from. -->

## 📔 Objective

<!-- Describe what the purpose of this PR is, for example what bug
you're fixing or new feature you're adding. -->

## ⏰ Reminders before review

- Contributor guidelines followed
- All formatters and local linters executed and passed
- Written new unit and / or integration tests where applicable
- Protected functional changes with optionality (feature flags)
- Used internationalization (i18n) for all UI strings
- CI builds passed
- Communicated to DevOps any deployment requirements
- Updated any necessary documentation (Confluence, contributing docs) or
informed the documentation
  team

## 🦮 Reviewer guidelines

<!-- Suggested interactions but feel free to use (or not) as you desire!
-->

- 👍 (`:+1:`) or similar for great changes
- 📝 (`:memo:`) or ℹ️ (`:information_source:`) for notes or general info
- ❓ (`:question:`) for questions
- 🤔 (`:thinking:`) or 💭 (`:thought_balloon:`) for more open inquiry
that's not quite a confirmed
  issue and could potentially benefit from discussion
- 🎨 (`:art:`) for suggestions / improvements
- ❌ (`:x:`) or ⚠️ (`:warning:`) for more significant problems or
concerns needing attention
- 🌱 (`:seedling:`) or ♻️ (`:recycle:`) for future improvements or
indications of technical debt
- ⛏ (`:pick:`) for minor or nitpick changes
@claude
Copy link

claude bot commented Oct 22, 2025

Claude finished @quexten's task —— View job


Code Review Complete

I've completed a comprehensive review of this PR. Here are my findings:


Summary of Changes

This PR makes significant improvements to the crypto key management system:

  • Core crypto refactoring: Improved DataEnvelope and PasswordProtectedKeyEnvelope implementations with better namespace validation
  • Key ID system overhaul: Transitioned from hardcoded string-based local key IDs to UUID-based LocalId pattern, eliminating the need for developers to manually create unique key identifiers
  • Repository pattern unification: Consolidated client-managed repositories using new macro-based patterns in both WASM and UniFFI bindings
  • Migrations restructuring: Moved migrations from standalone bitwarden-state-migrations crate into bitwarden-pm
  • API updates: Auto-generated API changes from swagger spec updates (billing, events, tax endpoints)

Critical Issues

⚠️ Breaking Change: Missing Migration Path

Location: Removal of bitwarden-state-migrations crate

The PR removes the entire bitwarden-state-migrations crate and moves migration logic to bitwarden-pm/src/migrations.rs. However, CLAUDE.md states:

Breaking API changes - Document migration path for clients.

Issue: No migration documentation or changelog entry explains how consuming applications should handle this breaking change. Applications that imported bitwarden-state-migrations will experience compile errors.

Recommendation:

  • Add migration guide in PR description or CHANGELOG
  • Consider deprecation period if feasible
  • Document the new pattern: bitwarden_pm::get_sdk_managed_migrations()

⚠️ Crypto Changes Without Justification

Location: crates/bitwarden-crypto/src/safe/data_envelope.rs

Per CLAUDE.md:

Changes to bitwarden-crypto/ core functionality - Generally speaking, this crate should not be modified. Changes need a comment explaining why.

Changes observed:

  • Modified seal() and unseal() signatures to work with KeyStoreContext
  • Added seal_with_wrapping_key() and unseal_with_wrapping_key() convenience methods
  • Updated key operation restrictions (disabling Encrypt, WrapKey, UnwrapKey on CEKs after sealing)

Issue: No inline comments or documentation explaining the rationale for these crypto changes.

Recommendation: Add inline comments explaining:

  • Why the API changed from seal_ref() to using KeyStoreContext
  • Security rationale for disabling key operations post-seal (lines 156-158)
  • Why wrapping key convenience methods were needed

⚠️ Auto-Generated API Code Changes

Location: crates/bitwarden-api-api/src/models/*.rs (numerous files)

Per CLAUDE.md:

Auto-generated code changes - Changes to bitwarden-api-api/ or bitwarden-api-identity/ are generally discouraged. These are auto-generated from swagger specs.

Issue: 81 files changed with extensive modifications to auto-generated API code. While these appear to be legitimate swagger spec updates (billing v-next, tax endpoints, event types), the PR lacks context about:

  • Which swagger spec version was used
  • Why manual review was needed
  • Whether these changes are backward compatible

Recommendation:

  • Add PR description noting swagger spec version/commit
  • Confirm all API changes are auto-generated (no manual edits)
  • Note any breaking API changes that affect consumers

Security Issues

❌ No Secret Logging Found

Good: Grep search found no instances of secrets being logged in error paths or debug statements.

❌ Unsafe Code Review

Files with unsafe:

  • crates/bitwarden-uniffi/swift/Package.swift
  • crates/bitwarden-uniffi/src/android_support.rs
  • crates/bitwarden-crypto/src/wordlist.rs
  • crates/bitwarden-crypto/src/safe/data_envelope.rs

Note: These are existing files, not modified in this PR. All unsafe usages appear unchanged.


Significant Issues

🎨 Inconsistent Error Handling in DataEnvelope

Location: crates/bitwarden-crypto/src/safe/data_envelope.rs:196

pub fn unseal_with_wrapping_key<Ids: KeyIds, T>(
    &self,
    wrapping_key: &Ids::Symmetric,
    wrapped_cek: &EncString,
    ctx: &mut crate::store::KeyStoreContext<Ids>,
) -> Result<T, DataEnvelopeError>
where
    T: DeserializeOwned + SealableVersionedData,
{
    let cek = ctx
        .unwrap_symmetric_key(*wrapping_key, wrapped_cek)
        .map_err(|_| DataEnvelopeError::DecryptionError)?;  // ❌ Error detail lost
    self.unseal(cek, ctx)
}

Issue: The error from unwrap_symmetric_key() is mapped to a generic DataEnvelopeError::DecryptionError, losing important context (e.g., MissingKeyId, InvalidKey).

Recommendation: Either:

  • Preserve the underlying CryptoError in DataEnvelopeError
  • Map to more specific error variants (e.g., KeyStoreError, WrongKey)

🎨 Similar Issue in PasswordProtectedKeyEnvelope

Location: crates/bitwarden-crypto/src/safe/password_protected_key_envelope.rs:68, 147

Same pattern of swallowing error details with generic error mapping.


🤔 LocalId Uses UUIDv4 - Potential Performance Consideration

Location: crates/bitwarden-crypto/src/traits/key_id.rs:49-51

impl LocalId {
    pub(crate) fn new() -> Self {
        LocalId(uuid::Uuid::new_v4())
    }
}

Observation: Every local key creation generates a new UUIDv4. For high-frequency operations (e.g., encrypting thousands of vault items), this could add overhead.

Question: Was performance profiling done? Consider:

  • Using a monotonic counter instead of UUID for local-only IDs
  • Benchmarking UUID generation impact on batch operations

Recommendation: If profiling shows negligible impact, add a comment explaining the UUID choice (e.g., future-proofing for distributed/async scenarios).


🎨 Macro Hygiene: Missing $crate:: Prefix

Location: crates/bitwarden-pm/src/migrations.rs:24

$macro! {
    $container_name;
    ::bitwarden_vault::Cipher, Cipher, cipher, CipherRepository;
    ::bitwarden_vault::Folder, Folder, folder, FolderRepository;
}

Issue: The macro uses absolute paths (::bitwarden_vault::) which requires the consuming crate to have these dependencies in scope. This creates a hidden dependency.

Recommendation: Use $crate:: prefix where possible or document the required imports for consumers.


❓ KeyStoreContext API Design Question

Location: crates/bitwarden-crypto/src/store/context.rs:155-200

Before:

// Developers had to manually create unique key IDs
const CIPHER_KEY: SymmetricKeyId = SymmetricKeyId::Local("cipher_key");
ctx.unwrap_symmetric_key(wrapping_key, CIPHER_KEY, wrapped_key)?;

After:

// System auto-generates unique IDs
let cipher_key = ctx.unwrap_symmetric_key(wrapping_key, wrapped_key)?;

Question: The new API removes the need for explicit new_key_id parameter. This is cleaner, but:

  • How do developers track multiple unwrapped keys?
  • Is there a risk of ID collision in complex scenarios?

Observation: The implementation uses LocalId::new() which generates UUIDs, so collision risk is negligible. ✅

Recommendation: Add doc comment example showing how to work with multiple unwrapped keys in a single context.


🎨 Repository Macro Error Messages

Location: crates/bitwarden-wasm-internal/src/platform/repository.rs:144-146

let err = ::wasm_bindgen::JsValue::from_str(&format!("Repository error: {:?}", e));
Err(err)

Issue: Debug formatting ({:?}) may expose internal details in production. Consider using Display or redacting sensitive info.

Recommendation: Use {e} instead of {e:?} for user-facing errors, or implement custom error formatting.


Good Practices Observed

  • Test coverage: All crypto changes include comprehensive unit tests with test vectors
  • Backward compatibility: Test vectors verify old envelopes can still be unsealed
  • Namespace validation: Added protection against cross-namespace envelope attacks (lines 585-660 in data_envelope.rs)
  • Key operation restrictions: CEKs properly restricted to decrypt-only after sealing
  • Zeroization: Sensitive key material uses Zeroizing wrapper

Action Items for Author

Must Address (before merge):

  1. Document migration path for removal of bitwarden-state-migrations crate
  2. Add inline comments in bitwarden-crypto/ explaining why core crypto changes were needed
  3. Clarify API changes: Note swagger spec version and confirm all changes are auto-generated

Should Address:

  1. Improve error handling in DataEnvelope::unseal_with_wrapping_key() to preserve error context
  2. Document LocalId design choice (why UUIDv4 vs counter)
  3. Add example to KeyStoreContext docs showing multi-key usage pattern

Consider:

  1. Performance profiling of UUID generation in high-frequency scenarios
  2. Macro hygiene in create_client_managed_repositories! macro
  3. Error message sanitization in repository implementations

Detailed File-by-File Changes (Click to expand)

Core Crypto Changes

  • data_envelope.rs: Added context-based API, namespace validation, convenience methods
  • password_protected_key_envelope.rs: Simplified seal/unseal, improved KDF handling
  • context.rs: Refactored unwrap_symmetric_key to return generated ID instead of requiring explicit ID parameter
  • key_id.rs: No functional changes (already reviewed, macro looks good)

API Changes (Auto-generated)

  • 30+ new models for billing v-next endpoints
  • Event type additions (EventType enum)
  • Tax preview endpoints
  • Organization subscription models

Repository Pattern Changes

  • Unified WASM/UniFFI repository initialization
  • Type-safe container structs for client-managed repositories
  • Removed boilerplate via macro consolidation

Test Changes

  • Vault cipher tests updated to use new unwrap_symmetric_key API
  • All tests passing with new pattern

@github-actions
Copy link
Contributor

Logo
Checkmarx One – Scan Summary & Detailsc1ce147e-eb7a-469a-8832-f984453ddead

Great job! No new security vulnerabilities introduced in this pull request

@codecov
Copy link

codecov bot commented Oct 22, 2025

Codecov Report

❌ Patch coverage is 54.58333% with 109 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.00%. Comparing base (217f649) to head (d704375).
⚠️ Report is 46 commits behind head on km/beeep/safe-data-envelope.

Files with missing lines Patch % Lines
...bitwarden-wasm-internal/src/platform/repository.rs 0.00% 33 Missing ⚠️
crates/bitwarden-uniffi/src/platform/repository.rs 0.00% 28 Missing ⚠️
crates/bitwarden-crypto/src/safe/data_envelope.rs 27.02% 27 Missing ⚠️
crates/bitwarden-pm/src/migrations.rs 0.00% 8 Missing ⚠️
crates/bitwarden-uniffi/src/platform/mod.rs 0.00% 4 Missing ⚠️
crates/bitwarden-wasm-internal/src/platform/mod.rs 0.00% 4 Missing ⚠️
crates/bitwarden-pm/src/lib.rs 0.00% 3 Missing ⚠️
crates/bitwarden-core/src/admin_console/policy.rs 0.00% 1 Missing ⚠️
crates/bitwarden-vault/src/cipher/cipher_client.rs 75.00% 1 Missing ⚠️
Additional details and impacted files
@@                       Coverage Diff                       @@
##           km/beeep/safe-data-envelope     #523      +/-   ##
===============================================================
- Coverage                        78.10%   78.00%   -0.11%     
===============================================================
  Files                              289      289              
  Lines                            28202    28162      -40     
===============================================================
- Hits                             22028    21967      -61     
- Misses                            6174     6195      +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@quexten quexten merged commit b23fcbf into km/beeep/safe-data-envelope Oct 23, 2025
48 of 53 checks passed
@quexten quexten deleted the km/data-envelope-follow-up branch October 23, 2025 14:59
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.

5 participants