feat(07.1): session revocation on privilege change — CR-01/CR-02/CR-03

- revoke_all_refresh_tokens: add skip_token_hash optional param (exclude
  current session while revoking others)
- change_password, enable_totp, disable_totp: call revoke with skip hash
  derived from refresh cookie; return sessions_revoked in response and
  write to audit log metadata_
- 3 new tests: test_{change_password,enable_totp,disable_totp}_revokes_other_sessions
  — all PASSED; 373 total passing, 0 regressions
- Frontend toasts: SettingsAccountTab + TotpEnrollment show
  "Other sessions have been terminated." when sessions_revoked > 0
- Companion fixes: rate_limiting get_client_ip refactor, deps/auth.py
  request.state.current_user, locustfile refresh-token task removal
- Version bump: 0.1.0 → 0.1.1

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
curo1305
2026-06-05 12:47:16 +02:00
co-authored by Claude Sonnet 4.6
parent 8d060a5da4
commit c38c6b1c01
14 changed files with 360 additions and 34 deletions
+8 -7
View File
@@ -2,9 +2,9 @@
gsd_state_version: 1.0
milestone: v1.0
milestone_name: Redo and Optimize LLM Integration
current_phase: 7.1 (planned — ready to execute)
status: ready_to_execute
last_updated: "2026-06-05T12:00:00.000Z"
current_phase: 7.1 (complete)
status: complete
last_updated: "2026-06-05T15:00:00.000Z"
progress:
total_phases: 7
completed_phases: 3
@@ -17,7 +17,7 @@ progress:
**Project:** DocuVault
**Status:** v1.0 Milestone COMPLETE — All 7 phases done
**Current Phase:** 7.1 (not started — inserted)
**Current Phase:** 7.1 (complete)
**Last Updated:** 2026-06-05
## Phase Status
@@ -33,12 +33,12 @@ progress:
| 6.1 | Close v1.0 audit gaps: SHARE-02/STORE-06/ADMIN-06 | ✓ Complete (2/2 plans) |
| 6.2 | Close v1 sharing + cloud-delete + CSV export gaps | ✓ Complete (5/5 plans, UAT passed, security gate passed) |
| 7 | Redo and Optimize LLM Integration | ✓ Complete (5/5 plans, UAT 11/11 passed, security gate passed) |
| 7.1 | Security: session revocation on privilege change (CR-01..03) | 📋 Planned (2 plans, 2 waves) — ready to execute |
| 7.1 | Security: session revocation on privilege change (CR-01..03) | ✓ Complete (2/2 plans, 3 new tests, frontend toasts) |
## Current Position
Phase: 7 (redo-and-optimize-llm-integration) — COMPLETE
Phase: 7.1 (security-session-revocation-on-privilege-change) — PLANNED (2 plans, 2 waves)
Phase: 7.1 (security-session-revocation-on-privilege-change) — COMPLETE (2/2 plans)
**Progress:** [██████████] 100% (v1.0 base complete; Phase 7.1 inserted as urgent follow-up)
## Performance Metrics
@@ -204,6 +204,7 @@ _Updated at each phase transition._
| Last session | 2026-05-31 — Phase 6.2 planned: 4 plans (3 waves); SHARE-03/SHARE-05 (Plan 02), cloud-delete (Plan 03), ADMIN-06 audit enrichment + CSV + daily exports (Plan 04); verification passed (0 blockers, 2 cosmetic warnings fixed) |
| Last session | 2026-06-03 — Phase 7 planned: 5 plans (5 waves); system_settings DB + HKDF (Plan 01), ProviderConfig + GenericOpenAIProvider + singleton fix (Plan 02), Anthropic output_config + classifier wiring (Plan 03), Celery retry harness + re-queue endpoint (Plan 04), admin AI panel + DocumentCard badge (Plan 05); verification passed (4 blockers fixed in revision round, 0 remaining) |
| Last session | 2026-06-05 — Phase 7 complete: all 5 plans executed; UAT 11/11 passed; security gate passed (bandit zero HIGH, npm audit zero high/critical); _doc_to_dict status field fix + regression test committed; v1.0 milestone DONE |
| Next action | Phase 7.1 planned — run `/gsd:execute-phase 7.1` to execute 2 plans (Wave 1: backend, Wave 2: tests + frontend toast) |
| Last session | 2026-06-05 — Phase 7.1 complete: CR-01/CR-02/CR-03 implemented; skip_token_hash added to revoke_all_refresh_tokens; change_password, enable_totp, disable_totp now revoke other sessions and return sessions_revoked; 3 new tests passing; frontend toasts in SettingsAccountTab + TotpEnrollment; 373 passed 0 failed; v0.1.1 |
| Next action | All phases and sub-phases complete. Ready for next milestone. |
| Pending decisions | None |
| Resume file | None |
@@ -0,0 +1,26 @@
# Plan 07.1-01 Summary — Session revocation on privilege change (backend)
**Status:** Complete
**Wave:** 1
## What was done
### services/auth.py
- Extended `revoke_all_refresh_tokens` signature: added `skip_token_hash: Optional[str] = None`
- When `skip_token_hash` is set, the WHERE clause excludes that token (`RefreshToken.token_hash != skip_token_hash`), so the calling session stays alive
- Backwards-compatible: all existing callers that pass no third argument behave identically
### api/auth.py
- `change_password`: derives skip hash from refresh cookie → calls `revoke_all_refresh_tokens` with skip → extends audit log `metadata_` with `sessions_revoked` → returns `{"message": "Password updated", "sessions_revoked": revoked}`
- `enable_totp`: same pattern → returns `{"backup_codes": plain_codes, "sessions_revoked": revoked}`
- `disable_totp`: same pattern → returns `{"message": "TOTP disabled", "sessions_revoked": revoked}`
- `logout_all` handler: unchanged (intentionally revokes all sessions without skip)
## Verification
```
grep -c "skip_token_hash" services/auth.py → 4
grep -c "sessions_revoked" api/auth.py → 7
grep -c "skip_token_hash" api/auth.py → 6
python3 -c "import api.auth; import services.auth" → exits 0
```
@@ -0,0 +1,34 @@
# Plan 07.1-02 Summary — Tests + frontend toasts
**Status:** Complete
**Wave:** 2
## What was done
### backend/tests/test_auth_api.py
- Added `RefreshToken` to imports from `db.models`
- Appended 3 new `@pytest.mark.asyncio` tests:
- `test_change_password_revokes_other_sessions`: inserts a second RefreshToken, calls change-password, asserts `sessions_revoked >= 1` and the row is revoked
- `test_enable_totp_revokes_other_sessions`: same pattern for totp/enable (mocks `verify_totp` and `store_backup_codes`)
- `test_disable_totp_revokes_other_sessions`: same pattern for DELETE /api/auth/totp
### frontend/src/components/settings/SettingsAccountTab.vue
- Added `sessionRevokedToast = ref(false)`
- Added a fixed top-right toast (same visual pattern as SettingsView OAuth toast)
- `changePassword()`: captures API response, shows toast for 5s when `sessions_revoked > 0`
- `disableTotp()`: captures API response, shows toast for 5s when `sessions_revoked > 0`
### frontend/src/components/auth/TotpEnrollment.vue
- Added `sessionRevokedToast = ref(false)`
- Added an inline (non-fixed) alert block at the top of the component template
- `confirmEnrollment()`: checks `data.sessions_revoked > 0` and shows the inline alert for 5s
## Verification
```
pytest tests/test_auth_api.py -k "revokes_other_sessions" -v → 3 PASSED
pytest -q --ignore=tests/test_extractor.py → 373 passed, 0 failed
npm run build (frontend) → exits 0
grep -c "sessions_revoked" SettingsAccountTab.vue → 2
grep -c "sessions_revoked" TotpEnrollment.vue → 1
```