Forgeplane audit logging
Forgeplane audit logging records the actor, action, resource, and state transition for meaningful platform operations. Records are immutable and sensitive values are redacted before storage.
Automatic cleanup of audit_records runs when the coordinator starts and then
daily. Each cleanup reloads audit_retention_days, so a change applies to the
next cleanup without a restart. Supported periods are 30, 90, or 365 days; the
default is 90 days. The same policy applies to every action and outcome, including
security events such as authentication and authorization denials. Shortening the
window makes existing history older than the new window, including security
history, eligible to expire on the next cleanup. Records strictly older than the
fixed UTC cutoff expire; records exactly at the cutoff remain.
Retention uses the server-controlled recorded_at value. Occurrence time does not control retention, and redelivery does not reset recording time.
Cleanup deletes receipts for activity records with their history in the same transaction. It retains receipts for all other records and does not delete active execution-recovery state. A cleanup or policy-load failure is reported by the audit readiness check until a later cleanup succeeds.
Recording and history surfaces
Section titled “Recording and history surfaces”Coordinator writers store required evidence in audit_records. A record for a database mutation is committed in the same transaction as that mutation; if required evidence cannot be recorded, the mutation rolls back. Security denials remain denied when their independently committed evidence cannot be recorded, and the coordinator emits a safe recording-failure signal.
Records distinguish authenticated users, service accounts, scoped plugin background principals, named system principals, explicit processes, and anonymous authentication attempts. A receipt makes repeated delivery of the same occurrence idempotent and detects conflicting evidence. Receipts are not history. Activity receipts expire with their history because activity has no delivery owner or acknowledgement lifecycle. Non-activity receipts remain available for recovery after the corresponding history record expires. This includes every administrator_recovery.attempt outcome.
Plugin permission commands record the actual caller and captured ownership scope; internal invocation admission records the actual root/background actor separately from initiating provenance. A background actor is not an administrator or System fallback. Grant, ceiling and background-identity mutations commit their required audit and command result atomically. Historical evidence is not current execution authority; see Plugin action permissions.
Registry command receipts
Section titled “Registry command receipts”Registry command receipts are separate from audit occurrence receipts. Core plugin resource changes and permitted parent deletions commit their minimal command result, revisions and required audit atomically. These results retain original authoritative attribution and an audit reference without command keys, credentials or plugin feature content. Audit-history expiration does not erase the longer-lived command result or block existing audit cleanup.
The freshly authenticated original caller can reconcile that result even after membership or owning Team/Organization deletion. It is historical evidence, not authorization for a new write, restoration or execution. An absent receipt is not rollback proof. See original-key outcomes.
The history API, admin viewer, and export service read audit_records. Access is checked against the historical scope captured with each record, not current resource ownership or the active Team selector alone. User scope records historical user ownership; it does not grant the named user access, and Team-scoped reads exclude it. Missing and inaccessible details share the same private response.
Audit history is separate from execution acknowledgement and state-recovery evidence. The owner of an operation retains the state needed to recover or redeliver it; audit retention does not replace or delete that state.
External execution attempts keep their intent, safe outcome fingerprint, immutable receipt, and pending projection state independently of audit-history cleanup. The signed outcome envelope remains in the delivery stream only until the coordinator acknowledges it. Equivalent outcome redelivery reuses the receipt. Conflicting or stale evidence is rejected rather than rewriting history or completing another attempt.
Operator health and recovery
Section titled “Operator health and recovery”The authorized System Settings page and internal readiness expose one bounded audit check. It identifies:
- unavailable recorder configuration or storage;
- cleanup that has not completed or has failed;
- unresolved external outcomes; and
- pending or retrying terminal-outcome projection.
The signal contains safe reason codes, effective retention, timestamps, and remediation. It does not contain event evidence, resource identifiers, raw database errors, or secrets. A successful audit write clears a recording-availability failure. A successful cleanup clears a retention failure. Outcome projection recovery retries automatically without repeating the external effect.
For an unresolved outcome, do not infer that an absent or expired history record means the external effect did not happen. Inspect the retained Run and attempt state, allow a late signed outcome when available, and make cancellation or explicit requeue a separate operator decision.
Recorded operations
Section titled “Recorded operations”Audit records are grouped by operation area:
| Category | Examples |
|---|---|
| Authentication | auth.login.succeeded, auth.login.failed, auth.logout |
| Profile | Password changes and API-key regeneration |
| Instances and runs | Plan, apply, destroy, cancellation, failure, and version events |
| Drift | Finding creation, updates, action requests, resolution, reopening, and suppression |
| Registry | Template creation, validation, version creation, updates, and deletion |
| Plugin authority | plugin.action_grant.created, plugin.action_grant.revoked, plugin.installation_grant.changed, background-identity changes and plugin.invocation.admitted |
| Approval | run.approval.requested, run.approval.approved, run.approval.rejected |
Service-account activity records the service-account actor identity.
Event fields
Section titled “Event fields”Each event returned by the history API includes:
| Field | Purpose |
|---|---|
recorded_at |
ISO 8601 server recording time |
occurred_at |
Source occurrence time when supplied |
actor |
Historical user, service-account, plugin-background, system, process, or anonymous provenance |
action |
Exact action name, such as run.created |
outcome |
succeeded, failed, denied, pending, or unresolved |
resource_type / resource_id |
Affected resource |
scope |
Captured platform, Team, project, user, or unknown ownership scope |
correlation |
Available request, Run, attempt, and causation identifiers |
before_evidence / after_evidence |
Absent, complete, or incomplete safe evidence |
Complete before and after evidence makes resource changes reviewable without relying on application logs alone. Incomplete evidence remains visibly marked with its reason and measured limits; it is never presented as absent or complete.
Redaction and payload limits
Section titled “Redaction and payload limits”Sensitive data is redacted from audit state before storage. Sensitive keys and credentials embedded in URL strings are redacted. Redaction applies to both before and after and cannot be disabled. Producers must still submit safe projections: redaction cannot identify a secret hidden in arbitrary prose or an error string, and raw request headers are not audit evidence.
The combined before and after evidence in audit_records is limited to 4 MB by default. Oversized evidence is represented as incomplete with the omission reason, safe size, and configured limit; no public content digest is stored. Recovery checkpoints retain the complete redacted evidence when it is required for safe redelivery.
Audit records are evidence, not a secret store. Do not use the audit log to transport credentials or large artifacts.
Execution outcome projections likewise exclude raw tool output, raw errors, secret material, and digests derived from secret material. Recovery notes should contain only identifiers, timestamps, states, and safe reason codes. See Recover an unresolved execution.
Query and pagination
Section titled “Query and pagination”GET /api/v1/audit/actions returns the code-owned action catalog used for
filter discovery: action, label, supported outcomes, required evidence side, and
recording mode. It does not return observed event counts or last-seen timestamps.
Those activity statistics are not part of the vocabulary contract.
The history API filters canonical records by:
- date range;
- actor principal or process ID;
- resource type;
- project; and
- exact action string.
Filters can be combined. Queries use cursor-based pagination ordered by server recording time and record ID, so equal timestamps remain deterministic. Follow the response’s next_cursor to fetch the next page.
High-volume worker lifecycle events are included by default. Pass hide_noisy=true to exclude worker.registered, worker.status_changed, and worker.offline events when investigating higher-signal activity.
By default, history excludes unknown-scope records and the authorization.denied
and authorization.failed actions, even when those actions have a Team or project
scope. Platform audit readers can pass include_security_events=1 to include
both sets in queries, individual details, and exports. The admin viewer offers
an Include security and unscoped events checkbox for platform readers.
Unknown scope does not grant Team access, and Team readers never see either set.
A Team-scoped request with include_security_events=1 returns 403. Other
values and repeated occurrences of this parameter return 400.
Export
Section titled “Export”Export the current filtered history view as CSV or JSON:
| Format | Use case |
|---|---|
| CSV | Spreadsheet analysis and compliance handoff |
| JSON | Programmatic processing and SIEM ingestion |
Exports retain the query filters and are bounded by:
| Limit | Value |
|---|---|
| Maximum events per export | 5,000 |
| Maximum export size | 32 MB |
| Concurrent exports | 2 |
A request that exceeds the measured encoded event or byte limit returns an error. A third concurrent export is rejected until a slot is free. Each export uses one database snapshot so records committed after selection starts cannot enter later pages. Authorization is checked again after serialization and before the attachment response is released; revoked access returns an error without an export attachment.
Admin viewer and investigation flow
Section titled “Admin viewer and investigation flow”The admin audit viewer supports filters for resource type, actor, action, and date range, expandable evidence, and export of the current filtered view. Details show outcome, occurrence and recording times, process/system provenance, historical Team and project IDs, correlation IDs, and incomplete-evidence reasons with observed and configured byte sizes. Comparisons and copy controls are available only for complete evidence values.
For an infrastructure incident:
- identify the resource and time window;
- filter by project, actor, and action;
- compare the redacted
beforeandafterstate; - follow linked run, approval, drift, or service-account records; and
- export the filtered evidence when another system must process it.
See Run operations, Approval workflows, and Service accounts for the related operational records.