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
P0andP1(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/Criticalblocked + 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
Andrequirement) - 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:
- Runs CI checks (fmt, clippy, tests, deny, packaging, smoke test).
- Generates release supply-chain evidence with
scripts/ci/supply_chain_generate.sh(subjects, SBOMs, provenance, keyless signatures, vulnerability artifacts). - Verifies supply-chain evidence with
scripts/ci/supply_chain_verify.shas a hard gate. - Writes the Decision Gate release evidence bundle, including the new supply-chain verification booleans.
- Validates and projects the required booleans, then starts a local MCP server
with
configs/presets/ci-release-gate.tomland its exact environment-key allowlist. - Evaluates the scenario using the evidence bundle.
- Exports and verifies a runpack.
- 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 payloaddecision_summary.json: decision kind + allow/denyrunpack/manifest.json: deterministic runpack manifestrunpack_verify.json: runpack verification output
Related References
Docs/architecture/decision_gate_ci_and_workflow_architecture.mdconfigs/ci/release_gate_scenario.jsonscripts/ci/ci_release_gate.sh