[auth] Concurrent recovery-key rotation can reject both requests #266

Closed
opened 2026-09-27 20:23:49 +00:00 by kayg · 2 comments
Owner

Reproduction evidence

In the one full workspace cargo test pass for Forgejo #152 on job/import-calternaljs at 11816527, the unrelated calternal-auth test store::tests::key_rotation_revokes_sessions_and_rejects_competing_recovery failed at crates/calternal-auth/src/store.rs:2676.

The test started two concurrent enroll_recovery_key calls with the same old recovery phrase and expected exactly one success. The observed count was zero (left: 0, right: 1), so both calls returned errors. The other 49 tests in calternal-auth passed. Cargo stopped after this package and did not run the remaining workspace suites. Several other cargo builds/tests were active on the shared host during the run.

Follow-up

Investigate why both competing SQLite transactions can fail instead of one rotating the recovery key, then add a regression test for the case that causes both calls to return errors. This failure is outside the importer changes and was not retried in this one-pass gate run.

## Reproduction evidence In the one full workspace `cargo test` pass for Forgejo #152 on `job/import-calternaljs` at `11816527`, the unrelated `calternal-auth` test `store::tests::key_rotation_revokes_sessions_and_rejects_competing_recovery` failed at `crates/calternal-auth/src/store.rs:2676`. The test started two concurrent `enroll_recovery_key` calls with the same old recovery phrase and expected exactly one success. The observed count was zero (`left: 0`, `right: 1`), so both calls returned errors. The other 49 tests in `calternal-auth` passed. Cargo stopped after this package and did not run the remaining workspace suites. Several other cargo builds/tests were active on the shared host during the run. ## Follow-up Investigate why both competing SQLite transactions can fail instead of one rotating the recovery key, then add a regression test for the case that causes both calls to return errors. This failure is outside the importer changes and was not retried in this one-pass gate run.
Author
Owner

Already fixed on origin/dev. git log origin/dev --grep='competing recovery' shows 8cfb1c77d, which makes concurrent recovery rotation race-safe. The current file-backed test in crates/calternal-auth/src/store.rs starts both rotations at a barrier, then asserts exactly one success, one InvalidToken result, the old key is rejected and the new key works. Recommend recording the fix evidence here. Do not close the issue in this audit.

Already fixed on origin/dev. git log origin/dev --grep='competing recovery' shows 8cfb1c77d, which makes concurrent recovery rotation race-safe. The current file-backed test in crates/calternal-auth/src/store.rs starts both rotations at a barrier, then asserts exactly one success, one InvalidToken result, the old key is rejected and the new key works. Recommend recording the fix evidence here. Do not close the issue in this audit.
Author
Owner

Fixed in 8cfb1c77d (origin/dev); the recovery-rotation race has a regression test and adversarial coverage.

Fixed in 8cfb1c77d (origin/dev); the recovery-rotation race has a regression test and adversarial coverage.
kayg closed this issue 2026-10-03 11:55:25 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
kayg/calternal#266
No description provided.