Skip to content

Update SDK to 3.0.0-8379-cc7daf10 - #7267

Merged
david-livefront merged 9 commits into
mainfrom
sdlc/sdk-update
Aug 18, 2026
Merged

Update SDK to 3.0.0-8379-cc7daf10#7267
david-livefront merged 9 commits into
mainfrom
sdlc/sdk-update

Conversation

@bw-ghapp

@bw-ghapp bw-ghapp Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Updates the SDK version from 3.0.0-8288-99ffb6ef to com.bitwarden:sdk-android 3.0.0-8379-cc7daf10

What's Changed

Raw changelog
- Update API bindings to e19a9bbc8ab6507a6c66a66f27d3a861825822bc (#1366)
- [deps]: Update Rust to v1.97.1 (#1337)
- Update API bindings to 5358a2f14765c29b61063e33dccde6b1455d7a64 & wire in key id changes (#1383) 
- [PM-39455] Defer account recovery rotation to organizatio on a V1 to V2 user key rotation (#1365)
- feat(crypto): add sync handling and state write for user key id (#1388)
- [PM-39455] Return no untrusted organization public keys on v1 to v2 key rotation. (#1389)
- Add pull_request_target workflows for community PRs (#1386)

@bw-ghapp
bw-ghapp Bot requested a review from david-livefront as a code owner August 14, 2026 08:47
@bw-ghapp bw-ghapp Bot added automated-pr PR created by workflow or other automation t:deps Change Type - Dependencies labels Aug 14, 2026
@bw-ghapp
bw-ghapp Bot requested a review from a team as a code owner August 14, 2026 08:47
@bw-ghapp bw-ghapp Bot added automated-pr PR created by workflow or other automation t:deps Change Type - Dependencies labels Aug 14, 2026
@github-actions github-actions Bot added app:authenticator Bitwarden Authenticator app context app:password-manager Bitwarden Password Manager app context labels Aug 14, 2026
@claude

claude Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Claude finished @bw-ghapp[bot]'s task in 9m 37s —— View job


SDK bump evaluated

3.0.0-8288-99ffb6ef3.0.0-8379-cc7daf10 — 7 commits (99ffb6ef..cc7daf10), evaluated against the local bitwarden/sdk-internal clone per the evaluating-sdk-internal-updates skill.

Verification run on this checkout:

  • ./gradlew app:compileStandardDebugKotlin authenticator:compileDebugKotlinBUILD SUCCESSFUL
  • ./gradlew app:compileStandardDebugUnitTestKotlin authenticator:compileDebugUnitTestKotlinBUILD SUCCESSFUL (test sources matter here: two uniffi records gained fields)
  • ./gradlew app:testStandardDebugUnitTest --tests "*SdkStateBridgeTest*" --tests "*AuthDiskSourceTest*"BUILD SUCCESSFUL

Compile-time breaks

None found.

The one change that required Android work — the state bridge's new user_key_id slot (bitwarden/sdk-internal#1388, state_bridge! macro in crates/bitwarden-core/src/key_management/state_bridge.rs) — is already implemented on this branch by f24d6d70b and 8b27a1a25. StateBridgeForeignImpl is a with_foreign callback interface, so the added slot is a required implementation, not additive; SdkStateBridge.kt:42-50 covers set/get/clear and the tests pass.

Two other records gained fields without breaking Kotlin construction:

  • EncryptionContext.encrypted_by_key_id carries #[cfg_attr(feature = "uniffi", uniffi(default = None))], so createMockEncryptionContext and friends still compile.
  • CryptoSyncUserDecryption.user_key_id has no uniffi default, so its Kotlin constructor gained a required parameter — harmless only because Android constructs no CryptoSync* type anywhere.

Runtime considerations

1. EncryptionContext.encryptedByKeyId is populated by the SDK and dropped by Android (bitwarden/sdk-internal#1383)

The SDK now records the id of the wrapping key (org key for org ciphers, user key otherwise) at encrypt time, and its own CipherRequestModel / CipherWithIdRequestModel conversions forward it. Android doesn't use those conversions — it maps EncryptionContext into its own models at VaultSdkCipherExtensions.kt:813 / :820, and CipherJsonRequest.kt:99 / CipherWithIdJsonRequest.kt:75 have no such field, so the value is discarded on every create/edit (CipherManager, SdkCipherRepository.kt:40, CredentialExchangeImportManagerImpl.kt:88).

Not a regression — the field is optional server-side and Android never sent it. But the SDK comment is explicit that "the server uses it to reject writes made under a wrong key," so once that validation is enforced for V2 accounts, Android cipher writes would start failing. Wiring it up is feature work with a rollout/flagging call attached (which V2 flag gates it, whether the network contract change ships now), so I've flagged it rather than guessed. Fix this →

2. Persisting the user key id is the right call, and the lock/unlock caveat from my earlier comment doesn't apply

set_user_key_id / clear_user_key_id are driven from CryptoSyncHandlerClient::on_sync, mirroring the server's userDecryption.userKeyId: present → store, absent → clear. It's sync state, not lock-time teardown, so @quexten's request to persist rather than hold it in memory matches the SDK's intent. Practically the slot stays empty for now — Android has no crypto-sync-handler call site yet, so nothing writes it until sync is wired to the SDK.

3. New backfill API is available but uncalledbitwarden/sdk-internal#1388 adds uniffi-exported userKeyIdNeedsBackfill() / userKeyIdBackfill() on UserCryptoManagementClient. Purely additive; the SDK PR states it's meant to run from an encrypted migrator, not on sync. No Android caller.

Everything else in range — confirmed safe

Commit

No commit — nothing needed fixing. Working tree clean; the state bridge work this bump required was already committed to this branch.
· branch sdlc/sdk-update

@codecov

codecov Bot commented Aug 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.25%. Comparing base (38d79cb) to head (8b27a1a).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7267      +/-   ##
==========================================
- Coverage   86.25%   86.25%   -0.01%     
==========================================
  Files         891      891              
  Lines       65294    65302       +8     
  Branches     9808     9808              
==========================================
+ Hits        56320    56326       +6     
- Misses       5472     5474       +2     
  Partials     3502     3502              
Flag Coverage Δ
app-data 17.88% <100.00%> (+<0.01%) ⬆️
app-ui-auth-tools 18.76% <0.00%> (-0.01%) ⬇️
app-ui-platform 16.41% <0.00%> (-0.01%) ⬇️
app-ui-vault 27.31% <0.00%> (-0.01%) ⬇️
authenticator 6.09% <0.00%> (-0.01%) ⬇️
lib-core-network-bridge 4.10% <0.00%> (-0.01%) ⬇️
lib-data-ui 1.20% <0.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 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.

@bw-ghapp bw-ghapp Bot changed the title Update SDK to 3.0.0-8316-37817253 Update SDK to 3.0.0-8344-5b5e8573 Aug 14, 2026
@bw-ghapp bw-ghapp Bot changed the title Update SDK to 3.0.0-8344-5b5e8573 Update SDK to 3.0.0-8360-6d511f8c Aug 17, 2026
@bw-ghapp bw-ghapp Bot changed the title Update SDK to 3.0.0-8360-6d511f8c Update SDK to 3.0.0-8368-7fdc273e Aug 18, 2026
bw-ghapp Bot added 2 commits August 18, 2026 11:53
The SDK's state_bridge! macro gained a user_key_id slot in
bitwarden/sdk-internal#1388, adding setUserKeyId/getUserKeyId/
clearUserKeyId to the StateBridgeForeignImpl callback interface.

Nothing on Android reads the user key id yet, so it is held in memory
alongside the user key rather than persisted to AuthDiskSource.
@bw-ghapp bw-ghapp Bot changed the title Update SDK to 3.0.0-8368-7fdc273e Update SDK to 3.0.0-8371-b15ab941 Aug 18, 2026
private var inMemoryUserKey: SymmetricCryptoKey? = null

@Volatile
private var inMemoryUserKeyId: String? = null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be volatile, but persisted to disk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@claude Please persist the user key id to disk instead of making it volatile. The key id should be persisted.

@claude claude Bot Aug 18, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude finished @quexten's task in 5m 24s —— View job


User key id is now persisted

  • Read SdkStateBridge and the AuthDiskSource persistence patterns
  • Add a persisted userKeyId slot to AuthDiskSource / AuthDiskSourceImpl
  • Wire SdkStateBridge set/get/clear through the disk source
  • Update FakeAuthDiskSource and tests
  • Build + run tests — gradle is not in this run's allowed tools (see note below)
  • Commit and push — 8b27a1a

What changed

AuthDiskSource / AuthDiskSourceImpl — new per-user slot alongside the other cryptographic state:

private const val USER_KEY_ID_KEY = "userKeyId"

override fun getUserKeyId(userId: String): String? =
    getString(key = USER_KEY_ID_KEY.appendIdentifier(userId))

override fun storeUserKeyId(userId: String, userKeyId: String?) {
    putString(key = USER_KEY_ID_KEY.appendIdentifier(userId), value = userKeyId)
}

SdkStateBridge (app/.../sdk/statebridge/SdkStateBridge.kt:42-51) — the @Volatile inMemoryUserKeyId field and the "not persisted" comment are gone; the three callbacks now delegate to the disk source, matching how setEncryptedPin/setV2UpgradeToken/setPersistentPinEnvelope already behave:

override suspend fun setUserKeyId(value: String) {
    authDiskSource.storeUserKeyId(userId = userId, userKeyId = value)
}

override suspend fun getUserKeyId(): String? = authDiskSource.getUserKeyId(userId = userId)

override suspend fun clearUserKeyId() {
    authDiskSource.storeUserKeyId(userId = userId, userKeyId = null)
}

clearData(userId) now clears the key id too (AuthDiskSourceImpl.kt:205), so it is wiped along with the rest of the user's data on logout via UserLogoutManager. The inMemoryUserKey slot is deliberately left volatile — that one is actual key material and must not touch disk.

TestsSdkStateBridgeTest now asserts against the disk source rather than a round-trip through the bridge, FakeAuthDiskSource gained the backing map plus an assertUserKeyId helper and clears the slot in clearData, and AuthDiskSourceTest gained getUserKeyId/storeUserKeyId SharedPreferences tests plus a clearData assertion.

Two things worth your call

  1. Plain vs. encrypted preferences. I used putString/getString (plain bwPreferencesStorage), not putEncryptedString. The key id is an identifier the server already knows, not key material, and this matches how v2UpgradeToken and the persistent PIN envelope are stored. Say the word if you'd rather it live in the encrypted store.
  2. clearUserKeyId now erases the persisted value. That is the literal bridge contract, but note the SDK calls it whenever it tears down the user's crypto state — so if it fires on lock rather than only on logout, the id won't survive a lock/unlock cycle. Worth a look from the SDK side; I didn't add any Android-side special-casing.

Verification

I could not run ./gradlew in this job — every gradle invocation was rejected with "This command requires approval", unlike the earlier run on this PR. So the changes are not compile- or test-verified locally; the change is small and mechanical (interface method + impl + fake + delegation), but CI on this push is the actual check. If you want me to verify locally on a future run, gradle needs to be added to --allowedTools.
· branch sdlc/sdk-update

@bw-ghapp bw-ghapp Bot changed the title Update SDK to 3.0.0-8371-b15ab941 Update SDK to 3.0.0-8379-cc7daf10 Aug 18, 2026
The user key id slot on the state bridge was held in memory only, so the
id the server knows was lost on every process restart. Route it through
AuthDiskSource so it survives restarts and is cleared with the rest of
the user's data on logout.

Co-authored-by: Bernd Schoolmann <11866552+quexten@users.noreply.github.com>
@david-livefront
david-livefront added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit 109cf7b Aug 18, 2026
26 checks passed
@david-livefront
david-livefront deleted the sdlc/sdk-update branch August 18, 2026 15:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app:authenticator Bitwarden Authenticator app context app:password-manager Bitwarden Password Manager app context automated-pr PR created by workflow or other automation t:deps Change Type - Dependencies

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants