FileCache.Export (internal/token) writes the MSAL cache with a temp-file + atomic rename, which prevents torn/half-written reads but not lost updates: two concurrent az-devops-token invocations can each load the cache, then the later writer overwrites a newer refresh-token/cache update with stale state.
Raised by CodeRabbit on #1 (Major) and deferred from that PR. It's pre-existing — the tool has always written the cache without cross-process locking — and low-impact in practice: public-client refresh tokens aren't single-use and Entra keeps the prior token valid during a rotation grace window, so a stale clobber typically costs only a re-fetchable access token, not the login (worst case, a re-login).
When it matters
Parallel shim invocations (e.g. mise shims spawned by a parallel build) that trigger a token refresh concurrently. The forced-refresh path added in #1 slightly widens the write window in the last ~20 minutes of a token's life.
Fix options
- Wrap reload → (network refresh) → export in a cross-process advisory file lock (e.g.
gofrs/flock), released on all error paths. Robust, but adds a dependency and serializes concurrent invocations across the network refresh.
- Compare-and-retry on export: re-read the cache just before rename and, if it changed under us, reload/merge and retry. Lighter, no dependency, but trickier to get right.
Not doing now
Disproportionate for the current scope and pre-existing. Tracking here in case concurrency proves problematic in real use.
FileCache.Export(internal/token) writes the MSAL cache with a temp-file + atomic rename, which prevents torn/half-written reads but not lost updates: two concurrentaz-devops-tokeninvocations can each load the cache, then the later writer overwrites a newer refresh-token/cache update with stale state.Raised by CodeRabbit on #1 (Major) and deferred from that PR. It's pre-existing — the tool has always written the cache without cross-process locking — and low-impact in practice: public-client refresh tokens aren't single-use and Entra keeps the prior token valid during a rotation grace window, so a stale clobber typically costs only a re-fetchable access token, not the login (worst case, a re-login).
When it matters
Parallel shim invocations (e.g. mise shims spawned by a parallel build) that trigger a token refresh concurrently. The forced-refresh path added in #1 slightly widens the write window in the last ~20 minutes of a token's life.
Fix options
gofrs/flock), released on all error paths. Robust, but adds a dependency and serializes concurrent invocations across the network refresh.Not doing now
Disproportionate for the current scope and pre-existing. Tracking here in case concurrency proves problematic in real use.