Skip to content

ART-21809: Add doozer verify-image-consistency command - #3213

Closed
tomasdavidorg wants to merge 5 commits into
openshift-eng:mainfrom
tomasdavidorg:ART-21809
Closed

ART-21809: Add doozer verify-image-consistency command#3213
tomasdavidorg wants to merge 5 commits into
openshift-eng:mainfrom
tomasdavidorg:ART-21809

Conversation

@tomasdavidorg

@tomasdavidorg tomasdavidorg commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Verify that every image in the release payload is present in the shipment MR or has already been released in the Red Hat catalog.

Compares payload images (oc adm release info --pullspecs) against shipment components from GitLab MR YAML files. RHCOS images are skipped. Images matched by digest, list digest, or VCS reference, with Red Hat Catalog API as fallback.

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED

Summary by CodeRabbit

  • New Features

    • Added a verify-image-consistency command to compare release payload images with shipment components.
    • Reports payload and shipment versions, skipped images, per-image match status, and overall pass/fail results.
    • Supports text and JSON output, with catalog fallback when needed.
    • Returns a failure status when any image cannot be verified.
  • Tests

    • Added coverage for matching logic, image discovery, fallback behavior, error handling, and text/JSON output.

Verify that every image in the release payload is present in the
shipment MR or has already been released in the Red Hat catalog.

Compares payload images (oc adm release info --pullspecs) against
shipment components from GitLab MR YAML files. RHCOS images are
skipped. Images matched by digest, list digest, or VCS reference,
with Red Hat Catalog API as fallback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 30, 2026
@openshift-ci-robot

openshift-ci-robot commented Jul 30, 2026

Copy link
Copy Markdown

@tomasdavidorg: This pull request references ART-21809 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the sub-task to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Verify that every image in the release payload is present in the shipment MR or has already been released in the Red Hat catalog.

Compares payload images (oc adm release info --pullspecs) against shipment components from GitLab MR YAML files. RHCOS images are skipped. Images matched by digest, list digest, or VCS reference, with Red Hat Catalog API as fallback.

Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign fgallott for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: openshift-eng/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 935c4236-4734-4809-a27d-d784aed0e67f

📥 Commits

Reviewing files that changed from the base of the PR and between 9dac3e7 and a5b5a5c.

📒 Files selected for processing (1)
  • doozer/doozerlib/cli/verify_image_consistency.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • doozer/doozerlib/cli/verify_image_consistency.py

Walkthrough

The change adds a verify-image-consistency CLI command. It compares release payload images with shipment components, resolves image identifiers, checks the Red Hat catalog, renders JSON or text results, and exits with status 1 when images are missing.

Changes

Image consistency verification

Layer / File(s) Summary
Verification contracts and image discovery
doozer/doozerlib/cli/verify_image_consistency.py, doozer/tests/cli/test_verify_image_consistency.py
Defines result and identifier dataclasses, skip rules, identifier matching, payload extraction, shipment component extraction, and related tests.
Metadata resolution and consistency matching
doozer/doozerlib/cli/verify_image_consistency.py, doozer/tests/cli/test_verify_image_consistency.py
Resolves image metadata, queries the Red Hat catalog for unmatched images, matches payload images, and tests orchestration and fallback behavior.
CLI registration and result output
doozer/doozerlib/cli/verify_image_consistency.py, doozer/doozerlib/cli/__main__.py, doozer/tests/cli/test_verify_image_consistency.py
Resolves the shipment MR, registers the command, renders text and JSON results, handles failure status, and tests output behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Verification
  participant OpenShift
  participant GitLab
  participant Catalog
  CLI->>Verification: start image consistency verification
  Verification->>OpenShift: fetch payload images and identifiers
  Verification->>GitLab: fetch shipment components
  Verification->>Verification: match image identifiers
  Verification->>Catalog: check unmatched image digest
  Catalog-->>Verification: return catalog match
  Verification-->>CLI: render pass/fail result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 10 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Ai-Attribution ⚠️ Warning AI use is declared in the PR and all five PR commits use Co-Authored-By: Claude Opus 4.6; none has an Assisted-by or Generated-by trailer. Replace the AI Co-Authored-By trailers with the required Red Hat Assisted-by or Generated-by trailer format in the PR commits.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the new doozer verify-image-consistency command and matches the main change in the pull request.
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.
No-Weak-Crypto ✅ Passed The complete PR diff contains no MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB, or custom crypto; digest/VCS equality checks compare public image identifiers, not secrets.
Container-Privileges ✅ Passed The PR adds only Python CLI and test files; its diff contains no container/Kubernetes manifests or privileged settings such as privileged, hostPID, hostNetwork, SYS_ADMIN, or allowPrivilegeEscalation.
No-Sensitive-Data-In-Logs ✅ Passed Logging and output expose only public URLs, image references, and digest values. No passwords, API keys, tokens, or PII are logged. The code logs standard container image pullspecs, digests, and Gi...
No-Hardcoded-Secrets ✅ Passed No hardcoded secrets, API keys, tokens, passwords, or credentials found in the pull request code. Only public URLs (Red Hat Catalog API, Quay.io) without embedded credentials are present.
No-Injection-Vectors ✅ Passed No listed injection vector is present: YAML uses yaml.safe_load, commands use argument lists with create_subprocess_exec, and no shell=True, eval/exec, pickle.loads, os.system, SQL concatenation, o...
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
doozer/doozerlib/cli/verify_image_consistency.py (1)

160-176: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Set an explicit request timeout for the catalog lookup.

session.get(url) relies on aiohttp's session-level default; the library's own docs note aiohttp ClientSession has "Default client timeouts, ClientTimeout instance. The value can be tuned by passing timeout parameter to ClientSession constructor.", and that default is commonly cited as "the default timeout set by the library is 300 seconds". Without an explicit shorter timeout, a slow/unreachable catalog endpoint can stall each unmatched image's check for minutes.

♻️ Proposed fix
     try:
-        async with aiohttp.ClientSession() as session:
+        timeout = aiohttp.ClientTimeout(total=15)
+        async with aiohttp.ClientSession(timeout=timeout) as session:
             async with session.get(url) as resp:
🤖 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 `@doozer/doozerlib/cli/verify_image_consistency.py` around lines 160 - 176,
Update the catalog request in check_catalog to use an explicit shorter aiohttp
timeout, passing the configured timeout directly to session.get (or the
ClientSession constructor) instead of relying on aiohttp’s default. Preserve the
existing response handling and exception fallback behavior.
🤖 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 `@doozer/doozerlib/cli/verify_image_consistency.py`:
- Around line 179-183: Update the async flows around fetch_payload_images and
fetch_shipment_components to schedule both operations with asyncio.gather or
asyncio.create_task before awaiting results, preserving their existing result
ordering. Likewise, change the identifiers_tasks handling around
fetch_image_identifiers so all unique pullspec lookups are scheduled before
collecting results, allowing them to execute concurrently rather than
sequentially.
- Around line 113-114: Update the diff retrieval flow around
mr.diffs.list(all=True) to check whether the returned list is empty before
accessing its first element. Handle the no-diff-version case with a clear
descriptive error while preserving the existing mr.diffs.get call for available
diff versions.
- Around line 160-176: Update check_catalog() to query the Red Hat Catalog API
using the docker_image_digest filter instead of image_id, while preserving the
existing response handling and failure behavior.

---

Nitpick comments:
In `@doozer/doozerlib/cli/verify_image_consistency.py`:
- Around line 160-176: Update the catalog request in check_catalog to use an
explicit shorter aiohttp timeout, passing the configured timeout directly to
session.get (or the ClientSession constructor) instead of relying on aiohttp’s
default. Preserve the existing response handling and exception fallback
behavior.
🪄 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: Repository: openshift-eng/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b8ebef29-5f76-44c6-8d07-dbc8b96e1fba

📥 Commits

Reviewing files that changed from the base of the PR and between bc8e9a5 and 11ff8ab.

📒 Files selected for processing (3)
  • doozer/doozerlib/cli/__main__.py
  • doozer/doozerlib/cli/verify_image_consistency.py
  • doozer/tests/cli/test_verify_image_consistency.py

Comment thread doozer/doozerlib/cli/verify_image_consistency.py Outdated
Comment thread doozer/doozerlib/cli/verify_image_consistency.py
Comment thread doozer/doozerlib/cli/verify_image_consistency.py Outdated
- Guard against empty MR diff versions list with descriptive error
- Fix Catalog API filter: use docker_image_digest instead of image_id
- Use asyncio.gather for concurrent payload/shipment fetch and image
  identifier lookups instead of sequential awaits

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
doozer/doozerlib/cli/verify_image_consistency.py (1)

219-219: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the zip invariant explicit. Use strict=True here so any future length mismatch between pullspec_list and fetched fails fast.

🤖 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 `@doozer/doozerlib/cli/verify_image_consistency.py` at line 219, Update the zip
call that builds identifiers in the verify-image consistency flow to pass
strict=True, ensuring mismatched pullspec_list and fetched lengths fail
immediately while preserving the existing dictionary construction.

Source: Linters/SAST tools

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

Nitpick comments:
In `@doozer/doozerlib/cli/verify_image_consistency.py`:
- Line 219: Update the zip call that builds identifiers in the verify-image
consistency flow to pass strict=True, ensuring mismatched pullspec_list and
fetched lengths fail immediately while preserving the existing dictionary
construction.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift-eng/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4aeb5cf8-39b0-49ca-a0b7-ad2fe64b78b8

📥 Commits

Reviewing files that changed from the base of the PR and between 11ff8ab and 2846610.

📒 Files selected for processing (1)
  • doozer/doozerlib/cli/verify_image_consistency.py

- Add explicit 15s timeout for Red Hat Catalog API requests
- Use strict=True in zip() for pullspec/identifiers mapping

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
doozer/doozerlib/cli/verify_image_consistency.py (1)

234-236: 🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift

Bound catalog fallback concurrency.

Each unmatched image waits for its catalog request to finish before the next request starts. With the 15-second timeout, a catalog outage can make runtime grow to roughly 15 seconds × unmatched images; creating a new ClientSession per lookup also prevents connection reuse. Reuse a shared session and perform bounded-concurrency catalog checks.

🤖 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 `@doozer/doozerlib/cli/verify_image_consistency.py` around lines 234 - 236,
Update the unmatched-image handling around check_catalog so catalog lookups
reuse a shared aiohttp ClientSession and run with bounded concurrency instead of
being awaited serially per image. Add a concurrency limiter for the catalog
fallback requests, preserve setting check.found_in to "catalog" only when the
lookup succeeds, and ensure the shared session is properly closed.
🤖 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 `@doozer/doozerlib/cli/verify_image_consistency.py`:
- Around line 167-168: Validate the external digest with an allow-list matching
the documented digest grammar before constructing the catalog URL in the
verify-image flow. Reject malformed or empty values before the f-string
interpolation, and only build the RSQL filter after validation succeeds.

---

Outside diff comments:
In `@doozer/doozerlib/cli/verify_image_consistency.py`:
- Around line 234-236: Update the unmatched-image handling around check_catalog
so catalog lookups reuse a shared aiohttp ClientSession and run with bounded
concurrency instead of being awaited serially per image. Add a concurrency
limiter for the catalog fallback requests, preserve setting check.found_in to
"catalog" only when the lookup succeeds, and ensure the shared session is
properly closed.
🪄 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: Repository: openshift-eng/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 97a6b020-9098-4b0f-a0f4-3881faab4cd8

📥 Commits

Reviewing files that changed from the base of the PR and between 2846610 and bb55654.

📒 Files selected for processing (1)
  • doozer/doozerlib/cli/verify_image_consistency.py

Comment on lines +167 to +168
url = f"{CATALOG_API_URL}?filter=docker_image_digest=={digest}"
try:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Validate digest before interpolating it into the catalog filter.

digest originates from external image metadata but is only checked for emptiness before being inserted into the RSQL query. A malformed value containing query or RSQL delimiters could alter the filter and produce a false catalog match. Enforce the documented digest grammar with an allow-list before constructing the URL.

As per path instructions, validate at trust boundaries with allow-lists, not deny-lists.

🤖 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 `@doozer/doozerlib/cli/verify_image_consistency.py` around lines 167 - 168,
Validate the external digest with an allow-list matching the documented digest
grammar before constructing the catalog URL in the verify-image flow. Reject
malformed or empty values before the f-string interpolation, and only build the
RSQL filter after validation succeeds.

Source: Path instructions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
@tomasdavidorg tomasdavidorg added the tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges. label Jul 31, 2026
… verify-image-consistency

Resolve shipment MR URL from assembly config and construct payload
pullspec from assembly name, consistent with verify-image-grades pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
@openshift-ci

openshift-ci Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@tomasdavidorg: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/security a5b5a5c link false /test security

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@tomasdavidorg

Copy link
Copy Markdown
Contributor Author

Closing — elliott already has verify-payload which does the same check (payload vs advisory/shipment). For post-release ERT verification we'll reuse verify-payload instead of adding a new command.

@tomasdavidorg
tomasdavidorg deleted the ART-21809 branch August 3, 2026 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. tide/merge-method-squash Denotes a PR that should be squashed by tide when it merges.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants