test: pre-cache symkey for every account in setup (op-4b7) - #8
Merged
Conversation
Fixes flake: TestE2E_Migrated's parallel subtests share one env, and hence one keychain credential entry (namespaced per-env at keychainService = "opcli-test-<tmpDir>"). If a subtest is the first to touch an account, the CLI derives that account's symmetric key and writes it back to the entry via SetCachedSymKey. Under the migrated path each subprocess is slow (per-invocation v5->v61 in-memory migration) so many parallel subtests overlap with that one writer; the concurrent read/write pattern on the legacy ACL-protected keychain item surfaces transient OSStatus values. Observed in stress repro: - -25300 errSecItemNotFound on keychainGet (briefly "not found") - -67701 on keychainGet (under write contention) - -25299 errSecDuplicateItem on keychainSet Any of those propagates as `Error: account not found: <sh>` or `Error: no account configured` from the top-level command, which is what the flake reports. setupTestEnv already issued one verify read (op://Private/Test Login/password), which primed the 'my' account's symkey. Extend it to iterate every testDB.Accounts entry and verify-read a field from the first readable vault item we find, so 'work' (and any future account) is also primed before subtests start. Subtests then hit the symkey cache and the keychain workload is read-only against the shared entry — nothing to race against. Verified via `go test -run TestE2E_Migrated -count=100 ./...` in CI (3min, 0 failures). Pre-fix the same stress repro reliably failed within 30 iterations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
jeremyschlatter
approved these changes
Apr 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes a flake in
TestE2E_Migratedwhere parallel subtests surfaced errors likeError: no account configured (run 'opcli signin' first)orError: account not found: my, despite those credentials having been stored in setup.Un-namespaced resource (the root cause)
All of
TestE2E_Migrated's subtests share one env (onetmpDir, onekeychainService = \"opcli-test-<tmpDir>\", one shared keychain credential entry). The keychain entry is namespaced per-env, but the entry itself is concurrently written to by parallel subtests — that's the un-namespaced concurrency pattern.The concurrent writes come from
SetCachedSymKey. Whenever a subtest is the first to touch an account,newAccountKeychainderives the symmetric key (PBKDF2, expensive) and writes the result back into the credential store so subsequent invocations can skip the derivation. Under the migrated path every subprocess is slow (per-invocation v5→v61 in-memory migration), so one writer overlaps with many concurrent readers. Against a legacy ACL-protected Apple Keychain item, those overlaps surface as transient OSStatus values — verified via stress-repro CI traces:-25300errSecItemNotFoundonkeychainGet(entry briefly "not found" during a peer's write)-67701onkeychainGet(under write contention)-25299errSecDuplicateItemonkeychainSetAny non-zero status from the credential-store load propagates up as
Error: account not found: <sh>(for OP_ACCOUNT branches) orError: no account configured(for default-account branches) — exactly the flake symptom.Fix
setupTestEnvalready issued one verify read (op://Private/Test Login/password), which primed themyaccount's symkey. Iterate everytestDB.Accountsand verify-read a field from the first readable vault item we find, sowork(and any future account) is primed too. After this, the parallel subtest workload against the shared keychain entry is read-only — there is nothing for the reads to race against, and the OS-level transient-error surface disappears.This is the minimal targeted fix the bead called for — no refactor of the test framework or of
keychainSetitself. Related: op-xev.3 (PR #6) atomized writes; this PR eliminates writes during the stress window.Test plan
go test -run TestE2E_Migrated -count=100 ./...) and watched it pass on CI (3min, 0 failures). Before the fix,-count=30and-count=50stress runs failed within a few iterations. Temporary stress job removed from this PR before review.make testin normal CI passes.🤖 Generated with Claude Code