mirror of
https://github.com/azaion/admin.git
synced 2026-06-21 21:51:10 +00:00
8e7c602f51
AZ-535: POST /logout (caller's session), /logout/all (all sessions for user),
admin POST /sessions/{sid}/revoke, and verifier-only GET /sessions/revoked
snapshot. New Service role gates the snapshot. Idempotent revoke; reason +
revoked_by_user_id audited per row.
AZ-533: POST /sessions/mission mints a long-lived no-refresh ES256 token bound
to one aircraft + one mission. Audience narrowed to satellite-provider, hard
12 h cap, persisted as class='mission' so the existing logout/revoke surface
covers it. Successful CompanionPC /login or /token/refresh auto-revokes that
aircraft's open mission session (post-flight reconnect).
Schema: 09_sessions_logout_and_mission.sql adds revoked_by_user_id, class,
aircraft_id; drops NOT NULL on refresh_hash for mission rows; adds two partial
indexes for the auto-revoke and snapshot hot paths.
Tests: 13 new e2e tests, all green; full suite 75/76 (1 pre-existing flake in
PasswordHashingTests AC5 timing assertion, unrelated to this batch).
Co-authored-by: Cursor <cursoragent@cursor.com>
38 lines
2.1 KiB
SQL
38 lines
2.1 KiB
SQL
-- AZ-535 + AZ-533 (Epic AZ-529): logout/revocation surface + mission tokens.
|
|
--
|
|
-- AZ-535 adds `revoked_by_user_id` so admin / system revocations can be audited.
|
|
-- AZ-533 adds `class` and `aircraft_id` so mission tokens (long-lived, no refresh,
|
|
-- bound to a specific aircraft) live in the same row store as interactive sessions
|
|
-- and the auto-revoke-on-reconnect middleware can index them cheaply.
|
|
--
|
|
-- The two columns ride together because mission token revocation reuses the same
|
|
-- code path the logout endpoints exercise; splitting them into separate migrations
|
|
-- would just force duplicate ALTER TABLE round-trips in the test bootstrap.
|
|
|
|
ALTER TABLE public.sessions
|
|
ADD COLUMN IF NOT EXISTS revoked_by_user_id uuid NULL REFERENCES public.users(id) ON DELETE SET NULL,
|
|
ADD COLUMN IF NOT EXISTS class varchar(32) NOT NULL DEFAULT 'interactive',
|
|
ADD COLUMN IF NOT EXISTS aircraft_id uuid NULL REFERENCES public.users(id) ON DELETE SET NULL,
|
|
-- AZ-533: mission tokens have no refresh value, so refresh_hash is now nullable.
|
|
-- Interactive rows continue to set it; the unique index already ignores nulls
|
|
-- by default in Postgres.
|
|
ALTER COLUMN refresh_hash DROP NOT NULL;
|
|
|
|
-- AZ-533: cheap "find every mission session belonging to UAV-X that hasn't been
|
|
-- revoked yet" — driven on every successful auth call so it must be O(active rows
|
|
-- for that aircraft), not O(all sessions). Partial index excludes the cold pile of
|
|
-- already-revoked rows.
|
|
CREATE INDEX IF NOT EXISTS sessions_aircraft_active_idx
|
|
ON public.sessions (aircraft_id, class)
|
|
WHERE revoked_at IS NULL AND aircraft_id IS NOT NULL;
|
|
|
|
-- AZ-535: snapshot endpoint pulls every revocation since <ts>; index on revoked_at
|
|
-- makes the "since" filter O(matching rows) instead of full-table scan.
|
|
CREATE INDEX IF NOT EXISTS sessions_revoked_at_idx
|
|
ON public.sessions (revoked_at)
|
|
WHERE revoked_at IS NOT NULL;
|
|
|
|
-- AZ-535: session-revoke and snapshot endpoints both write/read these columns;
|
|
-- existing grants in 08_sessions.sql already cover the table, so no new grants
|
|
-- needed.
|