Audit Log
Query the org-scoped audit trail — who did what, when
Audit API
State-changing API calls are recorded in the audit_log table — app operations, cluster registrations, secret-store changes, webhook events, team creation, remediation approvals. Entries are org-scoped and immutable.
Endpoints
List Audit Entries
GET /api/v1/auditPermission: audit:read (every org role except Viewer has it).
Query Parameters
| Parameter | Type | Description |
|---|---|---|
limit | int | Max results (default 50, max 200) |
offset | int | Pagination offset |
There are no actor/action/resource/from/to filters — the endpoint only pages. Filtering server-side is a good first issue; until then, page and filter client-side.
Response — 200 OK
{
"entries": [
{
"id": 182,
"created_at": "2024-01-15T10:30:00Z",
"user_id": "usr_01H8X2K3",
"action": "app.sync",
"resource_type": "app",
"resource_id": "my-app",
"resource_name": "my-app",
"details": { "operation": "Sync", "revision": "a1b2c3d4e5f6" }
},
{
"id": 181,
"created_at": "2024-01-15T10:28:15Z",
"user_id": "",
"action": "incident.emit",
"resource_type": "incident",
"resource_name": "deploy/my-app",
"details": { "title": "…", "severity": "warning" }
}
],
"limit": 50,
"offset": 0
}Fields are ordered newest-first. user_id is empty for system/caller-less actions (webhook deliveries, tag poller).
Audited Actions
From the handlers (server/internal/handler) — the actual values emitted:
| Action | Emitted by |
|---|---|
app.create | POST /apps |
app.delete | DELETE /apps/{ns}/{name} |
app.sync / app.deploy / app.rollback / app.restart / app.approve | operation endpoints |
app.scale / app.freeze / app.unfreeze | workload controls |
app.promote / app.clone / app.adopt | pro endpoints |
cluster.register / cluster.update / cluster.remove / cluster.test | /clusters |
cluster.shell | POST /clusters/{name}/shell |
team.create | POST /teams |
webhook.create / webhook.delete / webhook.test | /webhooks |
incident.emit | POST /incidents |
secretstore.create / secretstore.update / secretstore.delete / secretstore.test | /secret-stores |
registry.create / registry.update / registry.delete / registry.test | /registries |
remediation.approve / remediation.reject | /remediations (MCP) |
apikey.create / apikey.revoke | /auth/api-keys |
Example
Paginated export
offset=0
while true; do
curl "http://localhost:8080/api/v1/audit?limit=200&offset=$offset" \
-b cookies.txt > "audit-$offset.json"
count=$(jq '.entries | length' "audit-$offset.json")
[ "$count" -lt 200 ] && break
offset=$((offset + 200))
doneRetention
📋 Not implemented — entries accumulate indefinitely; there is no TTL or AUDIT_RETENTION_DAYS setting.
Access Control
GET /auditrequiresaudit:read— held by orgOwner,Admin, andContributor;Viewercannot read it- Entries are immutable — no API can edit or delete them
- Entries are org-scoped — callers only see their own org's log
Related
- Server Overview —
audit_logtable schema - RBAC — who can see what