Guides

Gate CI on a verdict

Generate an artifact in CI and fail the build unless it comes back valid.

If an artifact your build ships is made from an intent, make it in CI through Forma and let the verdict decide: valid writes the artifact and its citation, anything else fails the build. Forma does not check an artifact you already have — it checks the one it returns.

The script

bash
#!/usr/bin/env bash
set -euo pipefail

answer=$(curl -sS --fail-with-body \
  "https://api.formalogic.io/v1/oracles/chart/ask" \
  -H "Authorization: Bearer $FORMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d @intent.json)

status=$(jq -r .status <<<"$answer")

case "$status" in
  valid)
    jq -r .result <<<"$answer" > artifact.json
    echo "checked against $(jq -r .verified_by <<<"$answer")"
    ;;
  invalid)
    echo "::error::the check refused it: $(jq -r .detail <<<"$answer")"
    exit 1
    ;;
  error)
    echo "::warning::the oracle could not answer; nothing was billed"
    exit 75          # EX_TEMPFAIL — retry the job, do not fail the branch
    ;;
  *)
    echo "::error::unexpected answer: $status"
    exit 1
    ;;
esac

--fail-with-body matters: without it curl exits 0 on a 401 and the script parses an error envelope as a verdict.

Distinguish "refused" from "unavailable"

invalid means the artifact is wrong — fail the build; a human should look.

error means we were unavailable — that is not the branch's fault. Exiting 75 rather than 1 lets a retry policy pick it up without a red mark against someone's commit.

Keep the citation

Write verified_by into the build output next to the artifact. It is what tells a reader six months later which version of the rules the file in the repository passed.

Budget

Every gated build spends credits. On a busy repository, gate on merge rather than on every push. Usage shows what this period has spent and Credits your balance — check both before turning it on across many pipelines.