Skip to content

feat(ci): add release artifact signing workflow#27

Closed
williaby wants to merge 1 commit into
mainfrom
feat/add-release-sign
Closed

feat(ci): add release artifact signing workflow#27
williaby wants to merge 1 commit into
mainfrom
feat/add-release-sign

Conversation

@williaby
Copy link
Copy Markdown
Contributor

@williaby williaby commented May 7, 2026

Adds cosign-based signing for release assets. Part of standard workflow set for python-package repos.

Summary by CodeRabbit

  • Chores
    • Implemented automated cryptographic signing of release artifacts to enable integrity and authenticity verification for downloaded releases.

Adds cosign-based signing for all release assets (.whl and .tar.gz).
Signatures (.sig) and certificates (.pem) are uploaded back to the
GitHub release after successful signing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 7, 2026

@codecov
Copy link
Copy Markdown

codecov Bot commented May 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

Walkthrough

This PR introduces a new GitHub Actions workflow that automatically signs Python release artifacts (wheels and tarballs) using Cosign when releases are published. The workflow downloads assets from the release, signs each with Cosign, and uploads the generated signature files back to the release for distribution.

Changes

Release Artifact Signing Workflow

Layer / File(s) Summary
Workflow Trigger & Permissions
.github/workflows/release-sign.yml
Workflow triggers on published releases with id-token: write and contents: write permissions.
Asset Acquisition & Setup
.github/workflows/release-sign.yml
Runner is hardened, repository checked out, Cosign installed, and release assets downloaded via gh with skip logic for empty releases.
Artifact Signing
.github/workflows/release-sign.yml
Downloads release artifacts are signed using cosign sign-blob for both .whl and .tar.gz files, generating .sig and .pem output files.
Signature Upload
.github/workflows/release-sign.yml
Generated signature files are collected and uploaded back to the release via gh release upload.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

ci, security

Poem

🐰 A rabbit runs swift through the release,
With cosign keys and blessed peace,
Each artifact signed, each signature sealed,
The workflow now guards what is revealed! 🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a GitHub Actions workflow for signing release artifacts using cosign.
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 feat/add-release-sign

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: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/release-sign.yml:
- Around line 7-9: Remove the top-level "id-token: write" entry from the
workflow-level permissions block so the workflow-wide default no longer grants
OIDC token write access; keep "permissions: contents: read" at top-level and
rely on the "permissions" block defined on the "sign" job (the job-level
permissions will still control OIDC access for that job), ensuring no unintended
jobs inherit id-token write.
- Around line 24-25: Remove the unnecessary "Checkout" step that uses
actions/checkout in the release-sign workflow: delete the step block with name
"Checkout" and the uses: actions/checkout@... entry (ensure no other steps
reference checked-out repo files or rely on workspace contents) so the job only
downloads release assets via the GitHub API, signs with cosign, and uploads
signatures without executing the checkout action.
- Around line 19-22: The "Harden runner" step using
step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 currently
sets egress-policy: audit which only logs outbound connections; change the input
egress-policy from audit to block (egress-policy: block) to prevent outbound
network exfiltration for this signing workflow and, if the action requires
specific allowed endpoints, add the appropriate allow list via the harden-runner
inputs after switching to block.
- Line 28: The cosign-installer action SHA is incorrect: replace the pinned SHA
`dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da` used in the `uses:
sigstore/cosign-installer@...` step with the correct commit
`1aa8e0f2454b781fbf0fbf306a4c9533a0c57409` or simply reference the `v3.7.0` tag
(e.g., `sigstore/cosign-installer@v3.7.0`) to fix the mismatch; additionally, if
this workflow requires cosign v3+, update the action to a v4+ release (e.g., use
`sigstore/cosign-installer@v4` or the appropriate v4 commit) because
cosign-installer v3.x installs cosign v2.x.
- Around line 58-62: Replace the deprecated cosign sign-blob flags
--output-signature and --output-certificate with the recommended --bundle flag:
update the cosign sign-blob invocation (the command using the "$artifact"
variable) to write a single bundle file (e.g. "${artifact}.bundle") instead of
separate .sig and .pem files, and update any downstream upload/consume steps
that referenced "${artifact}.sig" or "${artifact}.pem" to use the new bundle
filename; ensure the bundle filename is consistently used across the workflow.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 57f461cc-e39b-4d2d-a0a1-1d857c75ca5a

📥 Commits

Reviewing files that changed from the base of the PR and between 911ab53 and 30efd2a.

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

Comment on lines +7 to +9
permissions:
contents: read
id-token: write
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 | ⚡ Quick win

Remove id-token: write from the workflow-level permissions block

The job already declares its own permissions block (lines 15–17), which completely replaces the workflow-level permissions for that job. The top-level id-token: write here has no effect on the sign job but does become the default permission for any future job that is added without its own permissions block, silently granting OIDC token write access to unanticipated steps.

🔒 Proposed fix
 permissions:
   contents: read
-  id-token: write
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-sign.yml around lines 7 - 9, Remove the top-level
"id-token: write" entry from the workflow-level permissions block so the
workflow-wide default no longer grants OIDC token write access; keep
"permissions: contents: read" at top-level and rely on the "permissions" block
defined on the "sign" job (the job-level permissions will still control OIDC
access for that job), ensuring no unintended jobs inherit id-token write.

Comment on lines +19 to +22
- name: Harden runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
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 | ⚡ Quick win

Upgrade egress-policy from audit to block for this signing workflow

audit mode only logs outbound connections — it does not block them. A compromised transitive dependency running in this job could exfiltrate the OIDC token or signed artifacts without obstruction. Because this workflow specifically requests id-token: write and calls out to Sigstore services, restricting egress to the required endpoints is especially important.

🔒 Proposed fix
       - name: Harden runner
         uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
         with:
-          egress-policy: audit
+          egress-policy: block
+          allowed-endpoints: >
+            api.github.com:443
+            fulcio.sigstore.dev:443
+            rekor.sigstore.dev:443
+            tuf-repo-cdn.sigstore.dev:443
+            oauth2.sigstore.dev:443
+            uploads.github.com:443

As per coding guidelines: "Security best practices (minimal permissions, pinned actions)" — restricting egress is a key hardening control for sensitive workflows.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Harden runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
- name: Harden runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: block
allowed-endpoints: >
api.github.com:443
fulcio.sigstore.dev:443
rekor.sigstore.dev:443
tuf-repo-cdn.sigstore.dev:443
oauth2.sigstore.dev:443
uploads.github.com:443
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-sign.yml around lines 19 - 22, The "Harden runner"
step using step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7
currently sets egress-policy: audit which only logs outbound connections; change
the input egress-policy from audit to block (egress-policy: block) to prevent
outbound network exfiltration for this signing workflow and, if the action
requires specific allowed endpoints, add the appropriate allow list via the
harden-runner inputs after switching to block.

Comment on lines +24 to +25
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

The actions/checkout step is unnecessary and increases attack surface

This workflow only downloads release assets from the GitHub API, signs them with cosign, and uploads the resulting signature files back. No repository source files are referenced at any point. Removing checkout eliminates one more action execution path from the signing environment.

♻️ Proposed fix
-      - name: Checkout
-        uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
-
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
# (Previous workflow steps would appear here)
# The checkout step and its blank line are removed entirely
# (Next workflow steps would appear here)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-sign.yml around lines 24 - 25, Remove the
unnecessary "Checkout" step that uses actions/checkout in the release-sign
workflow: delete the step block with name "Checkout" and the uses:
actions/checkout@... entry (ensure no other steps reference checked-out repo
files or rely on workspace contents) so the job only downloads release assets
via the GitHub API, signs with cosign, and uploads signatures without executing
the checkout action.

uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Install cosign
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the SHA pinned in the workflow matches the v3.7.0 tag on cosign-installer
git ls-remote https://github.com/sigstore/cosign-installer.git refs/tags/v3.7.0

Repository: ByronWilliamsCPA/python-libs

Length of output: 130


🌐 Web query:

cosign-installer v3 v4 cosign binary version compatibility

💡 Result:

cosign-installer v3.x is incompatible with cosign binary v3.x and later; it cannot install cosign v3.x and defaults to cosign v2.x versions (e.g., v2.6.1 in v3.10.1).[1][2][3] cosign-installer v4.x (starting v4.0.0) adds support for installing cosign v3.x and later, with defaults like v3.0.2 in v4.0.0 progressing to v3.0.5 in v4.1.1.[4][5][3][6] v4.x can still install cosign v2.x via the cosign-release input.[1][3] To use cosign v3+, upgrade to cosign-installer v4+; v3.x is limited to cosign v2.x.[1][2]

Citations:


Fix SHA pinning mismatch for cosign-installer v3.7.0

The pinned SHA dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da does not correspond to the v3.7.0 tag. The actual commit for v3.7.0 is 1aa8e0f2454b781fbf0fbf306a4c9533a0c57409. Either update the SHA to the correct value or use the tag reference directly.

Additionally, cosign-installer v3.x installs cosign v2.x (not v3.x). If cosign v3+ is required for this workflow, upgrade to cosign-installer v4+, which supports cosign v3.x.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-sign.yml at line 28, The cosign-installer action
SHA is incorrect: replace the pinned SHA
`dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da` used in the `uses:
sigstore/cosign-installer@...` step with the correct commit
`1aa8e0f2454b781fbf0fbf306a4c9533a0c57409` or simply reference the `v3.7.0` tag
(e.g., `sigstore/cosign-installer@v3.7.0`) to fix the mismatch; additionally, if
this workflow requires cosign v3+, update the action to a v4+ release (e.g., use
`sigstore/cosign-installer@v4` or the appropriate v4 commit) because
cosign-installer v3.x installs cosign v2.x.

Comment on lines +58 to +62
cosign sign-blob \
--yes \
--output-signature "${artifact}.sig" \
--output-certificate "${artifact}.pem" \
"$artifact"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does cosign v2 (installed by cosign-installer v3.7.0) support the --bundle flag for cosign sign-blob?

💡 Result:

Yes. Cosign v2’s cosign sign-blob supports the --bundle flag to write the Sigstore “bundle” file for the blob signature/verification metadata. [1][2] In particular, the Sigstore documentation shows cosign sign-blob <file> --bundle artifact.sigstore.json as the recommended way to sign blobs. [1] Additionally, the cosign sign-blob flag reference documents --bundle string as “write everything required to verify the blob to a FILE”. [2] Note: if you install Cosign v2 using cosign-installer, whether --bundle is available is independent of the installer version; --bundle is a cosign sign-blob CLI flag in v2. [1][2]

Citations:


Switch from --output-signature/--output-certificate to --bundle for cosign sign-blob

The --output-signature and --output-certificate flags are deprecated in Cosign v2. Sigstore documentation officially recommends using the --bundle flag to write the entire Sigstore bundle (containing both signature and certificate) to a single file. This avoids a future breaking change, simplifies verification workflows (one file instead of two), and aligns with standardized Sigstore practices.

♻️ Proposed fix
           cosign sign-blob \
             --yes \
-            --output-signature "${artifact}.sig" \
-            --output-certificate "${artifact}.pem" \
+            --bundle "${artifact}.sigstore.json" \
             "$artifact"

The upload step filter would also need updating:

-          for f in *.sig *.pem; do
+          for f in *.sigstore.json; do
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release-sign.yml around lines 58 - 62, Replace the
deprecated cosign sign-blob flags --output-signature and --output-certificate
with the recommended --bundle flag: update the cosign sign-blob invocation (the
command using the "$artifact" variable) to write a single bundle file (e.g.
"${artifact}.bundle") instead of separate .sig and .pem files, and update any
downstream upload/consume steps that referenced "${artifact}.sig" or
"${artifact}.pem" to use the new bundle filename; ensure the bundle filename is
consistently used across the workflow.

@williaby
Copy link
Copy Markdown
Contributor Author

williaby commented May 8, 2026

Closing — not mergeable after other CI workflow PRs merged. Renovate will recreate.

@williaby williaby closed this May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant