The predictable lock path was opened with Path.open("w"), following (and
truncating through) a pre-positioned symlink. Open it via os.open with
O_NOFOLLOW and no O_TRUNC, raising StoreLockError on a symlinked lock path.
Third review pass (security): the store temp file used a predictable
subscription-auth.json.tmp name, so a local attacker could pre-plant a symlink
there and divert the OAuth token write. Create it with tempfile.mkstemp
(random name, mode 0600, no symlink following) in the same directory, then
atomically rename over the target.
Third review pass: the shared credential store no longer proceeds with an
unlocked read-modify-write when fcntl is missing or flock fails. It now retries
on EINTR and otherwise raises StoreLockError, so concurrent provider
login/refresh/logout can never race by silently skipping the cross-process lock.
Addresses PR review:
- Extract the shared ~/.strix/subscription-auth.json handling into subscription_store, writing tokens owner-only (0600) from creation via os.open instead of chmod-after-write, closing the window where credentials were briefly world/group-readable.
- Serialize read-modify-write across providers and processes with a reentrant lock, so overlapping ChatGPT/Grok save/logout/refresh operations no longer clobber each other.
- Live/TUI stats label the subscription from the persisted run record (falling back to provider-aware settings), so resumed runs no longer mislabel the provider when STRIX_LLM changes.