Files
git.stella-ops.org/docs/modules/release-orchestrator/appendices/evidence-schema.md

12 KiB

Evidence Packet Schema

Overview

Evidence packets are cryptographically signed, immutable records of deployment decisions and outcomes. They provide audit-grade proof of who did what, when, and why.

Evidence Packet Types

Type Description Generated When
release_decision Promotion decision evidence Promotion approved/rejected
deployment Deployment execution evidence Deployment completes
rollback Rollback evidence Rollback completes
ab_promotion A/B release promotion evidence A/B promotion completes

Schema Definition

Evidence Packet Structure

interface EvidencePacket {
  // Identification
  id: UUID;
  version: "1.0";
  type: EvidencePacketType;

  // Metadata
  generatedAt: DateTime;
  generatorVersion: string;
  tenantId: UUID;

  // Content
  content: EvidenceContent;

  // Integrity
  contentHash: string;           // SHA-256 of canonical JSON content
  signature: string;             // Base64-encoded signature
  signatureAlgorithm: string;    // "RS256", "ES256"
  signerKeyRef: string;          // Reference to signing key
}

type EvidencePacketType =
  | "release_decision"
  | "deployment"
  | "rollback"
  | "ab_promotion";

Evidence Content

interface EvidenceContent {
  // What was released
  release: ReleaseEvidence;

  // Where it was released
  environment: EnvironmentEvidence;

  // Who requested and approved
  actors: ActorEvidence;

  // Why it was allowed
  decision: DecisionEvidence;

  // How it was executed (deployment only)
  execution?: ExecutionEvidence;

  // Previous state (for rollback)
  previous?: PreviousStateEvidence;
}

Release Evidence

interface ReleaseEvidence {
  id: UUID;
  name: string;
  displayName: string;
  createdAt: DateTime;
  createdBy: ActorRef;

  components: Array<{
    id: UUID;
    name: string;
    digest: string;
    semver: string;
    tag: string;
    role: "primary" | "sidecar" | "init" | "migration";
  }>;

  sourceRef?: {
    scmIntegrationId?: UUID;
    repository?: string;
    commitSha?: string;
    branch?: string;
    ciIntegrationId?: UUID;
    buildId?: string;
    pipelineUrl?: string;
  };
}

Environment Evidence

interface EnvironmentEvidence {
  id: UUID;
  name: string;
  displayName: string;
  orderIndex: number;

  targets: Array<{
    id: UUID;
    name: string;
    type: string;
    healthStatus: string;
  }>;

  configuration: {
    requiredApprovals: number;
    requireSeparationOfDuties: boolean;
    promotionPolicy?: string;
    deploymentTimeout: number;
  };
}

Actor Evidence

interface ActorEvidence {
  requester: ActorRef;
  requestReason: string;
  requestedAt: DateTime;

  approvers: Array<{
    actor: ActorRef;
    action: "approved" | "rejected";
    comment?: string;
    timestamp: DateTime;
    roles: string[];
  }>;

  deployer?: {
    agent: AgentRef;
    triggeredBy: ActorRef;
    startedAt: DateTime;
  };
}

interface ActorRef {
  id: UUID;
  type: "user" | "system" | "agent";
  name: string;
  email?: string;
}

interface AgentRef {
  id: UUID;
  name: string;
  version: string;
}

Decision Evidence

interface DecisionEvidence {
  promotionId: UUID;
  decision: "allow" | "block";
  decidedAt: DateTime;

  gateResults: Array<{
    gateName: string;
    gateType: string;
    passed: boolean;
    blocking: boolean;
    message: string;
    evaluatedAt: DateTime;
    details: object;
  }>;

  freezeWindowCheck: {
    checked: boolean;
    windowActive: boolean;
    windowId?: UUID;
    exemption?: {
      grantedBy: UUID;
      reason: string;
    };
  };

  separationOfDuties: {
    required: boolean;
    satisfied: boolean;
    requesterIds: UUID[];
    approverIds: UUID[];
  };
}

Execution Evidence

interface ExecutionEvidence {
  deploymentJobId: UUID;
  strategy: string;
  startedAt: DateTime;
  completedAt: DateTime;
  status: "succeeded" | "failed" | "rolled_back";

  tasks: Array<{
    targetId: UUID;
    targetName: string;
    agentId: UUID;
    status: string;
    startedAt: DateTime;
    completedAt: DateTime;
    digest: string;
    stickerWritten: boolean;
    error?: string;
  }>;

  artifacts: Array<{
    name: string;
    type: string;
    sha256: string;
    storageRef: string;
  }>;

  metrics: {
    totalTasks: number;
    succeededTasks: number;
    failedTasks: number;
    totalDurationSeconds: number;
  };
}

Previous State Evidence

interface PreviousStateEvidence {
  releaseId: UUID;
  releaseName: string;
  deployedAt: DateTime;
  deployedBy: ActorRef;
  components: Array<{
    name: string;
    digest: string;
  }>;
}

Example Evidence Packet

{
  "id": "evid-12345-uuid",
  "version": "1.0",
  "type": "deployment",
  "generatedAt": "2026-01-10T14:35:00Z",
  "generatorVersion": "stella-evidence-generator@1.5.0",
  "tenantId": "tenant-uuid",

  "content": {
    "release": {
      "id": "rel-uuid",
      "name": "myapp-v2.3.1",
      "displayName": "MyApp v2.3.1",
      "createdAt": "2026-01-10T10:00:00Z",
      "createdBy": {
        "id": "user-uuid",
        "type": "user",
        "name": "John Doe",
        "email": "john@example.com"
      },
      "components": [
        {
          "id": "comp-api-uuid",
          "name": "api",
          "digest": "sha256:abc123def456...",
          "semver": "2.3.1",
          "tag": "v2.3.1",
          "role": "primary"
        },
        {
          "id": "comp-worker-uuid",
          "name": "worker",
          "digest": "sha256:789xyz...",
          "semver": "2.3.1",
          "tag": "v2.3.1",
          "role": "primary"
        }
      ],
      "sourceRef": {
        "repository": "github.com/myorg/myapp",
        "commitSha": "abc123",
        "branch": "main",
        "buildId": "build-456"
      }
    },

    "environment": {
      "id": "env-prod-uuid",
      "name": "production",
      "displayName": "Production",
      "orderIndex": 2,
      "targets": [
        {
          "id": "target-1-uuid",
          "name": "prod-web-01",
          "type": "compose_host",
          "healthStatus": "healthy"
        },
        {
          "id": "target-2-uuid",
          "name": "prod-web-02",
          "type": "compose_host",
          "healthStatus": "healthy"
        }
      ],
      "configuration": {
        "requiredApprovals": 2,
        "requireSeparationOfDuties": true,
        "deploymentTimeout": 600
      }
    },

    "actors": {
      "requester": {
        "id": "user-john-uuid",
        "type": "user",
        "name": "John Doe",
        "email": "john@example.com"
      },
      "requestReason": "Release v2.3.1 with performance improvements",
      "requestedAt": "2026-01-10T12:00:00Z",
      "approvers": [
        {
          "actor": {
            "id": "user-jane-uuid",
            "type": "user",
            "name": "Jane Smith",
            "email": "jane@example.com"
          },
          "action": "approved",
          "comment": "LGTM, tests passed",
          "timestamp": "2026-01-10T13:00:00Z",
          "roles": ["release_manager"]
        },
        {
          "actor": {
            "id": "user-bob-uuid",
            "type": "user",
            "name": "Bob Johnson",
            "email": "bob@example.com"
          },
          "action": "approved",
          "comment": "Approved for production",
          "timestamp": "2026-01-10T13:30:00Z",
          "roles": ["approver"]
        }
      ],
      "deployer": {
        "agent": {
          "id": "agent-prod-uuid",
          "name": "prod-agent-01",
          "version": "1.5.0"
        },
        "triggeredBy": {
          "id": "system",
          "type": "system",
          "name": "Stella Orchestrator"
        },
        "startedAt": "2026-01-10T14:00:00Z"
      }
    },

    "decision": {
      "promotionId": "promo-uuid",
      "decision": "allow",
      "decidedAt": "2026-01-10T13:55:00Z",
      "gateResults": [
        {
          "gateName": "security-gate",
          "gateType": "security",
          "passed": true,
          "blocking": true,
          "message": "No critical or high vulnerabilities",
          "evaluatedAt": "2026-01-10T13:50:00Z",
          "details": {
            "critical": 0,
            "high": 0,
            "medium": 5,
            "low": 12
          }
        },
        {
          "gateName": "approval-gate",
          "gateType": "approval",
          "passed": true,
          "blocking": true,
          "message": "2/2 required approvals received",
          "evaluatedAt": "2026-01-10T13:55:00Z",
          "details": {
            "required": 2,
            "received": 2
          }
        }
      ],
      "freezeWindowCheck": {
        "checked": true,
        "windowActive": false
      },
      "separationOfDuties": {
        "required": true,
        "satisfied": true,
        "requesterIds": ["user-john-uuid"],
        "approverIds": ["user-jane-uuid", "user-bob-uuid"]
      }
    },

    "execution": {
      "deploymentJobId": "job-uuid",
      "strategy": "rolling",
      "startedAt": "2026-01-10T14:00:00Z",
      "completedAt": "2026-01-10T14:35:00Z",
      "status": "succeeded",
      "tasks": [
        {
          "targetId": "target-1-uuid",
          "targetName": "prod-web-01",
          "agentId": "agent-prod-uuid",
          "status": "succeeded",
          "startedAt": "2026-01-10T14:00:00Z",
          "completedAt": "2026-01-10T14:15:00Z",
          "digest": "sha256:abc123def456...",
          "stickerWritten": true
        },
        {
          "targetId": "target-2-uuid",
          "targetName": "prod-web-02",
          "agentId": "agent-prod-uuid",
          "status": "succeeded",
          "startedAt": "2026-01-10T14:20:00Z",
          "completedAt": "2026-01-10T14:35:00Z",
          "digest": "sha256:abc123def456...",
          "stickerWritten": true
        }
      ],
      "artifacts": [
        {
          "name": "compose.stella.lock.yml",
          "type": "compose-lock",
          "sha256": "checksum...",
          "storageRef": "s3://artifacts/job-uuid/compose.stella.lock.yml"
        }
      ],
      "metrics": {
        "totalTasks": 2,
        "succeededTasks": 2,
        "failedTasks": 0,
        "totalDurationSeconds": 2100
      }
    }
  },

  "contentHash": "sha256:content-hash...",
  "signature": "base64-signature...",
  "signatureAlgorithm": "RS256",
  "signerKeyRef": "stella/signing/prod-key-2026"
}

Signature Verification

async function verifyEvidencePacket(packet: EvidencePacket): Promise<VerificationResult> {
  // 1. Verify content hash
  const canonicalContent = canonicalize(packet.content);
  const computedHash = sha256(canonicalContent);

  if (computedHash !== packet.contentHash) {
    return { valid: false, error: "Content hash mismatch" };
  }

  // 2. Get signing key
  const publicKey = await getPublicKey(packet.signerKeyRef);

  // 3. Verify signature
  const signatureValid = await verify(
    packet.signature,
    packet.contentHash,
    publicKey,
    packet.signatureAlgorithm
  );

  if (!signatureValid) {
    return { valid: false, error: "Invalid signature" };
  }

  return { valid: true };
}

Storage

Evidence packets are stored in an append-only table:

CREATE TABLE release.evidence_packets (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    tenant_id UUID NOT NULL REFERENCES tenants(id),
    promotion_id UUID NOT NULL REFERENCES release.promotions(id),
    type TEXT NOT NULL,
    version TEXT NOT NULL DEFAULT '1.0',
    content JSONB NOT NULL,
    content_hash TEXT NOT NULL,
    signature TEXT NOT NULL,
    signature_algorithm TEXT NOT NULL,
    signer_key_ref TEXT NOT NULL,
    generated_at TIMESTAMPTZ NOT NULL,
    generator_version TEXT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
    -- Note: No updated_at - packets are immutable
);

-- Prevent modifications
REVOKE UPDATE, DELETE ON release.evidence_packets FROM app_role;

Export Formats

Evidence packets can be exported in multiple formats:

Format Use Case
JSON API consumption, archival
PDF Human-readable compliance reports
CSV Spreadsheet analysis
SLSA SLSA provenance format

References