GUIDE
CI/CD integration
Your pipeline already produces the evidence an admissibility decision needs — test results, reviews, policy checks, sign-offs. This guide shows you how to assemble that evidence into a claim, ask the Decision Receipt API for a verdict at a gate, and let the verdict decide whether the build proceeds.
The pattern is provider-agnostic. It works the same whether you run GitHub Actions, GitLab CI, Jenkins, or Buildkite, because all you need is a step that can run curl and read a secret. The examples below use plain shell so you can drop them into any of them.
Assemble a claim at the gate
Pick the moment in your pipeline where a decision actually matters — typically just before a merge or a deploy. At that gate you have artifacts from earlier stages. Map each one to an evidence source, then submit them together as a claim to POST /v1/evaluate.
The source types that fit a pipeline map directly onto stages you already run:
test_resultorci— your test job's outcome (counts, pass/fail).code_review— the approval state of the change under review.policy_check— the result of a linter, scanner, or policy-as-code gate.human_approval— present only if a sign-off gate cleared; require it throughrequireHumanApprovalwhen a human must be in the loop.
Pair the evidence with an action object describing what the pipeline is about to do. For a deploy step set action_type to deployment and include the target_system, environment, commit, and branch. For a pre-merge gate use merge instead. Both are valid action_type values.
A CI STEP THAT EVALUATES A DEPLOY GATE
#!/usr/bin/env bash
set -euo pipefail
# DECREC_API_KEY is injected from your CI secret store.
API="https://decrec.summitcognitive.ai"
# Values your pipeline already knows.
COMMIT="${CI_COMMIT_SHA}"
BRANCH="${CI_COMMIT_BRANCH}"
TESTS_PASSED="${TESTS_PASSED:-0}"
RESPONSE=$(curl -s "$API/v1/evaluate" \
-H "Content-Type: application/json" \
-H "X-API-Key: $DECREC_API_KEY" \
-d @- <<JSON
{
"claim_id": "deploy-${COMMIT}",
"entity": "acme-corp/widget-api",
"claim": "Deploy ${COMMIT} to production",
"action": {
"action_type": "deployment",
"target_system": "kubernetes",
"environment": "production",
"commit": "${COMMIT}",
"branch": "${BRANCH}"
},
"sources": [
{
"id": "evd_tests_${COMMIT}",
"type": "test_result",
"uri": "${CI_PIPELINE_URL}",
"confidence": 0.9,
"content": "${TESTS_PASSED} tests passing, 0 failures"
},
{
"id": "evd_review_${COMMIT}",
"type": "code_review",
"uri": "${CI_MERGE_REQUEST_URL}",
"confidence": 0.85,
"content": "Approved, no blocking comments"
},
{
"id": "evd_policy_${COMMIT}",
"type": "policy_check",
"uri": "${CI_PIPELINE_URL}",
"confidence": 0.95,
"content": "Security scan clean"
}
]
}
JSON
)
echo "$RESPONSE" > receipt-response.json
The same shape works on any provider — substitute your platform's variables (GITHUB_SHA, BUILDKITE_COMMIT, Jenkins $GIT_COMMIT, and so on) for the GitLab-style ones above, and read the API key from your platform's secret mechanism.
Gate the build on the verdict
The response carries a verdict at .policy.verdict. There are three, and each one maps cleanly to a pipeline outcome:
- ALLOWED — evidence cleared the policy. Let the step proceed.
- BLOCKED — a check failed. Fail the build and stop.
- ESCALATED — the decision needs a human. Pause and route for review rather than auto-proceeding.
Read the field with jq and exit accordingly. A non-zero exit fails the step on every CI system:
GATE ON THE VERDICT
VERDICT=$(jq -r '.policy.verdict' receipt-response.json)
case "$VERDICT" in
ALLOWED) echo "Admissible — proceeding."; ;;
ESCALATED) echo "Escalated — pausing for human review."; exit 1; ;;
BLOCKED) echo "Blocked — failing the build."; exit 1; ;;
*) echo "Unexpected verdict: $VERDICT"; exit 1; ;;
esac
If you want a manual-approval path for ESCALATED rather than a hard failure, route to your platform's pause-for-approval feature instead of exiting — the verdict tells you which builds need a human, so only those wait.
Test the policy before you enforce it
Before you turn a gate into a hard failure, run it in dry-run. POST /v1/simulate evaluates a claim and returns the same verdict shape as /v1/evaluate, but it does not persist a receipt. Wire a non-blocking job that calls /v1/simulate on every build for a release or two, observe which builds would have been blocked or escalated, and tune your thresholds before you flip the gate to enforcing.
Both endpoints accept a policyConfig object to override thresholds per request — handy for setting a stricter bar on production deploys than on staging. See Custom policies for the full field reference and how to save a reusable policy.
Store the receipt as a build artifact
An ALLOWED verdict is only half the value. The response also includes a signed receipt — an Ed25519-attested record of the evidence, the policy result, and the replay result. Persist it the way you persist any build output:
SAVE THE RECEIPT
jq '.receipt' receipt-response.json > receipt-${COMMIT}.json
# then upload receipt-${COMMIT}.json as a pipeline artifact
Anyone can confirm later that the receipt is genuine and unaltered, without trusting your pipeline — by submitting it to POST /v1/verify or checking the Ed25519 signature offline against the server's published public key. See Verifying receipts for how that independent check works.