CI Release Gate Dogfooding

Use Decision Gate as a release-gate workflow.

This guide documents how Decision Gate dogfoods itself by gating release eligibility using deterministic CI evidence. The goal is to demonstrate a real, auditable policy layer without replacing the CI system.

Why This Is Rigorous

  • Separation of concerns: CI executes tests; Decision Gate evaluates the policy and emits a deterministic decision.
  • Evidence-driven: The decision is based on a versioned evidence bundle rather than implicit CI logs.
  • Auditable output: Decision Gate exports a runpack containing the current decision trail and integrity metadata. Runpack verification does not by itself establish semantic replay, evidence authenticity, accepted-history correctness, external binding, or nonrepudiation.
  • Deterministic: The same evidence bundle yields the same decision.

What Is Gated

The release tag workflow validates that a release is eligible based on:

  • Formatting, lint, and unit tests
  • System-test priorities P0 and P1 (not roadmap phases)
  • cargo-deny
  • Generator drift checks
  • Complete SBOM coverage for every release subject
  • Provenance attestation verification for every release subject
  • Keyless OIDC signature verification for artifact and provenance payloads
  • Vulnerability policy pass (High/Critical blocked + KEV blocked at any severity)
  • Packaging dry runs (Python + TypeScript)
  • Docker smoke test
  • Tag/version consistency (tag matches workspace version)

If any requirement is missing or false, the gate denies the release.

Evidence Bundle

The release workflow writes a JSON evidence bundle and validates every required field as an exact boolean. The wrapper constructs one hostile typed record and submits it directly for the exact condition under boundary-derived caller authority and receipt time. DG admits that record against the exact closed record domain and evidence-use policy; no fictional caller binding, dynamic JSON, or provider-coupled condition enters the validated scenario law.

Example (shape only):

{
  "release": {
    "tag": "v0.1.0",
    "version": "0.1.0",
    "tag_matches_version": true,
    "sha": "<git sha>",
    "generated_at": 1710000000000,
    "sbom_path": ".tmp/ci/sbom/decision-gate.sbom.spdx.json"
  },
  "checks": {
    "fmt": true,
    "clippy": true,
    "cargo_deny": true,
    "generate_all": true,
    "unit_tests": true,
    "system_tests_p0": true,
    "system_tests_p1": true,
    "sbom": true,
    "sbom_complete": true,
    "sbom_verified": true,
    "provenance_verified": true,
    "signature_verified": true,
    "vuln_policy_pass": true,
    "package_dry_run": true,
    "docker_smoke": true
  }
}

Policy Scenario

The release gate is expressed as a standard Decision Gate scenario:

  • Template: configs/ci/release_gate_scenario.json
  • Policy: All conditions must be true (one full RET And requirement)
  • Acquisition: one boundary-attributed caller submission targets the exact condition directly
  • Execution: live scenario run (not precheck) so a runpack is produced

The scenario is instantiated at runtime by replacing the template placeholders:

  • {{SCENARIO_ID}} -> unique scenario identifier

How It Runs in CI

The release workflow performs the following sequence:

  1. Runs CI checks (fmt, clippy, tests, deny, packaging, smoke test).
  2. Generates release supply-chain evidence with scripts/ci/supply_chain_generate.sh (subjects, SBOMs, provenance, keyless signatures, vulnerability artifacts).
  3. Verifies supply-chain evidence with scripts/ci/supply_chain_verify.sh as a hard gate.
  4. Writes the Decision Gate release evidence bundle, including the new supply-chain verification booleans.
  5. Validates and projects the required booleans, then starts a local MCP server with configs/presets/ci-release-gate.toml and its exact environment-key allowlist.
  6. Evaluates the scenario using the evidence bundle.
  7. Exports and verifies a runpack.
  8. Uploads artifacts:
    • Evidence bundle
    • Runpack
    • Supply-chain evidence bundle (SBOM/provenance/signatures/vuln artifacts)
    • Decision payload and summary
    • Artifact name: decision-gate-release-gate

The implementation lives in scripts/ci/ci_release_gate.sh and is called by the release workflow.

Source-Only Distribution Posture

This repository currently stops at tagged, source-first releases. .github/workflows/release.yml still generates audited release evidence, but there is no active workflow that publishes packages or container images to public registries.

That means release eligibility remains strict and reproducible, while external distribution requires a separate future policy decision outside the current CI contract.

Running Locally

You can run the same release gate locally with a custom evidence bundle:

python3 - <<'PY'
import json
from pathlib import Path

Path("evidence/release_evidence.json").write_text(json.dumps({
    "release": {
        "tag": "v0.1.0",
        "version": "0.1.0",
        "tag_matches_version": True,
        "sha": "local",
        "generated_at": 0,
        "sbom_path": "evidence/sbom/decision-gate.sbom.spdx.json",
    },
    "checks": {
        "fmt": True,
        "clippy": True,
        "cargo_deny": True,
        "generate_all": True,
        "unit_tests": True,
        "system_tests_p0": True,
        "system_tests_p1": True,
        "sbom": True,
        "package_dry_run": True,
        "docker_smoke": True,
    },
}, indent=2))
PY

bash scripts/ci/ci_release_gate.sh \
  --evidence-file evidence/release_evidence.json \
  --output-dir evidence/release-runpack \
  --config configs/presets/ci-release-gate.toml

If any check is false, the script exits non-zero and the decision summary will show the denial reason.

To run local release-parity supply-chain generation + verification before gate evaluation:

bash scripts/ci/verify_all.sh --release-parity

Artifacts to Inspect

  • decision_payload.json: raw Decision Gate response payload
  • decision_summary.json: decision kind + allow/deny
  • runpack/manifest.json: deterministic runpack manifest
  • runpack_verify.json: runpack verification output
  • Docs/architecture/decision_gate_ci_and_workflow_architecture.md
  • configs/ci/release_gate_scenario.json
  • scripts/ci/ci_release_gate.sh