Skip to content

Audit trail

Audit Trail is a read-only view over what happened on the deployment — there is nothing to edit or configure here. Use it to answer “who did this, and when,” whether you are investigating an incident, confirming a change actually landed, or checking whether a scheduled job ran.

  1. Choose User or System events

    User events are actions a person took; System events are platform-generated (for example a scheduled job firing). Each has its own tab.

  2. Filter

    Narrow by date range (with quick presets like 30 minutes, today, yesterday, 7 days, or 30 days, plus an explicit From/To), event type, project, user, or errors-only.

  3. Use the heatmap

    A calendar-style heatmap shows activity density over time, so a spike is visible before you drill into individual events.

Audit Trail page with heatmap and filtered table

A second view mode, alongside events, shows execution traces and their individual spans — each row names the action and, when there is one, the tool or model that ran it. Spans can be filtered by duration band (under 10 ms, up to over 10 seconds), which is the fastest way to find what is running slowly across the deployment rather than one conversation at a time.

From the Users page’s row menu, the activity drawer filters this same audit data to one account — useful when investigating a specific person’s actions rather than browsing the whole trail. See Users and roles.

Audit Trail is the place to look; it is not where evidence should be kept. The hash chain on security audit events makes tampering detectable, but immutability and long retention belong to your SIEM or WORM store. Elitea sends two streams there, in one versioned envelope, elitea.audit.v1:

  • Security audit events from the security audit outbox (credential decisions, grant, binding, mandate and delegation changes). These exist when enterprise credential governance is on. Approval events (ai.elitea.security.v1.agent.approval) are written for every run, with or without governance: one event for each pause, decision, timeout and unattended outcome of a sensitive tool or review node. Each stop by the agent circuit breaker writes one ai.elitea.security.v1.agent.breaker event (action agent.breaker.tripped) with the rule, the observed value and the limit. Each change of the platform preamble writes one ai.elitea.security.v1.config.changed event (action config.platform_preamble.revised) with the revision and the SHA-256 of the text. Each OIDC relink writes one ai.elitea.security.v1.identity.link.changed event (action identity.oidc_link.replaced, .cleared or .added) with the user and the operator. It holds no subject and no hash of one. Each event carries its position in the tamper-evident chain.
  • The audit trail on this page (centry.audit_events): one event per completed request, scheduled job or admin task.

Two transports are built in, and you can use either or both:

TransportUse it whenSet
OTLP logsYour collector or SIEM speaks OpenTelemetryELITEA_AUDIT_EXPORT_OTLP_ENDPOINT
Signed webhookYou run your own receiver, or a SIEM with an HTTP intakeELITEA_AUDIT_EXPORT_WEBHOOK_URL and ELITEA_AUDIT_EXPORT_WEBHOOK_KEYS_FILE

With neither set, export is off, no relay starts and nothing dials out. The full list of settings is in Post-install configuration, and the field-by-field schema, a sample event, signature verification and a collector configuration are in the audit event schema reference.

  • At least once. A row is marked exported, or a receiver’s position in the audit trail advances, only after that receiver accepted it. If your receiver is down, nothing is lost: events wait and are sent in order when it returns. Deduplicate on event_id.
  • No row is skipped. The audit trail is read in commit order: a row is exported only once every transaction that could still add an earlier row has finished. A long-running database write transaction therefore delays export (the lag alert shows it) rather than letting a late row slip past.
  • Each receiver has its own position. With both transports on, a receiver that is down does not make the healthy one receive the same events again; when it returns it resumes from where it stopped.
  • Asynchronous. Export runs in background relays. It never slows or fails the request or run that produced the event, and it holds no database transaction open while it calls your receiver.
  • Outages do not drop evidence. When the webhook receiver refuses a batch as malformed or too large (HTTP 400, 413 or 422), Elitea splits it in halves and sends each again, down to single events, so the other events in the batch are delivered. Only a single event the receiver refuses on its own, on five passes, is dead-lettered, by itself. A receiver that is down, rate limiting, or rejecting your credentials (401, 403, 404, 429, 5xx) is never dead-lettered; the lag alert fires instead. A security audit record that cannot be decoded is dead-lettered alone (sink decode) and the rest of its batch is sent. A dead-lettered event is still in its source table and is also listed in elitea_runtime.audit_export_dead_letters.
  • Retention never outruns the export. While audit export is on, the audit trail retention sweep in elitea-scheduler does not delete a row that has not yet reached every receiver, however old it is. If you switch the export off, delete its positions (DELETE FROM elitea_runtime.audit_export_cursors WHERE stream = 'admin_audit') so retention resumes; the scheduler logs a warning while it is holding rows back for a position that has not moved within the retention window.
  • Egress is guarded. A webhook receiver on a private or loopback address is refused unless ELITEA_AUDIT_EXPORT_EGRESS_ALLOWLIST names it. Redirects are never followed.

Each approval event names the actor (principal_ref, user:<id> or system:elitea-main), the outcome (data.action, for example agent.approval.approved or agent.approval.unattended_failed), the tool (tool_name), the toolkit (toolkit_name) and the SHA-256 digest of the tool arguments (arguments_digest). The arguments are never in the event. invocation_id is the interrupt id, and decision_id is the row of elitea_runtime.approval_ledger. See Approval evidence and unattended runs.

  • It does not make the stored events immutable, and it does not retain them for you. Keeping them is your SIEM’s job; the shared-responsibility split is in the enterprise controls section.
  • Existing audit trail history is not replayed by default. Export starts at the newest row when you turn it on; a row still being written at that exact moment may count as history. Set ELITEA_AUDIT_EXPORT_AUDIT_EVENTS_FROM to beginning before the first start to send the whole table.
  • Audit trail rows are not chained yet, so the chain object is present only on security audit events.

elitea-main serves Prometheus metrics for the export on port 9464 (ELITEA_AUDIT_EXPORT_METRICS_ADDR): elitea_audit_export_lag_seconds, elitea_audit_export_backlog, and the delivered, failed and dead_lettered counters. The chart ships a PodMonitor and three alerts, EliteaAuditExportLag, EliteaAuditExportBacklog and EliteaAuditExportDeadLettered, wherever the Prometheus Operator API is served. The same port serves the runtime safety metrics and has their alerts (see Agent circuit breaker).