Auditor Session Countdown UI
Status
Implemented in OP-066n.
Related Requirements
- ADR references: ADR-0014 auditor export and redaction controls.
- Runtime references: OP-057 auditor session enforcement runtime.
- Task board references: OP-066n auditor session countdown/expiry notice.
Problem Statement
Auditors need visible confirmation that their read-only access is time-boxed. The console also needs to warn as the OP-057 access window nears expiry without confusing that window with JWT/session-token expiry.
Architectural Intent
The backend remains authoritative. /api/v1/session now returns the
redaction-safe active_auditor_session summary only after the OP-057 auditor
access gate passes. The frontend uses that access-window metadata for the
countdown and never derives auditor access from token expires_at.
What Was Implemented
- Added
active_auditor_sessionto the authenticated session response for auditor requests with an active OP-057 session. - Added
remaining_secondsto auditor session summaries. - Added
auditor.session_status.readaudit records when auditors read their active session status through/api/v1/session. - Added a global console header notice for auditor sessions with active, warning, and expired states.
- Hid the notice for non-auditor roles even if a malformed fixture includes auditor session metadata.
Components Involved
poc/ingest_api/http_routes.pypoc/ingest_api/auditor_session_service.pypoc/ingest_api/api_models.pyfrontend/src/lib/api.tsfrontend/src/components/app-shell.tsxfrontend/src/test/oneprotect-ui.test.tsxtests/test_auditor_session_enforcement.pytests/test_frontend_response_contracts.py
APIs / Events / Schemas
GET /api/v1/sessionspecs/openapi.yaml- No event payload changes.
Deployment Notes
No Helm, Terraform, AWS, ECR, or docs deployment changes were made. This is a backend contract and console UI update inside the existing application services.
Security / Tenant Isolation
Auditor access still fails closed in the auth layer before protected route handlers run. The UI receives only tenant-scoped, redaction-safe session metadata: session identifiers, auditor actor/name/org, status, validity window, creator, revocation metadata, and remaining lifetime. The response does not include secrets, bearer tokens, raw evidence, or raw export content.
Validation Steps
UI Validation
- Sign in or mock a backend session with
role = auditor. - Confirm the console header shows the remaining auditor access window.
- Confirm the notice changes to an expired state when the access window is no longer active.
- Confirm tenant admins, operators, and system admins do not see the auditor countdown.
API Validation
.venv/bin/python -m unittest tests.test_auditor_session_enforcement tests.test_frontend_response_contracts
Smoke Validation
npm --prefix frontend test -- --run
make validate-contracts
make typecheck-python
make lint
make test-sqlite
make docs-build
Known Limitations
- Tenant settings for auditor duration bounds are still not exposed in the console.
- Auditor session administration remains the existing API path; this task does not add a session-management UI.
- Reloading after an already-expired auditor access window still receives the OP-057 fail-closed 403 from the backend.
Follow-Up Work
- Tenant settings UI for auditor access bounds if scoped separately.
- Richer auditor session administration table if scoped separately.
Acceptance Criteria Mapping
| Acceptance criterion | Evidence |
|---|---|
| Auditor sees remaining session time | frontend/src/components/app-shell.tsx renders active_auditor_session from /api/v1/session |
| Warning before expiry | Header notice changes styling when remaining lifetime is 15 minutes or less |
| Expired notice on timeout | Header notice flips to Auditor access expired when the access window reaches zero |
| Uses backend access-window metadata | frontend/src/lib/api.ts maps active_auditor_session; docs and skills forbid using JWT expiry for this UX |
| Backend contract is tested | tests/test_auditor_session_enforcement.py and tests/test_frontend_response_contracts.py |
| Frontend role behavior is tested | frontend/src/test/oneprotect-ui.test.tsx covers auditor, expired, and non-auditor rendering |