[PM-40519] feat: Add passkey cipher storage and identity foundation to TestHarness - #2977
[PM-40519] feat: Add passkey cipher storage and identity foundation to TestHarness#2977morganzellers-bw wants to merge 1 commit into
Conversation
|
Claude Code is reviewing this pull request... If this comment does not update with results, check the Actions log. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2977 +/- ##
==========================================
- Coverage 79.53% 79.51% -0.02%
==========================================
Files 1169 1169
Lines 75095 75095
==========================================
- Hits 59724 59715 -9
- Misses 15371 15380 +9 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
e3f6aa9 to
4d77e40
Compare
c91e387 to
51be49b
Compare
There was a problem hiding this comment.
🎨 I think we should think about moving our current CipherView fixtures from BitwardenSdk+VaultFixtures in BitwardenShared to BitwardenKit so it can be shared amongst all apps.
Same applies to Fido2CredentialAutofillView and Fido2CredentialView.
Perhaps moving the whole file there. What do you think @bitwarden/team-ios @matt-livefront ?
There was a problem hiding this comment.
I like that idea
| // sourcery: AutoMockable | ||
| /// A service that locally persists the SDK-encrypted `Cipher`s created by the SDK-backed passkey | ||
| /// scenarios, so they survive app relaunches. | ||
| /// | ||
| protocol CipherStorageService: AnyObject { |
There was a problem hiding this comment.
⛏️ We usually put sourcery inline with the protocol definition. I'm almost certain that you should get a warning on how it's done there above the DocC.
| // sourcery: AutoMockable | |
| /// A service that locally persists the SDK-encrypted `Cipher`s created by the SDK-backed passkey | |
| /// scenarios, so they survive app relaunches. | |
| /// | |
| protocol CipherStorageService: AnyObject { | |
| /// A service that locally persists the SDK-encrypted `Cipher`s created by the SDK-backed passkey | |
| /// scenarios, so they survive app relaunches. | |
| /// | |
| protocol CipherStorageService: AnyObject { // sourcery: AutoMockable |
| /// The `UserDefaults` key under which the persisted ciphers are stored. | ||
| private static let storageKey = "PasskeyStoredCiphers" |
There was a problem hiding this comment.
🤔 I wonder if we should use some key format alike what we use now in AppSettingsStore, i.e. bwPreferencesStorage:{key}. So in here it'd would be something like thPreferencesStorage:{key}.
| func loadCiphers() -> [Cipher] { | ||
| guard let data = userDefaults.data(forKey: Self.storageKey), | ||
| let storedCiphers = try? JSONDecoder().decode([StoredCipher].self, from: data) else { | ||
| return [] | ||
| } | ||
| return storedCiphers.map(\.cipher) | ||
| } | ||
|
|
||
| func save(ciphers: [Cipher]) { | ||
| let storedCiphers = ciphers.compactMap(StoredCipher.init(cipher:)) | ||
| guard let data = try? JSONEncoder().encode(storedCiphers) else { return } | ||
| userDefaults.set(data, forKey: Self.storageKey) | ||
| } |
There was a problem hiding this comment.
🤔 I usually like to avoid try? as we wouldn't have any errors logged if one would happen. Could you add some logging here or rethrow the error in case it happens? At least on the OSLog.
There was a problem hiding this comment.
⛏️ Update string keys to follow standards.
Introduces the persistence and data-model layer for the SDK-backed passkey scenarios: a UserDefaults-backed cipher store, its Codable mirror of the SDK's Cipher/Fido2Credential shape, the synthetic identity model, keychain item, and supporting errors/fixtures. This is the foundation the Fido2-driving services (registration, assertion, credential listing) build on top of in a follow-up PR.
51be49b to
f4b8cb4
Compare
🤖 Claude Security Code Review 🤖PR: (#2945) - PM-40519 feat: Add SDK-backed passkey registration and assertion services to TestHarness — 2026-08-27 Date: 2026-08-27 Commits reviewed: c419835..c4f80a6 · 2 commits · TestHarnessShared/Core/Autofill/Passkey/
Summary
📝 NotesExpand for details on (14) notes
✅ StrengthsExpand for details on (13) strengths
❌ DismissedExpand for details on (5) dismissed findings
Net result: 0 Blockers, 0 Improvements — nothing here should hold up the PR. The 14 Notes are all low-cost hardening opportunities around the synthetic identity's error handling, keychain namespacing, and defensive serialization; worth a follow-up cleanup pass but not urgent given the complete isolation from production trust boundaries. |
🎟️ Tracking
PM-40519
📔 Objective
Adds the persistence and data-model foundation for passkey test scenarios in the TestHarness, split from PR #2945 for size.
CipherStorageServicepersists SDK-encrypted ciphers across app relaunches, backed byUserDefaults.StoredCipheris aCodablemirror of the handful ofCipher/Fido2Credentialfields these scenarios populate, sinceBitwardenSdk.Cipherisn't itselfCodable.SyntheticIdentity/PasskeyKeychainItemmodel the throwaway identity persisted in the Keychain so the same crypto keys survive relaunches.PasskeyErrorand supporting fixtures round out the layer.Fido2CredentialStore/Fido2UserInterface/PasskeyServicelayer on top of this.testHarness_passkeys_flow.MP4
Stack: #2977 → #2945 → #2946 → #2947 → #2948