Skip to content

Commit c618f25

Browse files
committed
feat: add Claude Code infrastructure and documentation
1 parent c4038a9 commit c618f25

7 files changed

Lines changed: 83 additions & 54 deletions

File tree

.claude/hooks/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Used for local development with internal network access.
138138

139139
**Usage**:
140140
```bash
141-
prek run --all-files
141+
prek run --config hack/prek.ci.toml
142142
```
143143

144144
### 2. **hack/prek.ci.toml** (CI-compatible)
@@ -179,13 +179,13 @@ This sets up pre-commit hooks that run validation automatically.
179179

180180
### Automatic Validation
181181
Prek runs automatically:
182-
- **On every turn**: Stop hook runs `prek run --all-files`
182+
- **On every turn**: Stop hook runs `prek run --config hack/prek.ci.toml`
183183
- **On commit**: Pre-commit hook runs relevant checks
184184

185185
### Manual Validation
186186
```bash
187187
# Run all checks
188-
prek run --all-files
188+
prek run --config hack/prek.ci.toml
189189

190190
# Run specific check
191191
prek run gitleaks
@@ -320,7 +320,7 @@ SKIP=hook-id git commit
320320
- Open an issue documenting the problem
321321
- Request reviewer approval before merge
322322
3. **Re-run full validation:**
323-
- `prek run --all-files` locally
323+
- `prek run --config hack/prek.ci.toml` locally
324324
- Ensure all required CI checks pass
325325
- Get explicit code review approval
326326

.claude/hooks/pre-edit.sh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,27 @@ fi
1818
# Normalize file path to be repo-relative for consistent pattern matching
1919
# This ensures patterns like vendor/* work regardless of whether the input is absolute or relative
2020
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
21+
22+
# Reject absolute paths outside the repo
2123
if [[ "$FILE" = /* ]]; then
24+
if [[ ! "$FILE" == "$REPO_ROOT"/* ]]; then
25+
echo "❌ ERROR: File path is outside repository: $FILE"
26+
exit 1
27+
fi
2228
# Convert absolute path to repo-relative
2329
FILE="${FILE#"$REPO_ROOT"/}"
2430
fi
31+
32+
# Canonicalize and reject traversal segments
33+
if command -v realpath >/dev/null 2>&1; then
34+
CANONICAL=$(realpath -s --relative-to="$REPO_ROOT" "$FILE" 2>/dev/null || echo "")
35+
if [[ -z "$CANONICAL" ]] || [[ "$CANONICAL" == *".."* ]]; then
36+
echo "❌ ERROR: Invalid file path (contains traversal): $FILE"
37+
exit 1
38+
fi
39+
FILE="$CANONICAL"
40+
fi
41+
2542
# Strip leading ./
2643
FILE="${FILE#./}"
2744

.claude/hooks/stop-prek-validation.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if [[ -z "$REPO_ROOT" ]]; then
2727
jq -n '{"decision": "block", "reason": "Not in a git repository. Cannot run prek validation."}'
2828
exit 0
2929
fi
30-
cd "$REPO_ROOT"
30+
cd "$REPO_ROOT" || exit 1
3131

3232
# Check for jq dependency
3333
if ! command -v jq &> /dev/null; then

.claude/skills/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Skills can be referenced in Claude conversations:
3333
```text
3434
"Use the prow-ci skill to investigate the failed test in PR #123"
3535
"Check Prow CI results for the latest build"
36-
```
36+
```text
3737
3838
### Skill Components
3939
@@ -63,13 +63,13 @@ To add a new skill:
6363
6. Test the skill workflow
6464

6565
**Directory structure**:
66-
```
66+
```text
6767
.claude/skills/
6868
├── README.md
6969
└── skillname/
7070
├── SKILL.md # Required: skill definition
7171
└── reference/ # Optional: supporting docs
72-
```
72+
```text
7373
7474
## Integration with Other Components
7575

.claude/skills/prow-ci/SKILL.md

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ description: Fetch and analyze OpenShift Prow CI job failures with automated art
44
trigger: prow, prow-ci, /prow-ci, ci results, check ci, analyze ci failure
55
---
66

7-
# Prow CI Analysis for Rbac Permissions Operator
7+
# Prow CI Analysis
88

99
This skill fetches Prow CI job artifacts from Google Cloud Storage and provides automated failure analysis.
1010

@@ -29,7 +29,7 @@ gh pr checks <PR_NUMBER>
2929
/prow-ci <prow-job-url>
3030

3131
# Or ask naturally:
32-
"Analyze the lint failure in PR 328"
32+
"Analyze the lint failure in PR <NUMBER>"
3333
"Check why the validate job failed"
3434
"Show me what broke in the coverage job"
3535
```
@@ -70,14 +70,14 @@ gh pr view <PR_NUMBER> --json statusCheckRollup --jq '.statusCheckRollup[] | sel
7070

7171
Example Prow job URL:
7272
```
73-
https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_rbac-permissions-operator/328/pull-ci-openshift-rbac-permissions-operator-master-lint/2059308810190721024
73+
https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_splunk_forwarder_operator/<PR_NUMBER>/pull-ci-openshift-splunk-forwarder-operator-master-lint/<BUILD_ID>
7474
```
7575

7676
### Step 2: Fetch and Analyze
7777

7878
Run the fetch script first:
7979
```bash
80-
cd /Users/ppanda/rh-projects/ROSA-730/rbac-permissions-operator/.claude/skills/prow-ci
80+
cd $PWD/.claude/skills/prow-ci
8181

8282
python3 fetch_prow_artifacts.py "<prow-job-url>" -o .work/prow-artifacts
8383
```
@@ -109,18 +109,18 @@ Create a clear summary for the user with:
109109
### Example Workflow
110110

111111
```bash
112-
# User provides: "Analyze the lint failure in PR 328"
112+
# User provides: "Analyze the lint failure in PR <NUMBER>"
113113

114114
# 1. Get Prow job URL
115-
gh pr checks 328 | grep lint
115+
gh pr checks <PR_NUMBER> | grep lint
116116

117117
# 2. Fetch artifacts
118118
python3 .claude/skills/prow-ci/fetch_prow_artifacts.py \
119-
"https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_rbac-permissions-operator/328/pull-ci-openshift-rbac-permissions-operator-master-lint/2059308810190721024"
119+
"https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_splunk_forwarder_operator/<PR_NUMBER>/pull-ci-openshift-splunk-forwarder-operator-master-lint/<BUILD_ID>"
120120

121121
# 3. Analyze
122122
python3 .claude/skills/prow-ci/analyze_failure.py \
123-
.work/prow-artifacts/2059308810190721024 \
123+
.work/prow-artifacts/<BUILD_ID> \
124124
-f markdown
125125

126126
# 4. Review the output and provide actionable summary
@@ -130,15 +130,15 @@ python3 .claude/skills/prow-ci/analyze_failure.py \
130130

131131
**Main Dashboard**: https://prow.ci.openshift.org/
132132
**CI Search**: https://github.com/openshift/ci-search
133-
**Job History**: https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator
133+
**Job History**: https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator
134134

135135
## Common Use Cases
136136

137137
### 1. Check Recent CI Results
138138

139139
```bash
140140
# View recent PR jobs
141-
curl -s "https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator&type=presubmit" | grep -E "pull-ci-openshift-rbac-permissions-operator"
141+
curl -s "https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator&type=presubmit" | grep -E "pull-ci-openshift-splunk-forwarder-operator"
142142

143143
# Check latest job status for specific PR
144144
# Replace PR_NUMBER with actual PR number
@@ -148,12 +148,12 @@ gh pr view PR_NUMBER --json statusCheckRollup --jq '.statusCheckRollup[] | selec
148148
### 2. Access Build Logs
149149

150150
Prow logs are stored at:
151-
- **Pull request jobs**: `gs://test-platform-results/pr-logs/pull/openshift_rbac-permissions-operator/[PR_NUMBER]/[JOB_NAME]/[JOB_ID]`
151+
- **Pull request jobs**: `gs://test-platform-results/pr-logs/pull/openshift_splunk_forwarder_operator/[PR_NUMBER]/[JOB_NAME]/[JOB_ID]`
152152
- **Periodic jobs**: `gs://test-platform-results/logs/[JOB_NAME]/[JOB_ID]`
153153

154154
**Viewing logs via web**:
155155
```text
156-
https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_rbac-permissions-operator/[PR_NUMBER]/[JOB_NAME]/[JOB_ID]
156+
https://prow.ci.openshift.org/view/gs/test-platform-results/pr-logs/pull/openshift_splunk_forwarder_operator/[PR_NUMBER]/[JOB_NAME]/[JOB_ID]
157157
```
158158

159159
### 3. Analyze Test Failures
@@ -175,16 +175,16 @@ gh pr checks PR_NUMBER | grep -i "fail"
175175
### 4. Common Job Names
176176

177177
**Prow CI Jobs** (configured in openshift/release):
178-
- `pull-ci-openshift-rbac-permissions-operator-master-e2e-binary-build-success` - E2E binary build verification
179-
- `pull-ci-openshift-rbac-permissions-operator-master-coverage` - Code coverage analysis (with Codecov)
180-
- `pull-ci-openshift-rbac-permissions-operator-master-lint` - Linting checks
181-
- `pull-ci-openshift-rbac-permissions-operator-master-test` - Unit tests
182-
- `pull-ci-openshift-rbac-permissions-operator-master-validate` - Validation checks
178+
- `pull-ci-openshift-splunk-forwarder-operator-master-e2e-binary-build-success` - E2E binary build verification
179+
- `pull-ci-openshift-splunk-forwarder-operator-master-coverage` - Code coverage analysis (with Codecov)
180+
- `pull-ci-openshift-splunk-forwarder-operator-master-lint` - Linting checks
181+
- `pull-ci-openshift-splunk-forwarder-operator-master-test` - Unit tests
182+
- `pull-ci-openshift-splunk-forwarder-operator-master-validate` - Validation checks
183183

184184
**Tekton Pipelines** (configured in `.tekton/`):
185-
- `rbac-permissions-operator-pull-request` - Main PR pipeline (docker build with OCI-TA)
186-
- `rbac-permissions-operator-e2e-pull-request` - E2E testing pipeline
187-
- `rbac-permissions-operator-pko-pull-request` - PKO (Package Operator) pipeline
185+
- `splunk-forwarder-operator-pull-request` - Main PR pipeline (docker build with OCI-TA)
186+
- `splunk-forwarder-operator-e2e-pull-request` - E2E testing pipeline
187+
- `splunk-forwarder-operator-pko-pull-request` - PKO (Package Operator) pipeline
188188
- Corresponding `-push` pipelines for merged commits
189189

190190
## Debugging CI Failures
@@ -197,7 +197,7 @@ gh pr checks PR_NUMBER
197197
### Step 2: Access Prow UI
198198
Open the Prow link from PR checks or construct manually:
199199
```text
200-
https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator&type=presubmit
200+
https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator&type=presubmit
201201
```
202202

203203
### Step 3: Review Logs
@@ -238,15 +238,15 @@ make docker-build
238238
This repo uses **both Prow and Tekton** for comprehensive CI:
239239

240240
**Prow CI** (openshift/release):
241-
- Configuration: `ci-operator/config/openshift/rbac-permissions-operator/openshift-rbac-permissions-operator-master.yaml`
241+
- Configuration: `ci-operator/config/openshift/splunk-forwarder-operator/openshift-splunk-forwarder-operator-master.yaml`
242242
- Runs: lint, test, validate, coverage, e2e-binary-build
243-
- Uses Codecov for coverage reporting (secret: `rbac-permissions-operator-codecov-token`)
243+
- Uses Codecov for coverage reporting (secret: `splunk-forwarder-operator-codecov-token`)
244244
- Skip rules: Changes to `.tekton/`, `.github/`, `.md` files, `OWNERS`, `LICENSE` don't trigger most jobs
245245

246246
**Tekton Pipelines** (`.tekton/`):
247247
- Primary build pipeline using Pipelines as Code
248248
- Three pipeline types: main, e2e, pko
249-
- Builds container images to Quay (rbac-permissions-operator-tenant)
249+
- Builds container images to Quay (splunk-forwarder-operator-tenant)
250250
- Pull request images expire after 5 days
251251
- Uses boilerplate framework from `openshift/boilerplate` (docker-build-oci-ta pipeline)
252252

@@ -260,31 +260,31 @@ gh pr checks <PR_NUMBER>
260260
gh pr view <PR_NUMBER> --json statusCheckRollup
261261

262262
# Filter only Prow jobs
263-
gh pr checks <PR_NUMBER> | grep "pull-ci-openshift-rbac-permissions-operator"
263+
gh pr checks <PR_NUMBER> | grep "pull-ci-openshift-splunk-forwarder-operator"
264264

265265
# Check Tekton pipeline status
266266
gh pr view <PR_NUMBER> --json statusCheckRollup --jq '.statusCheckRollup[] | select(.context | contains("Tekton"))'
267267

268268
# Open Prow dashboard in browser (cross-platform)
269269
# Copy and paste this URL into your browser:
270-
# https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator
270+
# https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator
271271

272272
# Or use platform-specific command:
273-
# macOS: open "https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator"
274-
# Linux: xdg-open "https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator"
275-
# Windows: start "https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator"
273+
# macOS: open "https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator"
274+
# Linux: xdg-open "https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator"
275+
# Windows: start "https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator"
276276

277277
# View specific PR on Prow (replace <PR_NUMBER>)
278-
# https://prow.ci.openshift.org/?repo=openshift%2Frbac-permissions-operator&type=presubmit&pull=<PR_NUMBER>
278+
# https://prow.ci.openshift.org/?repo=openshift%2Fsplunk-forwarder-operator&type=presubmit&pull=<PR_NUMBER>
279279
```
280280

281281
## Troubleshooting
282282

283283
### Can't find job results?
284284
- Check both Prow AND Tekton - this repo uses both systems
285-
- Prow jobs: `pull-ci-openshift-rbac-permissions-operator-master-*`
285+
- Prow jobs: `pull-ci-openshift-splunk-forwarder-operator-master-*`
286286
- Tekton jobs: Usually show as "Tekton" or pipeline names in PR checks
287-
- Verify repo name format in Prow: `openshift_rbac-permissions-operator` (underscore, not dash)
287+
- Verify repo name format in Prow: `openshift_splunk_forwarder_operator` (underscore, not dash)
288288
- Ensure PR has been opened and CI has run
289289

290290
### Logs show permission denied?
@@ -303,7 +303,7 @@ gh pr view <PR_NUMBER> --json statusCheckRollup --jq '.statusCheckRollup[] | sel
303303
- Common issues:
304304
- Image build failures → Check Dockerfile syntax and build context
305305
- Pipeline timeout → Check for slow steps or network issues
306-
- Auth failures → Secret configuration in `rbac-permissions-operator-tenant` namespace
306+
- Auth failures → Secret configuration in `splunk-forwarder-operator-tenant` namespace
307307
- Local validation:
308308
```bash
309309
# Validate Tekton YAML syntax
@@ -333,27 +333,27 @@ git clone https://github.com/openshift/ci-search.git
333333
## CI Configuration Files
334334

335335
**Prow Configuration** (in openshift/release repo):
336-
- Location: `ci-operator/config/openshift/rbac-permissions-operator/openshift-rbac-permissions-operator-master.yaml`
336+
- Location: `ci-operator/config/openshift/splunk-forwarder-operator/openshift-splunk-forwarder-operator-master.yaml`
337337
- Update process: Submit PR to openshift/release repository
338-
- Auto-generated jobs in: `ci-operator/jobs/openshift/rbac-permissions-operator/`
338+
- Auto-generated jobs in: `ci-operator/jobs/openshift/splunk-forwarder-operator/`
339339

340340
**Tekton Pipelines** (in this repo):
341341
- Location: `.tekton/` directory
342342
- Files:
343-
- `rbac-permissions-operator-pull-request.yaml` - Main PR pipeline
344-
- `rbac-permissions-operator-push.yaml` - Post-merge pipeline
345-
- `rbac-permissions-operator-e2e-pull-request.yaml` - E2E testing
346-
- `rbac-permissions-operator-pko-pull-request.yaml` - PKO validation
343+
- `splunk-forwarder-operator-pull-request.yaml` - Main PR pipeline
344+
- `splunk-forwarder-operator-push.yaml` - Post-merge pipeline
345+
- `splunk-forwarder-operator-e2e-pull-request.yaml` - E2E testing
346+
- `splunk-forwarder-operator-pko-pull-request.yaml` - PKO validation
347347
- Triggered by: Pipelines as Code (via Tekton)
348348
- Uses: Boilerplate docker-build-oci-ta pipeline from openshift/boilerplate
349349

350350
## Coverage Reporting
351351

352352
This repository uses Codecov for coverage tracking:
353-
- Secret: `rbac-permissions-operator-codecov-token` (stored in Prow)
353+
- Secret: `splunk-forwarder-operator-codecov-token` (stored in Prow)
354354
- Generate coverage locally: `make coverage`
355355
- Coverage runs on PRs and post-merge (`publish-coverage`)
356-
- Dashboard: Check Codecov for rbac-permissions-operator
356+
- Dashboard: Check Codecov for splunk-forwarder-operator
357357

358358
## Integration with Other Skills
359359

.claude/skills/prow-ci/analyze_failure.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ def parse_junit_xml(xml_file):
1919
root = tree.getroot()
2020

2121
failures = []
22-
for testsuite in root.findall('.//testsuite'):
22+
# Handle root-level testsuite or nested testsuites
23+
suites = [root] if root.tag == 'testsuite' else []
24+
suites.extend(root.findall('.//testsuite'))
25+
26+
for testsuite in suites:
2327
suite_name = testsuite.get('name', 'unknown')
2428
for testcase in testsuite.findall('.//testcase'):
2529
test_name = testcase.get('name', 'unknown')
@@ -106,8 +110,12 @@ def analyze_prowjob(prowjob_file):
106110
if not os.path.exists(prowjob_file):
107111
return None
108112

109-
with open(prowjob_file, 'r') as f:
110-
data = json.load(f)
113+
try:
114+
with open(prowjob_file, 'r') as f:
115+
data = json.load(f)
116+
except (json.JSONDecodeError, OSError) as e:
117+
print(f"Error: Could not parse prowjob from {prowjob_file}: {e}", file=sys.stderr)
118+
return None
111119

112120
status = data.get('status', {})
113121
spec = data.get('spec', {})

.claude/skills/prow-ci/fetch_prow_artifacts.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,12 @@ def fetch_prowjob_json(gcs_base_path, output_dir):
8181
local_path = os.path.join(output_dir, 'prowjob.json')
8282

8383
if download_from_gcs(gcs_path, local_path):
84-
with open(local_path, 'r') as f:
85-
return json.load(f)
84+
try:
85+
with open(local_path, 'r') as f:
86+
return json.load(f)
87+
except json.JSONDecodeError as e:
88+
print(f"Error: Could not parse JSON from {local_path}: {e}", file=sys.stderr)
89+
return None
8690
return None
8791

8892

0 commit comments

Comments
 (0)