Audit & Compliance Posture

This document describes how Hexarch produces, retains, verifies, and exports audit evidence.

Evidence Production

What Gets Recorded

Every significant event produces an audit record:

Event TypeTriggerRecorded Data
Policy Decision/authorize callaction, resource, decision, reason, matched policies
Policy ChangeCRUD on /policiesbefore/after state, actor, timestamp
Rule ChangeCRUD on /rulesbefore/after state, actor, timestamp
Configuration DeploymentSnapshot appliedsnapshot ID, target clusters, actor, justification
Subscription ChangeEntitlement modifiedapp ID, API version, plan, status change
Force ReconciliationAdmin overridetarget node/cluster, justification, actor

Audit Record Structure

From the AuditLog interface and SSE stream events:

interface AuditLog {
  id: string;
  timestamp: string;
  action: string;          // CREATE, UPDATE, DELETE, DECISION
  entity_type: string;     // policy, rule, subscription, config
  entity_id: string;
  actor_id: string;
  actor_type: 'user' | 'api_key' | 'system';

  // Chain linkage
  entry_hash: string;      // SHA-256 of this record
  prev_hash: string;       // Hash of previous record
  chain_id: string;        // Which chain (default: 'global')

  // Content
  payload: Record<string, unknown>;
  merkle_root?: string;    // Commitment to payload fields
  signature?: string;      // Authority signature
}

Actor Attribution

Every record includes who performed the action:

// From request headers
'X-Actor-Id': 'admin@example.com'
'X-Actor-Type': 'user'

// Recorded in audit log
actor_id: 'admin@example.com'
actor_type: 'user'

System-initiated actions (scheduled jobs, reconciliation) use actor_type: 'system' with an identifier for the process.

Evidence Retention

Default Retention

From the AuditLogs.tsx compliance note:

// Logs older than 90 days are archived to long-term storage
// per SOC2 retention requirements

Active storage: 90 days of audit logs in the primary database, queryable via API.

Archive storage: Older records are moved to long-term storage (configurable destination). The chain remains continuous—archival doesn’t break hash links.

Chain Continuity

When records are archived:

  1. The prev_hash of the first post-archive record points to the last archived record
  2. Verification requires access to both active and archived storage
  3. Export functions can produce complete chains spanning both

Retention Configuration

Retention periods are configurable per deployment:

Evidence Verification

Chain Verification

The /audit-logs/verify endpoint checks chain integrity:

// Request
GET /audit-logs/verify?chain_id=global

// Response (success)
{
  "ok": true,
  "chain_id": "global",
  "records_verified": 15847,
  "first_record": "2024-01-01T00:00:00Z",
  "last_record": "2024-03-15T14:32:01Z"
}

// Response (failure)
{
  "ok": false,
  "chain_id": "global",
  "error": "hash_mismatch",
  "broken_at": "rec_12345",
  "expected_prev_hash": "abc123...",
  "actual_prev_hash": "def456..."
}

What Verification Proves

CheckProvesDoesn’t Prove
Hash chain intactRecords weren’t altered after creationRecords were accurate when created
Signature validRecord was signed by expected authorityAuthority wasn’t compromised
No gapsAll records in sequence are presentNo records were prevented from being created

Verification Frequency

Recommendations:

Evidence Export

Export Formats

From the AuditLogs.tsx component:

// CSV export for spreadsheet analysis
exportFormat: 'csv'

// JSON export for programmatic verification
exportFormat: 'json'

Evidence Bundle Structure

A complete evidence bundle includes:

{
  "export_timestamp": "2024-03-15T14:32:01Z",
  "chain_id": "global",
  "verification_status": "ok",
  "records": [
    {
      "id": "rec_001",
      "entry_hash": "...",
      "prev_hash": "...",
      "payload": { ... }
    }
  ],
  "chain_summary": {
    "first_hash": "...",
    "last_hash": "...",
    "record_count": 1500
  }
}

Selective Disclosure Export

For privacy-sensitive exports, Merkle proofs enable partial disclosure:

{
  "disclosed_fields": ["actor_id", "decision", "timestamp"],
  "redacted_fields": ["payload.user_email", "payload.request_body"],
  "merkle_proof": {
    "root": "...",
    "path": ["...", "..."]
  }
}

The proof allows verification that disclosed fields were part of the original record without revealing redacted fields.

Compliance Mapping

SOC 2

ControlHexarch Capability
CC6.1 - Logical accessPolicy-based authorization with audit
CC6.2 - Access authenticationActor attribution on all records
CC6.3 - Access authorizationVersion-locked entitlements, approval workflows
CC7.2 - System monitoringReal-time SSE streams, fleet cohesion metrics
CC7.3 - Change detectionHash chain verification, configuration drift detection

GDPR

RequirementHexarch Capability
Right to accessExport audit logs filtered by actor
Right to erasureSelective disclosure hides PII while preserving proof
Data minimizationMerkle proofs allow partial evidence without full payload
AccountabilityComplete audit trail of all processing decisions

HIPAA

SafeguardHexarch Capability
Access controlsPolicy enforcement with fail-closed default
Audit controlsHash-linked, tamper-evident audit chain
Integrity controlsCryptographic verification of records
Transmission security(Dependent on deployment TLS configuration)

Auditor Workflow

For external auditors reviewing Hexarch evidence:

  1. Request evidence bundle for the audit period
  2. Verify chain integrity using provided verification tools or independent implementation
  3. Validate signatures if signed evidence is required
  4. Review selective disclosures with Merkle proof validation
  5. Cross-reference with independent system logs if desired

The evidence is self-validating. Auditors don’t need to trust the Hexarch UI or database—they can verify the chain independently.

Further Reading