code<spar>

Audit API

Query the append-only audit trail with pagination, filtering by risk level, and hash chain integrity verification.

Audit API

CodeSpar maintains an append-only audit trail of all agent actions, user commands, and system events. Every entry is cryptographically linked to the previous one via a hash chain, ensuring tamper-evident integrity.

Query Audit Entries

Retrieve paginated audit log entries with optional filtering.

GET /api/audit

Query Parameters

ParameterTypeDefaultDescription
limitinteger20Entries per page (max: 100)
pageinteger1Page number (1-indexed)
riskstringallFilter by risk level: low, medium, high, critical, all

Request

curl "http://localhost:3000/api/audit?limit=20&page=1"

With risk filtering:

curl "http://localhost:3000/api/audit?limit=10&page=1&risk=high"

With multi-tenant scoping:

curl "http://localhost:3000/api/audit?limit=20&page=1" \
  -H "x-org-id: org-acme-corp"

Response

{
  "entries": [
    {
      "id": "audit-001",
      "timestamp": "2024-01-15T14:32:00Z",
      "actorType": "user",
      "actorId": "slack:U1234ABCD",
      "action": "deploy",
      "result": "approved",
      "metadata": {
        "target": "staging",
        "commit": "abc1234",
        "branch": "main",
        "approvedBy": "slack:U5678EFGH",
        "approvalToken": "dp-a1b2c3",
        "duration": 105
      },
      "hash": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    },
    {
      "id": "audit-002",
      "timestamp": "2024-01-15T14:30:00Z",
      "actorType": "agent",
      "actorId": "agent-proj-abc123",
      "action": "review",
      "result": "completed",
      "metadata": {
        "prNumber": 42,
        "repo": "codespar/codespar",
        "verdict": "approve_with_suggestions",
        "suggestions": 2
      },
      "hash": "sha256:d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592"
    },
    {
      "id": "audit-003",
      "timestamp": "2024-01-15T14:28:00Z",
      "actorType": "system",
      "actorId": "webhook-handler",
      "action": "ci_event",
      "result": "processed",
      "metadata": {
        "event": "workflow_run",
        "repo": "codespar/codespar",
        "status": "failure",
        "branch": "feature/auth"
      },
      "hash": "sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b"
    }
  ],
  "total": 150,
  "page": 1,
  "pageSize": 20,
  "totalPages": 8,
  "hasMore": true
}

Response Schema

Pagination Wrapper

FieldTypeDescription
entriesAuditEntry[]Array of audit entries
totalnumberTotal number of entries matching the filter
pagenumberCurrent page number
pageSizenumberEntries per page
totalPagesnumberTotal number of pages
hasMorebooleanWhether more pages exist

AuditEntry Schema

FieldTypeDescription
idstringUnique entry identifier
timestampstringISO 8601 timestamp
actorTypestringWho performed the action: user, agent, system
actorIdstringIdentifier of the actor (e.g., slack:U1234, agent-proj-abc123)
actionstringThe command or event (e.g., deploy, review, ci_event, kill)
resultstringOutcome: completed, approved, denied, failed, processed
metadataobjectAction-specific data (varies by action type)
hashstringSHA-256 hash linking this entry to the previous one

Actor Types

Actor TypeDescriptionExample actorId
userHuman user via a channelslack:U1234ABCD, whatsapp:5511999990000
agentCodeSpar agentagent-proj-abc123, agent-task-def456
systemInternal system eventwebhook-handler, scheduler, startup

Common Action Types

ActionActor TypeDescription
statususerUser queried status
instructuserUser requested a coding task
fixuser/agentIssue investigation triggered
reviewuser/agentPR review performed
deployuserDeployment requested or completed
rollbackuserRollback requested or completed
approveuserAction approved
denyuserAction denied
killuserEmergency kill switch activated
autonomy_changeuserAutonomy level changed
linkuserRepository linked
unlinkuserRepository unlinked
ci_eventsystemCI/CD webhook event received
agent_spawnsystemEphemeral agent created
agent_terminatesystemEphemeral agent completed and terminated
erroragent/systemError occurred during processing

Hash Chain Integrity

Each audit entry includes a hash field computed as:

hash = SHA-256(previousHash + timestamp + actorType + actorId + action + result + JSON(metadata))

The first entry in the chain uses a zero hash as the previous hash. This creates a tamper-evident log: modifying any entry would break the chain for all subsequent entries.

Verifying Integrity

To verify the audit chain integrity, iterate through entries in chronological order and recompute each hash:

import { createHash } from 'crypto';
 
function verifyChain(entries) {
  let previousHash = '0'.repeat(64); // genesis hash
 
  for (const entry of entries) {
    const payload = previousHash
      + entry.timestamp
      + entry.actorType
      + entry.actorId
      + entry.action
      + entry.result
      + JSON.stringify(entry.metadata);
 
    const expectedHash = 'sha256:' + createHash('sha256')
      .update(payload)
      .digest('hex');
 
    if (entry.hash !== expectedHash) {
      return { valid: false, brokenAt: entry.id };
    }
 
    previousHash = entry.hash.replace('sha256:', '');
  }
 
  return { valid: true };
}

Retention

Audit entries are retained for 365 days by default. After the retention period, entries are archived (if configured) or deleted.

SettingDefaultDescription
Retention period365 daysHow long entries are kept
StorageFile-based (.codespar/audit/)Default storage backend
ArchiveNot configuredOptional external archive (S3, etc.)

Examples

Get the latest 5 entries

curl "http://localhost:3000/api/audit?limit=5&page=1"

Get only high-risk actions

curl "http://localhost:3000/api/audit?risk=high&limit=50"

Get only critical actions (deploys, rollbacks, kills)

curl "http://localhost:3000/api/audit?risk=critical&limit=20"

Paginate through all entries

# Page 1
curl "http://localhost:3000/api/audit?limit=50&page=1"
 
# Page 2
curl "http://localhost:3000/api/audit?limit=50&page=2"
 
# Continue until hasMore is false

Next Steps