Skip to content

Fork-based evidence signing workflow driven by committed unsigned pointers #1433

Description

@njhensley

Part of #1431.

Summary

Add a GitHub Actions workflow that a contributor runs in their fork to complete the signing leg of evidence publishing. The contributor first does the network-light work locally with AICR: publish the unsigned bundle to their own registry and commit the pointer (see two-phase publish issue). The workflow then operates purely on the branch — it discovers any pointer in recipes/evidence/*.yaml whose signer is empty / rekorLogIndex is nil, signs the bundle that pointer already references (ambient OIDC → Fulcio/Rekor), patches the pointer's signer block in place, and commits it back. No recipe-name or bundle-ref inputs to thread through workflow_dispatch.

Why this shape

  • Eliminates the friction of passing a bundle artifact or recipe name into the workflow — the committed pointer is the work item, and it already carries bundle.oci + bundle.digest.
  • The only step that genuinely needs Fulcio (signing) runs where Fulcio is reachable (Actions); everything else stays local and VPN-friendly. Sigstore keyless signing from a laptop is currently blocked on corporate VPN and some home networks (upstream Fulcio IP-level rejection).
  • The signer becomes the GitHub Actions OIDC identity, not a personal one.

Contributor flow

  1. Local (on VPN, no Fulcio): aicr validate ... --emit-attestation ./out --push ghcr.io/<owner>/aicr-evidence --no-sign → unsigned bundle pushed, pointer written with empty signer (two-phase publish issue).
  2. Make the fork's aicr-evidence package public so verify pulls don't 403.
  3. Commit the pointer, push the branch.
  4. Workflow runs → signs, logs to Rekor, patches signer.identity / issuer / rekorLogIndex, commits back.

Trigger — open design question (resolve in this issue)

  • Option A (explicit): workflow_dispatch only — predictable, no surprise commits, but one manual click.
  • Option B (automatic on push): trigger on push to fork branches when an unsigned pointer is present. Lowest friction, but a workflow that commits back to the branch that triggered it needs loop-guards (skip when no unsigned pointers; don't re-trigger on its own signing commit) and clear behavior on forks where Actions / id-token may be disabled by default.
  • Recommend landing A first, with B as a fast-follow once the discover-and-patch path is proven.

Acceptance criteria

  • .github/workflows/evidence-publish.yaml, runnable in a fork, permissions: id-token: write (+ contents: write for commit-back); no required inputs.
  • Discovers all unsigned pointers on the branch; signs each referenced bundle with ambient OIDC; patches the pointer and commits it back.
  • No-op (clean exit, no commit) when there are no unsigned pointers.
  • Fork aicr-evidence package must be reachable for verification — documented, and the workflow fails with a clear message if it can't pull the bundle it's about to sign (ties to the gate-error-feedback issue).
  • Auto-trigger (Option B) tracked as a follow-up with the loop-guard requirements written down.

References

  • Discovery target: recipes/evidence/*.yaml; pkg/evidence/attestation/types.go (Pointer, nil RekorLogIndex = unsigned)
  • Signing: pkg/cli/evidence_publish.go sign-existing path; ambient OIDC pkg/bundler/attestation/oidc.go (FetchAmbientOIDCToken)
  • Depends on the two-phase push-without-sign issue.

Metadata

Metadata

Assignees

Labels

External DSXarea/citheme/ci-dxCI pipelines, developer experience, and build toolingtheme/supply-chainSLSA, SBOM, Sigstore, and provenance verification

Fields

No fields configured for Enhancement.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions