Skip to content

fix(build): retry cosign signing when on_existing_tag skips the build - #603

Merged
bedatty merged 4 commits into
developfrom
fix/cosign-retry-existing-tag
Jul 22, 2026
Merged

bedatty merged 4 commits into
developfrom
fix/cosign-retry-existing-tag

Conversation

@bedatty

@bedatty bedatty commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Description

When on_existing_tag: skip skips build/push because the tag already exists in a registry, the cosign signing steps were also skipped — they depended on steps.build-push.outputs.digest (only set when the build actually ran) and were gated on steps.preflight.outputs.should_build != 'false'.

Net effect: once a tag is successfully pushed but fails to sign (e.g. a transient network flake in sigstore/cosign-installer), there was no way to retry just the signing step. The only recovery paths were a full rebuild (blocked by the immutable-tag pre-flight guard) or cutting an entirely new release just to get a signed image.

Real-world case: LerianStudio/br-ccs run https://github.com/LerianStudio/br-ccs/actions/runs/28989167685/job/86024981607 — image pushed successfully, cosign signing failed transiently, and re-running hit the tag-immutability guard before signing could even be attempted again.

Fix

  • New Resolve digest for existing tag step in .github/workflows/build.yml, gated on inputs.enable_cosign_sign && steps.preflight.outputs.should_build == 'false'. Resolves the digest of the already-pushed tag via docker buildx imagetools inspect <ref> --format '{{json .Manifest}}' | jq -r '.digest'.
  • Build cosign image references, Sign container images with cosign, and Report cosign signing status are now gated on inputs.enable_cosign_sign alone (dropped the should_build != 'false' condition), and use steps.build-push.outputs.digest || steps.existing-digest.outputs.digest for the digest.
  • docs/build-workflow.md: documented that on_existing_tag: skip now also retries cosign signing.

This turns skip into a genuine idempotent re-run path for signing, not just for build/push — a maintainer can flip on_existing_tag: skip for one re-run to recover from a transient signing failure instead of cutting a new release.

Type of Change

  • fix: Bug fix in a workflow (incorrect behavior, broken step, wrong condition)

Breaking Changes

None. When should_build is true (the normal build path), behavior is unchanged — digest still comes from steps.build-push.outputs.digest. The change only affects the skip path, which previously skipped signing entirely.

Testing

  • YAML syntax validated locally
  • Triggered a real workflow run on a caller repository using @this-branch or the beta tag
  • Verified all existing inputs still work with default values
  • Confirmed no secrets or tokens are printed in logs
  • Checked that unrelated workflows are not affected

Related Issues

Closes #559

When on_existing_tag: skip skips build/push because the tag already
exists, the cosign steps were also skipped since they depended on
steps.build-push.outputs.digest and should_build != 'false'. A
transient cosign/Rekor failure on an already-pushed tag then had no
retry path short of a full rebuild or a brand new release.

Add a 'Resolve digest for existing tag' step that resolves the
digest from the existing registry tag via docker buildx imagetools
inspect when the build was skipped, and gate the cosign steps on
enable_cosign_sign alone, feeding
steps.build-push.outputs.digest || steps.existing-digest.outputs.digest.

Closes #559
@bedatty
bedatty requested a review from a team as a code owner July 22, 2026 13:18
@lerian-studio lerian-studio added size/XS PR changes < 50 lines documentation Improvements or additions to documentation workflow Changes to one or more reusable workflow files labels Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 09b55218-5d7e-4f56-addb-2bccf6eee727

📥 Commits

Reviewing files that changed from the base of the PR and between 9d71835 and 71fe9a4.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Summary by CodeRabbit

  • Bug Fixes
    • Improved cosign signing reliability for workflow re-runs when the target image tag already exists.
    • When the build/push step is skipped, the workflow now looks up existing per-registry digests and signs using image@digest references for consistent retry behavior.
    • Signing status reporting now uses the actual digest-based refs list for clearer warnings.
  • Documentation
    • Updated build-workflow guidance to reflect idempotent artifact generation and digest-based cosign signing when tags already exist.

Walkthrough

The build workflow resolves existing registry digests when on_existing_tag: skip bypasses build/push, constructs digest-qualified cosign references, and retries signing. Documentation describes this behavior.

Changes

Cosign retry flow

Layer / File(s) Summary
Existing digest resolution
.github/workflows/build.yml, docs/build-workflow.md
The workflow resolves per-registry image digests for existing tags, and documentation describes cosign retries in this mode.
Cosign signing and status reporting
.github/workflows/build.yml
Cosign references use build or existing digests, signing no longer depends on a build, and failure reporting uses the resolved references.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

  • LerianStudio/github-actions-shared-workflows#559 — Covers resolving existing image digests and enabling cosign-only retries when builds are skipped.

Possibly related PRs

Suggested labels: security, build

Suggested reviewers: gandalf-at-lerian

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main workflow change.
Description check ✅ Passed The PR description covers the required sections and includes the change summary, type, breaking changes, testing, and related issue.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cosign-retry-existing-tag

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
.github/workflows/build.yml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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

@lerian-studio

lerian-studio commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

🔍 PR Validation Summary

✅ PR Mergeable — no blocking failures

Check Status Blocking
Source Branch ✅ success yes
PR Title ✅ success yes
PR Description ✅ success yes
PR Size ✅ success no
Auto Labels ✅ success no
PR Metadata ✅ success no

🔍 View workflow run

@lerian-studio

lerian-studio commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

🔍 Lint Analysis

Check Files Scanned Status
YAML Lint 1 file(s) ✅ success
Action Lint 1 file(s) ✅ success
Pinned Actions 1 file(s) ✅ success
Markdown Link Check 1 file(s) ✅ success
Spelling Check 2 file(s) ✅ success
Shell Check 1 file(s) ✅ success
README Check 1 file(s) ✅ success
Composite Schema no changes ⏭️ skipped
Deployment Matrix no changes ⏭️ skipped

🔍 View full scan logs

@lerian-studio

lerian-studio commented Jul 22, 2026 •

Copy link
Copy Markdown
Contributor

🛡️ CodeQL Analysis Results

Languages analyzed: actions

Found 1 issue(s): 1 Medium

Severity Rule File Message
🟡 Medium actions/untrusted-checkout/medium .github/workflows/build.yml:300 Potential unsafe checkout of untrusted pull request on non-privileged workflow.

🔍 View full scan logs | 🛡️ Security tab

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 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/build.yml:
- Around line 476-492: Update the existing-digest resolution step and its
corresponding later block to handle Docker Hub and GHCR independently when both
registries are enabled. Check each registry’s tag separately, emit a reference
only when that tag exists, and use that registry’s own digest; alternatively,
make preflight fail when only one registry tag exists so signing never uses a
nonexistent ref or the other registry’s digest. Preserve single-registry
behavior and the existing signing flow.
🪄 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.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 424da934-7b8d-46f0-aba3-6a26d44298b4

📥 Commits

Reviewing files that changed from the base of the PR and between 102f5c9 and c4fe894.

📒 Files selected for processing (2)
  • .github/workflows/build.yml
  • docs/build-workflow.md

Comment thread .github/workflows/build.yml
Address CodeRabbit finding on PR #603: when both DockerHub and GHCR
are enabled, the existing-tag digest resolution always picked
DockerHub (or GHCR alone) and reused that single digest for both
registries' refs. If a tag existed in only one registry, this could
construct a nonexistent ref for the other registry using the wrong
digest.

Resolve each enabled registry's digest independently and only emit a
ref for a registry when its own digest was actually found.
@lerian-studio lerian-studio added size/S PR changes 50–199 lines and removed size/XS PR changes < 50 lines labels Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 2

🤖 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/build.yml:
- Around line 562-565: Update the failure-report environment setup for the
cosign signing step to preserve both Docker Hub and GHCR digests when signing an
existing tag. Replace the singular DIGEST fallback chain with registry-qualified
digest/ref pairs, ensuring the report can correlate each digest with its
corresponding registry reference without discarding either value.
- Around line 487-510: Update the digest lookup logic in the cosign-sign step
for the Docker Hub and GHCR branches to distinguish inspection or jq failures
from a genuinely missing digest. Track an error state separately for each
enabled registry, propagate failures from docker buildx imagetools inspect or
jq, and abort before signing if any enabled registry cannot be resolved, while
preserving the existing per-registry digest outputs.
🪄 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.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7f94278-35d8-410c-a718-b49cb7601af0

📥 Commits

Reviewing files that changed from the base of the PR and between c4fe894 and e158f99.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml
Comment thread .github/workflows/build.yml Outdated
…t digests

Address CodeRabbit findings on PR #603:

- Resolve digest for existing tag: distinguish a genuine 'tag not
  found' from an inspect/lookup failure (transient network error,
  auth issue) by emitting a ::warning:: with the actual error in the
  latter case, instead of silently treating both as 'no digest'.
  Kept fail-open (skip that registry, don't abort the job) to match
  this file's existing convention for the same tradeoff in the
  pre-flight tag-existence check just above.
- Report cosign signing status: stop collapsing to a single DIGEST
  value that discarded one registry's digest when both were
  resolved; REFS already lists each registry's fully-qualified ref
  with its own digest, so the redundant/lossy single-digest line was
  removed instead of duplicating that same registry-qualified data.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 2

🤖 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/build.yml:
- Around line 497-502: Update both registry branches in the imagetools
inspection logic to keep each ::warning:: message static and avoid interpolating
raw OUTPUT. Print the captured diagnostics separately using safe escaping or a
non-workflow-command diagnostic path, while preserving the existing no-digest
and inspection-failure handling.
- Around line 568-584: The unsigned-image summary in the failure step must not
claim that every ref is unsigned, since earlier refs may already have been
signed before the loop failed. Update the messages in the failure-summary run
block and related wording to state only that signing did not complete for every
requested ref, without asserting per-ref status; use the existing
steps.cosign-sign failure flow and REFS output.
🪄 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.yml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d7e48f0b-2165-4422-8f47-04d7b7ba7c41

📥 Commits

Reviewing files that changed from the base of the PR and between e158f99 and 9d71835.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml
Comment thread .github/workflows/build.yml Outdated
…rding

Address CodeRabbit findings on PR #603:

- Resolve digest for existing tag: percent-encode the captured
  'docker buildx imagetools inspect' output (%, CR, LF) before
  embedding it in a ::warning:: line, so it can't corrupt or spoof a
  workflow command annotation.
- Report cosign signing status: cosign-sign signs refs one by one, so
  a failure partway through the list doesn't mean every ref is
  unsigned. Reworded the summary to reflect that signing didn't
  complete for every ref instead of asserting all refs are unsigned.
@bedatty
bedatty merged commit 5d74912 into develop Jul 22, 2026
2 checks passed
@github-actions
github-actions Bot deleted the fix/cosign-retry-existing-tag branch July 22, 2026 14:07
@coderabbitai coderabbitai Bot mentioned this pull request Jul 22, 2026
1 of 14 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/S PR changes 50–199 lines workflow Changes to one or more reusable workflow files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build.yml: no way to retry cosign signing alone after a transient failure on an already-pushed tag

2 participants