Files
git.stella-ops.org/docs/modules/release-orchestrator/security/audit-trail.md

5.5 KiB

Audit Trail

Audit event structure and audited operations for compliance and forensics.

Status: Planned (not yet implemented) Source: Architecture Advisory Section 8.5 Related Modules: Evidence Module, Security Overview Sprints: 109_001 Evidence Collector

Overview

The Release Orchestrator maintains a tamper-evident audit trail of all security-relevant operations. Audit events are cryptographically chained to detect tampering.


Audit Event Structure

TypeScript Interface

interface AuditEvent {
  id: UUID;
  timestamp: DateTime;
  tenantId: UUID;

  // Actor
  actorType: "user" | "agent" | "system" | "plugin";
  actorId: UUID;
  actorName: string;
  actorIp?: string;

  // Action
  action: string;              // "promotion.approved", "deployment.started"
  resource: string;            // "promotion"
  resourceId: UUID;

  // Context
  environmentId?: UUID;
  releaseId?: UUID;
  promotionId?: UUID;

  // Details
  before?: object;             // State before (for updates)
  after?: object;              // State after
  metadata?: object;           // Additional context

  // Integrity
  previousEventHash: string;   // Hash chain for tamper detection
  eventHash: string;
}

Audited Operations

Category Operations
Authentication Login, logout, token refresh, failed attempts
Authorization Permission denied events
Environments Create, update, delete, freeze window changes
Releases Create, deprecate, archive
Promotions Request, approve, reject, cancel
Deployments Start, complete, fail, rollback
Targets Register, update, delete, health changes
Agents Register, heartbeat gaps, capability changes
Integrations Create, update, delete, test
Plugins Enable, disable, config changes
Evidence Create (never update/delete)

Hash Chain

Chain Verification

The audit trail uses SHA-256 hash chaining for tamper detection:

interface HashChainEntry {
  eventId: UUID;
  eventHash: string;
  previousEventHash: string;
}

function computeEventHash(event: AuditEvent): string {
  const payload = JSON.stringify({
    id: event.id,
    timestamp: event.timestamp,
    tenantId: event.tenantId,
    actorType: event.actorType,
    actorId: event.actorId,
    action: event.action,
    resource: event.resource,
    resourceId: event.resourceId,
    previousEventHash: event.previousEventHash,
  });

  return sha256(payload);
}

function verifyChain(events: AuditEvent[]): VerificationResult {
  for (let i = 1; i < events.length; i++) {
    const current = events[i];
    const previous = events[i - 1];

    if (current.previousEventHash !== previous.eventHash) {
      return {
        valid: false,
        brokenAt: i,
        reason: "Hash chain broken"
      };
    }

    const computed = computeEventHash(current);
    if (computed !== current.eventHash) {
      return {
        valid: false,
        brokenAt: i,
        reason: "Event hash mismatch"
      };
    }
  }

  return { valid: true };
}

Example Audit Events

Promotion Approved

{
  "id": "evt-123",
  "timestamp": "2026-01-09T14:32:15Z",
  "tenantId": "tenant-uuid",
  "actorType": "user",
  "actorId": "user-uuid",
  "actorName": "jane@example.com",
  "actorIp": "192.168.1.100",
  "action": "promotion.approved",
  "resource": "promotion",
  "resourceId": "promo-uuid",
  "environmentId": "env-uuid",
  "releaseId": "rel-uuid",
  "promotionId": "promo-uuid",
  "before": {
    "status": "pending"
  },
  "after": {
    "status": "approved",
    "approvals": 2
  },
  "metadata": {
    "comment": "LGTM"
  },
  "previousEventHash": "sha256:abc...",
  "eventHash": "sha256:def..."
}

Deployment Started

{
  "id": "evt-124",
  "timestamp": "2026-01-09T14:32:20Z",
  "tenantId": "tenant-uuid",
  "actorType": "system",
  "actorId": "system",
  "actorName": "deployment-orchestrator",
  "action": "deployment.started",
  "resource": "deployment",
  "resourceId": "deploy-uuid",
  "environmentId": "env-uuid",
  "releaseId": "rel-uuid",
  "promotionId": "promo-uuid",
  "after": {
    "status": "deploying",
    "strategy": "rolling",
    "targetCount": 5
  },
  "previousEventHash": "sha256:def...",
  "eventHash": "sha256:ghi..."
}

Retention Policy

Environment Retention Period
All tenants 7 years (compliance)
After tenant deletion 7 years (legal hold)
Archive format NDJSON, signed

Export Format

Audit events can be exported for compliance reporting:

# Export audit trail for a date range
GET /api/v1/audit/export?
  start=2026-01-01T00:00:00Z&
  end=2026-01-31T23:59:59Z&
  format=ndjson

Response includes signed digest for verification:

{
  "export": {
    "startDate": "2026-01-01T00:00:00Z",
    "endDate": "2026-01-31T23:59:59Z",
    "eventCount": 15234,
    "firstEventHash": "sha256:abc...",
    "lastEventHash": "sha256:xyz...",
    "downloadUrl": "https://..."
  },
  "signature": "base64-signature",
  "signedAt": "2026-02-01T00:00:00Z"
}

See Also