Skip to content

ci(cosign): canonical signing workflow per ADR-041#21

Open
Cramraika wants to merge 1 commit into
mainfrom
cosign-ci-rollout-20260428
Open

ci(cosign): canonical signing workflow per ADR-041#21
Cramraika wants to merge 1 commit into
mainfrom
cosign-ci-rollout-20260428

Conversation

@Cramraika
Copy link
Copy Markdown
Owner

@Cramraika Cramraika commented Apr 28, 2026

Summary

Adds canonical Cosign image-signing workflow per ADR-041 (Trivy + Cosign deploy gate). Distributed via PCN Session 14 Track 14-J Pattern 1 fanout from PR #50 on host_page (squash 11db81c).

Mechanism

  • Triggers on push to main + tag pushes (v*) + workflow_dispatch
  • Builds + pushes image to GHCR via existing GITHUB_TOKEN
  • Signs image with Cosign keypair (Infisical /cosign/ in backups workspace)
  • Generates SPDX SBOM and attaches as cosign attestation
  • Smoke-test verifies signature against published public key

Required secrets (already populated)

  • COSIGN_PRIVATE_KEY (set via gh secret set, sourced from Infisical)
  • COSIGN_PASSWORD (set via gh secret set, sourced from Infisical)

Public verification key

https://gist.githubusercontent.com/Cramraika/c246bdb779518a588617839bfe2a75c1/raw/cosign.pub

Refs

  • ADR-041: Trivy + Cosign deploy gate
  • platform-docs/docs/audits/cosign-distribute-19-repos-20260427.md
  • host_page PR #50 (canonical template)

Summary by CodeRabbit

  • Chores
    • Added automated image signing and verification workflow. Container images are now digitally signed and include Software Bill of Materials (SBOM) attestations for enhanced security and supply chain transparency.

@Cramraika Cramraika enabled auto-merge (squash) April 28, 2026 13:53
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

A new GitHub Actions workflow is introduced that automates building, pushing, and signing Docker images to GHCR using Cosign. The workflow computes image tags, constructs the image, captures its digest, signs it with a private key, generates SBOM attestations, and verifies the signature.

Changes

Cohort / File(s) Summary
Cosign Image Signing Workflow
.github/workflows/cosign-sign-image.yml
New CI workflow triggered on pushes to main, version tags (v*), and manual dispatch. Builds and pushes Docker images to GHCR, signs them with Cosign using base64-encoded private key and passphrase secrets, generates SPDX JSON SBOM, attaches SBOM as Cosign attestation, and performs signature verification smoke test.

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Actions
    participant Docker as Docker Registry<br/>(GHCR)
    participant Cosign as Cosign Tool
    participant SBOM as SBOM Action
    participant Verify as Verification

    GH->>Docker: Build & push image<br/>(capture digest)
    Docker-->>GH: Return image digest
    GH->>Cosign: Install Cosign
    GH->>Cosign: Sign image<br/>(private key + passphrase)
    Cosign->>Docker: Store signature
    GH->>SBOM: Generate SPDX JSON<br/>attestation
    SBOM-->>GH: SBOM data
    GH->>Cosign: Attach SBOM as<br/>Cosign attestation
    Cosign->>Docker: Upload attestation
    GH->>Verify: Verify signature<br/>(public key)
    Verify->>Docker: Check signature validity
    Verify-->>GH: Verification result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit's ode to secure images

With Cosign's mark, our images stay true,
Each signature signed, each attestation through,
From GHCR to verification's gleam,
We've hopped through the pipeline—a cryptographer's dream! 🔐✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a canonical Cosign image-signing CI workflow per ADR-041, which is the primary objective of this PR.
Description check ✅ Passed The description is comprehensive, covering all required template sections with detailed information about the workflow's mechanism, triggers, signing process, SBOM generation, verification, required secrets, and relevant references.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cosign-ci-rollout-20260428

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
.github/workflows/cosign-sign-image.yml (2)

24-27: Drop the unused OIDC permission.

id-token: write is not used anywhere in this key-based flow, so it broadens the job's privileges without providing value. Remove it unless you are actually enabling keyless Cosign signing here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/cosign-sign-image.yml around lines 24 - 27, The workflow
permissions include an unused OIDC permission `id-token: write` which
unnecessarily broadens job privileges; remove the `id-token: write` entry from
the permissions block (the lines showing `permissions:` under `contents: read` /
`packages: write`) so only the necessary permissions remain for the key-based
Cosign signing flow.

33-68: Pin the third-party actions to immutable SHAs.

This workflow is part of your signing trust chain, so moving tags like @v4, @v5, and @v0 leave you exposed to upstream tag retargeting. Pin each uses: reference to a commit SHA before shipping.

Example pinning pattern
- uses: actions/checkout@v4
+ uses: actions/checkout@<commit-sha>

Apply the same pattern to the other uses: entries in this workflow.

Also applies to: 82-83

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/cosign-sign-image.yml around lines 33 - 68, Update every
`uses:` action reference to pin to an immutable commit SHA instead of a floating
tag; specifically replace occurrences like `actions/checkout@v4`,
`docker/setup-buildx-action@v3`, `docker/login-action@v3`,
`docker/metadata-action@v5`, `docker/build-push-action@v5`, and
`sigstore/cosign-installer@v3` with their respective `@<commit-sha>` values (and
apply the same change to the additional `uses:` entries referenced at lines
82-83) so the workflow uses fixed commits rather than mutable tags.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/cosign-sign-image.yml:
- Around line 98-102: The Verify signature (smoke test) step uses a mutable gist
URL for the cosign key; update the cosign verify invocation in the "Verify
signature (smoke test)" step to use an immutable key source by either replacing
the gist URL with the gist raw URL that includes a specific commit hash (format:
https://gist.githubusercontent.com/Cramraika/c246bdb779518a588617839bfe2a75c1/raw/<commit_hash>/cosign.pub)
or vendoring the public key into the repo and referencing it locally (e.g.,
--key ./cosign.pub), then ensure the workflow downloads or checks out that
pinned key before running cosign verify.

---

Nitpick comments:
In @.github/workflows/cosign-sign-image.yml:
- Around line 24-27: The workflow permissions include an unused OIDC permission
`id-token: write` which unnecessarily broadens job privileges; remove the
`id-token: write` entry from the permissions block (the lines showing
`permissions:` under `contents: read` / `packages: write`) so only the necessary
permissions remain for the key-based Cosign signing flow.
- Around line 33-68: Update every `uses:` action reference to pin to an
immutable commit SHA instead of a floating tag; specifically replace occurrences
like `actions/checkout@v4`, `docker/setup-buildx-action@v3`,
`docker/login-action@v3`, `docker/metadata-action@v5`,
`docker/build-push-action@v5`, and `sigstore/cosign-installer@v3` with their
respective `@<commit-sha>` values (and apply the same change to the additional
`uses:` entries referenced at lines 82-83) so the workflow uses fixed commits
rather than mutable tags.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 49aed386-d9f2-4747-8a47-0ba601f493ac

📥 Commits

Reviewing files that changed from the base of the PR and between d77a78d and c42f800.

📒 Files selected for processing (1)
  • .github/workflows/cosign-sign-image.yml

Comment on lines +98 to +102
- name: Verify signature (smoke test)
run: |
cosign verify \
--key https://gist.githubusercontent.com/Cramraika/c246bdb779518a588617839bfe2a75c1/raw/cosign.pub \
"ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

GitHub gist URL immutable revision pinning raw.githubusercontent.com

💡 Result:

To pin a GitHub Gist to an immutable revision using raw.githubusercontent.com URLs: The standard raw URL format for a specific revision (immutable, as it won't change even if the Gist is updated) is: https://gist.githubusercontent.com/[username]/[gist_id]/raw/[revision_hash]/[filename] - [username]: Gist owner's username - [gist_id]: The Gist ID (e.g., from https://gist.github.com/username/123abc) - [revision_hash]: Git commit SHA for that revision (found in Gist history or "Raw" button URL) - [filename]: Name of the file in the Gist For single-file Gists without specifying filename, it returns the first/default file. Example: https://gist.githubusercontent.com/atenni/5604615/raw/30d74d258442c7c65512eafab474568dd706c430/testNewGist Omitting [revision_hash] (e.g., https://gist.githubusercontent.com/[username]/[gist_id]/raw/[filename]) points to the latest version (mutable). To get the revision hash: - View Gist revisions via the clock icon or API (GET /gists/{gist_id}). - Click "Raw" on a file; the URL includes the current revision hash. - Use GitHub Gist API: https://api.github.com/gists/[gist_id] returns files with raw_url (latest) and history. Note: https://gist.github.com/.../raw redirects to the gist.githubusercontent.com equivalent. Use curl -L if needed for redirects. Updates to non-pinned URLs may take 2-5 minutes due to caching. Gists are Git repos, so revisions are Git commits; pinning the SHA ensures immutability.

Citations:


🏁 Script executed:

# Check if the gist URL is accessible and look for gist structure
# GitHub gist URLs can be pinned to specific commits using the commit hash
# The format is: https://gist.githubusercontent.com/username/gist_id/raw/commit_hash/filename

# Let's verify the gist exists and understand its structure
curl -s -I "https://gist.githubusercontent.com/Cramraika/c246bdb779518a588617839bfe2a75c1/raw/cosign.pub" | head -20

Repository: Cramraika/bulk

Length of output: 784


🏁 Script executed:

# Also check if there's documentation in the repo about this approach
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "*.yml" -o -name "*.yaml" \) | head -20
ls -la .github/workflows/ | grep -i cosign

Repository: Cramraika/bulk

Length of output: 542


🏁 Script executed:

cat -n .github/workflows/cosign-sign-image.yml | sed -n '95,105p'

Repository: Cramraika/bulk

Length of output: 532


Pin the gist URL to an immutable revision to prevent silent signature validation changes.

The current gist URL lacks a revision hash and points to the latest version, which can be edited at any time. Use the immutable format: https://gist.githubusercontent.com/Cramraika/c246bdb779518a588617839bfe2a75c1/raw/[commit_hash]/cosign.pub (obtain the commit hash from the gist's Raw button or revision history), or vendor the public key directly in the repository.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/cosign-sign-image.yml around lines 98 - 102, The Verify
signature (smoke test) step uses a mutable gist URL for the cosign key; update
the cosign verify invocation in the "Verify signature (smoke test)" step to use
an immutable key source by either replacing the gist URL with the gist raw URL
that includes a specific commit hash (format:
https://gist.githubusercontent.com/Cramraika/c246bdb779518a588617839bfe2a75c1/raw/<commit_hash>/cosign.pub)
or vendoring the public key into the repo and referencing it locally (e.g.,
--key ./cosign.pub), then ensure the workflow downloads or checks out that
pinned key before running cosign verify.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant