Skip to content

feat(SREP-4410): Update Claude configuration from MUO PR #641#288

Open
devppratik wants to merge 1 commit into
openshift:masterfrom
devppratik:update-claude-from-muo-pr641
Open

feat(SREP-4410): Update Claude configuration from MUO PR #641#288
devppratik wants to merge 1 commit into
openshift:masterfrom
devppratik:update-claude-from-muo-pr641

Conversation

@devppratik

@devppratik devppratik commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

What type of PR is this?

feature/docs

What this PR does / why we need it?

Updates Claude Code configuration with improvements based on feedback for other operators to make it upto standard

Which Jira/Github issue(s) this PR fixes?

SREP-4410

Special notes for your reviewer:

All repo-specific references updated for ocm-agent-operator.

Pre-checks:

  • Ran prek validation locally
  • Tested latest changes against a cluster
  • Ran make generate command locally to validate code changes
  • Included documentation changes with PR

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Prow CI failure analysis tools for extracting and analyzing CI artifacts
    • New session-start hook for automatic prerequisite setup
  • Improvements

    • Validation hooks now run conditionally on changed files only (strict mode available via configuration)
    • Enhanced file path validation and canonicalization in edit protection
    • Expanded file edit protection to detect additional high-risk file patterns
    • Updated tool versions and configurations
  • Documentation

    • Improved documentation for hooks and CI analysis workflows

Apply additional improvements from managed-upgrade-operator PR #641
that were merged after the initial ocm-agent-operator PR openshift#257.

New files:
- .claude/hooks/session-start-prek-setup.sh: Auto-setup prek on session start
- .claude/skills/prow-ci/analyze_failure.py: Automated CI failure analysis
- .claude/skills/prow-ci/fetch_prow_artifacts.py: Fetch Prow artifacts from GCS

Updated files:
- .claude/hooks/pre-edit.sh: Enhanced path validation and security checks
- .claude/hooks/stop-prek-validation.sh: Improved change detection logic
- .claude/settings.json: Added SessionStart hook and enhanced git safety
- .claude/skills/prow-ci/SKILL.md: Enhanced with artifact analysis workflow
- .claude/hooks/README.md: Updated hook behavior documentation
- .gitleaks.toml: Enhanced test file patterns and custom rules
- .gitignore: Added .work/ for prow-ci skill artifacts

All repo-specific references updated for ocm-agent-operator.

Source: openshift/managed-upgrade-operator#641

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Walkthrough

This PR enhances Claude Code's developer experience by automating prek hook setup, refining path validation in file edits, implementing conditional changed-file-only validation, and introducing a new Prow CI failure analysis skill with artifact fetching and pattern-based log analysis.

Changes

Claude Code Infrastructure and Prow CI Skill

Layer / File(s) Summary
Session startup and prek installation wiring
.claude/hooks/session-start-prek-setup.sh
New session-start hook detects git repo root, checks prek installation status, and runs prek install if hooks aren't already configured, with non-blocking guidance on failure.
Path canonicalization and edit safety
.claude/hooks/pre-edit.sh
Enhanced pre-edit hook now validates absolute paths are in-repo, canonicalizes file paths via realpath/readlink with Python fallback, rejects traversal sequences, and updates ClusterRole pattern matching to be case-insensitive.
Conditional changed-file validation on stop
.claude/hooks/stop-prek-validation.sh
Stop-prek-validation hook now detects repo root, validates git context early, and runs prek against only changed files (staged, unstaged, untracked) with fallback to --all-files for edge cases.
Hook command permissions and configuration
.claude/settings.json
Settings.json permits prek commands (run, install, version), expands git push force-flag denials with additional wildcard patterns, and configures SessionStart and Stop hooks using repository-root-absolute paths.
Hook system and validation documentation
.claude/hooks/README.md
Hooks README updated to reflect conditional default validation mode, revised prek command examples using CI-compatible config, expanded file-edit-protection detection categories, and updated version pinning and troubleshooting guidance.
Prow CI artifact fetching from GCS
.claude/skills/prow-ci/fetch_prow_artifacts.py
New fetch_prow_artifacts.py script extracts Prow job metadata from URL, downloads prowjob.json (optional) and build-log.txt (required) from Google Cloud Storage, and organizes artifacts by build ID.
Prow CI failure analysis and reporting
.claude/skills/prow-ci/analyze_failure.py
New analyze_failure.py script reads artifacts, scans build logs with regex pattern matching for errors/failures/warnings, extracts prowjob metadata, and generates aggregated reports in text, JSON, or Markdown format.
Prow CI skill documentation and usage
.claude/skills/prow-ci/SKILL.md
Comprehensive SKILL.md documentation for prow-ci skill covering prerequisites, quick start, implementation workflow, step-by-step usage instructions, and example end-to-end commands for fetching and analyzing failed Prow jobs.
Repository configuration and documentation updates
.gitignore, .gitleaks.toml, .claude/agents/README.md, .claude/skills/README.md
Minor updates: .gitignore adds .work/ directory, .gitleaks.toml exempts testdata file patterns, agent README fixes Markdown capitalization, and skills README adds code block formatting.

🎯 3 (Moderate) | ⏱️ ~25 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Ote Binary Stdout Contract ❌ Error PR violates OTE Stdout Contract: main.go line 116 routes zap logging to os.Stdout in main(), fips.go line 15 prints to stdout in init(). Non-JSON stdout will corrupt OTE test listings. Redirect os.Stdout to os.Stderr: main.go line 116 WriteTo(os.Stdout) → WriteTo(os.Stderr), fips.go line 15 fmt.Println → fmt.Fprintf(os.Stderr,)
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary change: updating Claude configuration based on a specific upstream PR, which is reflected across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.
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 test files. Modified files are configuration (.claude/, .gitignore, .gitleaks.toml), documentation, and helper scripts (Python/Bash utilities) only.
Test Structure And Quality ✅ Passed No Ginkgo test code present in PR; check only applies to test code. PR contains documentation, configuration, shell hooks, and Python utility scripts only.
Microshift Test Compatibility ✅ Passed No new Ginkgo e2e tests added in this PR. Changes are only Claude IDE configuration and utility scripts, so the MicroShift test compatibility check does not apply.
Single Node Openshift (Sno) Test Compatibility ✅ Passed This PR contains no new Ginkgo e2e tests. It only adds documentation, Bash hooks, Python CI utilities, and configuration updates - not test cases.
Topology-Aware Scheduling Compatibility ✅ Passed PR contains only Claude IDE configuration, documentation, and tooling changes; no deployment manifests, operator code, or scheduling constraints were modified.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e tests were added in this PR. All changes are documentation, configuration files, and CLI helper scripts (Bash/Python utilities). The custom check is not applicable.
No-Weak-Crypto ✅ Passed Comprehensive search found no weak cryptography patterns (MD5, SHA1, DES, RC4, 3DES, Blowfish, ECB), custom crypto implementations, or non-constant-time secret comparisons in the PR changes.
Container-Privileges ✅ Passed No Kubernetes/container manifests with privilege escalation settings found in the PR. All changed files are documentation, configuration, and utility scripts without container security concerns.
No-Sensitive-Data-In-Logs ✅ Passed No hardcoded passwords, tokens, API keys, or PII found. Logging statements output non-sensitive data like file paths, job names, and status messages.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci openshift-ci Bot requested review from ravitri and typeid June 6, 2026 10:42
@openshift-ci

openshift-ci Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

@codecov-commenter

codecov-commenter commented Jun 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.04%. Comparing base (313f984) to head (d3d39e0).
⚠️ Report is 6 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #288   +/-   ##
=======================================
  Coverage   66.04%   66.04%           
=======================================
  Files          23       23           
  Lines        1546     1546           
=======================================
  Hits         1021     1021           
  Misses        447      447           
  Partials       78       78           
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 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 @.claude/hooks/pre-edit.sh:
- Around line 53-56: The traversal check currently rejects any path containing
the substring ".." (using CANONICAL) and wrongly blocks valid filenames; change
the condition to detect ".." only as a path segment (e.g. leading, trailing, or
between slashes). Replace the boolean test that references CANONICAL with a
pattern or regex match that looks for '(^|/)..(/|$)' so it only flags true
directory-traversal segments, and keep the same echo using FILE and exit 1 on
match.
- Around line 45-50: The CANONICAL assignment is unsafe because it injects $FILE
into an inline Python string and only uses normpath (which doesn't resolve
symlinks); change the two python invocations so they pass "$FILE" and
"$REPO_ROOT" as command-line arguments (not embedded in the -c string) and have
the Python snippet call os.path.realpath on both inputs then os.path.relpath on
the realpath values (use try/except and write to stdout or return empty on
error) before assigning to CANONICAL; update both the python3 and python
fallback invocations (the lines creating CANONICAL) to use this safer
argument-passing + realpath-based resolution.

In @.claude/hooks/stop-prek-validation.sh:
- Around line 23-29: The script calls jq (the command `jq -n '{"decision":
"block", "reason": "Not in a git repository. Cannot run prek validation."}'`)
before verifying jq exists, causing a shell error if jq is missing; change the
logic to check for jq availability (e.g., `command -v jq` or `type jq`) before
any `jq` invocation and if jq is not found produce the same hook JSON using a
plain shell fallback (echo the JSON string) or emit a deterministic JSON error
message; update the branch that uses REPO_ROOT and replace the direct `jq -n
...` call with a guarded call that uses jq when available and the fallback when
not.
- Around line 80-87: The script currently builds CHANGED_FILES and pipes it
through xargs which splits on whitespace and breaks filenames with
spaces/newlines; change the collection to NUL-separated (use git diff
--name-only -z and git ls-files --others --exclude-standard -z) and invoke prek
with xargs -0 (or use printf '%s' "$CHANGED_FILES" | xargs -0 ...) so filenames
are passed safely; update the CHANGED_FILES assignment and the PREK_OUTPUT
branch that calls xargs, keeping the existing fallback path (prek run
--all-files) for the empty-case logic and preserving the PREK_OUTPUT capture.

In @.claude/skills/prow-ci/analyze_failure.py:
- Around line 200-203: The current write to args.output in analyze_failure.py
can raise FileNotFoundError when parent directories don't exist; before opening
the file in the block that references args.output, ensure the parent directory
exists by computing parent = os.path.dirname(args.output) and calling
os.makedirs(parent, exist_ok=True) when parent is non-empty, then proceed to
open and write; update the block that contains the with open(args.output, 'w')
as f: ... logic to perform this directory creation step first.

In @.claude/skills/prow-ci/fetch_prow_artifacts.py:
- Around line 63-75: The try/except around subprocess.run that downloads from
GCS currently only catches subprocess.CalledProcessError, so a missing gcloud
binary raises FileNotFoundError and crashes; update the block around
subprocess.run (the download routine that builds cmd and calls subprocess.run)
to also catch FileNotFoundError (or add a separate except FileNotFoundError) and
handle it by printing a clear warning like "gcloud not found" (including the
gcs_path context) to stderr and returning False so the function fails
gracefully.
🪄 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: 09f7b4ac-35d0-4e55-8cfa-4a92b97aa2b6

📥 Commits

Reviewing files that changed from the base of the PR and between 313f984 and d3d39e0.

📒 Files selected for processing (12)
  • .claude/agents/README.md
  • .claude/hooks/README.md
  • .claude/hooks/pre-edit.sh
  • .claude/hooks/session-start-prek-setup.sh
  • .claude/hooks/stop-prek-validation.sh
  • .claude/settings.json
  • .claude/skills/README.md
  • .claude/skills/prow-ci/SKILL.md
  • .claude/skills/prow-ci/analyze_failure.py
  • .claude/skills/prow-ci/fetch_prow_artifacts.py
  • .gitignore
  • .gitleaks.toml

Comment thread .claude/hooks/pre-edit.sh
Comment on lines +45 to +50
if [[ -z "$CANONICAL" ]]; then
if command -v python3 >/dev/null 2>&1; then
CANONICAL=$(python3 -c "import os.path; print(os.path.relpath(os.path.normpath('$FILE'), '$REPO_ROOT'))" 2>/dev/null || echo "")
elif command -v python >/dev/null 2>&1; then
CANONICAL=$(python -c "import os.path; print(os.path.relpath(os.path.normpath('$FILE'), '$REPO_ROOT'))" 2>/dev/null || echo "")
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Harden Python fallback to avoid path-based code injection and symlink escape.

Line 47 and Line 49 embed $FILE directly into Python code. A crafted filename containing quotes can break out of the string and execute arbitrary Python. Also, normpath alone doesn’t resolve symlinks, so out-of-repo symlink targets can be misclassified.

Suggested fix
-  if command -v python3 >/dev/null 2>&1; then
-    CANONICAL=$(python3 -c "import os.path; print(os.path.relpath(os.path.normpath('$FILE'), '$REPO_ROOT'))" 2>/dev/null || echo "")
-  elif command -v python >/dev/null 2>&1; then
-    CANONICAL=$(python -c "import os.path; print(os.path.relpath(os.path.normpath('$FILE'), '$REPO_ROOT'))" 2>/dev/null || echo "")
+  if command -v python3 >/dev/null 2>&1; then
+    CANONICAL=$(python3 - "$REPO_ROOT" "$FILE" <<'PY' 2>/dev/null || echo ""
+import os, sys
+repo_root = os.path.realpath(sys.argv[1])
+raw = sys.argv[2]
+target = raw if os.path.isabs(raw) else os.path.join(repo_root, raw)
+target = os.path.realpath(target)
+print(os.path.relpath(target, repo_root))
+PY
+)
+  elif command -v python >/dev/null 2>&1; then
+    CANONICAL=$(python - "$REPO_ROOT" "$FILE" <<'PY' 2>/dev/null || echo ""
+import os, sys
+repo_root = os.path.realpath(sys.argv[1])
+raw = sys.argv[2]
+target = raw if os.path.isabs(raw) else os.path.join(repo_root, raw)
+target = os.path.realpath(target)
+print(os.path.relpath(target, repo_root))
+PY
+)
   fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ -z "$CANONICAL" ]]; then
if command -v python3 >/dev/null 2>&1; then
CANONICAL=$(python3 -c "import os.path; print(os.path.relpath(os.path.normpath('$FILE'), '$REPO_ROOT'))" 2>/dev/null || echo "")
elif command -v python >/dev/null 2>&1; then
CANONICAL=$(python -c "import os.path; print(os.path.relpath(os.path.normpath('$FILE'), '$REPO_ROOT'))" 2>/dev/null || echo "")
fi
if [[ -z "$CANONICAL" ]]; then
if command -v python3 >/dev/null 2>&1; then
CANONICAL=$(python3 - "$REPO_ROOT" "$FILE" <<'PY' 2>/dev/null || echo ""
import os, sys
repo_root = os.path.realpath(sys.argv[1])
raw = sys.argv[2]
target = raw if os.path.isabs(raw) else os.path.join(repo_root, raw)
target = os.path.realpath(target)
print(os.path.relpath(target, repo_root))
PY
)
elif command -v python >/dev/null 2>&1; then
CANONICAL=$(python - "$REPO_ROOT" "$FILE" <<'PY' 2>/dev/null || echo ""
import os, sys
repo_root = os.path.realpath(sys.argv[1])
raw = sys.argv[2]
target = raw if os.path.isabs(raw) else os.path.join(repo_root, raw)
target = os.path.realpath(target)
print(os.path.relpath(target, repo_root))
PY
)
fi
🤖 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 @.claude/hooks/pre-edit.sh around lines 45 - 50, The CANONICAL assignment is
unsafe because it injects $FILE into an inline Python string and only uses
normpath (which doesn't resolve symlinks); change the two python invocations so
they pass "$FILE" and "$REPO_ROOT" as command-line arguments (not embedded in
the -c string) and have the Python snippet call os.path.realpath on both inputs
then os.path.relpath on the realpath values (use try/except and write to stdout
or return empty on error) before assigning to CANONICAL; update both the python3
and python fallback invocations (the lines creating CANONICAL) to use this safer
argument-passing + realpath-based resolution.

Comment thread .claude/hooks/pre-edit.sh
Comment on lines +53 to +56
if [[ -z "$CANONICAL" ]] || [[ "$CANONICAL" == *".."* ]]; then
echo "❌ ERROR: Invalid file path (contains traversal): $FILE"
exit 1
fi

Copy link
Copy Markdown

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

Traversal check is too broad and blocks legitimate filenames.

Line 53 rejects any path containing .. as a substring, including valid names like docs/v1..notes.md. Match traversal as a segment instead.

Suggested fix
-if [[ -z "$CANONICAL" ]] || [[ "$CANONICAL" == *".."* ]]; then
+if [[ -z "$CANONICAL" ]] || [[ "$CANONICAL" =~ (^|/)\.\.(/|$) ]]; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ -z "$CANONICAL" ]] || [[ "$CANONICAL" == *".."* ]]; then
echo "❌ ERROR: Invalid file path (contains traversal): $FILE"
exit 1
fi
if [[ -z "$CANONICAL" ]] || [[ "$CANONICAL" =~ (^|/)\.\.(/|$) ]]; then
echo "❌ ERROR: Invalid file path (contains traversal): $FILE"
exit 1
fi
🤖 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 @.claude/hooks/pre-edit.sh around lines 53 - 56, The traversal check
currently rejects any path containing the substring ".." (using CANONICAL) and
wrongly blocks valid filenames; change the condition to detect ".." only as a
path segment (e.g. leading, trailing, or between slashes). Replace the boolean
test that references CANONICAL with a pattern or regex match that looks for
'(^|/)..(/|$)' so it only flags true directory-traversal segments, and keep the
same echo using FILE and exit 1 on match.

Comment on lines +23 to +29
# Ensure we're running from the git repository root
# This handles cases where Claude Code's CWD is in a subdirectory (e.g., .claude/skills/)
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
if [[ -z "$REPO_ROOT" ]]; then
jq -n '{"decision": "block", "reason": "Not in a git repository. Cannot run prek validation."}'
exit 0
fi

Copy link
Copy Markdown

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

Do not call jq before verifying it exists.

Line 27 invokes jq before the dependency check at Line 32. In environments without jq, this branch emits a shell error instead of deterministic hook JSON.

Suggested fix
 if [[ -z "$REPO_ROOT" ]]; then
-  jq -n '{"decision": "block", "reason": "Not in a git repository. Cannot run prek validation."}'
+  if command -v jq >/dev/null 2>&1; then
+    jq -n '{"decision": "block", "reason": "Not in a git repository. Cannot run prek validation."}'
+  else
+    cat <<'EOF'
+{"decision":"block","reason":"Not in a git repository. Cannot run prek validation."}
+EOF
+  fi
   exit 0
 fi
🤖 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 @.claude/hooks/stop-prek-validation.sh around lines 23 - 29, The script calls
jq (the command `jq -n '{"decision": "block", "reason": "Not in a git
repository. Cannot run prek validation."}'`) before verifying jq exists, causing
a shell error if jq is missing; change the logic to check for jq availability
(e.g., `command -v jq` or `type jq`) before any `jq` invocation and if jq is not
found produce the same hook JSON using a plain shell fallback (echo the JSON
string) or emit a deterministic JSON error message; update the branch that uses
REPO_ROOT and replace the direct `jq -n ...` call with a guarded call that uses
jq when available and the fallback when not.

Comment on lines +80 to +87
CHANGED_FILES=$(git diff --name-only --diff-filter=d HEAD; git ls-files --others --exclude-standard)
if [[ -z "$CHANGED_FILES" ]]; then
# No files changed, but we're here because git status showed changes
# Fall back to --all-files to catch any edge cases
PREK_OUTPUT=$(prek run --all-files --config hack/prek.ci.toml 2>&1)
else
# Pass changed files explicitly to prek
PREK_OUTPUT=$(echo "$CHANGED_FILES" | xargs prek run --config hack/prek.ci.toml --files 2>&1)

Copy link
Copy Markdown

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

Use NUL-safe file collection instead of xargs splitting.

Line 87 splits CHANGED_FILES on whitespace, so filenames with spaces/newlines are passed incorrectly to prek, which can skip intended files or fail unexpectedly.

Suggested fix
-CHANGED_FILES=$(git diff --name-only --diff-filter=d HEAD; git ls-files --others --exclude-standard)
-if [[ -z "$CHANGED_FILES" ]]; then
+mapfile -d '' -t CHANGED_FILES < <(
+  {
+    git diff -z --name-only --diff-filter=d HEAD 2>/dev/null || true
+    git ls-files -z --others --exclude-standard
+  }
+)
+if (( ${`#CHANGED_FILES`[@]} == 0 )); then
   # No files changed, but we're here because git status showed changes
   # Fall back to --all-files to catch any edge cases
   PREK_OUTPUT=$(prek run --all-files --config hack/prek.ci.toml 2>&1)
 else
   # Pass changed files explicitly to prek
-  PREK_OUTPUT=$(echo "$CHANGED_FILES" | xargs prek run --config hack/prek.ci.toml --files 2>&1)
+  PREK_OUTPUT=$(prek run --config hack/prek.ci.toml --files "${CHANGED_FILES[@]}" 2>&1)
 fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
CHANGED_FILES=$(git diff --name-only --diff-filter=d HEAD; git ls-files --others --exclude-standard)
if [[ -z "$CHANGED_FILES" ]]; then
# No files changed, but we're here because git status showed changes
# Fall back to --all-files to catch any edge cases
PREK_OUTPUT=$(prek run --all-files --config hack/prek.ci.toml 2>&1)
else
# Pass changed files explicitly to prek
PREK_OUTPUT=$(echo "$CHANGED_FILES" | xargs prek run --config hack/prek.ci.toml --files 2>&1)
mapfile -d '' -t CHANGED_FILES < <(
{
git diff -z --name-only --diff-filter=d HEAD 2>/dev/null || true
git ls-files -z --others --exclude-standard
}
)
if (( ${`#CHANGED_FILES`[@]} == 0 )); then
# No files changed, but we're here because git status showed changes
# Fall back to --all-files to catch any edge cases
PREK_OUTPUT=$(prek run --all-files --config hack/prek.ci.toml 2>&1)
else
# Pass changed files explicitly to prek
PREK_OUTPUT=$(prek run --config hack/prek.ci.toml --files "${CHANGED_FILES[@]}" 2>&1)
fi
🤖 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 @.claude/hooks/stop-prek-validation.sh around lines 80 - 87, The script
currently builds CHANGED_FILES and pipes it through xargs which splits on
whitespace and breaks filenames with spaces/newlines; change the collection to
NUL-separated (use git diff --name-only -z and git ls-files --others
--exclude-standard -z) and invoke prek with xargs -0 (or use printf '%s'
"$CHANGED_FILES" | xargs -0 ...) so filenames are passed safely; update the
CHANGED_FILES assignment and the PREK_OUTPUT branch that calls xargs, keeping
the existing fallback path (prek run --all-files) for the empty-case logic and
preserving the PREK_OUTPUT capture.

Comment on lines +200 to +203
if args.output:
with open(args.output, 'w') as f:
f.write(output)
print(f"Analysis saved to: {args.output}")

Copy link
Copy Markdown

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

Make output file writing resilient for nested paths.

On Line 201, writing directly to args.output will fail with FileNotFoundError when parent directories don’t exist, causing an avoidable traceback.

Suggested fix
     # Write output
     if args.output:
-        with open(args.output, 'w') as f:
-            f.write(output)
-        print(f"Analysis saved to: {args.output}")
+        try:
+            output_path = Path(args.output)
+            output_path.parent.mkdir(parents=True, exist_ok=True)
+            with open(output_path, 'w', encoding='utf-8') as f:
+                f.write(output)
+            print(f"Analysis saved to: {output_path}")
+        except OSError as e:
+            print(f"Error: Could not write output file {args.output}: {e}", file=sys.stderr)
+            return 1
     else:
         print(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 @.claude/skills/prow-ci/analyze_failure.py around lines 200 - 203, The
current write to args.output in analyze_failure.py can raise FileNotFoundError
when parent directories don't exist; before opening the file in the block that
references args.output, ensure the parent directory exists by computing parent =
os.path.dirname(args.output) and calling os.makedirs(parent, exist_ok=True) when
parent is non-empty, then proceed to open and write; update the block that
contains the with open(args.output, 'w') as f: ... logic to perform this
directory creation step first.

Comment on lines +63 to +75
try:
os.makedirs(os.path.dirname(local_path), exist_ok=True)
cmd = [
'gcloud', 'storage', 'cp',
gcs_path,
local_path,
'--no-user-output-enabled'
]
subprocess.run(cmd, check=True, capture_output=True)
return True
except subprocess.CalledProcessError as e:
print(f"Warning: Could not download {gcs_path}: {e.stderr.decode()}", file=sys.stderr)
return False

Copy link
Copy Markdown

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

Handle missing gcloud binary explicitly.

On Line 71, subprocess.run(...) can raise FileNotFoundError when gcloud is not installed, which currently escapes and crashes with a traceback instead of returning a controlled failure.

Suggested fix
 def download_from_gcs(gcs_path, local_path):
     """Download a file from GCS using gcloud storage cp."""
     try:
         os.makedirs(os.path.dirname(local_path), exist_ok=True)
         cmd = [
             'gcloud', 'storage', 'cp',
             gcs_path,
             local_path,
             '--no-user-output-enabled'
         ]
         subprocess.run(cmd, check=True, capture_output=True)
         return True
+    except FileNotFoundError:
+        print(
+            "Error: gcloud CLI not found. Install Google Cloud SDK and ensure `gcloud` is on PATH.",
+            file=sys.stderr,
+        )
+        return False
     except subprocess.CalledProcessError as e:
         print(f"Warning: Could not download {gcs_path}: {e.stderr.decode()}", file=sys.stderr)
         return False
🧰 Tools
🪛 Ruff (0.15.15)

[error] 71-71: subprocess call: check for execution of untrusted input

(S603)

🤖 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 @.claude/skills/prow-ci/fetch_prow_artifacts.py around lines 63 - 75, The
try/except around subprocess.run that downloads from GCS currently only catches
subprocess.CalledProcessError, so a missing gcloud binary raises
FileNotFoundError and crashes; update the block around subprocess.run (the
download routine that builds cmd and calls subprocess.run) to also catch
FileNotFoundError (or add a separate except FileNotFoundError) and handle it by
printing a clear warning like "gcloud not found" (including the gcs_path
context) to stderr and returning False so the function fails gracefully.

@devppratik

Copy link
Copy Markdown
Contributor Author

/test ocm-agent-operator-on-pull-request

@devppratik

Copy link
Copy Markdown
Contributor Author

/test validate

@openshift-ci

openshift-ci Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

@devppratik: 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/validate d3d39e0 link true /test validate

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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants