Audited post-execution state: all 11 tasks (9 original + CR-02 gap fix + activate anti-pattern guard) have green automated tests. 84/84 passing. Zero xfail stubs remaining. Sign-off approved. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.8 KiB
5.8 KiB
phase, slug, status, nyquist_compliant, wave_0_complete, created, audited
| phase | slug | status | nyquist_compliant | wave_0_complete | created | audited |
|---|---|---|---|---|---|---|
| 7.2 | security-jti-claim-redis-access-token-revocation-inserted | complete | true | true | 2026-06-05 | 2026-06-06 |
Phase 7.2 — Validation Strategy
Per-phase validation contract for feedback sampling during execution.
Test Infrastructure
| Property | Value |
|---|---|
| Framework | pytest + pytest-asyncio |
| Config file | backend/pytest.ini |
| Quick run command | pytest tests/test_auth_deps.py tests/test_auth_api.py tests/test_admin_api.py -v |
| Full suite command | cd backend && pytest -v |
| Estimated runtime | ~30 seconds |
Sampling Rate
- After every task commit: Run
pytest tests/test_auth_deps.py tests/test_auth_api.py tests/test_admin_api.py -v - After every plan wave: Run
cd backend && pytest -v - Before
/gsd:verify-work: Full suite must be green - Max feedback latency: ~30 seconds
Per-Task Verification Map
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Test Function | File Exists | Status |
|---|---|---|---|---|---|---|---|---|---|
| jti-claim | 01 | 0 | SEC (JTI) | D-01 | Every access token contains a jti UUID claim |
unit | test_create_access_token_includes_jti_claim, test_create_access_token_jti_is_unique_per_call |
✅ tests/test_task2_auth_service.py |
✅ green |
| test-fakeredis | 01 | 0 | SEC (infra) | — | test_auth_deps.py test app has app.state.redis = FakeRedis() set |
unit | FakeRedis mounted in make_test_app() fixture |
✅ tests/test_auth_deps.py |
✅ green |
| nbf-write-change-password | 03 | 2 | SEC (NBF-write) | T-7.2-01 | change_password writes user_nbf:{user_id} to Redis |
integration | test_change_password_writes_user_nbf_to_redis |
✅ tests/test_auth_api.py |
✅ green |
| nbf-write-enable-totp | 03 | 2 | SEC (NBF-write) | T-7.2-01 | enable_totp writes user_nbf:{user_id} to Redis |
integration | test_enable_totp_writes_user_nbf_to_redis |
✅ tests/test_auth_api.py |
✅ green |
| nbf-write-disable-totp | 03 | 2 | SEC (NBF-write) | T-7.2-01 | disable_totp writes user_nbf:{user_id} to Redis |
integration | test_disable_totp_writes_user_nbf_to_redis |
✅ tests/test_auth_api.py |
✅ green |
| nbf-write-password-reset-confirm | 03 | 2 | SEC (NBF-write) | CR-02 | password_reset_confirm writes user_nbf:{user_id} to Redis |
integration | test_password_reset_confirm_writes_user_nbf_to_redis |
✅ tests/test_auth_api.py |
✅ green |
| nbf-write-deactivation | 03 | 2 | SEC (NBF-write) | T-7.2-01, D-05 | admin deactivation writes user_nbf:{user_id} to Redis |
integration | test_deactivate_user_writes_user_nbf_to_redis |
✅ tests/test_admin_api.py |
✅ green |
| activate-no-nbf | 03 | 2 | SEC (anti-pattern) | D-05 | admin activation does NOT write user_nbf |
integration | test_activate_user_does_not_write_user_nbf |
✅ tests/test_admin_api.py |
✅ green |
| nbf-check-reject | 02 | 1 | SEC (NBF-check) | T-7.2-02 | Token with iat < user_nbf returns HTTP 401 "Session invalidated" |
integration | test_get_current_user_rejects_token_when_iat_before_user_nbf |
✅ tests/test_auth_deps.py |
✅ green |
| nbf-check-allow | 02 | 1 | SEC (NBF-check) | T-7.2-03 | Token with iat > user_nbf is accepted (HTTP 200) |
integration | test_get_current_user_allows_token_when_iat_after_user_nbf |
✅ tests/test_auth_deps.py |
✅ green |
| nbf-fail-open | 02 | 1 | SEC (fail-open) | T-7.2-04, D-04 | Redis error in NBF check does not block request (HTTP 200) | unit | test_get_current_user_failopen_on_redis_error |
✅ tests/test_auth_deps.py |
✅ green |
Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky
Manual-Only Verifications
| Behavior | Requirement | Why Manual | Test Instructions |
|---|---|---|---|
| Recovering session after password change | SEC (pitfall 3) | Requires live frontend + token refresh flow | 1. Login. 2. Change password via API. 3. Use old access token → expect 401. 4. Use refresh token → expect new access token with iat > nbf. 5. Confirm new token works. |
Threat Model
| Threat | STRIDE | Mitigation in this phase |
|---|---|---|
| T-7.2-01: Stolen access token replay after security event | EoP | user_nbf:{user_id} Redis key blocks all tokens with iat before the event |
| T-7.2-02: HTTPException swallowed by fail-open catch | EoP | Explicit except HTTPException: raise guard before broad except Exception in get_current_user |
| T-7.2-03: Wrong comparison direction in NBF check | EoP | payload["iat"] < nbf_timestamp — token issued BEFORE event → reject |
| T-7.2-04: Redis outage bypasses revocation check | DoS/EoP | Fail-open accepted (D-04); availability > revocation during outage — known trade-off |
Validation Audit 2026-06-06
| Metric | Count |
|---|---|
| Tasks in original map | 9 |
| Extra tasks added (CR-02 gap + anti-pattern guard) | 2 |
| Total tasks audited | 11 |
| Gaps found | 0 |
| Resolved | 0 |
| Escalated to manual-only | 0 |
| Tests passing (full suite) | 84/84 |
| xfail stubs remaining | 0 |
All Wave 0 xfail stubs were promoted to passing assertions during Phase 7.2 execution. The CR-02 gap (password_reset_confirm missing user_nbf write) was closed in the phase and has full test coverage.
Validation Sign-Off
- All tasks have automated verify commands
- Sampling continuity: no 3 consecutive tasks without automated verify
- Wave 0 covers all MISSING references (stubs promoted to green)
- No watch-mode flags
- Feedback latency < 30s
nyquist_compliant: trueset in frontmatter
Approval: 2026-06-06 — 84/84 tests passing, 0 gaps, nyquist-compliant