Fifth commit in the session-expiration-policy series. Surfaces the session-policy override controls to account owners. - schemas/account_security.py: NEW. SessionPolicyResponse returns both the override (Optional[int]) and the effective value (always present) plus the system min/max bounds, so the frontend can render the Custom-preset form without re-implementing the defaults logic. SessionPolicyUpdateRequest accepts NULL to clear an override. - endpoints/account_security.py: NEW. GET and PATCH on /me/security. Owner-only via require_account_owner. PATCH validates per-field bounds, then validates the effective idle <= absolute invariant (catching the partial-override case the DB CHECK can't see), then writes the row + an account.session_policy_update audit event with old/new/effective_old/effective_new payload. - router.py: registers the new router under _tenant_deps next to accounts.router. Tests added in test_session_policy.py (8 cases): - GET returns NULL overrides + Strict defaults + system bounds. - PATCH persists override; next login JWT reflects new values (60min/240min -> idle_max=3600, abs_max=14400 seconds). - PATCH rejects idle < min (422). - PATCH rejects absolute > max (422). - PATCH rejects idle > absolute when both are set (422). - PATCH rejects partial override that produces effective idle > effective absolute (idle=43200, absolute=NULL with default 20160). - Engineer-role user gets 403. - PATCH writes exactly one audit row with the expected payload shape. 16/16 in test_session_policy. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
8.4 KiB
8.4 KiB