Skip to content

ART-21816: Add doozer verify-image-grades command for Pyxis freshness… - #3216

Open
tomasdavidorg wants to merge 8 commits into
openshift-eng:mainfrom
tomasdavidorg:ART-21816
Open

ART-21816: Add doozer verify-image-grades command for Pyxis freshness…#3216
tomasdavidorg wants to merge 8 commits into
openshift-eng:mainfrom
tomasdavidorg:ART-21816

Conversation

@tomasdavidorg

@tomasdavidorg tomasdavidorg commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

… grade check

Queries the Red Hat Catalog (Pyxis) API for container image freshness grades from a shipment MR. Flags images with grade worse than B or Unknown as unhealthy.

Uses standard --group + --assembly global options with config_only initialization. Resolves shipment MR URL from assembly config in releases.yml via assembly_config_struct().

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 the verify-image-grades command to assess shipment container image freshness.
    • Supports text and JSON output with healthy, unhealthy, and unknown results.
    • Returns a failing status when any image is unhealthy.
    • Reports warnings for missing data, invalid dates, unavailable grades, service errors, and malformed shipment files.
  • Tests

    • Added comprehensive coverage for verification, error handling, result aggregation, and output formats.

… grade check

Queries the Red Hat Catalog (Pyxis) API for container image freshness
grades from a shipment MR. Flags images with grade worse than B or
Unknown as unhealthy.

Uses standard --group + --assembly global options with config_only
initialization. Resolves shipment MR URL from assembly config in
releases.yml via assembly_config_struct().

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 commented Jul 31, 2026

Copy link
Copy Markdown

@tomasdavidorg: This pull request references ART-21816 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:

… grade check

Queries the Red Hat Catalog (Pyxis) API for container image freshness grades from a shipment MR. Flags images with grade worse than B or Unknown as unhealthy.

Uses standard --group + --assembly global options with config_only initialization. Resolves shipment MR URL from assembly config in releases.yml via assembly_config_struct().

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-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jul 31, 2026
@openshift-ci

openshift-ci Bot commented Jul 31, 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 thegreyd 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 31, 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

Walkthrough

Adds the verify-image-grades CLI command. It resolves shipment data, extracts image digests, queries Pyxis freshness grades concurrently, renders text or JSON results, and exits with status 1 when images are unhealthy.

Changes

Image Grade Verification

Layer / File(s) Summary
Shipment resolution and component extraction
doozer/doozerlib/cli/verify_image_grades.py, doozer/tests/cli/test_verify_image_grades.py
Resolves the shipment merge request and extracts validated component images from shipment YAML and advisory files.
Grade contracts and selection
doozer/doozerlib/cli/verify_image_grades.py, doozer/tests/cli/test_verify_image_grades.py
Defines result models, extracts digests, selects current grades, and classifies image health.
Concurrent Pyxis verification
doozer/doozerlib/cli/verify_image_grades.py, doozer/tests/cli/test_verify_image_grades.py
Queries Pyxis concurrently and handles missing digests, unavailable grades, API failures, and unhealthy results.
CLI registration and output
doozer/doozerlib/cli/__main__.py, doozer/doozerlib/cli/verify_image_grades.py, doozer/tests/cli/test_verify_image_grades.py
Registers the command, renders text or JSON output, and validates command behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant verify_image_grades_cli
  participant resolve_shipment_mr_url
  participant fetch_shipment_components
  participant GitLab
  participant verify_image_grades
  participant query_freshness_grades
  participant Pyxis
  participant render_result

  verify_image_grades_cli->>resolve_shipment_mr_url: Resolve shipment MR URL
  resolve_shipment_mr_url->>fetch_shipment_components: Pass MR URL
  fetch_shipment_components->>GitLab: Read shipment YAML and advisory files
  GitLab-->>fetch_shipment_components: Return component images
  fetch_shipment_components-->>verify_image_grades_cli: Return components and shipment version
  verify_image_grades_cli->>verify_image_grades: Verify image digests
  verify_image_grades->>query_freshness_grades: Query grades concurrently
  query_freshness_grades->>Pyxis: Request freshness grades
  Pyxis-->>query_freshness_grades: Return grades or failures
  query_freshness_grades-->>verify_image_grades: Return image grades
  verify_image_grades-->>render_result: Return verification result
  render_result-->>verify_image_grades_cli: Render text or JSON output
Loading

Possibly related PRs

  • openshift-eng/art-tools#3213: Adds a related shipment-verification CLI command with similar shipment merge-request resolution and component parsing.
🚥 Pre-merge checks | ✅ 4 | ❌ 7

❌ Failed checks (1 warning, 6 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
No-Weak-Crypto ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Container-Privileges ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
No-Sensitive-Data-In-Logs ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
No-Hardcoded-Secrets ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
No-Injection-Vectors ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
Ai-Attribution ❓ Inconclusive Repository clone failed, so this custom check could not run with code access. Retry the review run. If this persists, inspect pre-merge custom-check logs for infrastructure or agent runtime failures.
✅ Passed checks (4 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-grades command and its Pyxis freshness purpose.
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

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

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

155-184: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Distinguish "grade unavailable" from "bad grade".

query_freshness_grades returns [] for a non-200 status, a timeout, and a genuine empty result. All three become grade Unknown, which healthy treats as unhealthy. During a Pyxis outage every image is reported unhealthy, and the operator cannot tell an actual grade regression from a failed lookup.

Add a distinct state, for example an available: bool field on ImageGradeResult, and add a small retry with backoff for 5xx and timeout responses. Report unavailable counts separately in the output.

🤖 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_grades.py` around lines 155 - 184, Update
ImageGradeResult and the verify_image_grades flow to distinguish unavailable
freshness lookups from genuinely returned Unknown grades: have
query_freshness_grades expose availability, add limited retry with backoff for
5xx and timeout failures, propagate the state through _check_grade, and report
unavailable results separately from unhealthy grades.
doozer/tests/cli/test_verify_image_grades.py (4)

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

Assert the request parameters and use a realistic digest.

The aiohttp async-context-manager mocking is correct. Two gaps remain:

  • No test asserts what URL or query parameters query_freshness_grades sends. An assertion on the filter value would cover the query-construction change requested on doozer/doozerlib/cli/verify_image_grades.py lines 139-152.
  • The fixture digest "abc123" is not a 64-character hex digest. If you add digest validation, update this fixture to a valid digest and add a case that asserts a malformed digest is rejected without an HTTP call.
🤖 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/tests/cli/test_verify_image_grades.py` around lines 148 - 186, Enhance
the TestQueryFreshnessGrades tests around query_freshness_grades by replacing
"abc123" with a valid 64-character hexadecimal digest, asserting the request URL
and filter query parameter, and adding a malformed-digest case that verifies
rejection occurs without calling the HTTP session. Keep the existing success,
empty-data, and API-error expectations unchanged.

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

Add a test for the CLI exit code.

The mocking is correct here. patch returns an AsyncMock for query_freshness_grades because it is an async def, so the awaited return value works. fetch_shipment_components is synchronous and is patched at module scope, so asyncio.to_thread resolves the patched attribute.

No test covers verify_image_grades_cli. Add a click.testing.CliRunner test that asserts exit code 1 for unhealthy images and exit code 0 for a passing run. That path is where raise SystemExit(1) on line 258 takes effect.

🤖 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/tests/cli/test_verify_image_grades.py` around lines 231 - 323, Add a
CliRunner-based test class for verify_image_grades_cli covering both unhealthy
and passing results, reusing the existing fetch_shipment_components and
query_freshness_grades mocks. Assert that the unhealthy invocation exits with
code 1 and the passing invocation exits with code 0, exercising the CLI’s
SystemExit behavior.

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

Add a test for a Z-suffixed start_date.

Every test here builds the timestamp with datetime.now(timezone.utc).isoformat(), which always produces a +00:00 offset. Pyxis also returns start_date values with a trailing Z. The current tests cannot detect the parse failure described in the comment on doozer/doozerlib/cli/verify_image_grades.py lines 62-82.

Add cases for "2024-01-01T00:00:00Z" and for a naive timestamp without an offset.

🤖 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/tests/cli/test_verify_image_grades.py` around lines 33 - 64, Extend
TestGetCurrentGrade with cases covering a start_date formatted with a trailing Z
and a naive timestamp without an offset, using fixed historical values and
asserting the expected grade is returned. Keep the existing timezone-aware test
coverage unchanged and ensure both formats exercise get_current_grade parsing.

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

Add negative-path tests for shipment parsing.

Only the happy path is covered. The except Exception block in fetch_shipment_components hides every failure, so these paths need explicit tests:

  • An empty YAML file, where yaml.safe_load returns None.
  • A YAML document that is not a mapping.
  • A source_project.files.get call that raises.
  • An MR title with no version, which must yield version == "".
  • A diff that contains no .yaml or .yml files.
🤖 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/tests/cli/test_verify_image_grades.py` around lines 189 - 228, Add
five new test methods to the TestFetchShipmentComponents class to cover the
negative paths currently hidden by the broad exception handling in
fetch_shipment_components: test for when yaml.safe_load returns None (empty
YAML), test for non-mapping YAML documents, test for source_project.files.get
raising an exception, test for MR titles without version information (expecting
version == ""), and test for diffs containing no .yaml or .yml files. Each test
should follow the same mocking setup pattern as test_parses_components,
adjusting mock configurations to trigger the specific failure condition.
🤖 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_grades.py`:
- Around line 155-184: The grade lookup currently conflates unavailable results
with genuinely unhealthy grades. In ImageGradeResult and verify_image_grades,
add and populate an available flag, setting it false for lookup failures while
preserving graded results, and update render_result to report unavailable images
separately from graded-but-unhealthy images. In get_current_grade, normalize
trailing Z and naive timestamps before datetime.fromisoformat and log every
skipped start_date instead of silently returning Unknown; apply these changes at
the affected locations in doozer/doozerlib/cli/verify_image_grades.py (lines
155-184 and 62-82).
- Around line 119-136: Update the shipment-file parsing flow around
yaml.safe_load and the surrounding try/except to validate that the parsed
document is a mapping before accessing shipment fields, and track any read or
parse failure instead of silently continuing. Propagate the failure to the
caller so VerifyImageGradesResult.passed cannot report PASS or exit successfully
when shipment files are unreadable or invalid, while preserving normal component
extraction for valid mappings.
- Around line 139-152: Update query_freshness_grades to validate digest at the
trust boundary using Unicode normalization and an anchored allow-list for the
expected digest format, returning no grades for invalid values. Stop
interpolating digest into the URL; keep the fixed Pyxis endpoint and pass the
filter through aiohttp’s params argument so query parameters are encoded safely.

In `@doozer/tests/cli/test_verify_image_grades.py`:
- Around line 102-105: Decide the intended zero-component behavior in the
verify-image-grades result flow and update test_empty accordingly. If an empty
image set is invalid, replace the current passed assertion with assertions for
the expected error or failure outcome while preserving the total_scanned == 0
check; otherwise retain the PASS expectation and align the implementation
consistently.

---

Nitpick comments:
In `@doozer/doozerlib/cli/verify_image_grades.py`:
- Around line 155-184: Update ImageGradeResult and the verify_image_grades flow
to distinguish unavailable freshness lookups from genuinely returned Unknown
grades: have query_freshness_grades expose availability, add limited retry with
backoff for 5xx and timeout failures, propagate the state through _check_grade,
and report unavailable results separately from unhealthy grades.

In `@doozer/tests/cli/test_verify_image_grades.py`:
- Around line 148-186: Enhance the TestQueryFreshnessGrades tests around
query_freshness_grades by replacing "abc123" with a valid 64-character
hexadecimal digest, asserting the request URL and filter query parameter, and
adding a malformed-digest case that verifies rejection occurs without calling
the HTTP session. Keep the existing success, empty-data, and API-error
expectations unchanged.
- Around line 231-323: Add a CliRunner-based test class for
verify_image_grades_cli covering both unhealthy and passing results, reusing the
existing fetch_shipment_components and query_freshness_grades mocks. Assert that
the unhealthy invocation exits with code 1 and the passing invocation exits with
code 0, exercising the CLI’s SystemExit behavior.
- Around line 33-64: Extend TestGetCurrentGrade with cases covering a start_date
formatted with a trailing Z and a naive timestamp without an offset, using fixed
historical values and asserting the expected grade is returned. Keep the
existing timezone-aware test coverage unchanged and ensure both formats exercise
get_current_grade parsing.
- Around line 189-228: Add five new test methods to the
TestFetchShipmentComponents class to cover the negative paths currently hidden
by the broad exception handling in fetch_shipment_components: test for when
yaml.safe_load returns None (empty YAML), test for non-mapping YAML documents,
test for source_project.files.get raising an exception, test for MR titles
without version information (expecting version == ""), and test for diffs
containing no .yaml or .yml files. Each test should follow the same mocking
setup pattern as test_parses_components, adjusting mock configurations to
trigger the specific failure condition.
🪄 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: 2e28598e-f715-4b66-98f3-b29f0e0d565d

📥 Commits

Reviewing files that changed from the base of the PR and between bc8e9a5 and 06bfa64.

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

Comment thread doozer/doozerlib/cli/verify_image_grades.py
Comment thread doozer/doozerlib/cli/verify_image_grades.py Outdated
Comment thread doozer/doozerlib/cli/verify_image_grades.py
Comment thread doozer/tests/cli/test_verify_image_grades.py
…yxis API

Read images from shipment advisory internal_url (registry.stage.redhat.io
pullspecs) instead of snapshot components (quay.io Konflux builds). Query
catalog.stage.redhat.com via corporate proxy, matching OAR behavior. Skip
FBC files. Add debug logging for individual grades.

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: 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 `@doozer/doozerlib/cli/verify_image_grades.py`:
- Around line 137-139: Validate advisory_url before requests.get in the advisory
verification flow: parse it and allow only HTTPS, explicitly allow-listed
advisory hosts, no user-info, and standard ports. Disable redirects or validate
every redirect target with the same policy, and reject invalid URLs before
making any request. Add tests covering disallowed hosts and redirect targets.

In `@doozer/tests/cli/test_verify_image_grades.py`:
- Line 270: Update the fetch_shipment_components unpacking at both test
locations to bind the unused second return value to _ instead of version, while
preserving the components assignment and existing 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: 22f92263-7603-442a-b15c-cc245b1d9381

📥 Commits

Reviewing files that changed from the base of the PR and between 06bfa64 and bd8f21c.

📒 Files selected for processing (2)
  • doozer/doozerlib/cli/verify_image_grades.py
  • doozer/tests/cli/test_verify_image_grades.py

Comment thread doozer/doozerlib/cli/verify_image_grades.py Outdated
Comment thread doozer/tests/cli/test_verify_image_grades.py Outdated
…andling

Validate digest format and advisory URL host at trust boundaries, prevent
false-positive PASS when all shipment files fail to parse, guard against
non-mapping YAML documents.

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/tests/cli/test_verify_image_grades.py (1)

195-383: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Add coverage for non-mapping YAML handling.

No test covers a shipment YAML document that parses to a list or scalar. Add a test that asserts the file is skipped, a warning is logged, and no advisory request is made.

🤖 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/tests/cli/test_verify_image_grades.py` around lines 195 - 383, Add a
test in TestFetchShipmentComponents covering shipment YAML that parses to a
non-mapping value such as a list or scalar; configure the mocked file and GitLab
objects like the existing shipment tests, assert fetch_shipment_components skips
the file, emits a warning through the module’s logger, and does not call
requests.get.
🧹 Nitpick comments (2)
doozer/tests/cli/test_verify_image_grades.py (2)

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

Consider extracting shared mock scaffolding for Pyxis response tests.

test_successful_query, test_empty_data, and test_api_error each rebuild the same mock_resp/mock_session boilerplate (AsyncMock with __aenter__/__aexit__, status, and json). Extract a small helper to build the mocked session for a given status/JSON payload. This reduces duplication and makes adding new grade-response cases easier.

♻️ Proposed helper extraction
+    def _mock_session(self, status=200, json_data=None):
+        mock_resp = AsyncMock()
+        mock_resp.status = status
+        if json_data is not None:
+            mock_resp.json = AsyncMock(return_value=json_data)
+        mock_resp.__aenter__ = AsyncMock(return_value=mock_resp)
+        mock_resp.__aexit__ = AsyncMock(return_value=False)
+        mock_session = AsyncMock(spec=ClientSession)
+        mock_session.get = MagicMock(return_value=mock_resp)
+        return mock_session
+
     async def test_successful_query(self):
         grades = [{"start_date": "2026-01-01T00:00:00+00:00", "grade": "A"}]
-        mock_resp = AsyncMock()
-        mock_resp.status = 200
-        mock_resp.json = AsyncMock(return_value={"data": [{"freshness_grades": grades}]})
-        mock_resp.__aenter__ = AsyncMock(return_value=mock_resp)
-        mock_resp.__aexit__ = AsyncMock(return_value=False)
-
-        mock_session = AsyncMock(spec=ClientSession)
-        mock_session.get = MagicMock(return_value=mock_resp)
-
+        mock_session = self._mock_session(200, {"data": [{"freshness_grades": grades}]})
         result = await query_freshness_grades(mock_session, "a" * 64)
         self.assertEqual(result, grades)
🤖 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/tests/cli/test_verify_image_grades.py` around lines 148 - 193, Extract
the repeated mock response/session setup from test_successful_query,
test_empty_data, and test_api_error into a shared helper that accepts the HTTP
status and JSON payload, configures the AsyncMock context-manager methods, and
returns the mocked ClientSession. Update those tests to use the helper while
preserving their existing inputs and assertions.

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

Extract shared GitLab mock fixture for TestFetchShipmentComponents.

Every test in this class (lines 198-258, 262-281, 285-318, 322-346, 350-382) rebuilds nearly identical mock_diff/mock_mr/mock_gl scaffolding. Move the common setup into a helper (e.g., a _build_gitlab_mocks(diff_paths) method or a fixture in setUp) that returns the configured mock_gl_cls/mock_project. This removes roughly 60-70 lines of repeated boilerplate and keeps each test focused on the behavior it targets.

🤖 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/tests/cli/test_verify_image_grades.py` around lines 195 - 383, Extract
the repeated GitLab setup from TestFetchShipmentComponents into a shared helper
such as _build_gitlab_mocks(diff_paths) or setUp, configuring the mock diff,
merge request, project, and GitLab client while allowing each test to supply its
changed paths. Update all five tests to reuse the helper and retain only
test-specific shipment files, advisory responses, and assertions.
🤖 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_grades.py`:
- Line 146: The advisory URL is embedded in the RuntimeError and may expose
credentials when logged with exc_info. Update the validation error in the
advisory URL handling block to use a generic message or a safely redacted value,
while preserving the rejected-host validation behavior.

---

Outside diff comments:
In `@doozer/tests/cli/test_verify_image_grades.py`:
- Around line 195-383: Add a test in TestFetchShipmentComponents covering
shipment YAML that parses to a non-mapping value such as a list or scalar;
configure the mocked file and GitLab objects like the existing shipment tests,
assert fetch_shipment_components skips the file, emits a warning through the
module’s logger, and does not call requests.get.

---

Nitpick comments:
In `@doozer/tests/cli/test_verify_image_grades.py`:
- Around line 148-193: Extract the repeated mock response/session setup from
test_successful_query, test_empty_data, and test_api_error into a shared helper
that accepts the HTTP status and JSON payload, configures the AsyncMock
context-manager methods, and returns the mocked ClientSession. Update those
tests to use the helper while preserving their existing inputs and assertions.
- Around line 195-383: Extract the repeated GitLab setup from
TestFetchShipmentComponents into a shared helper such as
_build_gitlab_mocks(diff_paths) or setUp, configuring the mock diff, merge
request, project, and GitLab client while allowing each test to supply its
changed paths. Update all five tests to reuse the helper and retain only
test-specific shipment files, advisory responses, and assertions.
🪄 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: 0d72381d-690a-48a4-a7b7-49a8cba41ce1

📥 Commits

Reviewing files that changed from the base of the PR and between bd8f21c and ef59baf.

📒 Files selected for processing (2)
  • doozer/doozerlib/cli/verify_image_grades.py
  • doozer/tests/cli/test_verify_image_grades.py

Comment thread doozer/doozerlib/cli/verify_image_grades.py Outdated
Log only the hostname instead of the full URL to avoid leaking
credentials in exception traces.

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

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
Empty image set no longer reports PASS — a shipment must contain at
least one image. Unparseable or missing start_date values are now
logged as warnings instead of silently skipped.

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

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

Add available field to ImageGradeResult to separate Pyxis lookup
failures from real grade regressions. Report unavailable images
separately in both text and JSON output. Normalize Z-suffix and
naive timestamps in grade date parsing.

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 Aug 3, 2026
Konflux advisory YAMLs are hosted on GitLab, not Errata Tool.
The internal_url field in shipment files legitimately points to
gitlab.cee.redhat.com/rhtap-release/advisories/ or
gitlab.cee.redhat.com/releng/advisories/.

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

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
Instead of checking only the hostname (which allows any path on
gitlab.cee.redhat.com), validate that the full URL starts with one of
the known advisory origins: errata hosts or specific GitLab advisory
repos (rhtap-release/advisories, releng/advisories).

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 Aug 3, 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 2ffaf16 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.

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