Skip to content

Authorization

Authorization is role-based with rank and row-level overlays, enforced server-side on every protected route and re-checked inside the database for the operations that matter most. Frontend visibility (which buttons render) mirrors these rules for usability only — it is never the security boundary.

The layers

text
1. Identity        browser session (live agents row) or API key
2. Clearance       clearance_level ≥ threshold (CLEARANCE_POLICY)
3. Rank            supervisor / reassignment / Director gates
4. Allowlist       admin_users table (System Administration)
5. Row-level       assignment + supervisor-flag checks per report
6. Database        RPC whitelists, rank/self-edit guards, row locks

Clearance-based authorization

CLEARANCE_POLICY (in authz.py) maps capabilities to minimum clearance levels 1–5. /auth/me returns every flag; authorize_dashboard(permission) enforces it. The full table is in the Permissions reference.

Key entries: view_dashboard 1, view_agents 1, view_analytics 2, add_case_note/add_evidence 1, manage_dockets 2, reassign_docket 4, decide_appeal 4, manage_agents 5, delete_docket 5, view_punishments 2, manage_punishments 4.

Clearance is checked against the live agents row every request — a demotion takes effect immediately, independent of any cached frontend state.

Rank-based authorization

Ranks (lowest → highest): Trial Agent, Probationary Agent, Agent, Senior Agent, Head Investigator, Lead Agent, Director, Department Director.

GateRank requirement
Supervisor reports, supervisor queue, audit visibility, trainer eligibilitySenior Agent +
Case reassignmentHead Investigator +
Director-only admin capabilities (admin_reports, admin_schema, access management)Director / Department Director
Rank/clearance changes on other agentsDirector (via rpc_admin_agent_update guards)

Director authority is derived from the live rank — a demotion to Lead Agent revokes Director capabilities immediately even if clearance_level is left untouched. This is enforced both in authz.py and inside the RPCs (admin_requester_is_director).

Agent permissions and claims

  • Assignment claims: a report's assigned_agent is compared exactly (never prefix/substring) against the caller's identifiers — Name (userid) forms split and compare the userid against discord_id/agent_id/name. Unassigned is never a match. Only the assigned agent (or supervisor rank) may update, note, evidence, timeline, action, or contact a case.
  • Supervisor reports: is_supervisor rows are invisible to agents below Senior Agent: list items are replaced with restricted placeholders, supervisor counts are zeroed, and row-level routes return 403.
  • Claim: claiming requires manage_dockets; the database rejects claims on already-assigned cases (ALREADY_CLAIMED).

Supervisor/admin restrictions

  • System Administration (require_admin) requires, in order:
    1. a valid browser session (the API key is always rejected — 403);
    2. membership in admin_users with active = true;
    3. the clearance level for the specific capability;
    4. Director rank for Director-only capabilities (admin_reports, admin_schema, access management) — a Lead Agent with clearance 5 is still rejected.
  • Hierarchy guard: admins may only modify agents at or below their own rank (_rank_ge + DB RANK_MANAGE_REQUIRED).
  • Self-modification is blocked entirely (SELF_PROMOTION_BLOCKED) — nobody can edit their own agent record, preventing both self-promotion and soft-locking yourself out of the site.
  • Directors are protected: they cannot be removed from the admin allowlist (DIRECTOR_PROTECTED).

Mutation authorization

Every mutation type re-checks its own authorization inside the authoritative RPC:

MutationAPI gateDB re-check
Report actionsmanage_dockets + assignment + supervisor rowstatus guard under row lock
Report updatemanage_dockets/reassign_docket + assignment(whitelist at API; RPC for actions)
Report deletedelete_docket + reasonpre-image + audit in transaction
Agent updateadmin_agents + allowlist + reasonfield whitelist, Director/rank/self-edit guards
Punishment CRUDview_punishments/manage_punishmentsfield whitelist, status enum, revoke guard
Admin queue/access/schemaadmin_* + allowlist (+ Director)p_requester_id Director checks
Training controlstrainer role + session ownership(API-owned; no RPCs)

Ownership/claim restrictions

  • Reports are owned by their assigned_agent (or claimable when unassigned); supervisors can act on any case.
  • Training sessions are owned by their trainer_id for controls and their trainee_id for trainee views; the trainee is additionally locked to active/paused/completed states (NO_ACTIVE_SESSION otherwise).
  • Punishments are issuer-recorded but not issuer-owned: management is clearance-gated (manage_punishments), not ownership-gated.