Accounts, Roles & Audit

Every request to the test runner goes through the gateway, which owns authentication, role enforcement, and the audit trail. This page covers logging in, the three roles, the admin Users tab, the Activity audit log, and how cases are attributed to their author.

At a glance
  • Log in at the overlay — bearer-token session, throttled after ~5 bad tries.

  • Bootstrap account is admin / admin — rotate it immediately.

  • Three roles: admin (everything), editor (run + edit, no admin tabs), viewer (read/observe only).

  • Users / Settings / Workers / Activity tabs are admin-only.

  • Activity records logins, runs, imports, and user-management changes.

Auth is provided by the gateway (Environments & the Gateway). The store is a SQLite file (scripts/auth_db.pyrun-reports/test_runner.db) on the persistent volume, so accounts and the audit log survive redeploys.

Logging In

On first load the SPA shows a full-screen login overlay (everything else is hidden until isAuthed). Submitting the form calls POST /api/auth/login:

  • On success the server returns a token plus the user record; the SPA stores the token and sends it as Authorization: Bearer <token> on every subsequent call.

  • Sessions use a sliding TTL — each authenticated request refreshes last_seen; an idle session past the TTL is pruned and returns 401.

  • Logout (POST /api/auth/logout) deletes the server-side session.

  • GET /api/auth/me echoes the current identity (username + role).

Login is rate-limited: after 5 failed attempts within 60s (keyed by username|ip) the endpoint returns 429 Too many attempts. Try again later. A successful login clears the counter.

Bootstrap Account — Rotate It

On first boot the gateway seeds a single admin from config (admin / admin by default). This is a convenience for the very first login and is a known weak default on production deployments.

Change the bootstrap password (or replace the account) before exposing the runner. Log in as admin, create your own admin via the Users tab, then reset or delete the default. There is no forced password change on first login.

Changing a Password

Users do not self-service passwords — an admin resets them from the Users tab (POST /api/users/{username}/reset-password). Disabling a user also invalidates their active sessions, forcing a re-login.

Roles & Capabilities

The role is stored on the user row and constrained at the schema level (role IN ('admin','editor','viewer')). Capabilities:

Capability admin editor viewer

Log in; view Dashboard, Tests, Runner, Notes, Learning

Open a case in the Editor (read YAML)

Run a test / batch (POST /api/run, /api/run/batch)

Create / edit / delete cases; regenerate, reimport

Import from TestRail / upload YAML

Assign cases to a project

Settings tab

Users tab (manage accounts)

Workers tab (stands / profiles)

Activity tab (audit log)

In the SPA this maps to two guards: canRun() (true for admin + editor) gates every run/edit/import/delete button, and isAdmin() gates the four admin-only tabs. A viewer sees the data tabs with no action buttons — pure read/observe. The admin tabs and their endpoints are additionally server-enforced via require_role("admin").

New users default to the editor role when none is supplied.

Users Tab (admin)

The Users tab lists every account (GET /api/users) and exposes full lifecycle management:

Action Endpoint

Create user (username, password, role)

POST /api/users

Change role / enable / disable

PATCH /api/users/{username}

Reset password

POST /api/users/{username}/reset-password

Delete user

DELETE /api/users/{username}

  • Disable flips the disabled flag and clears the user’s sessions (immediate logout) without losing the account. Enable restores access.

  • Delete removes the account and its sessions outright.

Last-admin guard

You cannot delete the final active admindelete_user raises cannot delete the last admin (surfaced as 400) when the target is the only non-disabled admin. This stops you from locking everyone out via deletion.

The guard covers deletion only. Demoting or disabling the last admin is not blocked, so rotate the bootstrap account by adding a new admin first, then removing the old one.

Activity Audit Log

The Activity tab (admin-only) reads GET /api/activity — a reverse-chronological feed backed by the activity table. Each row captures ts, username, role, action, method, path, target, detail, ip, status. Filter by username or action (query params), with limit / offset paging. Auditing is best-effort and never blocks the request path; the table is bounded (oldest rows pruned past a retention cap).

Recorded actions include:

action Logged on

login / login_failed / login_blocked

Successful, rejected, and rate-limited sign-ins (with status 200/401/429)

run_start / batch_start / run_xml_start

A single run, a batch, or a pasted-XML run is triggered (target = case ID)

user_create / user_update / password_reset / user_delete

Account management from the Users tab

backfill_fields, profile / stand / project changes

Admin maintenance actions

Case Attribution & History

Separately from the activity feed, each YAML case carries authorship metadata in the case_meta table (created_by / created_at, edited_by / edited_at) plus an append-only case_history log. The runner records an event on every case mutation:

  • created / imported set the original author once (preserved on later edits).

  • edited / reimported update edited_by + edited_at and append history.

  • deleted appends history but does not overwrite the creator.

The Editor surfaces the Author and last-editor on each case, so you can see who created or last touched a YAML and trace its full edit history — useful when a converted case behaves unexpectedly after a manual edit.

See Also

  • Environments & the Gateway — the gateway that terminates auth and routes to stands.

  • Settings — admin-only environment configuration.

  • REST API — full endpoint reference, including the auth and user routes.