fix: auth store data-integrity improvements#377
Conversation
- Combine double write-lock acquisition in FileRevocationStore::revoke() into a single guard (fixes #345) - Add File::sync_all() in write_secure before the atomic rename and fsync the parent directory afterwards for crash durability (fixes #331) - Add flock-based advisory file locking around all tokens.json and revoked.json read-modify-write operations so CLI and server cannot clobber each other's writes (fixes #329) - Add regression tests for all three fixes Closes #329 Closes #331 Closes #345 Signed-off-by: StreamKit Devin <devin@streamkit.dev> Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
|
✅ Reviewed on |
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
ReviewOverall: Solid implementation. The RAII Must fix before merge
Should address (or file tracking issue)
Nits (non-blocking)
|
Extends the cross-process file locking from #329 to cover key rotation and reload operations on auth.jwk/jwks.json. Without this, concurrent CLI rotate-key + server reload-keys could clobber each other's writes. Adds a regression test that runs two KeyProvider instances rotating concurrently and verifies all generated keys survive in the final JWKS. Signed-off-by: StreamKit Devin <devin@streamkit.dev> Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
Summary
Fixes four auth data-integrity issues in
FileTokenMetadataStore,FileRevocationStore, andFileKeyProvider(apps/skit/src/auth/stores/file.rs):1. Double write-lock in
revoke()(fixes #345)FileRevocationStore::revoke()acquired theRwLockwrite guard twice — once forinsertand again forprune_expired_locked. Combined into a single lock acquisition so both operations execute atomically under one guard.2. fsync after
write_securefor crash durability (fixes #331)FileKeyProvider::write_securecalledflush()but notsync_all(), so data could be lost on crash before the OS flushed dirty pages. Now callsfile.sync_all()before the atomic rename and fsyncs the parent directory afterwards, ensuring durability foradmin.token,auth.jwk,jwks.json,tokens.json, andrevoked.json.3. flock-based file locking for concurrent access (fixes #329)
Added cross-process advisory file locking (
flockvia thefs2crate) around all read-modify-write operations ontokens.json,revoked.json,auth.jwk, andjwks.json. Each mutation now: acquires an exclusive flock → re-reads from disk (to pick up changes from other processes) → applies the modification → persists → releases the lock. This prevents the CLI and server from clobbering each other's writes when running concurrently (e.g. duringrotate-key).This covers:
FileRevocationStore::revoke()andreload()FileTokenMetadataStore::store(),mark_revoked(), andreload()FileKeyProvider::rotate()andreload()New dependency:
fs2(0.4.3) — small, well-maintained crate wrapping platformflock/LockFileEx.Review & Testing Checklist for Human
revoke()single-guard change is correct: theRwLockwrite guard must cover bothinsertandprune_expired_lockedto maintain atomicity — confirm the#[allow(clippy::significant_drop_tightening)]is justifiedsync_all()placement inwrite_secure: called afterflush()but before the file handle is dropped and the atomicrename()— this is the standard durable-write patternwrite_secure's atomic rename: the flock is on a companion.lockfile (not the data file itself), so rename doesn't break the lockskitserver, then usestreamkit-client rotate-keyconcurrently — verifytokens.json/revoked.json/jwks.jsonare not corrupted.lockfiles don't cause issues with permission checks (they are separate from the data files and not subject toverify_permissions)Notes
plugin_integration_testfailures in CI are pre-existing and unrelated to this changeauth::stores::file::testspass, including 8 new regression tests covering all four fixesCloses #329
Closes #331
Closes #345
Link to Devin session: https://staging.itsdev.in/sessions/cc069cb4915148c9a6e1938684e08d32
Requested by: @streamer45