CGA Attestation workflow (Cranot/roam-code)
The CGA Attestation workflow from Cranot/roam-code, explained and optimized by Latchkey.
CI health: A - excellent
Point runs-on at Latchkey and get caching, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the CGA Attestation workflow from the Cranot/roam-code repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
# Real cosign integration for the v12 Code Graph Attestation chain.
#
# Why a separate workflow:
# - The unit suite mocks `subprocess.run` so the CGA + cosign code paths
# run on every developer machine without needing the cosign binary or
# Sigstore network access. That gives correctness coverage but does not
# prove the chain works end-to-end with the real binary + Fulcio + Rekor.
# - This workflow runs the *real* cosign binary in two modes:
# 1. Offline keypair (deterministic, no network, no secrets)
# 2. Keyless OIDC (Fulcio + Rekor, exercises the production path)
# - Both modes round-trip emit -> sign -> verify and exit 5 on tamper.
#
# Triggers:
# - push to main when attest/, security/, or this workflow changes
# - manual workflow_dispatch
# Not gated on PRs to avoid flaking on Sigstore availability issues.
name: CGA Attestation
on:
push:
branches: [main]
paths:
- 'src/roam/attest/**'
- 'src/roam/security/taint_engine.py'
- 'src/roam/commands/cmd_cga.py'
- 'src/roam/commands/cmd_taint.py'
- '.github/workflows/cga-attestation.yml'
workflow_dispatch:
# Serialize attestation runs against the same ref so two simultaneous
# pushes to main cannot race the Fulcio / Rekor sign path. The keyless
# OIDC chain is not idempotent on collision. ``cancel-in-progress: false``
# preserves any in-flight signing operation.
concurrency:
group: cga-attestation-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
id-token: write # required for keyless OIDC signing
jobs:
# -- Mode 1: offline keypair signing --------------------------------------
# Generates an ephemeral cosign keypair per run, signs and verifies.
# Deterministic, no network. This is the path most enterprise users will
# take for air-gapped or compliance-sensitive deployments.
offline-key:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history needed for git_stats during indexing
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install roam-code
run: pip install -e .
- name: Install cosign
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
- name: Index the repo
run: |
roam index
roam clones --persist
- name: Generate ephemeral cosign keypair
env:
COSIGN_PASSWORD: '' # empty password for ephemeral CI key
run: cosign generate-key-pair
- name: Emit signed CGA statement (offline)
env:
COSIGN_PASSWORD: ''
run: |
# W1302: --allow-dirty needed because `roam index` + `roam clones
# --persist` + cosign keypair generation all write artifacts into
# the working tree, and `cosign.key` / `.roam/index.db` are not
# part of the source commit. The dirty-hash is recorded in the
# predicate explicitly per cmd_cga.py guidance.
# W472: --also-vsa additionally emits a SLSA v1 Verification
# Summary Attestation (predicateType
# https://slsa.dev/verification_summary/v1) - the format
# external auditors consume. It lands as a sibling of the CGA:
# the .intoto.json suffix is stripped and .vsa.json appended,
# so .roam/cga-offline.intoto.json yields
# .roam/cga-offline.vsa.json. --sign covers both statements,
# so the VSA is cosign-signed alongside the CGA and gets its
# own .roam/cga-offline.vsa.bundle.
roam cga emit \
--include-taint \
--sign \
--key cosign.key \
--allow-dirty \
--also-vsa \
--output .roam/cga-offline.intoto.json
- name: Verify CGA statement (offline round-trip)
run: |
roam cga verify \
.roam/cga-offline.intoto.json \
--cosign-key cosign.pub
- name: Tamper-detection sanity check
run: |
# Mutate one byte in the predicate. Predicate-only verify must
# exit 5 (the digest re-derivation fails). --no-cosign makes the
# intent explicit: this test exercises predicate tamper, not
# cosign-signature tamper.
cp .roam/cga-offline.intoto.json .roam/cga-tampered.intoto.json
python -c "import json,pathlib; p=pathlib.Path('.roam/cga-tampered.intoto.json'); d=json.loads(p.read_text()); d['predicate']['edge_bundle_digest']='deadbeef'+d['predicate']['edge_bundle_digest'][8:]; p.write_text(json.dumps(d))"
set +e
roam cga verify .roam/cga-tampered.intoto.json --no-cosign
rc=$?
set -e
if [ "$rc" != "5" ]; then
echo "Expected verify to exit 5 on tamper; got $rc" >&2
exit 1
fi
- name: Upload offline statement
uses: actions/upload-artifact@v4
with:
name: cga-offline-attestation
path: |
.roam/cga-offline.intoto.json
.roam/cga-offline.intoto.bundle
.roam/cga-offline.vsa.json
.roam/cga-offline.vsa.bundle
cosign.pub
# -- Mode 2: keyless OIDC signing -----------------------------------------
# Uses GitHub's OIDC token + Fulcio + Rekor. This is the real Sigstore
# path - exercises code that the unit tests mock. We trust the check:
# if Sigstore is reachable, a fresh sign+verify must succeed; if it
# isn't, the job fails loudly and we fix it. Hiding flakes behind
# ``continue-on-error`` masks real regressions in our own emit/verify
# code path. The offline-key job (above) is the deterministic gate
# that always runs without network - this one is the production-path
# smoke. If Sigstore has an outage, re-run the job after they recover.
keyless-oidc:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install roam-code
run: pip install -e .
- name: Install cosign
uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3
- name: Index the repo
run: |
roam index
roam clones --persist
- name: Emit + sign keyless
env:
COSIGN_EXPERIMENTAL: '1'
run: |
# W1302: see offline-key job for --allow-dirty rationale
# (.roam/index.db not committed, dirty tree by design).
# W472: --also-vsa emits a sibling SLSA v1 Verification Summary
# Attestation at .roam/cga-keyless.vsa.json (the .intoto.json
# suffix is stripped, .vsa.json appended). --sign --keyless
# covers both statements, so the VSA is keyless-signed via
# Fulcio + Rekor alongside the CGA and gets its own
# .roam/cga-keyless.vsa.bundle (+ .vsa.cert for keyless).
roam cga emit \
--include-taint \
--sign \
--keyless \
--allow-dirty \
--also-vsa \
--output .roam/cga-keyless.intoto.json
- name: Verify keyless (Fulcio + Rekor round-trip)
env:
COSIGN_EXPERIMENTAL: '1'
# Cosign >= 2.0 refuses keyless verification without an explicit
# signer-identity check. For GitHub Actions OIDC the certificate
# subject is the workflow file path on the ref that ran the job,
# and the issuer is GitHub's token endpoint. The expected identity
# must match the workflow that signed the bundle one step earlier
# - i.e. this same workflow file, on this same ref. Constructed
# from $GITHUB_SERVER_URL / $GITHUB_REPOSITORY / $GITHUB_WORKFLOW_REF
# (the latter is "<owner>/<repo>/.github/workflows/<wf>@<ref>").
ROAM_CGA_CERT_IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }}
ROAM_CGA_CERT_OIDC_ISSUER: https://token.actions.githubusercontent.com
run: |
roam cga verify .roam/cga-keyless.intoto.json
- name: Upload keyless statement
if: always()
uses: actions/upload-artifact@v4
with:
name: cga-keyless-attestation
path: |
.roam/cga-keyless.intoto.json
.roam/cga-keyless.intoto.bundle
.roam/cga-keyless.vsa.json
.roam/cga-keyless.vsa.bundle
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
# Real cosign integration for the v12 Code Graph Attestation chain. # # Why a separate workflow: # - The unit suite mocks `subprocess.run` so the CGA + cosign code paths # run on every developer machine without needing the cosign binary or # Sigstore network access. That gives correctness coverage but does not # prove the chain works end-to-end with the real binary + Fulcio + Rekor. # - This workflow runs the *real* cosign binary in two modes: # 1. Offline keypair (deterministic, no network, no secrets) # 2. Keyless OIDC (Fulcio + Rekor, exercises the production path) # - Both modes round-trip emit -> sign -> verify and exit 5 on tamper. # # Triggers: # - push to main when attest/, security/, or this workflow changes # - manual workflow_dispatch # Not gated on PRs to avoid flaking on Sigstore availability issues. name: CGA Attestation on: push: branches: [main] paths: - 'src/roam/attest/**' - 'src/roam/security/taint_engine.py' - 'src/roam/commands/cmd_cga.py' - 'src/roam/commands/cmd_taint.py' - '.github/workflows/cga-attestation.yml' workflow_dispatch: # Serialize attestation runs against the same ref so two simultaneous # pushes to main cannot race the Fulcio / Rekor sign path. The keyless # OIDC chain is not idempotent on collision. ``cancel-in-progress: false`` # preserves any in-flight signing operation. concurrency: group: cga-attestation-${{ github.ref }} cancel-in-progress: false permissions: contents: read id-token: write # required for keyless OIDC signing jobs: # -- Mode 1: offline keypair signing -------------------------------------- # Generates an ephemeral cosign keypair per run, signs and verifies. # Deterministic, no network. This is the path most enterprise users will # take for air-gapped or compliance-sensitive deployments. offline-key: runs-on: latchkey-small timeout-minutes: 15 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # full history needed for git_stats during indexing - uses: actions/setup-python@v5 with: cache: 'pip' python-version: '3.12' - name: Install roam-code run: pip install -e . - name: Install cosign uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3 - name: Index the repo run: | roam index roam clones --persist - name: Generate ephemeral cosign keypair env: COSIGN_PASSWORD: '' # empty password for ephemeral CI key run: cosign generate-key-pair - name: Emit signed CGA statement (offline) env: COSIGN_PASSWORD: '' run: | # W1302: --allow-dirty needed because `roam index` + `roam clones # --persist` + cosign keypair generation all write artifacts into # the working tree, and `cosign.key` / `.roam/index.db` are not # part of the source commit. The dirty-hash is recorded in the # predicate explicitly per cmd_cga.py guidance. # W472: --also-vsa additionally emits a SLSA v1 Verification # Summary Attestation (predicateType # https://slsa.dev/verification_summary/v1) - the format # external auditors consume. It lands as a sibling of the CGA: # the .intoto.json suffix is stripped and .vsa.json appended, # so .roam/cga-offline.intoto.json yields # .roam/cga-offline.vsa.json. --sign covers both statements, # so the VSA is cosign-signed alongside the CGA and gets its # own .roam/cga-offline.vsa.bundle. roam cga emit \ --include-taint \ --sign \ --key cosign.key \ --allow-dirty \ --also-vsa \ --output .roam/cga-offline.intoto.json - name: Verify CGA statement (offline round-trip) run: | roam cga verify \ .roam/cga-offline.intoto.json \ --cosign-key cosign.pub - name: Tamper-detection sanity check run: | # Mutate one byte in the predicate. Predicate-only verify must # exit 5 (the digest re-derivation fails). --no-cosign makes the # intent explicit: this test exercises predicate tamper, not # cosign-signature tamper. cp .roam/cga-offline.intoto.json .roam/cga-tampered.intoto.json python -c "import json,pathlib; p=pathlib.Path('.roam/cga-tampered.intoto.json'); d=json.loads(p.read_text()); d['predicate']['edge_bundle_digest']='deadbeef'+d['predicate']['edge_bundle_digest'][8:]; p.write_text(json.dumps(d))" set +e roam cga verify .roam/cga-tampered.intoto.json --no-cosign rc=$? set -e if [ "$rc" != "5" ]; then echo "Expected verify to exit 5 on tamper; got $rc" >&2 exit 1 fi - name: Upload offline statement uses: actions/upload-artifact@v4 with: name: cga-offline-attestation path: | .roam/cga-offline.intoto.json .roam/cga-offline.intoto.bundle .roam/cga-offline.vsa.json .roam/cga-offline.vsa.bundle cosign.pub # -- Mode 2: keyless OIDC signing ----------------------------------------- # Uses GitHub's OIDC token + Fulcio + Rekor. This is the real Sigstore # path - exercises code that the unit tests mock. We trust the check: # if Sigstore is reachable, a fresh sign+verify must succeed; if it # isn't, the job fails loudly and we fix it. Hiding flakes behind # ``continue-on-error`` masks real regressions in our own emit/verify # code path. The offline-key job (above) is the deterministic gate # that always runs without network - this one is the production-path # smoke. If Sigstore has an outage, re-run the job after they recover. keyless-oidc: runs-on: latchkey-small timeout-minutes: 15 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-python@v5 with: cache: 'pip' python-version: '3.12' - name: Install roam-code run: pip install -e . - name: Install cosign uses: sigstore/cosign-installer@398d4b0eeef1380460a10c8013a76f728fb906ac # v3 - name: Index the repo run: | roam index roam clones --persist - name: Emit + sign keyless env: COSIGN_EXPERIMENTAL: '1' run: | # W1302: see offline-key job for --allow-dirty rationale # (.roam/index.db not committed, dirty tree by design). # W472: --also-vsa emits a sibling SLSA v1 Verification Summary # Attestation at .roam/cga-keyless.vsa.json (the .intoto.json # suffix is stripped, .vsa.json appended). --sign --keyless # covers both statements, so the VSA is keyless-signed via # Fulcio + Rekor alongside the CGA and gets its own # .roam/cga-keyless.vsa.bundle (+ .vsa.cert for keyless). roam cga emit \ --include-taint \ --sign \ --keyless \ --allow-dirty \ --also-vsa \ --output .roam/cga-keyless.intoto.json - name: Verify keyless (Fulcio + Rekor round-trip) env: COSIGN_EXPERIMENTAL: '1' # Cosign >= 2.0 refuses keyless verification without an explicit # signer-identity check. For GitHub Actions OIDC the certificate # subject is the workflow file path on the ref that ran the job, # and the issuer is GitHub's token endpoint. The expected identity # must match the workflow that signed the bundle one step earlier # - i.e. this same workflow file, on this same ref. Constructed # from $GITHUB_SERVER_URL / $GITHUB_REPOSITORY / $GITHUB_WORKFLOW_REF # (the latter is "<owner>/<repo>/.github/workflows/<wf>@<ref>"). ROAM_CGA_CERT_IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }} ROAM_CGA_CERT_OIDC_ISSUER: https://token.actions.githubusercontent.com run: | roam cga verify .roam/cga-keyless.intoto.json - name: Upload keyless statement if: always() uses: actions/upload-artifact@v4 with: name: cga-keyless-attestation path: | .roam/cga-keyless.intoto.json .roam/cga-keyless.intoto.bundle .roam/cga-keyless.vsa.json .roam/cga-keyless.vsa.bundle
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cache dependency installs on the setup step so they are served from cache.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 2 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.