Skip to content

chore(ci): add cosign signing to community image builds - #5197

Open
Fortune-Ndlovu wants to merge 5 commits into
redhat-developer:mainfrom
Fortune-Ndlovu:add-cosign-community-images
Open

chore(ci): add cosign signing to community image builds#5197
Fortune-Ndlovu wants to merge 5 commits into
redhat-developer:mainfrom
Fortune-Ndlovu:add-cosign-community-images

Conversation

@Fortune-Ndlovu

@Fortune-Ndlovu Fortune-Ndlovu commented Jul 30, 2026

Copy link
Copy Markdown
Member
  • Add keyless cosign signing to the multi-arch merge job in next-build-image.yaml
  • Community images at quay.io/rhdh-community/rhdh will be signed after the multi-arch manifest is created
  • Consumers can verify image provenance with cosign verify using the GitHub Actions OIDC issuer

Resolves: https://redhat.atlassian.net/browse/RHDHBUGS-3541

How to test: https://redhat.atlassian.net/browse/RHDHBUGS-3541?focusedCommentId=17811069

Signed-off-by: Fortune Ndlovu fndlovu@redhat.com

Add keyless cosign signing to the multi-arch merge job so that
community images at quay.io/rhdh-community/rhdh are signed after
the multi-arch manifest is created. This allows consumers to verify
image provenance using cosign verify with the GitHub Actions OIDC
issuer.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
@openshift-ci
openshift-ci Bot requested review from PatAKnight and jonkoops July 30, 2026 13:32
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.96%. Comparing base (e431ad4) to head (4bf22d1).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #5197      +/-   ##
==========================================
- Coverage   63.69%   59.96%   -3.74%     
==========================================
  Files         123      111      -12     
  Lines        2424     2198     -226     
  Branches      571      546      -25     
==========================================
- Hits         1544     1318     -226     
  Misses        878      878              
  Partials        2        2              
Flag Coverage Δ
rhdh 59.96% <ø> (-3.74%) ⬇️
Components Coverage Δ
Backend plugins ∅ <ø> (∅)
Backend app 66.66% <ø> (ø)
Frontend app 58.89% <ø> (ø)
Plugin utils ∅ <ø> (∅)
Dynamic plugins utils ∅ <ø> (∅)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e431ad4...4bf22d1. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Fortune-Ndlovu Fortune-Ndlovu changed the title ci: add cosign signing to community image builds chore(ci): add cosign signing to community image builds Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Image was built and published successfully. It is available at:

@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/review

@rhdh-qodo-merge

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Warning

/review is deprecated. Use /agentic_review instead (removal date not yet scheduled).

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Invalid Digest

imagetools inspect --format '{{json .Manifest}}' returns the manifest document, whose top-level object generally has no digest property. Consequently, DIGEST may become null, and cosign will attempt to sign an invalid reference. Retrieve and validate the registry descriptor digest before signing.

primary_tag=$(echo "$meta" | jq -r '.tags[0]')
DIGEST=$(docker buildx imagetools inspect --format '{{json .Manifest}}' "$primary_tag" | jq -r '.digest')

echo "$meta" | jq -r '.tags | unique[]' | while IFS= read -r tag; do
  [ -z "$tag" ] && continue
  echo "Signing ${tag}@${DIGEST}"
  cosign sign --yes "${tag}@${DIGEST}"
Missing Guard

The signing step is not conditioned on HAS_QUAY_AUTH, unlike registry-dependent workflow operations. Runs without Quay credentials may attempt to inspect and sign images that were not published by this job, causing otherwise supported unauthenticated runs to fail.

- name: Sign the published images
  env:
    META_RELEASE_JSON: ${{ steps.meta-release.outputs.json }}
    META_NEXT_JSON: ${{ steps.meta-next.outputs.json }}
  run: |
    meta="$META_RELEASE_JSON"
    if [ -z "$meta" ] || [ "$meta" = "null" ]; then
      meta="$META_NEXT_JSON"
    fi

    primary_tag=$(echo "$meta" | jq -r '.tags[0]')
    DIGEST=$(docker buildx imagetools inspect --format '{{json .Manifest}}' "$primary_tag" | jq -r '.digest')

    echo "$meta" | jq -r '.tags | unique[]' | while IFS= read -r tag; do
      [ -z "$tag" ] && continue
      echo "Signing ${tag}@${DIGEST}"
      cosign sign --yes "${tag}@${DIGEST}"
    done
📄 References
  1. No matching references available

Use buildx template for digest retrieval instead of fragile JSON
parsing, add credential guard and null-check for graceful fallback.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
Signed-off-by: Fortune-Ndlovu <fndlovu@redhat.com>
@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentic_review

@rhdh-qodo-merge

rhdh-qodo-merge Bot commented Jul 31, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 46 rules
✅ Cross-repo context
  Not relevant to this PR: redhat-developer/rhdh-plugins
  Not relevant to this PR: redhat-developer/rhdh-chart
  Not relevant to this PR: redhat-developer/rhdh-operator
  Not relevant to this PR: redhat-developer/rhdh-local

Grey Divider


Action required

1. Unsigned images may pass CI ✓ Resolved 🐞 Bug ⛨ Security
Description
If digest resolution returns empty or null, the new signing step exits successfully and the
workflow continues, leaving published images unsigned while the overall run is green. This
undermines the workflow’s supply-chain guarantee because unsigned tags can be shipped without an
explicit failure.
Code

.github/workflows/next-build-image.yaml[R349-352]

+            if [ -z "$DIGEST" ] || [ "$DIGEST" = "null" ]; then
+              echo "::warning::Could not resolve digest for ${primary_tag}, skipping signing"
+              exit 0
+            fi
Relevance

●●● Strong

PR #2922 accepted guidance that exit 0/skip can mislead; likely want signing failure/explicit
gating.

PR-#2922

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added signing step explicitly prints a warning and exit 0 when the digest is empty or null,
which means no cosign sign runs but the job can still complete successfully.

.github/workflows/next-build-image.yaml[335-358]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The signing step treats an empty/`null` resolved digest as a warning and exits 0, allowing the workflow to succeed without producing any cosign signatures.

## Issue Context
This workflow’s purpose is to publish signed community images; a successful run with no signatures is a correctness/security failure that will be easy to miss.

## Fix Focus Areas
- .github/workflows/next-build-image.yaml[346-352]

### Suggested implementation direction
- Add a short retry loop around digest resolution (similar to the manifest propagation check).
- If the digest still can’t be resolved after retries, emit `::error::` and `exit 1` so the workflow fails loudly (or gate downstream steps on a `signed=true/false` output if you intentionally want non-blocking behavior).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Digest reused across tags ✓ Resolved 🐞 Bug ≡ Correctness
Description
The new signing step resolves a single digest from the first tag and then signs every published tag
with that digest, but the workflow creates/pushes the multi-arch manifest separately per tag so
different tags can legitimately point to different digests. This can cause signing to fail for some
tags or leave some tags without a verifiable signature when users run cosign verify <image>:<tag>.
Code

.github/workflows/next-build-image.yaml[R346-358]

+            primary_tag=$(echo "$meta" | jq -r '.tags[0]')
+            DIGEST=$(docker buildx imagetools inspect "$primary_tag" --format '{{println .Digest}}')
+
+            if [ -z "$DIGEST" ] || [ "$DIGEST" = "null" ]; then
+              echo "::warning::Could not resolve digest for ${primary_tag}, skipping signing"
+              exit 0
+            fi
+
+            echo "$meta" | jq -r '.tags | unique[]' | while IFS= read -r tag; do
+              [ -z "$tag" ] && continue
+              echo "Signing ${tag}@${DIGEST}"
+              cosign sign --yes "${tag}@${DIGEST}"
+            done
Relevance

●●● Strong

PR #3307 creates/annotates manifests per tag; per-tag correctness focus implies fixing per-tag
digest signing accepted.

PR-#3307
PR-#3047

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The workflow pushes a manifest list for each tag in a loop, meaning each tag may reference a
distinct manifest digest, but the new signing step inspects only .tags[0] to get a single digest
and applies it to all tags.

.github/workflows/next-build-image.yaml[262-281]
.github/workflows/next-build-image.yaml[335-358]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The signing step computes one digest from `.tags[0]` and reuses it for all tags, which is unsafe if different tags resolve to different manifest digests.

## Issue Context
This workflow intentionally pushes the manifest list separately for each tag, so the signing step should either (a) verify all tags resolve to the same digest and sign once, or (b) resolve and sign each tag’s digest.

## Fix Focus Areas
- .github/workflows/next-build-image.yaml[335-359]

### Suggested implementation direction
- Option A (robust, minimal signatures):
 - For each tag in `.tags`, resolve `digest=$(docker buildx imagetools inspect "$tag" --format '{{println .Digest}}')`.
 - Deduplicate by digest (e.g., `sort -u`) and `cosign sign --yes "${REGISTRY}/${REGISTRY_IMAGE}@${digest}"` once per unique digest.
- Option B (assert invariant):
 - Resolve digests for all tags; if any differ, fail with an error explaining which tag differs; otherwise sign once by digest.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Address review feedback: resolve each tag's digest independently
instead of assuming all tags share one digest, and fail the build
if digest resolution fails rather than silently skipping signing.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
Signed-off-by: Fortune-Ndlovu <fndlovu@redhat.com>
@github-actions

Copy link
Copy Markdown
Contributor

The container image build workflow finished with status: cancelled.

@Fortune-Ndlovu

Copy link
Copy Markdown
Member Author

/agentc_review

@Fortune-Ndlovu
Fortune-Ndlovu force-pushed the add-cosign-community-images branch from d32b50d to a2d5621 Compare July 31, 2026 14:51
@github-actions

Copy link
Copy Markdown
Contributor

The container image build workflow finished with status: cancelled.

The --format '{{println .Digest}}' template field does not exist in
imagetools inspect. Parse the standard output instead.

Signed-off-by: Fortune Ndlovu <fndlovu@redhat.com>
Signed-off-by: Fortune-Ndlovu <fndlovu@redhat.com>
@github-actions

Copy link
Copy Markdown
Contributor

The container image build workflow finished with status: cancelled.

@github-actions

Copy link
Copy Markdown
Contributor

Image was built and published successfully. It is available at:

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Image was built and published successfully. It is available at:

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