* Isolate tests from the developer's real login keychain
Every test run prompted for the login keychain password (repeatedly,
since the xctest runner's code signature changes each build, so
"Always Allow" can never stick) and silently deleted the developer's
real Nostr identity via panic-mode tests.
Two holes let tests reach the real keychain:
- NostrIdentityBridge() defaulted to the real KeychainManager. Tests
inject mocks, but app-side constructions with no injection point
(LocationNotesManager's static bridge, GeohashPresenceService,
BoardManager, AppRuntime) read the real chat.bitchat.nostr item
when exercised under test.
- clearAllAssociations() used raw SecItem* calls that bypassed the
injected keychain entirely, so panicClearAllData tests wiped the
real Nostr identity items on every run.
Fix: centralize FavoritesPersistenceService's test-guarded in-memory
default as KeychainManager.makeDefault() and use it for all default
keychain parameters, and add deleteAll(service:) to
KeychainManagerProtocol so clearAllAssociations() goes through the
injected keychain like every other operation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Share one in-memory test keychain per process (Codex P2)
A fresh store per makeDefault() call diverges from production, where
separate default-constructed bridges share chat.bitchat.nostr —
BoardManager's publish and NIP-09 delete paths would derive different
geohash identities under test. PreviewKeychainManager gains a lock
since the shared instance is reached from arbitrary threads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: jack <jackjackbits@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Add proper error classification to distinguish expected states (item not
found) from critical failures (access denied, storage full) and
recoverable errors (device locked, auth failed).
Changes:
- Add KeychainReadResult and KeychainSaveResult enums with error types
- Add getIdentityKeyWithResult/saveIdentityKeyWithResult protocol methods
- Implement retry logic with exponential backoff for transient errors
- Add consistent SecureLogger logging for all keychain operations
- Update NoiseEncryptionService identity loading to handle errors gracefully
- Update MockKeychain and TrackingMockKeychain with error simulation
- Add comprehensive KeychainErrorHandlingTests (18 new tests)
Security: Applications can now properly detect and respond to critical
keychain failures, improving resilience during device lock states and
providing actionable diagnostics for access issues.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Added secureClear() calls for all 6 DH operations in NoiseProtocol.swift
to properly clear sensitive shared secrets from memory after use:
- writeMessage(): .es initiator/responder, .se initiator/responder
- performDHOperation(): .ee and .ss operations
This fixes a forward secrecy vulnerability where shared secrets could
persist in memory after handshake completion.
Also adds:
- TrackingMockKeychain to count secureClear calls in tests
- 3 new tests verifying secureClear is called during handshake
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Merge KeychainHelper functionality into KeychainManager to provide
a single, unified API for all keychain operations.
- Remove KeychainHelper.swift and KeychainHelperProtocol
- Add generic save/load/delete methods to KeychainManagerProtocol
- Update NostrIdentityBridge to use KeychainManagerProtocol
- Update FavoritesPersistenceService to use KeychainManagerProtocol
- Update PreviewKeychainManager with new methods
- Update MockKeychain and add MockKeychainHelper typealias for backwards compatibility
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Extract each type to a separate file
* Nostr ID Bridge: Convert static func/vars to instance
* `KeychainHelper` behind a protocol to easily mock
* Update tests with ID Bridge and MockKeychainHelper
---------
Co-authored-by: jack <212554440+jackjackbits@users.noreply.github.com>