Skip to content

Add Claude Code hooks, agents, skills, and developer docs#447

Open
anispate wants to merge 1 commit into
openshift:masterfrom
anispate:ROSAENG-60008-claude-code-hooks-and-docs
Open

Add Claude Code hooks, agents, skills, and developer docs#447
anispate wants to merge 1 commit into
openshift:masterfrom
anispate:ROSAENG-60008-claude-code-hooks-and-docs

Conversation

@anispate

@anispate anispate commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds standardized Claude Code tooling: agents (ci, docs, lint, security, test), hooks (pre-edit, session-start, stop-validation), skills (prow-ci), and .claude/settings.json
  • Adds developer documentation: CONTRIBUTING.md, DEVELOPMENT.md, TESTING.md
  • Adds prek.toml, hack/prek.ci.toml, .gitleaks.toml, .prek-version, hack/ci.sh
  • Sourced from the ocm-agent-operator reference implementation and adapted for this repo

Fixes vs closed PR #437

All issues identified in ROSAENG-60008 have been addressed:

Major:

  • Go version corrected to 1.25+ (was 1.22.7)
  • Removed nonexistent make tools, make run, make run-verbose targets; replaced with correct commands
  • Replaced all pre-commit references with prek equivalents throughout docs and agents
  • Removed OCM copy-paste artifacts: ocm_agent_token gitleaks rule replaced with splunk-auth-token, fleet notification filtering example updated, pkg/handler/deployment.go path examples replaced with real paths
  • Fixed command injection in pre-edit.sh python3 fallback: shell variables no longer interpolated into -c strings; uses sys.argv instead

Minor:

  • Narrowed Bash(find *) permission in settings.json to Bash(find . -name *) and Bash(find . -type *)
  • Fixed nested code block in TESTING.md
  • Corrected operator name to "Splunk Forwarder Operator" throughout all docs
  • Removed links to nonexistent docs/design.md and docs/how-to-test.md
  • Removed reference to nonexistent pkg/util/test/generated/ path

Closes ROSAENG-60008

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added an assistant skill to help diagnose Prow CI failures using fetched job artifacts and auto-generated summaries.
    • Introduced Claude Code hooks and settings to enforce safe edits and run required validation when starting/stopping sessions.
  • Documentation

    • Added/expanded developer and testing guides, including quick start, workflow, and best-practice checklists.
    • Published detailed agent/runbook documentation for CI parity, linting, testing, and security scanning.
  • Chores

    • Added comprehensive pre-commit/CI validation: formatting, linting, build checks, dependency hygiene, RBAC policy checks, and secret scanning.

@openshift-ci openshift-ci Bot requested review from boranx and clcollins June 22, 2026 17:57
@openshift-ci

openshift-ci Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: anispate

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

The pull request process is described 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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jun 22, 2026
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

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: aca063af-5795-4331-8203-7639bfd22997

📥 Commits

Reviewing files that changed from the base of the PR and between b2848ed and 619376c.

📒 Files selected for processing (23)
  • .claude/agents/ci-agent.md
  • .claude/agents/docs-agent.md
  • .claude/agents/lint-agent.md
  • .claude/agents/security-agent.md
  • .claude/agents/test-agent.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
  • .prek-version
  • CONTRIBUTING.md
  • DEVELOPMENT.md
  • TESTING.md
  • hack/ci.sh
  • hack/prek.ci.toml
  • prek.toml
✅ Files skipped from review due to trivial changes (12)
  • .prek-version
  • .claude/agents/test-agent.md
  • .gitignore
  • DEVELOPMENT.md
  • .claude/agents/lint-agent.md
  • .gitleaks.toml
  • .claude/agents/docs-agent.md
  • TESTING.md
  • .claude/skills/README.md
  • .claude/agents/ci-agent.md
  • .claude/hooks/README.md
  • CONTRIBUTING.md
🚧 Files skipped from review as they are similar to previous changes (8)
  • hack/prek.ci.toml
  • hack/ci.sh
  • .claude/settings.json
  • prek.toml
  • .claude/agents/security-agent.md
  • .claude/hooks/session-start-prek-setup.sh
  • .claude/hooks/pre-edit.sh
  • .claude/hooks/stop-prek-validation.sh

Walkthrough

Adds Claude Code hooks and permissions, pre-commit/CI configuration, agent instructions, a Prow CI analysis skill, and repository documentation for development, testing, and contribution workflows.

Changes

Claude Code governance and repo tooling

Layer / File(s) Summary
Hook runtime and permissions
.claude/settings.json, .claude/hooks/*, .claude/hooks/README.md
settings.json wires SessionStart and Stop hooks with command permissions. The hook scripts add pre-commit setup, path validation, stop-time prek validation, and hook documentation.
Pre-commit and CI configuration
prek.toml, hack/prek.ci.toml, hack/ci.sh, .gitleaks.toml, .prek-version, .gitignore
Adds prek configs for hygiene, lint, build, RBAC, InfoSec, and secret scanning, plus a CI wrapper script, gitleaks rules, a pinned prek version, and .work/ ignore rules.
Claude agent instructions
.claude/agents/*.md
Adds agent docs for CI parity, docs maintenance, linting, security scanning, and test execution.
Skills and repository docs
.claude/skills/*, CONTRIBUTING.md, DEVELOPMENT.md, TESTING.md
Adds the Prow CI skill and scripts for artifact fetch/analyze, plus repository guides for contribution, development, and testing workflows.

Sequence Diagram(s)

sequenceDiagram
  participant ClaudeCode
  participant session-start-prek-setup.sh
  participant pre-edit.sh
  participant stop-prek-validation.sh
  participant prek
  participant fetch_prow_artifacts.py
  participant analyze_failure.py
  participant GCS

  ClaudeCode->>session-start-prek-setup.sh: SessionStart
  session-start-prek-setup.sh->>prek: check/install hook wiring
  ClaudeCode->>pre-edit.sh: edit target file
  pre-edit.sh->>pre-edit.sh: canonicalize path and gate edit
  ClaudeCode->>stop-prek-validation.sh: Stop
  stop-prek-validation.sh->>prek: run validation on changed files
  ClaudeCode->>fetch_prow_artifacts.py: analyze Prow failure URL
  fetch_prow_artifacts.py->>GCS: download prowjob.json and build-log.txt
  fetch_prow_artifacts.py->>analyze_failure.py: hand off artifacts
  analyze_failure.py-->>ClaudeCode: report output
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes


Important

Pre-merge checks failed

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

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error FAIL: stop-prek-validation.sh embeds raw prek stdout/stderr in JSON, and analyze_failure.py prints build-log lines verbatim, so secrets/PII could leak. Redact secret/token/PII patterns and summarize failures instead of returning raw command output or raw build-log lines.
Test Structure And Quality ⚠️ Warning FAIL: The Ginkgo e2e suite has many cluster Eventually/Consistently calls without explicit timeouts and several bare Expect(err).NotTo(HaveOccurred()) assertions. Add explicit timeouts to every cluster wait and include meaningful failure messages on error assertions; justify or refactor suite-level setup/cleanup as needed.
Topology-Aware Scheduling Compatibility ⚠️ Warning FAIL: the DaemonSet generator uses a wildcard Exists toleration with no topology check, so Splunk Forwarder pods can land on TNA arbiter nodes. Add topology-aware scheduling: avoid wildcard toleration or explicitly exclude node-role.kubernetes.io/arbiter, and gate placement on infrastructure.Status.ControlPlaneTopology.
✅ Passed checks (12 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main additions: Claude Code hooks, agents, skills, and developer documentation.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% 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 adds only docs/config/scripts; no Go test/spec files changed, and the Ginkgo snippets in TESTING.md are static examples, not dynamic titles.
Microshift Test Compatibility ✅ Passed No new Go/e2e test files were added; this PR only adds docs/tooling scripts, so MicroShift API compatibility is not applicable.
Single Node Openshift (Sno) Test Compatibility ✅ Passed The added osde2e Ginkgo tests only validate CR/config/DaemonSet rendering and secrets; they don’t assert node counts, cross-node scheduling, drain/failover, or topology spread.
Ote Binary Stdout Contract ✅ Passed PASS: The PR only adds docs/hooks/config and doesn't modify Go process-level entrypoints; no new stdout writes in main/init/TestMain/RunSpecs were introduced.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No Ginkgo e2e test files or test code were added; the PR only changes docs, hooks, skills, and config scripts.
No-Weak-Crypto ✅ Passed PASS: the new hook/script files contain no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or crypto/comparison code; only docs mention weak algorithms.
Container-Privileges ✅ Passed PR touches only docs/scripts/config; no changed file is a K8s/container manifest, and no touched file contains privileged/hostPID/allowPrivilegeEscalation settings.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.23.0)
.claude/skills/prow-ci/fetch_prow_artifacts.py

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

[00.20][ERROR]: unable to find a config; path .coderabbit-opengrep-fallback.yml does not exist

🔧 markdownlint-cli2 (0.22.1)
.claude/agents/lint-agent.md

markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)
Error: Unable to use configuration file '/coderabbit-2.markdownlint-cli2.jsonc'; ENOENT: no such file or directory, open '/coderabbit-2.markdownlint-cli2.jsonc'
at throwForConfigurationFile (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:48:9)
at readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:169:5)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
[cause]: Error: ENOENT: no such file or directory, open '/coderabbit-2.markdownlint-cli2.jsonc'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:141:17)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/coderabbit-2.markdownlint-cli2.jsonc'
}
}

TESTING.md

markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)
Error: Unable to use configuration file '/coderabbit-10.markdownlint-cli2.jsonc'; ENOENT: no such file or directory, open '/coderabbit-10.markdownlint-cli2.jsonc'
at throwForConfigurationFile (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:48:9)
at readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:169:5)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
[cause]: Error: ENOENT: no such file or directory, open '/coderabbit-10.markdownlint-cli2.jsonc'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:141:17)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/coderabbit-10.markdownlint-cli2.jsonc'
}
}

.claude/skills/README.md

markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)
Error: Unable to use configuration file '/coderabbit-6.markdownlint-cli2.jsonc'; ENOENT: no such file or directory, open '/coderabbit-6.markdownlint-cli2.jsonc'
at throwForConfigurationFile (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:48:9)
at readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:169:5)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
[cause]: Error: ENOENT: no such file or directory, open '/coderabbit-6.markdownlint-cli2.jsonc'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:141:17)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/coderabbit-6.markdownlint-cli2.jsonc'
}
}

  • 8 others

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.

@codecov-commenter

codecov-commenter commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 72.44%. Comparing base (33a3a5a) to head (619376c).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##           master     #447   +/-   ##
=======================================
  Coverage   72.44%   72.44%           
=======================================
  Files          11       11           
  Lines         704      704           
=======================================
  Hits          510      510           
  Misses        173      173           
  Partials       21       21           
🚀 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
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 11

🤖 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/agents/ci-agent.md:
- Around line 40-76: Update the Pre-commit ↔ CI Mapping section documentation to
align with the current prek contract. Replace all references to
`.pre-commit-config.yaml` with `prek.toml` or `hack/prek.ci.toml` in the version
validation grep commands. Replace the outdated `prek run --all` command with the
correct invocation using `--all-files` flag. Update all example commands and
paths throughout the "Pre-commit ↔ CI Mapping" and "Running Full CI Locally"
sections to reflect the current repository's prek configuration structure and
hook script conventions.

In @.claude/agents/docs-agent.md:
- Around line 33-35: The docs-agent.md file contains references to nonexistent
documentation paths (docs/design.md, docs/development.md) at lines 33-35, 93-95,
and 163-164. Replace these stale file path references with either actual
existing documentation files that are currently available in the repository, or
use more generic/flexible wording that doesn't depend on specific doc paths.
This will prevent guidance drift and align with the cleanup of broken
documentation references.

In @.claude/agents/security-agent.md:
- Around line 208-210: The documentation incorrectly claims that Tekton CI runs
both gitleaks and gosec, but the actual CI configuration only runs gosec via
golangci-lint. Correct the bullet point that currently states "**CI**: Tekton
runs gitleaks and gosec" to accurately reflect that only gosec runs in the
Tekton CI pipeline, while gitleaks only runs locally as a pre-commit hook.
Remove the reference to gitleaks from the CI section to ensure the documentation
accurately represents the actual security controls and scanning tools executed
in the pipeline.

In @.claude/agents/test-agent.md:
- Around line 31-39: The script does not handle the case when no `.go` files are
changed, which causes the package extraction and test execution to fail. Add a
guard clause after the CHANGED_FILES variable assignment to check if the result
is empty, and if so, exit cleanly with a success message. This prevents the
downstream PACKAGES extraction and the for loop from attempting to process empty
data.

In @.claude/hooks/pre-edit.sh:
- Around line 142-165: The HIGH_RISK_PATTERNS array in the pre-edit.sh script
does not include patterns to protect critical Claude automation configuration
files. Add three new patterns to the HIGH_RISK_PATTERNS array to flag changes to
.claude directory files: one pattern for .claude/settings.json, one pattern for
.claude/hooks/* files, and one pattern for .claude/agents/* files. These
patterns will ensure that modifications to Claude IDE configuration, hook
scripts, and agent definitions trigger the high-risk warning and require user
confirmation before proceeding.

In @.claude/hooks/stop-prek-validation.sh:
- Around line 25-29: The jq command is being used in the error handling branch
when REPO_ROOT is empty (when not in a git repository), but jq may not be
available on all machines. Either add a check to verify jq is installed before
using it, or replace the jq call in this error branch with a plain printf
statement to output the JSON decision object. The error path for "Not in a git
repository" should not depend on external tools like jq being present.
- Around line 80-89: The git commands and xargs invocation in the conditional
block (checking CHANGED_FILES and passing to prek run) do not properly handle
filenames with spaces or special characters. Modify the git diff and git
ls-files commands to use the -z flag for null-delimited output, and update the
xargs invocation to use the -0 flag to handle null-delimited input. This will
ensure that filenames with spaces, newlines, or other special characters are
correctly passed to the prek run command without being incorrectly split.

In @.claude/skills/prow-ci/fetch_prow_artifacts.py:
- Around line 63-75: The current exception handling in the try block only
catches subprocess.CalledProcessError, but when the gcloud binary is not
installed, subprocess.run raises FileNotFoundError instead, causing an unhandled
exception. Add an additional except clause after the existing
subprocess.CalledProcessError handler to catch FileNotFoundError (or OSError
more broadly) and print a user-friendly error message indicating that the gcloud
binary is not installed, then return False to maintain consistent error handling
behavior.
- Around line 84-89: The exception handling in the JSON file loading block only
catches json.JSONDecodeError, but filesystem errors from the open() call (such
as FileNotFoundError, PermissionError, or IOError) are not handled and will
cause the script to abort. Expand the exception handling to catch
filesystem-related errors in addition to JSONDecodeError. Either catch multiple
specific exceptions (FileNotFoundError, PermissionError, IOError, etc.) or use a
broader exception type like OSError or Exception to handle all potential errors
that could occur when opening and reading the local_path file, ensuring the
function gracefully returns None when any error occurs.

In @.claude/skills/prow-ci/SKILL.md:
- Line 214: The linting command documented in the SKILL.md file uses make
go-check, but this is inconsistent with the repository's actual declared linting
target. Replace the make go-check command with make lint to match the documented
lint target and ensure contributors following this workflow will use the correct
command.

In @.gitleaks.toml:
- Around line 50-59: The global stopwords array in the .gitleaks.toml
configuration is too permissive and can suppress legitimate secret detections by
matching overly common terms. Remove the entire stopwords array definition that
contains example, test, fake, dummy, placeholder, sample, and mock, and instead
implement path-specific or rule-specific allowlists for known false positives to
maintain tighter security controls that won't accidentally mask real credential
leaks.
🪄 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: e0180f3d-8ece-47a0-8ec5-c543dd1cd448

📥 Commits

Reviewing files that changed from the base of the PR and between ffbe888 and b2848ed.

📒 Files selected for processing (23)
  • .claude/agents/ci-agent.md
  • .claude/agents/docs-agent.md
  • .claude/agents/lint-agent.md
  • .claude/agents/security-agent.md
  • .claude/agents/test-agent.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
  • .prek-version
  • CONTRIBUTING.md
  • DEVELOPMENT.md
  • TESTING.md
  • hack/ci.sh
  • hack/prek.ci.toml
  • prek.toml

Comment on lines +40 to +76
### Pre-commit ↔ CI Mapping

| Pre-commit Hook | CI Equivalent | Purpose |
|----------------|---------------|---------|
| `go-build` | Tekton compile check | Ensure code compiles |
| `golangci-lint` | Tekton lint job | Static analysis |
| `gitleaks` | Tekton security scan | Secret detection |
| `go-mod-tidy` | CI dependency check | No uncommitted go.mod/sum |
| `rbac-wildcard-check` | CI security policy | No wildcard RBAC |

**Parity validation:**
```bash
# Check pre-commit uses same golangci-lint version as CI
grep "rev:" .pre-commit-config.yaml | grep golangci-lint
# Should match version in boilerplate pipeline

# Check gitleaks version
grep "rev:" .pre-commit-config.yaml | grep gitleaks
```

### Running Full CI Locally

```bash
# Lint (same as CI)
make go-check

# Tests (same environment as CI)
boilerplate/_lib/container-make go-test

# Build (same as CI)
make docker-build

# Full validation
prek run --all
make go-test
make go-build
```

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

Update the examples to match the repo's prek contract.

These snippets still grep .pre-commit-config.yaml and use prek run --all, but the repo now standardizes on prek.toml / hack/prek.ci.toml and the hook scripts use --all-files. Please align this walkthrough so the agent doesn't learn stale commands.

Suggested updates
-# Check pre-commit uses same golangci-lint version as CI
-grep "rev:" .pre-commit-config.yaml | grep golangci-lint
+# Check the pinned prek config used by CI
+grep -n "golangci-lint" prek.toml
-prek run --all
+prek run --all-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 @.claude/agents/ci-agent.md around lines 40 - 76, Update the Pre-commit ↔ CI
Mapping section documentation to align with the current prek contract. Replace
all references to `.pre-commit-config.yaml` with `prek.toml` or
`hack/prek.ci.toml` in the version validation grep commands. Replace the
outdated `prek run --all` command with the correct invocation using
`--all-files` flag. Update all example commands and paths throughout the
"Pre-commit ↔ CI Mapping" and "Running Full CI Locally" sections to reflect the
current repository's prek configuration structure and hook script conventions.

Comment on lines +33 to +35
- **API types changed**: Update `docs/design.md`
- **Test framework changes**: Update `TESTING.md`
- **New dependencies**: Update `docs/development.md`

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

Remove stale references to nonexistent docs paths.

This agent still points to docs/design.md / docs/development.md, which conflicts with the stated cleanup of broken doc references. Please replace with existing files (or generic wording) to avoid guidance drift.

Also applies to: 93-95, 163-164

🤖 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/agents/docs-agent.md around lines 33 - 35, The docs-agent.md file
contains references to nonexistent documentation paths (docs/design.md,
docs/development.md) at lines 33-35, 93-95, and 163-164. Replace these stale
file path references with either actual existing documentation files that are
currently available in the repository, or use more generic/flexible wording that
doesn't depend on specific doc paths. This will prevent guidance drift and align
with the cleanup of broken documentation references.

Comment on lines +208 to +210
- **Pre-commit**: gitleaks runs automatically
- **CI**: Tekton runs gitleaks and gosec
- **RBAC check**: Custom make target

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== CI entrypoints mentioning prek/gitleaks/gosec =="
rg -n -C2 'prek|gitleaks|gosec|ci\.sh|prek\.ci\.toml' \
  --iglob '*.yaml' --iglob '*.yml' --iglob '*.sh' --iglob '*.md'

echo
echo "== Tekton/Prow style configs (if present) =="
fd -i 'tekton|prow|pipeline|task' .

echo
echo "== Security agent claim lines =="
rg -n -C1 'CI.*gitleaks|gosec' .claude/agents/security-agent.md

Repository: openshift/splunk-forwarder-operator

Length of output: 8170


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "=== hack/prek.ci.toml content ==="
if [ -f "hack/prek.ci.toml" ]; then
  cat hack/prek.ci.toml
else
  echo "File not found"
fi

echo
echo "=== Prow config structure ==="
fd -t f . ./boilerplate/openshift/golang-osd-operator/prow-config/ 2>/dev/null | head -20

echo
echo "=== Tekton pipeline files in repo ==="
find . -maxdepth 3 -type f \( -name "*.yaml" -o -name "*.yml" \) -path "*tekton*" -o -path "*pipeline*" | grep -E "(tekton|pipeline)" | head -20

echo
echo "=== Check for Tekton PipelineRun or Task definitions ==="
rg -l "kind:\s*(PipelineRun|Pipeline|Task)" --max-count=10 2>/dev/null || echo "No Tekton definitions found via rg"

Repository: openshift/splunk-forwarder-operator

Length of output: 1971


Remove or correct the false claim that CI runs gitleaks.

The CI configuration (hack/prek.ci.toml) used by hack/ci.sh explicitly excludes gitleaks—it only includes golangci-lint (which runs gosec) and custom Go/RBAC checks. While gitleaks is defined in .pre-commit-config.yaml for local pre-commit hooks, it does not run in the Tekton CI pipeline. Line 209's claim that "CI: Tekton runs gitleaks and gosec" is inaccurate: CI runs gosec (via golangci-lint) but not gitleaks.

High-risk file per coding guidelines: Correct this documentation to avoid misleading developers about actual CI security controls.

🤖 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/agents/security-agent.md around lines 208 - 210, The documentation
incorrectly claims that Tekton CI runs both gitleaks and gosec, but the actual
CI configuration only runs gosec via golangci-lint. Correct the bullet point
that currently states "**CI**: Tekton runs gitleaks and gosec" to accurately
reflect that only gosec runs in the Tekton CI pipeline, while gitleaks only runs
locally as a pre-commit hook. Remove the reference to gitleaks from the CI
section to ensure the documentation accurately represents the actual security
controls and scanning tools executed in the pipeline.

Source: Coding guidelines

Comment on lines +31 to +39
CHANGED_FILES=$(git diff --name-only HEAD | grep "\.go$")

# Extract packages
PACKAGES=$(echo "$CHANGED_FILES" | xargs -n1 dirname | sort -u | tr '\n' ' ')

# Run targeted tests
for pkg in $PACKAGES; do
go test -v ./$pkg/...
done

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

Handle empty changed-file sets in test selection logic.

When no .go files are changed, this flow can error during package extraction. Add a guard so the agent exits cleanly instead of failing.

Proposed fix
 CHANGED_FILES=$(git diff --name-only HEAD | grep "\.go$")
+if [ -z "${CHANGED_FILES}" ]; then
+  echo "No changed Go files; skipping targeted tests."
+  exit 0
+fi
 
 # Extract packages
 PACKAGES=$(echo "$CHANGED_FILES" | xargs -n1 dirname | sort -u | tr '\n' ' ')
🤖 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/agents/test-agent.md around lines 31 - 39, The script does not
handle the case when no `.go` files are changed, which causes the package
extraction and test execution to fail. Add a guard clause after the
CHANGED_FILES variable assignment to check if the result is empty, and if so,
exit cleanly with a success message. This prevents the downstream PACKAGES
extraction and the for loop from attempting to process empty data.

Comment thread .claude/hooks/pre-edit.sh
Comment on lines +142 to +165
HIGH_RISK_PATTERNS=(
"*/rbac.go"
"*/auth*.go"
"*_rbac.yaml"
"*/networkpolicy*.go"
"*[Cc]luster[Rr]ole*.yaml"
".tekton/*.yaml"
"build/Dockerfile"
)

for pattern in "${HIGH_RISK_PATTERNS[@]}"; do
# shellcheck disable=SC2053
if [[ "$FILE" == $pattern ]]; then
echo "⚠️ HIGH-RISK FILE: $FILE"
echo " This file affects security or CI/CD."
echo " Changes require:"
echo " - Careful review"
echo " - Test coverage"
echo " - Security validation"
echo ""
confirm_or_exit " Continue? (y/N)"
break
fi
done

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

Protect the Claude automation files too.

As per coding guidelines, .claude is a HIGH RISK — IDE and AI tool configuration (prodsec-skills). This allowlist never warns on .claude/settings.json, .claude/hooks/*, or .claude/agents/*, so the files that control the agent itself can still be edited without confirmation.

Suggested pattern additions
 HIGH_RISK_PATTERNS=(
+  ".claude/settings.json"
+  ".claude/hooks/*"
+  ".claude/agents/*"
   "*/rbac.go"
📝 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
HIGH_RISK_PATTERNS=(
"*/rbac.go"
"*/auth*.go"
"*_rbac.yaml"
"*/networkpolicy*.go"
"*[Cc]luster[Rr]ole*.yaml"
".tekton/*.yaml"
"build/Dockerfile"
)
for pattern in "${HIGH_RISK_PATTERNS[@]}"; do
# shellcheck disable=SC2053
if [[ "$FILE" == $pattern ]]; then
echo "⚠️ HIGH-RISK FILE: $FILE"
echo " This file affects security or CI/CD."
echo " Changes require:"
echo " - Careful review"
echo " - Test coverage"
echo " - Security validation"
echo ""
confirm_or_exit " Continue? (y/N)"
break
fi
done
HIGH_RISK_PATTERNS=(
".claude/settings.json"
".claude/hooks/*"
".claude/agents/*"
"*/rbac.go"
"*/auth*.go"
"*_rbac.yaml"
"*/networkpolicy*.go"
"*[Cc]luster[Rr]ole*.yaml"
".tekton/*.yaml"
"build/Dockerfile"
)
for pattern in "${HIGH_RISK_PATTERNS[@]}"; do
# shellcheck disable=SC2053
if [[ "$FILE" == $pattern ]]; then
echo "⚠️ HIGH-RISK FILE: $FILE"
echo " This file affects security or CI/CD."
echo " Changes require:"
echo " - Careful review"
echo " - Test coverage"
echo " - Security validation"
echo ""
confirm_or_exit " Continue? (y/N)"
break
fi
done
🤖 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 142 - 165, The HIGH_RISK_PATTERNS
array in the pre-edit.sh script does not include patterns to protect critical
Claude automation configuration files. Add three new patterns to the
HIGH_RISK_PATTERNS array to flag changes to .claude directory files: one pattern
for .claude/settings.json, one pattern for .claude/hooks/* files, and one
pattern for .claude/agents/* files. These patterns will ensure that
modifications to Claude IDE configuration, hook scripts, and agent definitions
trigger the high-risk warning and require user confirmation before proceeding.

Source: Coding guidelines

Comment on lines +80 to +89
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)
fi
PREK_EXIT=$?

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

Preserve filenames when passing them to prek.

xargs will split valid paths on spaces/newlines, so the hook can validate the wrong files or fail on otherwise valid edits. Use a NUL-delimited path list (git diff -z / git ls-files -z) and pass it through a filename-safe transport.

🤖 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 - 89, The git commands
and xargs invocation in the conditional block (checking CHANGED_FILES and
passing to prek run) do not properly handle filenames with spaces or special
characters. Modify the git diff and git ls-files commands to use the -z flag for
null-delimited output, and update the xargs invocation to use the -0 flag to
handle null-delimited input. This will ensure that filenames with spaces,
newlines, or other special characters are correctly passed to the prek run
command without being incorrectly split.

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

Handle missing gcloud binary explicitly.

If gcloud is not installed, subprocess.run raises FileNotFoundError and the script exits with a traceback instead of a clean error.

Suggested fix
     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 retry.", 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
🪛 ast-grep (0.44.0)

[error] 70-70: Command coming from incoming request
Context: subprocess.run(cmd, check=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 70-70: Use of unsanitized data to create processes
Context: subprocess.run(cmd, check=True, capture_output=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(os-system-unsanitized-data)

🪛 Ruff (0.15.18)

[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
current exception handling in the try block only catches
subprocess.CalledProcessError, but when the gcloud binary is not installed,
subprocess.run raises FileNotFoundError instead, causing an unhandled exception.
Add an additional except clause after the existing subprocess.CalledProcessError
handler to catch FileNotFoundError (or OSError more broadly) and print a
user-friendly error message indicating that the gcloud binary is not installed,
then return False to maintain consistent error handling behavior.

Comment on lines +84 to +89
try:
with open(local_path, 'r') as f:
return json.load(f)
except json.JSONDecodeError as e:
print(f"Error: Could not parse JSON from {local_path}: {e}", file=sys.stderr)
return None

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 optional prowjob.json reads against filesystem errors.

This block treats prowjob.json as optional, but open() failures (e.g., permissions/partial writes) aren’t caught and can abort the script.

Suggested fix
-        except json.JSONDecodeError as e:
+        except (json.JSONDecodeError, OSError) as e:
             print(f"Error: Could not parse JSON from {local_path}: {e}", file=sys.stderr)
             return None
🧰 Tools
🪛 ast-grep (0.44.0)

[warning] 84-84: File path is request-/variable-derived; validate and normalize to prevent path traversal.
Context: open(local_path, 'r')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(open-filename-from-request)

🤖 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 84 - 89, The
exception handling in the JSON file loading block only catches
json.JSONDecodeError, but filesystem errors from the open() call (such as
FileNotFoundError, PermissionError, or IOError) are not handled and will cause
the script to abort. Expand the exception handling to catch filesystem-related
errors in addition to JSONDecodeError. Either catch multiple specific exceptions
(FileNotFoundError, PermissionError, IOError, etc.) or use a broader exception
type like OSError or Exception to handle all potential errors that could occur
when opening and reading the local_path file, ensuring the function gracefully
returns None when any error occurs.

make go-test

# For linting (matches: pull-ci-...-lint)
make go-check

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

Use the repository’s documented lint target here.

make go-check appears inconsistent with this repo’s declared commands and will likely fail for contributors following this workflow.

Suggested doc fix
- make go-check
+ make lint

As per coding guidelines, the documented linting command is make lint.

📝 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
make go-check
make lint
🤖 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/SKILL.md at line 214, The linting command documented
in the SKILL.md file uses make go-check, but this is inconsistent with the
repository's actual declared linting target. Replace the make go-check command
with make lint to match the documented lint target and ensure contributors
following this workflow will use the correct command.

Source: Coding guidelines

Comment thread .gitleaks.toml
Comment on lines +50 to +59
# Stopwords that appear in code but aren't secrets
stopwords = [
"example",
"test",
"fake",
"dummy",
"placeholder",
"sample",
"mock",
]

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

Narrow global stopwords to avoid suppressing real secret leaks.

These global stopwords are too broad and can mask valid detections (for example, real credentials containing test/example/sample). Keep only tightly scoped false-positive controls (path- or rule-specific allowlists) instead of global suppression.

Suggested hardening
 stopwords = [
-  "example",
-  "test",
-  "fake",
-  "dummy",
-  "placeholder",
-  "sample",
-  "mock",
+  "AKIAIOSFODNN7EXAMPLE",
 ]

Based on learnings: Never commit API keys, tokens, passwords, AWS credentials, kubeconfig files, private keys, certificates, .env files with secrets, or debug statements printing sensitive data.

📝 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
# Stopwords that appear in code but aren't secrets
stopwords = [
"example",
"test",
"fake",
"dummy",
"placeholder",
"sample",
"mock",
]
# Stopwords that appear in code but aren't secrets
stopwords = [
"AKIAIOSFODNN7EXAMPLE",
]
🤖 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 @.gitleaks.toml around lines 50 - 59, The global stopwords array in the
.gitleaks.toml configuration is too permissive and can suppress legitimate
secret detections by matching overly common terms. Remove the entire stopwords
array definition that contains example, test, fake, dummy, placeholder, sample,
and mock, and instead implement path-specific or rule-specific allowlists for
known false positives to maintain tighter security controls that won't
accidentally mask real credential leaks.

Source: Learnings

Adds standardized Claude Code tooling (agents, hooks, skills, settings)
and developer documentation (CONTRIBUTING.md, DEVELOPMENT.md, TESTING.md,
prek configs, gitleaks config) adapted from the ocm-agent-operator
reference implementation.

Fixes vs closed PR openshift#437:
- Go version corrected to 1.25+ (was 1.22.7)
- Removed nonexistent make targets (tools, run, run-verbose, help)
- Replaced all pre-commit references with prek equivalents
- Removed OCM copy-paste artifacts (ocm_agent_token rule, fleet
  notification example, pkg/handler/deployment.go path references)
- Fixed command injection in pre-edit.sh python3 fallback (sys.argv)
- Narrowed Bash(find *) permission to Bash(find . -name/type *)
- Fixed nested code block in TESTING.md
- Corrected operator name to "Splunk Forwarder Operator" throughout
- Removed links to nonexistent docs/ files

Related: ROSAENG-60008

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@anispate anispate force-pushed the ROSAENG-60008-claude-code-hooks-and-docs branch from b2848ed to 619376c Compare June 24, 2026 18:41
@openshift-ci

openshift-ci Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

@anispate: all tests passed!

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

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants