Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/release-sign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: Sign Release Artifacts

on:
release:
types: [published]

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


jobs:
sign:
name: Sign release artifacts with cosign
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- name: Harden runner
uses: step-security/harden-runner@91182cccc01eb5e619899d80e4e971d6181294a7 # v2.10.1
with:
egress-policy: audit
Comment on lines +19 to +22
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.


- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
Comment on lines +24 to +25
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.


- 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.


- name: Download release assets
id: download
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
mkdir -p release-assets
if ! gh release download "$RELEASE_TAG" --dir release-assets/; then
asset_count=$(gh release view "$RELEASE_TAG" --json assets --jq '.assets | length' 2>/dev/null || echo "unknown")
if [ "$asset_count" = "0" ]; then
echo "No assets attached to release $RELEASE_TAG; skipping signing" >&2
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Failed to download assets for release $RELEASE_TAG (asset count: $asset_count)" >&2
exit 1
fi

- name: Sign release artifacts
if: steps.download.outputs.skip != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
cd release-assets
signed_count=0
for artifact in *.whl *.tar.gz; do
[ -f "$artifact" ] || continue
cosign sign-blob \
--yes \
--output-signature "${artifact}.sig" \
--output-certificate "${artifact}.pem" \
"$artifact"
Comment on lines +58 to +62
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.

signed_count=$((signed_count + 1))
done
if [ "$signed_count" -eq 0 ]; then
echo "No .whl or .tar.gz artifacts found in release-assets; expected at least one" >&2
exit 1
fi

- name: Upload signatures
if: steps.download.outputs.skip != 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: |
cd release-assets
sig_files=()
for f in *.sig *.pem; do
[ -f "$f" ] && sig_files+=("$f")
done
if [ "${#sig_files[@]}" -gt 0 ]; then
gh release upload "$RELEASE_TAG" "${sig_files[@]}" --clobber
else
echo "No signature files found to upload; expected .sig and .pem from cosign" >&2
exit 1
fi
Loading