Skip to content
Latchkey

CGA Attestation workflow (Cranot/roam-code)

The CGA Attestation workflow from Cranot/roam-code, explained and optimized by Latchkey.

A

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.

Grade your own workflow free or run it on Latchkey →
Source: Cranot/roam-code.github/workflows/cga-attestation.ymlLicense Apache-2.0View source

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

workflow (.yml)
# 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

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:

This workflow runs 2 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow