Files
vantage-docs/docs/vantage/audit-log.md
T
mrhid6 bd7b3256fc feat(audit): server-side paging, search and category filter; one event format
The page rendered a map of eleven event types to labels and seven to colours.
The server emits forty-seven. Everything unmapped fell through to its raw
string, so "Key Assigned" in green sat above "workflow.schedule_updated" in
grey — the same kind of fact in two formats, which made the column look like it
carried a meaning it did not.

Presentation is now derived rather than enumerated. Event types are named
<category>.<action> by every call site, so the category becomes a chip, the
action is humanised, and the tone comes from the verb. A type added to the
server tomorrow gets a sensible label and colour with no second list to update;
the override table holds only the dozen the rule reads badly for. Every row is
one treatment, and colour never carries meaning alone — the sentence beside it
says the same thing in words.

Paging and filtering are server-side, unlike the fleet lists that answer with
everything and slice in the browser. audit_retention_days is a licensed
entitlement measured in months, and this log is read to answer questions about
the past, so a browser filtering the most recent page would report "no results"
for events that exist. GET /api/audit now takes q, category, limit and skip and
answers {events, total} — a short page is not evidence of the end of the log,
which is why the total is counted rather than inferred.

audit_logs had no indexes at all: every read was a collection scan with an
in-memory sort over an append-only collection. Adds (instance_id, created_at)
and warns rather than failing, matching EnsureSecretIndexes.

Two bugs found by running the deriver over all forty-seven real types rather
than eyeballing it: the tone rules matched only past-tense verbs, leaving
auth_provider.delete drawn as neutral beside key.deleted in red; and
"unaccepted" matched "accepted", so withdrawing an acceptance read as the same
caution as granting one.
2026-08-10 15:25:48 +01:00

2.2 KiB

id, title, sidebar_label
id title sidebar_label
audit-log Audit log Audit log

Every mutating API path writes an audit event. The log is at Audit.

What an event carries

Field Meaning
Action A dotted name, e.g. server.created, settings.updated
Actor Who did it
Target The object acted on
Detail A short human-readable note
Time When

What is recorded

Creation, modification and deletion across the product: servers and enrolments, keys and assignments, workflow and step changes, runs triggered, monitors and channels, secret groups and reveals, console sessions opened, settings and member changes, licence installs.

Reads are not recorded, with one deliberate exception: revealing a secret writes an event, because reading that particular thing is an act rather than a lookup.

What is not recorded

  • Sign-ins and sign-out.
  • Anything inside a console session.
  • Step output. That lives in the run log, kept under the workflow retention setting rather than with the audit log.

Retention

Audit events are not swept by the workflow log retention setting that setting governs run logs only. Audit history stays until the instance does.

:::warning It is a log, not a control The audit log tells you what happened. It does not restrict what can happen, and an admin can do anything an admin can do. Use roles for restriction and the log for accountability. :::

Getting events out

GET /api/audit returns one page of events as JSON:

{ "events": [ ... ], "total": 3214 }

It accepts limit (default 50, maximum 200), skip, q to search actor, details and event type, and category to match the part of an event type before the dot — workflow, key, server. total counts everything matching the filter, not the page, so a short page is not the end of the log.

There is no streaming or push export; if you need events in a SIEM, poll that endpoint, walking skip until you have total.