Skip to content

ART-14695: Add optional verify-art-manifests presubmit (LSO pilot)#79879

Draft
fbladilo wants to merge 4 commits into
openshift:mainfrom
fbladilo:art-14695-verify-art-manifests
Draft

ART-14695: Add optional verify-art-manifests presubmit (LSO pilot)#79879
fbladilo wants to merge 4 commits into
openshift:mainfrom
fbladilo:art-14695-verify-art-manifests

Conversation

@fbladilo
Copy link
Copy Markdown
Contributor

@fbladilo fbladilo commented May 29, 2026

Summary

  • Add ocp-art-validate-art-manifests step-registry step that validates operator image-references and art.yaml against the CSV before merge (R1 pullspec match, R2 branch-aware registry.redhat.io rules, R3 art.yaml search match).
  • Pilot on local-storage-operator for release-4.23 and release-5.0 with optional: true (phase 1 soak per ART-14695).
  • Validator source + unit tests live under hack/art-manifests-validate/; the step embeds the script in ocp-art-validate-art-manifests-commands.sh (step-registry only allows standard filenames).

Expected pilot behavior

On current release-5.0 / release-4.23 LSO trees, the job should fail on the stale mustgather pullspec:

registry.redhat.io/openshift4/ose-local-storage-mustgather-rhel9:v4.22.0

This demonstrates R2 (wrong namespace on release-5.0, z-stream tag on both branches). The job is optional so merges are not blocked until ART-14696 phase 2.

Test plan

  • python3 hack/art-manifests-validate/validate_art_manifests_test.py -v (8 unit tests)
  • make registry-metadata and make jobs
  • /pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests
  • /pj-rehearse pull-ci-openshift-local-storage-operator-release-4.23-verify-art-manifests

Links

Summary by CodeRabbit

This PR introduces an optional presubmit that validates operator ART manifests and pilots it in the local-storage-operator repo for release-5.0 and release-4.23 (ART-14695). The change adds a step-registry test, the validator implementation and tests, and wires the new optional presubmit into the LSO ci-operator configs so failures are reported during a soak without blocking merges.

What changed (practical impact)

  • Adds a new step-registry reference ocp-art-validate-art-manifests and owners/metadata for it.
  • Adds a generated CI entrypoint shell script (ocp-art-validate-art-manifests-commands.sh) that runs an embedded Python validator.
  • Wires the new optional test group verify-art-manifests into ci-operator configs for openshift/local-storage-operator release-5.0 and release-4.23 (inserted between verify-deps and security). The step is optional so merges remain unblocked during phase‑1 soak (ART-14695).
  • Validator sources, generator, and unit tests live under hack/art-manifests-validate/. The generator produces the step wrapper by embedding the Python validator.

Validator behavior (rules enforced)

  • R1 (Pullspec match): each spec.tags[] entry must have a non-empty from.name pullspec and that pullspec string must appear in the selected CSV content.
  • R2 (Branch-aware registry rules): for registry.redhat.io pullspecs, the namespace must match the branch-major (openshift5 for major=5, else openshift4) and allowed tags are only latest or the release minor (e.g., 5.0 or v5.0); z-stream tags (vX.Y.Z) are flagged.
  • R3 (art.yaml validation): when art.yaml exists adjacent to image-references, expand templates using branch-derived values, require updates be a list, validate each update has file and non-empty update_list, ensure each update_list entry has string search and replace and that the expanded search string appears in the referenced target file.

Implementation notes / differences to earlier description

  • The validator is a standalone Python CLI (hack/art-manifests-validate/validate_art_manifests.py) with unit tests and is embedded into a Bash CI wrapper produced by hack/art-manifests-validate/sync-commands.sh.
  • The generated wrapper bootstraps PyYAML in the job image if needed and invokes the embedded validator with --repo-root; it will pass RELEASE_BRANCH to the validator only if the env var is set by CI. (The generated wrapper does not itself derive RELEASE_BRANCH from JOB_SPEC.)
  • Exit codes: 0 = no image-references found or no violations; 1 = violations found; 2 = invalid repo-root or failure to resolve a valid release-X.Y branch.

Pilot expectations and testing

  • On current LSO trees for release-5.0 and release-4.23 the job should flag the stale must-gather pullspec (registry.redhat.io/openshift4/ose-local-storage-mustgather-rhel9:v4.22.0), demonstrating R2 (wrong namespace on release-5.0 and z-stream tag detection).
  • Unit tests: validate_art_manifests_test.py (8 tests) — passed locally.
  • make registry-metadata and make jobs completed locally. Two rehearsals for the LSO verify jobs have been requested and are pending.
  • The job is optional during phase 1 soak; phase 2 (making it blocking) is tracked in ART-14696.

Other small changes

  • Adds OWNERS and step metadata files for the new step-registry entry.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 29, 2026
@openshift-ci-robot
Copy link
Copy Markdown
Contributor

openshift-ci-robot commented May 29, 2026

@fbladilo: This pull request references ART-14695 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 story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

Summary

  • Add ocp-art-validate-art-manifests step-registry step that validates operator image-references and art.yaml against the CSV before merge (R1 pullspec match, R2 branch-aware registry.redhat.io rules, R3 art.yaml search match).
  • Pilot on local-storage-operator for release-4.23 and release-5.0 with optional: true (phase 1 soak per ART-14695).
  • Validator source + unit tests live under hack/art-manifests-validate/; the step embeds the script in ocp-art-validate-art-manifests-commands.sh (step-registry only allows standard filenames).

Expected pilot behavior

On current release-5.0 / release-4.23 LSO trees, the job should fail on the stale mustgather pullspec:

registry.redhat.io/openshift4/ose-local-storage-mustgather-rhel9:v4.22.0

This demonstrates R2 (wrong namespace on release-5.0, z-stream tag on both branches). The job is optional so merges are not blocked until ART-14696 phase 2.

Test plan

  • python3 hack/art-manifests-validate/validate_art_manifests_test.py -v (8 unit tests)
  • make registry-metadata and make jobs
  • /pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests
  • /pj-rehearse pull-ci-openshift-local-storage-operator-release-4.23-verify-art-manifests

Links

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 added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label May 29, 2026
@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 29, 2026

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: b9c92031-3880-4317-aef2-c6c014523c0d

📥 Commits

Reviewing files that changed from the base of the PR and between 7e38be1 and dc975b7.

📒 Files selected for processing (4)
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh
  • hack/art-manifests-validate/sync-commands.sh
  • hack/art-manifests-validate/validate_art_manifests.py
  • hack/art-manifests-validate/validate_art_manifests_test.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • hack/art-manifests-validate/validate_art_manifests_test.py

Walkthrough

This PR adds an ocp-art validation step to release pipelines and implements a validator (Bash wrapper with embedded Python and a standalone Python CLI), step-registry wiring/metadata/OWNERS, a sync script to generate the wrapper, and unit tests covering rules R1–R3.

Changes

ART Manifest Validation Step

Layer / File(s) Summary
CI Pipeline Integration
ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-*.yaml
New optional verify-art-manifests test step added to release 4.23 and 5.0 pipeline configurations, each running the ocp-art-validate-art-manifests reference.
Step Registry & Ownership
ci-operator/step-registry/ocp-art/validate/art-manifests/OWNERS, *-ref.metadata.json, *-ref.yaml
Adds OWNERS, metadata, and a step-registry reference YAML wiring ocp-art-validate-art-manifests with an optional RELEASE_BRANCH env, resource requests, and documentation.
Bash Entrypoint
ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh (top)
Wrapper sets strict shell options, ensures PyYAML availability, exports ART_VALIDATE_REPO_ROOT, and launches the embedded Python validator.
Embedded Python: types & helpers
ocp-art-validate-art-manifests-commands.sh (embedded sections)
Defines BranchVersion parsing, Violation dataclass, template expansion, discovery helpers to find image-references and CSV selection used by validations.
Embedded Python: R1,R2,R3 implementations
ocp-art-validate-art-manifests-commands.sh (embedded sections)
R1 checks pullspec presence in selected CSV; R2 enforces registry namespace and tag formats when branch is release-X.Y; R3 expands art.yaml templates and validates updates/search presence.
Embedded orchestration & CLI
ocp-art-validate-art-manifests-commands.sh (bottom)
validate_repo() runs per-repo validations across image-references; main() provides CLI and exit codes (0 pass, 1 violations, 2 invalid repo).
Standalone Python validator
hack/art-manifests-validate/validate_art_manifests.py
Standalone implementation of the same discovery, BranchVersion/Violation, R1–R3 validations, orchestration, and CLI for local use.
Sync script to generate wrapper
hack/art-manifests-validate/sync-commands.sh
Generates the CI Bash wrapper by embedding trimmed standalone Python, handling dependencies and RELEASE_BRANCH resolution, and writing the executable output.
Unit tests
hack/art-manifests-validate/validate_art_manifests_test.py
Tests dynamically import the validator, construct fixture repos exercising pass/fail cases for R1, R2, and R3, and assert expected violations and branch parsing.

🎯 4 (Complex) | ⏱️ ~50 minutes

Suggested labels: lgtm, area/pipelines, rehearsals-ack

🚥 Pre-merge checks | ✅ 14 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.78% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (14 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary change: adding an optional verify-art-manifests presubmit step for the local-storage-operator as a pilot.
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.
Stable And Deterministic Test Names ✅ Passed PR contains no Ginkgo tests; only Python unittest tests with stable, deterministic names (no dynamic identifiers, timestamps, or generated values).
Test Structure And Quality ✅ Passed PR contains no Ginkgo test code. It adds Python unittest tests and CI/CD config files. The custom check is specific to Ginkgo and is not applicable here.
Microshift Test Compatibility ✅ Passed PR does not add Ginkgo e2e tests. Changes are CI/CD infrastructure (YAML configs, step-registry components, Python validation modules). MicroShift test compatibility check is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR adds no Ginkgo e2e tests—only CI infrastructure code (YAML config, Python/Bash validators). SNO compatibility check does not apply.
Topology-Aware Scheduling Compatibility ✅ Passed This PR introduces only CI/CD infrastructure (pipeline configs, step registry steps, and validation scripts) with no Kubernetes deployment manifests or scheduling constraints.
Ote Binary Stdout Contract ✅ Passed OTE Binary Stdout Contract check does not apply to this PR; it adds Python/Bash validation scripts and CI configs, not Go test binaries using Ginkgo framework.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR does not add any Ginkgo e2e tests; it adds CI/CD pipeline configs, Python validation scripts, and bash wrappers. Custom check only applies to Ginkgo tests.
No-Weak-Crypto ✅ Passed No weak cryptographic algorithms (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB), custom crypto implementations, or non-constant-time secret comparisons detected in the PR code.
Container-Privileges ✅ Passed No container privilege escalation markers found in any PR files. The step-registry YAML defines only CPU/memory requests with no securityContext settings.
No-Sensitive-Data-In-Logs ✅ Passed All logging outputs only non-sensitive metadata: branch names, repo file paths, org/repo names, and container image references—no passwords, tokens, credentials, or PII.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh (1)

25-26: ⚡ Quick win

Embedded validator duplicates the tested standalone script; guard against drift.

The Python block here (lines 25–525) is a verbatim copy of hack/art-manifests-validate/validate_art_manifests.py, but the unit tests only exercise the standalone file. The copy that actually runs in CI is untested, so the two can silently diverge. Since step-registry naming requires embedding the script, consider adding a small test/CI check that asserts the embedded PYVALIDATOR block matches the standalone source.

🤖 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
`@ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh`
around lines 25 - 26, The embedded PYVALIDATOR Python block in
ocp-art-validate-art-manifests-commands.sh duplicates the standalone script
validate_art_manifests.py and can drift; add a CI/unit test that reads the
PYVALIDATOR heredoc from the shell step (identify by the marker PYVALIDATOR in
ocp-art-validate-art-manifests-commands.sh) and compares it byte-for-byte (or
normalized whitespace) to the contents of
hack/art-manifests-validate/validate_art_manifests.py (identify by that
filename) failing the job on any mismatch so the embedded block and the
standalone script cannot diverge.
🤖 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 `@hack/art-manifests-validate/validate_art_manifests.py`:
- Around line 142-148: load_image_references currently calls yaml.safe_load and
assumes the result is a mapping, which causes an AttributeError for empty or
non-mapping YAML; update load_image_references to validate that the loaded data
is a dict (e.g., isinstance(data, dict)) before using data.get, and if not,
raise a ValueError with a clear message referencing the Path (path) so
validate_repo can catch it; keep the subsequent logic for extracting "spec" and
"tags" unchanged.
- Around line 282-284: The validator assumes art_yaml_data is a mapping and
calls art_yaml_data.get("updates", []), which will raise AttributeError if
art_yaml_data is None or a non-mapping; update the code in
validate_art_manifests.py to explicitly guard the parsed value (art_yaml_data)
with an isinstance check (e.g., collections.abc.Mapping or dict) and handle
non-mapping results by returning early or raising a controlled error so .get is
only called on mappings; apply the same defensive check to the equivalent logic
in ocp-art-validate-art-manifests-commands.sh to avoid uncaught AttributeError
crashes.

---

Nitpick comments:
In
`@ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh`:
- Around line 25-26: The embedded PYVALIDATOR Python block in
ocp-art-validate-art-manifests-commands.sh duplicates the standalone script
validate_art_manifests.py and can drift; add a CI/unit test that reads the
PYVALIDATOR heredoc from the shell step (identify by the marker PYVALIDATOR in
ocp-art-validate-art-manifests-commands.sh) and compares it byte-for-byte (or
normalized whitespace) to the contents of
hack/art-manifests-validate/validate_art_manifests.py (identify by that
filename) failing the job on any mismatch so the embedded block and the
standalone script cannot diverge.
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 7a73fa9e-c2d2-49c2-a76f-48ddef601179

📥 Commits

Reviewing files that changed from the base of the PR and between 5e9c8ac and 02f9fa0.

⛔ Files ignored due to path filters (2)
  • ci-operator/jobs/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23-presubmits.yaml is excluded by !ci-operator/jobs/**
  • ci-operator/jobs/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0-presubmits.yaml is excluded by !ci-operator/jobs/**
📒 Files selected for processing (8)
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23.yaml
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0.yaml
  • ci-operator/step-registry/ocp-art/validate/art-manifests/OWNERS
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.metadata.json
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.yaml
  • hack/art-manifests-validate/validate_art_manifests.py
  • hack/art-manifests-validate/validate_art_manifests_test.py

Comment on lines +142 to +148
def load_image_references(path: Path) -> list[dict]:
with path.open(encoding="utf-8") as handle:
data = yaml.safe_load(handle)
tags = data.get("spec", {}).get("tags", [])
if not isinstance(tags, list) or not tags:
raise ValueError(f"Data in {path} is not a valid image-references file")
return tags
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against non-mapping YAML documents.

yaml.safe_load returns None for an empty file (or a scalar for a non-mapping document), so data.get(...) raises AttributeError, which validate_repo does not catch (only ValueError is handled). An empty/malformed image-references file would crash with a traceback instead of producing a clean R1 violation.

🛡️ Proposed guard
 def load_image_references(path: Path) -> list[dict]:
     with path.open(encoding="utf-8") as handle:
         data = yaml.safe_load(handle)
-    tags = data.get("spec", {}).get("tags", [])
+    if not isinstance(data, dict):
+        raise ValueError(f"Data in {path} is not a valid image-references file")
+    tags = data.get("spec", {}).get("tags", [])
     if not isinstance(tags, list) or not tags:
         raise ValueError(f"Data in {path} is not a valid image-references file")
     return tags
🤖 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 `@hack/art-manifests-validate/validate_art_manifests.py` around lines 142 -
148, load_image_references currently calls yaml.safe_load and assumes the result
is a mapping, which causes an AttributeError for empty or non-mapping YAML;
update load_image_references to validate that the loaded data is a dict (e.g.,
isinstance(data, dict)) before using data.get, and if not, raise a ValueError
with a clear message referencing the Path (path) so validate_repo can catch it;
keep the subsequent logic for extracting "spec" and "tags" unchanged.

Comment on lines +282 to +284
updates = art_yaml_data.get("updates", [])
if not updates:
return
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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Same non-mapping risk for art.yaml.

If the expanded art.yaml parses to None or a non-mapping value, art_yaml_data.get("updates", []) raises AttributeError, which is not in the caught (yaml.YAMLError, ValueError) set and will crash the validator. Note this also applies to the embedded copy in ocp-art-validate-art-manifests-commands.sh.

🛡️ Proposed guard
-    updates = art_yaml_data.get("updates", [])
+    if not isinstance(art_yaml_data, dict):
+        violations.append(
+            Violation(
+                rule="R3",
+                message="art.yaml did not parse to a mapping after template expansion",
+                art_yaml_path=art_yaml_path,
+            )
+        )
+        return
+    updates = art_yaml_data.get("updates", [])
🤖 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 `@hack/art-manifests-validate/validate_art_manifests.py` around lines 282 -
284, The validator assumes art_yaml_data is a mapping and calls
art_yaml_data.get("updates", []), which will raise AttributeError if
art_yaml_data is None or a non-mapping; update the code in
validate_art_manifests.py to explicitly guard the parsed value (art_yaml_data)
with an isinstance check (e.g., collections.abc.Mapping or dict) and handle
non-mapping results by returning early or raising a controlled error so .get is
only called on mappings; apply the same defensive check to the equivalent logic
in ocp-art-validate-art-manifests-commands.sh to avoid uncaught AttributeError
crashes.

@fbladilo
Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

@fbladilo: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

@fbladilo, pj-rehearse: unable prepare a candidate for rehearsal; rehearsals will not be run. This could be due to a branch that needs to be rebased. ERROR:

couldn't checkout base SHA cdfbf788181bbeb3652a0384aae761908720088e: error checking out "cdfbf788181bbeb3652a0384aae761908720088e": exit status 128 fatal: unable to read tree (cdfbf788181bbeb3652a0384aae761908720088e)

@fbladilo fbladilo force-pushed the art-14695-verify-art-manifests branch from 02f9fa0 to d073a37 Compare May 29, 2026 17:02
@fbladilo
Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

@fbladilo: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 29, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fbladilo
Once this PR has been reviewed and has the lgtm label, please assign jupierce 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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
hack/art-manifests-validate/validate_art_manifests_test.py (1)

3-13: 💤 Low value

Remove duplicated import block.

tempfile, textwrap, unittest, and pathlib.Path are imported twice. Consolidate into a single block (keeping importlib.util and sys).

♻️ Proposed cleanup
-import tempfile
-import textwrap
-import unittest
-from pathlib import Path
-
-import importlib.util
-import sys
-import tempfile
-import textwrap
-import unittest
-from pathlib import Path
+import importlib.util
+import sys
+import tempfile
+import textwrap
+import unittest
+from pathlib import Path
🤖 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 `@hack/art-manifests-validate/validate_art_manifests_test.py` around lines 3 -
13, The file validate_art_manifests_test.py contains duplicated import
statements; remove the redundant second block and consolidate into a single
import section that imports tempfile, textwrap, unittest, and Path once while
preserving importlib.util and sys. Edit the top-level imports so only one import
of tempfile, textwrap, unittest, and from pathlib import Path remains alongside
importlib.util and sys to eliminate duplication.
🤖 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 `@hack/art-manifests-validate/validate_art_manifests_test.py`:
- Around line 3-13: The file validate_art_manifests_test.py contains duplicated
import statements; remove the redundant second block and consolidate into a
single import section that imports tempfile, textwrap, unittest, and Path once
while preserving importlib.util and sys. Edit the top-level imports so only one
import of tempfile, textwrap, unittest, and from pathlib import Path remains
alongside importlib.util and sys to eliminate duplication.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 99b89866-9725-4b6c-a305-21d91121c5db

📥 Commits

Reviewing files that changed from the base of the PR and between 02f9fa0 and d073a37.

⛔ Files ignored due to path filters (2)
  • ci-operator/jobs/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23-presubmits.yaml is excluded by !ci-operator/jobs/**
  • ci-operator/jobs/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0-presubmits.yaml is excluded by !ci-operator/jobs/**
📒 Files selected for processing (8)
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23.yaml
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0.yaml
  • ci-operator/step-registry/ocp-art/validate/art-manifests/OWNERS
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.metadata.json
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.yaml
  • hack/art-manifests-validate/validate_art_manifests.py
  • hack/art-manifests-validate/validate_art_manifests_test.py
✅ Files skipped from review due to trivial changes (2)
  • ci-operator/step-registry/ocp-art/validate/art-manifests/OWNERS
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.metadata.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.yaml
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23.yaml
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0.yaml
  • hack/art-manifests-validate/validate_art_manifests.py
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh

fbladilo added 2 commits May 29, 2026 12:47
…-14695)

Introduce ocp-art-validate-art-manifests step-registry to catch image-references
and art.yaml misconfigurations before rebase, and pilot it on local-storage-operator
release-4.23 and release-5.0 with optional: true.

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
Use microdnf/dnf to install python3-pyyaml when pip is unavailable in
operator build-root containers. Add sync-commands.sh to regenerate the
embedded validator from hack/art-manifests-validate/validate_art_manifests.py.

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
@fbladilo fbladilo force-pushed the art-14695-verify-art-manifests branch from d073a37 to 4021e4d Compare May 29, 2026 17:52
@fbladilo
Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

@fbladilo: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

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)
hack/art-manifests-validate/validate_art_manifests_test.py (1)

225-286: ⚡ Quick win

Add malformed-YAML regression cases.

The suite covers the expected rule paths, but it doesn't lock in behavior for empty/non-mapping image-references, non-mapping art.yaml, or malformed update_list entries. A couple of negative fixtures here would protect the validator from regressing back to uncaught AttributeErrors.

🤖 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 `@hack/art-manifests-validate/validate_art_manifests_test.py` around lines 225
- 286, Add unit tests to ValidateArtManifestsTest that exercise malformed-YAML
regression cases so the validator won't raise AttributeError for unexpected
shapes: add tests similar to test_skip_when_no_image_references that point repo
fixtures like "fail-malformed-image-references" (empty or non-mapping
image-references), "fail-nonmapping-artyaml" (art.yaml not a mapping), and
"fail-malformed-update-list" (update_list entries that are not mappings) and
call validate_repo(repo, "release-4.23") (or relevant branch) asserting either
specific rule violations or an empty list as appropriate; use
find_image_references_files where relevant and rely on existing helper
build_fixture_tree to add these fixtures so the new tests reference the same
symbols (ValidateArtManifestsTest, validate_repo, find_image_references_files).
🤖 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 `@hack/art-manifests-validate/sync-commands.sh`:
- Around line 12-15: The current trim fails to remove the existing if __name__
== "__main__": block because the parameter expansion is misquoted; change to
first assign the marker (e.g. marker='if __name__ == "__main__":') and then
remove everything from that marker to the end using
py_content="${py_content%%"$marker"*}" (this correctly strips the marker and
following content), then keep the existing whitespace-trim line
py_content="${py_content%"${py_content##*[![:space:]]}"}" so the generated
wrapper will not contain a duplicate __main__ entrypoint.

In `@hack/art-manifests-validate/validate_art_manifests.py`:
- Around line 105-131: The function find_csv_for_image_refs currently returns
unique[0] when multiple candidate CSVs remain, which silently picks arbitrarily;
instead, change this fallback to raise an explicit error (e.g., ValueError or
RuntimeError) that includes a clear message and the list of ambiguous candidate
paths so callers see the ambiguity; modify the end of find_csv_for_image_refs to
raise that exception (referencing the function name find_csv_for_image_refs and
the variable unique) rather than returning unique[0], so ambiguity fails fast
and surfaces the candidates for debugging.
- Around line 296-330: The validator currently constructs target_path =
manifests_base / relative_file and can be tricked into escaping the manifests
tree via "../" or symlinks; update the logic in validate_art_manifests.py (the
block handling relative_file/update_list/target_path) to canonicalize and
constrain targets: reject absolute paths, resolve both manifests_base.resolve()
and candidate = (manifests_base / relative_file).resolve(strict=False) and
verify candidate is within manifests_base (use a path containment check like
comparing commonpath or prefix), and also ensure the resolved candidate is a
regular file inside the manifests tree (and not a symlink that points outside)
before opening; if the containment or file checks fail, append the R3 Violation
and continue.

---

Nitpick comments:
In `@hack/art-manifests-validate/validate_art_manifests_test.py`:
- Around line 225-286: Add unit tests to ValidateArtManifestsTest that exercise
malformed-YAML regression cases so the validator won't raise AttributeError for
unexpected shapes: add tests similar to test_skip_when_no_image_references that
point repo fixtures like "fail-malformed-image-references" (empty or non-mapping
image-references), "fail-nonmapping-artyaml" (art.yaml not a mapping), and
"fail-malformed-update-list" (update_list entries that are not mappings) and
call validate_repo(repo, "release-4.23") (or relevant branch) asserting either
specific rule violations or an empty list as appropriate; use
find_image_references_files where relevant and rely on existing helper
build_fixture_tree to add these fixtures so the new tests reference the same
symbols (ValidateArtManifestsTest, validate_repo, find_image_references_files).
🪄 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 YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: adf57b14-a55a-4406-b5c7-5296e8015984

📥 Commits

Reviewing files that changed from the base of the PR and between d073a37 and 4021e4d.

⛔ Files ignored due to path filters (2)
  • ci-operator/jobs/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23-presubmits.yaml is excluded by !ci-operator/jobs/**
  • ci-operator/jobs/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0-presubmits.yaml is excluded by !ci-operator/jobs/**
📒 Files selected for processing (9)
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23.yaml
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0.yaml
  • ci-operator/step-registry/ocp-art/validate/art-manifests/OWNERS
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.metadata.json
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.yaml
  • hack/art-manifests-validate/sync-commands.sh
  • hack/art-manifests-validate/validate_art_manifests.py
  • hack/art-manifests-validate/validate_art_manifests_test.py
✅ Files skipped from review due to trivial changes (2)
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.metadata.json
  • ci-operator/step-registry/ocp-art/validate/art-manifests/OWNERS
🚧 Files skipped from review as they are similar to previous changes (4)
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-5.0.yaml
  • ci-operator/config/openshift/local-storage-operator/openshift-local-storage-operator-release-4.23.yaml
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-ref.yaml
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh

Comment thread hack/art-manifests-validate/sync-commands.sh Outdated
Comment on lines +105 to +131
def find_csv_for_image_refs(image_refs_path: Path) -> Optional[Path]:
csv_files: list[Path] = []
for directory in candidate_csv_dirs(image_refs_path):
csv_files.extend(sorted(directory.glob("*.clusterserviceversion.yaml")))
unique = []
seen = set()
for path in csv_files:
if path not in seen:
unique.append(path)
seen.add(path)
if not unique:
return None
if len(unique) == 1:
return unique[0]
refs_dir = image_refs_path.parent
same_dir = [path for path in unique if path.parent == refs_dir]
if len(same_dir) == 1:
return same_dir[0]
stable_dir = refs_dir / "stable"
stable_matches = [path for path in unique if path.parent == stable_dir]
if len(stable_matches) == 1:
return stable_matches[0]
manifests_dir = refs_dir / "manifests"
manifests_matches = [path for path in unique if path.parent == manifests_dir]
if len(manifests_matches) == 1:
return manifests_matches[0]
return unique[0]
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fail closed when CSV discovery stays ambiguous.

Line 131 silently picks the first sorted CSV when multiple candidates remain after the directory heuristics. That can validate against the wrong CSV and either miss a real R1 failure or report a false one. Return an explicit ambiguity failure instead of choosing arbitrarily.

🤖 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 `@hack/art-manifests-validate/validate_art_manifests.py` around lines 105 -
131, The function find_csv_for_image_refs currently returns unique[0] when
multiple candidate CSVs remain, which silently picks arbitrarily; instead,
change this fallback to raise an explicit error (e.g., ValueError or
RuntimeError) that includes a clear message and the list of ambiguous candidate
paths so callers see the ambiguity; modify the end of find_csv_for_image_refs to
raise that exception (referencing the function name find_csv_for_image_refs and
the variable unique) rather than returning unique[0], so ambiguity fails fast
and surfaces the candidates for debugging.

Comment on lines +296 to +330
relative_file = update.get("file")
update_list = update.get("update_list", [])
if not relative_file:
violations.append(
Violation(
rule="R3",
message="art.yaml update is missing `file`",
art_yaml_path=art_yaml_path,
)
)
continue
if not update_list:
violations.append(
Violation(
rule="R3",
message=f"art.yaml update_list is empty for file {relative_file!r}",
art_yaml_path=art_yaml_path,
target_file=manifests_base / relative_file,
)
)
continue

target_path = manifests_base / relative_file
if not target_path.is_file():
violations.append(
Violation(
rule="R3",
message="art.yaml target file does not exist",
art_yaml_path=art_yaml_path,
target_file=target_path,
)
)
continue

with target_path.open(encoding="utf-8") as handle:
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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Constrain art.yaml update targets to the manifests tree.

file comes from repo content, but manifests_base / relative_file accepts ../ traversal and symlinks. A crafted PR can make this validator probe arbitrary files on the CI worker instead of only manifest files.

🔒 Proposed fix
-        target_path = manifests_base / relative_file
+        base_dir = manifests_base.resolve()
+        target_path = (manifests_base / relative_file).resolve()
+        if target_path != base_dir and base_dir not in target_path.parents:
+            violations.append(
+                Violation(
+                    rule="R3",
+                    message="art.yaml target file must stay within the manifests directory",
+                    art_yaml_path=art_yaml_path,
+                    target_file=target_path,
+                )
+            )
+            continue
         if not target_path.is_file():
             violations.append(
                 Violation(

As per coding guidelines, "Path traversal: canonicalize paths, reject ../".

🤖 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 `@hack/art-manifests-validate/validate_art_manifests.py` around lines 296 -
330, The validator currently constructs target_path = manifests_base /
relative_file and can be tricked into escaping the manifests tree via "../" or
symlinks; update the logic in validate_art_manifests.py (the block handling
relative_file/update_list/target_path) to canonicalize and constrain targets:
reject absolute paths, resolve both manifests_base.resolve() and candidate =
(manifests_base / relative_file).resolve(strict=False) and verify candidate is
within manifests_base (use a path containment check like comparing commonpath or
prefix), and also ensure the resolved candidate is a regular file inside the
manifests tree (and not a symlink that points outside) before opening; if the
containment or file checks fail, append the R3 Violation and continue.

RHEL9 operator build-root containers have python3 but no pip and cannot
run dnf in the test pod. Match the openshift/release pattern from
single-node/conf/aws: ensurepip --user then pip install --user pyyaml.

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
@fbladilo
Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

@fbladilo: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
hack/art-manifests-validate/sync-commands.sh (1)

27-31: ⚡ Quick win

Install via python3 -m pip to match the capability check.

The presence check uses python3 -m pip --version, but the install falls back to the pip3 executable. When the pip module exists (so ensurepip is skipped) but no pip3 wrapper is on PATH, line 31 fails under errexit. Using the module form keeps the interpreter/site consistent and avoids depending on a pip3 script.

♻️ Proposed change (heredoc body)
-    pip3 install --user --disable-pip-version-check --no-cache-dir 'pyyaml==6.0'
+    python3 -m pip install --user --disable-pip-version-check --no-cache-dir 'pyyaml==6.0'
🤖 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 `@hack/art-manifests-validate/sync-commands.sh` around lines 27 - 31, The check
uses the pip module via "python3 -m pip", but the install falls back to the
"pip3" executable which can be missing; change the install to use the module
form instead of the pip3 wrapper so the same interpreter/site is used.
Specifically, replace the "pip3 install --user --disable-pip-version-check
--no-cache-dir 'pyyaml==6.0'" invocation with "python3 -m pip install --user
--disable-pip-version-check --no-cache-dir 'pyyaml==6.0'" (keep the existing
ensurepip and PATH export logic intact).
🤖 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 `@hack/art-manifests-validate/sync-commands.sh`:
- Around line 27-31: The check uses the pip module via "python3 -m pip", but the
install falls back to the "pip3" executable which can be missing; change the
install to use the module form instead of the pip3 wrapper so the same
interpreter/site is used. Specifically, replace the "pip3 install --user
--disable-pip-version-check --no-cache-dir 'pyyaml==6.0'" invocation with
"python3 -m pip install --user --disable-pip-version-check --no-cache-dir
'pyyaml==6.0'" (keep the existing ensurepip and PATH export logic intact).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: df8ddac5-f980-4d6e-86b1-b4ccf89644ce

📥 Commits

Reviewing files that changed from the base of the PR and between 4021e4d and 7e38be1.

📒 Files selected for processing (2)
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh
  • hack/art-manifests-validate/sync-commands.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • ci-operator/step-registry/ocp-art/validate/art-manifests/ocp-art-validate-art-manifests-commands.sh

Delegate branch resolution to resolve_release_branch() so pj-rehearse
and real presubmits use PULL_BASE_REF or extra_refs instead of
openshift/release's main. RELEASE_BRANCH overrides conflicting sources.

rh-pre-commit.version: 2.3.2
rh-pre-commit.check-secrets: ENABLED
@fbladilo
Copy link
Copy Markdown
Contributor Author

/pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

@fbladilo: now processing your pj-rehearse request. Please allow up to 10 minutes for jobs to trigger or cancel.

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

[REHEARSALNOTIFIER]
@fbladilo: the pj-rehearse plugin accommodates running rehearsal tests for the changes in this PR. Expand 'Interacting with pj-rehearse' for usage details. The following rehearsable tests have been affected by this change:

Test name Repo Type Reason
pull-ci-openshift-local-storage-operator-release-4.23-verify-art-manifests openshift/local-storage-operator presubmit Presubmit changed
pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests openshift/local-storage-operator presubmit Presubmit changed
Interacting with pj-rehearse

Comment: /pj-rehearse to run up to 5 rehearsals
Comment: /pj-rehearse skip to opt-out of rehearsals
Comment: /pj-rehearse {test-name}, with each test separated by a space, to run one or more specific rehearsals
Comment: /pj-rehearse more to run up to 10 rehearsals
Comment: /pj-rehearse max to run up to 25 rehearsals
Comment: /pj-rehearse auto-ack to run up to 5 rehearsals, and add the rehearsals-ack label on success
Comment: /pj-rehearse list to get an up-to-date list of affected jobs
Comment: /pj-rehearse abort to abort all active rehearsals
Comment: /pj-rehearse network-access-allowed to allow rehearsals of tests that have the restrict_network_access field set to false. This must be executed by an openshift org member who is not the PR author

Once you are satisfied with the results of the rehearsals, comment: /pj-rehearse ack to unblock merge. When the rehearsals-ack label is present on your PR, merge will no longer be blocked by rehearsals.
If you would like the rehearsals-ack label removed, comment: /pj-rehearse reject to re-block merging.

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 29, 2026

@fbladilo: 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/rehearse/openshift/local-storage-operator/release-5.0/verify-art-manifests dc975b7 link unknown /pj-rehearse pull-ci-openshift-local-storage-operator-release-5.0-verify-art-manifests

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

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants