Skip to content

Refactor CVE fix skill into shell scripts#2383

Open
dfarrell07 wants to merge 3 commits intosubmariner-io:develfrom
dfarrell07:cve-fix-skill-redesign
Open

Refactor CVE fix skill into shell scripts#2383
dfarrell07 wants to merge 3 commits intosubmariner-io:develfrom
dfarrell07:cve-fix-skill-redesign

Conversation

@dfarrell07
Copy link
Copy Markdown
Member

@dfarrell07 dfarrell07 commented Apr 13, 2026

Extract all inline bash from skills/cve-fix/SKILL.md into shellcheck-linted scripts. The SKILL.md becomes a thin wrapper that delegates to fix-all.sh.

The deterministic orchestrator (fix-all.sh) handles the full flow: detect config, create fix branch, scan with grype, fix each CVE, verify, commit, run tests. After the deterministic phase, it invokes a Claude subagent (review.sh) to review all outcomes and handle edge cases like breaking changes or persistent CVEs.

Add make cve-fix target for standalone use outside the skill.

See SEP-0032 for design details.

Summary by CodeRabbit

  • New Features

    • End-to-end CVE remediation workflow: detect, scan, apply fixes (packages + stdlib), run tests, and produce PR commands and reviewer prompts; CLI tools to locate packages, ignore CVEs, and run reviews.
  • Documentation

    • Expanded commit-template abbreviations and added CVE-fix usage guides and a reviewer prompt template; updated skill metadata and quick usage docs.
  • Tests

    • CI step and unit/integration tests added to validate CVE tooling.
  • Chores

    • New top-level cve-fix make target and CI integration.

@dfarrell07 dfarrell07 self-assigned this Apr 13, 2026
@submariner-bot
Copy link
Copy Markdown

🤖 Created branch: z_pr2383/dfarrell07/cve-fix-skill-redesign

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 13, 2026

Warning

Rate limit exceeded

@dfarrell07 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 34 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 621f4988-287c-4898-98b9-7d75aa73d19e

📥 Commits

Reviewing files that changed from the base of the PR and between 0e1ad56 and 0d2a429.

📒 Files selected for processing (18)
  • .agents/commit-templates.md
  • .agents/workflows/cve-fix.md
  • .github/workflows/testing.yml
  • Makefile
  • scripts/cve/clean.sh
  • scripts/cve/detect.sh
  • scripts/cve/fix-all.sh
  • scripts/cve/fix-package.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/ignore.sh
  • scripts/cve/lib.sh
  • scripts/cve/locate.sh
  • scripts/cve/review-prompt.md
  • scripts/cve/review.sh
  • scripts/cve/scan.sh
  • scripts/cve/test-lib.sh
  • skills/cve-fix/SKILL.md
  • test/scripts/cve/test.sh

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a CVE remediation automation suite: detection, grype-based scanning, per-package and stdlib fixers, ignore management, orchestration (fix-all), review integration (agent prompt), CI/test wiring, skill/docs/commit-template updates, and unit/integration tests. All changes are scripts/docs/CI/tests; no exported library APIs changed.

Changes

CVE remediation automation

Layer / File(s) Summary
State / Paths
scripts/cve/lib.sh, scripts/cve/detect.sh
Add state-file helpers and detection flow: compute/normalize REPO and BRANCH, detect container runtime and Shipyard image/Go version, detect generated artifacts/DIFF_IGNORE_ARGS, optionally create a fix branch, and write a STATE_FILE.
Core Helpers / Scan Runner
scripts/cve/lib.sh, scripts/cve/scan.sh
Add shared utilities: state_file_path, load_state, detect_container_cmd, run_grype, abbreviate_package, find_gomods, clean_gomod, insert_grype_ignore, banner; add scan.sh wrapper enforcing CLI flags and optional build step.
Orchestration
scripts/cve/fix-all.sh, Makefile
Add fix-all.sh orchestrator: detect → scan → group CVEs → run per-package/stdlib fixers → run unit tests → re-scan → produce review evidence and PR push/create guidance; add cve-fix Make target and include in NON_DAPPER_GOALS.
Per-package Fixers
scripts/cve/fix-package.sh, scripts/cve/fix-stdlib.sh
Add fix-package.sh to update package versions across modules with verification, rollback and exit codes for breaking or persistent CVEs; add fix-stdlib.sh to bump root/module go directive with review gating on minor-version changes.
Reviewer / Utility CLIs
scripts/cve/locate.sh, scripts/cve/ignore.sh, scripts/cve/review.sh, scripts/cve/review-prompt.md
Add locator for package occurrences and replace directives, grype-ignore insertion CLI with commit, review orchestration that builds a prompt (envsubst) and invokes Claude when available, plus a review prompt template.
Tests / CI
scripts/cve/test-lib.sh, test/scripts/cve/test.sh, .github/workflows/testing.yml
Add unit/integration tests covering lib helpers and key scripts; add CI step to run the CVE script tests via make script-test.
Docs / Skill / Templates
skills/cve-fix/SKILL.md, .agents/workflows/cve-fix.md, .agents/commit-templates.md
Update skill to delegate to fix-all.sh (narrowed allowed-tools, removed version), add automated workflow docs, and extend commit-template package abbreviation mappings.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant FixAll as Fix-All
    participant Detect as Detect
    participant Grype as Grype
    participant Fixer as Fixers
    participant Git as Git
    participant Review as Review/Agent

    User->>FixAll: run fix-all.sh REPO BRANCH (or Make target)
    FixAll->>Detect: run --setup-branch
    Detect->>Git: validate repo, fetch, create/check out fix branch
    Detect-->>FixAll: return STATE_FILE
    FixAll->>Grype: run initial scan (--json)
    Grype-->>FixAll: scan results
    alt CVEs found
        FixAll->>FixAll: group CVEs by package
        loop per package
            FixAll->>Fixer: invoke fix-package or fix-stdlib
            Fixer->>Git: run go commands, commit or rollback
            Fixer-->>FixAll: FIXED or NEEDS_REVIEW
        end
        FixAll->>Grype: run verification scan
        Grype-->>FixAll: updated results
        FixAll->>Review: run review.sh with FIX_SUMMARY and scan
        Review->>Grype: optionally run locate/scan evidence
        Review->>Review: render prompt and invoke agent (if available)
        Review-->>FixAll: review summary (FIXED/IGNORED/UNRESOLVED)
    else No CVEs
        FixAll-->>User: report clean, delete fix branch
    end
    FixAll-->>User: print commits + git push / gh pr create guidance, exit code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • vthapar
  • sridhargaddam
  • tpantelis
  • Oats87
  • mkolesnik
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main refactoring work: extracting bash logic from a skill into shell scripts.
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.
Actionable Comments Resolved ✅ Passed No actionable comments related to this pull request found in codebase. All files complete and well-documented.

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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
Review rate limit: 0/1 reviews remaining, refill in 13 minutes and 34 seconds.

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

@github-actions
Copy link
Copy Markdown

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further
activity occurs. Thank you for your contributions.

@github-actions github-actions Bot added the stale label Apr 28, 2026
@dfarrell07 dfarrell07 removed the stale label Apr 28, 2026
@dfarrell07 dfarrell07 force-pushed the cve-fix-skill-redesign branch 3 times, most recently from 43aea4b to 43f1d40 Compare May 1, 2026 20:27
@dfarrell07 dfarrell07 marked this pull request as ready for review May 1, 2026 20:29
@dfarrell07 dfarrell07 moved this to In Review in Submariner 0.24 May 1, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Makefile`:
- Around line 68-70: The Makefile target cve-fix currently invokes
./scripts/cve/fix-all.sh with unquoted expansions of $(or $(REPO),.) and $(or
$(BRANCH),$(shell git branch --show-current)), which will split paths containing
spaces; update the cve-fix recipe to pass quoted arguments to fix-all.sh (wrap
the two expansions in double quotes) so REPO and BRANCH overrides are forwarded
as single arguments to ./scripts/cve/fix-all.sh.

In `@scripts/cve/detect.sh`:
- Around line 137-153: The heredoc that writes the sourced state file in
scripts/cve/detect.sh currently injects raw variable values (STATE_FILE, REPO,
BRANCH, FIX_BRANCH, ORIGINAL_REF, HAS_TOOLS_GOMOD, GENERATED_FILE,
DIFF_IGNORE_ARGS, NEEDS_BUILD_FOR_SCAN, CONTAINER_CMD, HAS_LOCAL_GRYPE,
SHIPYARD_IMAGE, SHIPYARD_GO_VERSION, FETCH_FAILED, CVE_SCRIPTS) unescaped, so
values containing quotes or command substitution can break or be executed when
the file is sourced; change the writer to shell-escape each value before
emitting it (for example, generate each line using a safe escape routine such as
printf '%q' or by safely single-quoting and escaping internal single quotes) and
write the escaped results into "$STATE_FILE" instead of the raw expansions in
the heredoc so the resulting file can be safely sourced by scan.sh, fix-all.sh,
review.sh, etc.

In `@scripts/cve/fix-all.sh`:
- Around line 145-152: The final post-fix scan and agent review results are
being ignored when deciding the script exit status; ensure the exit code
reflects unresolved CVEs or review failures by capturing the exit/status of
"$SCRIPT_DIR/scan.sh" "$STATE_FILE" (post-fix scan) and "$SCRIPT_DIR/review.sh"
"$STATE_FILE" "$FIX_SUMMARY", and combine them with the existing REVIEW_COUNT
logic so the script exits non-zero if the post-fix scan reports matches or if
review.sh returns non-zero; update handling around the scan.sh call and the
review.sh invocation (also mirror the same fix where similar logic appears
around lines 196-199) to aggregate their exit codes into the final exit
decision.
- Around line 78-83: The current fixedIn selection uses lexicographic sort
(map(.fixedIn) | sort | last) which misorders semantic versions; replace it with
a version-aware sort, e.g. compute a sortable key by stripping a leading "v",
splitting on dots and converting numeric segments, and then use sort_by(... ) |
last; update the fixedIn expression inside the map block (the object with keys
pkg,type,fixedIn,cves) so it uses something like (map(.fixedIn) |
sort_by(gsub("^v";"") | split(".") | map(tonumber? // 0)) | last) to pick the
true highest semantic version.
- Around line 11-17: The cleanup function currently always runs git checkout --
. and can discard the caller's uncommitted edits; change it to be conditional:
before making any repo changes, record the repo's initial dirty state (e.g., via
git status --porcelain or git ls-files -m) and set a flag (e.g., INITIAL_CLEAN)
or write that list to STATE_FILE; then update cleanup (and the trap) to only
revert files that the script created/modified (or only run git checkout if the
repo was initially clean) rather than unconditionally running git checkout -- .;
ensure you still remove STATE_FILE in cleanup. Reference: cleanup, trap EXIT,
STATE_FILE.

In `@scripts/cve/fix-package.sh`:
- Line 40: K8S_BEFORE currently only reads the top-level go.mod; instead, scan
all go.mod files recursively and record the module path alongside its k8s.io
version so you can compare per-module after the update. Update the logic that
builds GO_BEFORE to produce a list of module=>version pairs (use each module's
"module" line and grep 'k8s.io/' to extract the minor version) and store that as
K8S_BEFORE; do the same after the change to produce K8S_AFTER, then compare
versions for the same module names to detect breaking minor upgrades; update any
checks that reference K8S_BEFORE/K8S_AFTER and GO_BEFORE to iterate module keys
rather than assuming a single root module.
- Around line 45-50: Replace the fragile grep-based check that looks for
"$PACKAGE" in "$GOMOD" with a structured module inspection using Go's module
JSON output (e.g., run go list -m -json all or go mod edit -json and parse the
"Require" and "Replace" fields) to determine whether the package is required and
whether its required version is still vulnerable; use the parsed Require entry
for the post-update success test (and ensure Replace entries do not mask a
still-vulnerable require) before reporting FIXED. Update the logic around the
PACKAGE/GOMOD/MODDIR/VERSION blocks (both the instance shown and the similar
block at lines 91-100) so the script programmatically checks the module JSON for
the package name and version rather than grepping the go.mod text.
- Around line 108-109: The pipeline "git diff --name-only | grep -E
'go\.(mod|sum)$' | xargs -r git add" can fail under set -euo pipefail when there
are no matches; change the logic in scripts/cve/fix-package.sh to first collect
matches (e.g., into a variable or array using git diff --name-only and grep -E
'go\.(mod|sum)$'), then check if that collection is non-empty before calling git
add (or skip/add a no-op) so the script does not abort; update the block that
currently contains that pipeline to perform the collect-check-add flow (or
explicitly guard the no-match case) instead of relying on the pipeline to be
safe.

In `@scripts/cve/fix-stdlib.sh`:
- Around line 59-60: Replace the current staging pipeline that uses only "git
diff --name-only | grep -E 'go\\.(mod|sum)$' | xargs -r git add" with a command
that also includes untracked files; e.g. combine tracked-changes and untracked
lists by using "git diff --name-only" and "git ls-files -o --exclude-standard",
filter both with grep -E 'go\\.(mod|sum)$', then pipe to xargs -r git add so
newly created go.sum files are staged; update the line in
scripts/cve/fix-stdlib.sh that currently contains the git diff pipeline to use
this combined approach.

In `@scripts/cve/lib.sh`:
- Around line 120-139: The insert_grype_ignore function currently always inserts
a new YAML block, causing duplicates; change it to be idempotent by first
searching the target file for an existing ignore block that matches both the
cve_id and package (e.g., matching the lines "vulnerability: $cve_id" and "name:
$package") and, if found, replace that existing block with the new entry instead
of appending; otherwise fall back to the current insertion logic. Update the
logic inside insert_grype_ignore to locate the start/end of the matching block
(or use a multiline grep/awk/sed pattern), perform an in-place replacement of
that block with the constructed $entry when present, and only insert a new block
when no match exists, ensuring no duplicate entries for the same CVE+package
pair.

In `@scripts/cve/locate.sh`:
- Line 20: Change the grep invocations that search module/package variables to
use fixed-string matching: replace uses of grep -q "$PACKAGE" "$GOMOD" (and the
other grep calls that use PACKAGE or package-derived patterns) with grep -F --
"$PACKAGE" "$GOMOD" 2>/dev/null (and similarly add -F -- for the grep calls at
the other occurrences mentioned) so dots in module paths are treated as
literals; ensure you update all grep calls referencing the PACKAGE variable (and
any package-derived patterns) in this script.

In `@scripts/cve/review.sh`:
- Around line 33-35: NEEDS_REVIEW_PKGS loop is passing the literal "stdlib" into
locate.sh which produces spurious errors; update the loop in review.sh that
iterates NEEDS_REVIEW_PKGS to special-case the token "stdlib" (from fix-all.sh)
so it does not call locate.sh for that entry—either skip it or append a
dedicated message containing the stdlib-specific context (e.g., Go version
transition) to LOCATE_OUTPUT; reference the variables/commands in the diff
(NEEDS_REVIEW_PKGS, PKG, LOCATE_OUTPUT, STATE_FILE, and locate.sh) when making
the change.
- Around line 58-63: The review phase currently invokes the Claude agent with
Bash execution effectively enabled via the flags in the claude invocation (the
OUTPUT assignment calling claude with --allowedTools "Bash" and
--dangerously-skip-permissions), and the review prompt invites mutation
commands; to fix this remove mutate-inviting commands from review-prompt.md (the
lines that suggest running fix-package.sh, fix-stdlib.sh, ignore.sh) and change
the claude invocation that sets OUTPUT to not permit Bash by default (remove
--allowedTools "Bash" and drop --dangerously-skip-permissions), and instead
require an explicit opt-in flag (e.g., --allow-agent-mutations) before enabling
Bash in the claude call; update any gating logic that reads that flag so review
remains read-only unless explicitly opted into mutations.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1793d672-bd0c-426d-aa5d-66b3cbb499ad

📥 Commits

Reviewing files that changed from the base of the PR and between 0ee167c and 43f1d40.

📒 Files selected for processing (17)
  • .agents/commit-templates.md
  • .agents/workflows/cve-fix.md
  • .github/workflows/testing.yml
  • Makefile
  • scripts/cve/detect.sh
  • scripts/cve/fix-all.sh
  • scripts/cve/fix-package.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/ignore.sh
  • scripts/cve/lib.sh
  • scripts/cve/locate.sh
  • scripts/cve/review-prompt.md
  • scripts/cve/review.sh
  • scripts/cve/scan.sh
  • scripts/cve/test-lib.sh
  • skills/cve-fix/SKILL.md
  • test/scripts/cve/test.sh

Comment thread Makefile Outdated
Comment thread scripts/cve/detect.sh
Comment on lines +137 to +153
cat > "$STATE_FILE" <<EOF
STATE_FILE="$STATE_FILE"
REPO="$REPO"
BRANCH="$BRANCH"
FIX_BRANCH="$FIX_BRANCH"
ORIGINAL_REF="$ORIGINAL_REF"
HAS_TOOLS_GOMOD=$HAS_TOOLS_GOMOD
GENERATED_FILE="$GENERATED_FILE"
DIFF_IGNORE_ARGS="$DIFF_IGNORE_ARGS"
NEEDS_BUILD_FOR_SCAN=$NEEDS_BUILD_FOR_SCAN
CONTAINER_CMD="$CONTAINER_CMD"
HAS_LOCAL_GRYPE=$HAS_LOCAL_GRYPE
SHIPYARD_IMAGE="$SHIPYARD_IMAGE"
SHIPYARD_GO_VERSION="$SHIPYARD_GO_VERSION"
FETCH_FAILED=$FETCH_FAILED
CVE_SCRIPTS="$SCRIPT_DIR"
EOF
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

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

Shell-escape values before writing the sourced state file.

This file is later sourced by scan.sh, fix-all.sh, review.sh, and others. Writing raw values inside double quotes means a repo path or branch containing ", backticks, or $(...) can break parsing or execute commands when the state file is loaded.

🛡️ Proposed hardening
 STATE_FILE=$(state_file_path "$REPO" "$BRANCH")
-cat > "$STATE_FILE" <<EOF
-STATE_FILE="$STATE_FILE"
-REPO="$REPO"
-BRANCH="$BRANCH"
-FIX_BRANCH="$FIX_BRANCH"
-ORIGINAL_REF="$ORIGINAL_REF"
-HAS_TOOLS_GOMOD=$HAS_TOOLS_GOMOD
-GENERATED_FILE="$GENERATED_FILE"
-DIFF_IGNORE_ARGS="$DIFF_IGNORE_ARGS"
-NEEDS_BUILD_FOR_SCAN=$NEEDS_BUILD_FOR_SCAN
-CONTAINER_CMD="$CONTAINER_CMD"
-HAS_LOCAL_GRYPE=$HAS_LOCAL_GRYPE
-SHIPYARD_IMAGE="$SHIPYARD_IMAGE"
-SHIPYARD_GO_VERSION="$SHIPYARD_GO_VERSION"
-FETCH_FAILED=$FETCH_FAILED
-CVE_SCRIPTS="$SCRIPT_DIR"
-EOF
+{
+  printf 'STATE_FILE=%q\n' "$STATE_FILE"
+  printf 'REPO=%q\n' "$REPO"
+  printf 'BRANCH=%q\n' "$BRANCH"
+  printf 'FIX_BRANCH=%q\n' "$FIX_BRANCH"
+  printf 'ORIGINAL_REF=%q\n' "$ORIGINAL_REF"
+  printf 'HAS_TOOLS_GOMOD=%q\n' "$HAS_TOOLS_GOMOD"
+  printf 'GENERATED_FILE=%q\n' "$GENERATED_FILE"
+  printf 'DIFF_IGNORE_ARGS=%q\n' "$DIFF_IGNORE_ARGS"
+  printf 'NEEDS_BUILD_FOR_SCAN=%q\n' "$NEEDS_BUILD_FOR_SCAN"
+  printf 'CONTAINER_CMD=%q\n' "$CONTAINER_CMD"
+  printf 'HAS_LOCAL_GRYPE=%q\n' "$HAS_LOCAL_GRYPE"
+  printf 'SHIPYARD_IMAGE=%q\n' "$SHIPYARD_IMAGE"
+  printf 'SHIPYARD_GO_VERSION=%q\n' "$SHIPYARD_GO_VERSION"
+  printf 'FETCH_FAILED=%q\n' "$FETCH_FAILED"
+  printf 'CVE_SCRIPTS=%q\n' "$SCRIPT_DIR"
+} > "$STATE_FILE"
📝 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
cat > "$STATE_FILE" <<EOF
STATE_FILE="$STATE_FILE"
REPO="$REPO"
BRANCH="$BRANCH"
FIX_BRANCH="$FIX_BRANCH"
ORIGINAL_REF="$ORIGINAL_REF"
HAS_TOOLS_GOMOD=$HAS_TOOLS_GOMOD
GENERATED_FILE="$GENERATED_FILE"
DIFF_IGNORE_ARGS="$DIFF_IGNORE_ARGS"
NEEDS_BUILD_FOR_SCAN=$NEEDS_BUILD_FOR_SCAN
CONTAINER_CMD="$CONTAINER_CMD"
HAS_LOCAL_GRYPE=$HAS_LOCAL_GRYPE
SHIPYARD_IMAGE="$SHIPYARD_IMAGE"
SHIPYARD_GO_VERSION="$SHIPYARD_GO_VERSION"
FETCH_FAILED=$FETCH_FAILED
CVE_SCRIPTS="$SCRIPT_DIR"
EOF
{
printf 'STATE_FILE=%q\n' "$STATE_FILE"
printf 'REPO=%q\n' "$REPO"
printf 'BRANCH=%q\n' "$BRANCH"
printf 'FIX_BRANCH=%q\n' "$FIX_BRANCH"
printf 'ORIGINAL_REF=%q\n' "$ORIGINAL_REF"
printf 'HAS_TOOLS_GOMOD=%q\n' "$HAS_TOOLS_GOMOD"
printf 'GENERATED_FILE=%q\n' "$GENERATED_FILE"
printf 'DIFF_IGNORE_ARGS=%q\n' "$DIFF_IGNORE_ARGS"
printf 'NEEDS_BUILD_FOR_SCAN=%q\n' "$NEEDS_BUILD_FOR_SCAN"
printf 'CONTAINER_CMD=%q\n' "$CONTAINER_CMD"
printf 'HAS_LOCAL_GRYPE=%q\n' "$HAS_LOCAL_GRYPE"
printf 'SHIPYARD_IMAGE=%q\n' "$SHIPYARD_IMAGE"
printf 'SHIPYARD_GO_VERSION=%q\n' "$SHIPYARD_GO_VERSION"
printf 'FETCH_FAILED=%q\n' "$FETCH_FAILED"
printf 'CVE_SCRIPTS=%q\n' "$SCRIPT_DIR"
} > "$STATE_FILE"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/detect.sh` around lines 137 - 153, The heredoc that writes the
sourced state file in scripts/cve/detect.sh currently injects raw variable
values (STATE_FILE, REPO, BRANCH, FIX_BRANCH, ORIGINAL_REF, HAS_TOOLS_GOMOD,
GENERATED_FILE, DIFF_IGNORE_ARGS, NEEDS_BUILD_FOR_SCAN, CONTAINER_CMD,
HAS_LOCAL_GRYPE, SHIPYARD_IMAGE, SHIPYARD_GO_VERSION, FETCH_FAILED, CVE_SCRIPTS)
unescaped, so values containing quotes or command substitution can break or be
executed when the file is sourced; change the writer to shell-escape each value
before emitting it (for example, generate each line using a safe escape routine
such as printf '%q' or by safely single-quoting and escaping internal single
quotes) and write the escaped results into "$STATE_FILE" instead of the raw
expansions in the heredoc so the resulting file can be safely sourced by
scan.sh, fix-all.sh, review.sh, etc.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. All values are controlled (paths from pwd, git branch names, hardcoded strings like docker/true/false). No user-supplied input reaches the state file.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, fair point — looking at the concrete values: pwd-derived paths, git ref names (which cannot contain " or $()), true/false literals, hardcoded image strings, and go version output. None of these realistically carry shell-metacharacter payloads, so the heredoc approach is safe in practice here. Acknowledged, moving on.

😔

Comment thread scripts/cve/fix-all.sh Outdated
Comment on lines +11 to +17
# Clean up on exit: revert uncommitted changes and remove state file
# shellcheck disable=SC2317,SC2329 # invoked via trap EXIT
cleanup() {
git checkout -- . 2>/dev/null || true
rm -f "${STATE_FILE:-}"
}
trap cleanup EXIT
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

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

Don't reset the caller's working tree on exit.

The EXIT trap always runs git checkout -- ., but there is no clean-tree precondition before the script creates or switches to a fix branch. Any tracked edits the caller already had in the repo can be discarded on both success and failure.

🛡️ Safer guardrail
+git diff --quiet && git diff --cached --quiet || {
+  echo "ERROR: Working tree must be clean before running fix-all.sh" >&2
+  exit 1
+}
+
 # --- Phase 1: Deterministic ---
 
 banner "Phase 1: Detect and Scan"

Also applies to: 24-27

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/fix-all.sh` around lines 11 - 17, The cleanup function currently
always runs git checkout -- . and can discard the caller's uncommitted edits;
change it to be conditional: before making any repo changes, record the repo's
initial dirty state (e.g., via git status --porcelain or git ls-files -m) and
set a flag (e.g., INITIAL_CLEAN) or write that list to STATE_FILE; then update
cleanup (and the trap) to only revert files that the script created/modified (or
only run git checkout if the repo was initially clean) rather than
unconditionally running git checkout -- .; ensure you still remove STATE_FILE in
cleanup. Reference: cleanup, trap EXIT, STATE_FILE.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed differently. Added a precondition check in detect.sh that refuses to run on a dirty working tree (git diff --quiet && git diff --cached --quiet), preventing the cleanup trap from ever discarding uncommitted work.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n "git diff" scripts/cve/detect.sh

Length of output: 89


@dfarrell07, confirmed — Line 111 of detect.sh has the dirty-tree guard:

if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null;

That's a clean approach: failing fast at entry is simpler and more robust than trying to track and conditionally revert only script-modified files. The concern is fully addressed.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

Comment thread scripts/cve/fix-all.sh
Comment thread scripts/cve/fix-all.sh Outdated
Comment on lines +145 to +152
echo ""
echo "Final scan..."
"$SCRIPT_DIR/scan.sh" "$STATE_FILE" 2>/dev/null || true

# --- Phase 2: Agent Review ---

banner "Phase 2: Agent Review"
"$SCRIPT_DIR/review.sh" "$STATE_FILE" "$FIX_SUMMARY" || true
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Final success/failure ignores the post-fix scan.

The script runs a final scan and the agent review, but the exit code still depends only on the earlier REVIEW_COUNT. If every fix script returns 0 yet Grype still reports matches, this path still exits 0, which does not match the documented contract for unresolved CVEs.

Also applies to: 196-199

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/fix-all.sh` around lines 145 - 152, The final post-fix scan and
agent review results are being ignored when deciding the script exit status;
ensure the exit code reflects unresolved CVEs or review failures by capturing
the exit/status of "$SCRIPT_DIR/scan.sh" "$STATE_FILE" (post-fix scan) and
"$SCRIPT_DIR/review.sh" "$STATE_FILE" "$FIX_SUMMARY", and combine them with the
existing REVIEW_COUNT logic so the script exits non-zero if the post-fix scan
reports matches or if review.sh returns non-zero; update handling around the
scan.sh call and the review.sh invocation (also mirror the same fix where
similar logic appears around lines 196-199) to aggregate their exit codes into
the final exit decision.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. By design, the exit code reflects the deterministic phase. The agent review may fix additional CVEs, but parsing its output would be fragile. Exit 2 means "human should check," which is correct when there were unresolved CVEs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, understood — that's a clear and sensible design boundary. Keeping the exit code tied to the deterministic phase avoids brittleness from parsing agent output, and exit 2 correctly signals "human should review" for anything the deterministic phase couldn't resolve. Thanks for the explanation.


✏️ Learnings added
Learnt from: dfarrell07
Repo: submariner-io/shipyard PR: 2383
File: scripts/cve/fix-all.sh:0-0
Timestamp: 2026-05-02T04:41:18.760Z
Learning: In `scripts/cve/fix-all.sh` in the submariner-io/shipyard repo, the script exit code is intentionally based only on the deterministic phase (REVIEW_COUNT from fix-stdlib.sh/fix-package.sh). The post-fix scan and agent review (review.sh) are non-fatal by design. Exit 0 = clean, exit 1 = scan error, exit 2 = unresolved CVEs needing human review. Parsing agent review output for exit codes was deliberately avoided as fragile.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment thread scripts/cve/lib.sh
Comment thread scripts/cve/lib.sh
Comment on lines +120 to +139
insert_grype_ignore() {
local file="$1" cve_id="$2" package="$3" reason="$4"
local entry
entry=" # $reason
- vulnerability: $cve_id
package:
name: $package"

if grep -qn '^exclude:' "$file" 2>/dev/null; then
local exclude_line
exclude_line=$(grep -n '^exclude:' "$file" | head -1 | cut -d: -f1)
{
head -n "$((exclude_line - 1))" "$file"
printf '%s\n' "$entry"
tail -n +"$exclude_line" "$file"
} > "${file}.tmp"
mv "${file}.tmp" "$file"
else
printf '\n%s\n' "$entry" >> "$file"
fi
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

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 ignore insertion idempotent.

Re-running the ignore flow for the same CVE will append a second YAML block instead of updating the existing one. That keeps .grype.yaml noisy and makes repeated review passes harder to reason about.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/lib.sh` around lines 120 - 139, The insert_grype_ignore function
currently always inserts a new YAML block, causing duplicates; change it to be
idempotent by first searching the target file for an existing ignore block that
matches both the cve_id and package (e.g., matching the lines "vulnerability:
$cve_id" and "name: $package") and, if found, replace that existing block with
the new entry instead of appending; otherwise fall back to the current insertion
logic. Update the logic inside insert_grype_ignore to locate the start/end of
the matching block (or use a multiline grep/awk/sed pattern), perform an
in-place replacement of that block with the constructed $entry when present, and
only insert a new block when no match exists, ensuring no duplicate entries for
the same CVE+package pair.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. insert_grype_ignore is called once per CVE by ignore.sh. The orchestrator tracks what's been fixed/ignored, so duplicate calls don't happen in practice.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, understood — since fix-all.sh tracks per-CVE outcomes and drives ignore.sh exactly once per CVE, the orchestration layer already provides the idempotency guarantee. I'll drop the concern.


✏️ Learnings added
Learnt from: dfarrell07
Repo: submariner-io/shipyard PR: 2383
File: scripts/cve/lib.sh:120-139
Timestamp: 2026-05-02T04:41:55.538Z
Learning: In `scripts/cve/lib.sh` (submariner-io/shipyard), `insert_grype_ignore` is intentionally non-idempotent at the function level. Duplicate-call prevention is enforced by the orchestrator (`scripts/cve/fix-all.sh`), which tracks each CVE's fix/ignore outcome and invokes `ignore.sh` (and therefore `insert_grype_ignore`) exactly once per CVE. Do not flag the function itself for lacking idempotency checks.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Comment thread scripts/cve/locate.sh
# Find in all go.mod files
FOUND_IN=""
while IFS= read -r GOMOD; do
if grep -q "$PACKAGE" "$GOMOD" 2>/dev/null; then
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

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 fixed-string matching for package paths.

These grep calls treat . in module paths as regex wildcards, so the locator can report unrelated go.mod hits or graph edges. Switching package-derived matches to grep -F -- keeps the review evidence deterministic.

Also applies to: 35-35, 50-53

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/locate.sh` at line 20, Change the grep invocations that search
module/package variables to use fixed-string matching: replace uses of grep -q
"$PACKAGE" "$GOMOD" (and the other grep calls that use PACKAGE or
package-derived patterns) with grep -F -- "$PACKAGE" "$GOMOD" 2>/dev/null (and
similarly add -F -- for the grep calls at the other occurrences mentioned) so
dots in module paths are treated as literals; ensure you update all grep calls
referencing the PACKAGE variable (and any package-derived patterns) in this
script.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. Go module paths (github.com/docker/docker, k8s.io/client-go) don't contain regex metacharacters. grep -q is safe and readable.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, understood — Go module paths follow a well-defined format where the . in domain segments (e.g. github.com, k8s.io) won't produce harmful regex expansions in practice. I'll accept the decision.

Comment thread scripts/cve/review.sh
Comment on lines +33 to +35
NEEDS_REVIEW_PKGS=$(echo "$FIX_SUMMARY" | grep "^NEEDS_REVIEW:" | sed 's/NEEDS_REVIEW: \([^ ]*\).*/\1/' || true)
for PKG in $NEEDS_REVIEW_PKGS; do
LOCATE_OUTPUT+="$(bash "$SCRIPT_DIR/locate.sh" "$STATE_FILE" "$PKG" 2>&1 || true)"
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

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 stdlib review items separately.

fix-all.sh records stdlib failures as NEEDS_REVIEW: stdlib ..., but locate.sh only knows how to search module/package references. Passing stdlib here just appends a guaranteed error to the prompt and drops the useful context for this case, like the Go version transition.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/review.sh` around lines 33 - 35, NEEDS_REVIEW_PKGS loop is
passing the literal "stdlib" into locate.sh which produces spurious errors;
update the loop in review.sh that iterates NEEDS_REVIEW_PKGS to special-case the
token "stdlib" (from fix-all.sh) so it does not call locate.sh for that
entry—either skip it or append a dedicated message containing the
stdlib-specific context (e.g., Go version transition) to LOCATE_OUTPUT;
reference the variables/commands in the diff (NEEDS_REVIEW_PKGS, PKG,
LOCATE_OUTPUT, STATE_FILE, and locate.sh) when making the change.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. The review agent receives all items in FIX_SUMMARY and handles them uniformly. It understands both stdlib and package types from context.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, understood — since the Claude subagent consumes the full FIX_SUMMARY and can reason about stdlib vs. package entries from that context, the spurious locate.sh error output is handled gracefully. Thanks for the clarification!

😔 🐇

Comment thread scripts/cve/review.sh
Comment on lines +58 to +63
OUTPUT=$(claude -p "$PROMPT" \
--print \
--model sonnet \
--allowedTools "Bash" \
--dangerously-skip-permissions \
2>&1) || true
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 1, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

fd -t f scripts/cve | head -20

Repository: submariner-io/shipyard

Length of output: 416


🏁 Script executed:

cat -n scripts/cve/review.sh | head -100

Repository: submariner-io/shipyard

Length of output: 2673


🏁 Script executed:

cat -n scripts/cve/fix-all.sh | head -150

Repository: submariner-io/shipyard

Length of output: 5688


🏁 Script executed:

tail -n +150 scripts/cve/fix-all.sh | head -50

Repository: submariner-io/shipyard

Length of output: 1664


🏁 Script executed:

cat scripts/cve/locate.sh | head -80

Repository: submariner-io/shipyard

Length of output: 1622


🏁 Script executed:

ls -la scripts/cve/

Repository: submariner-io/shipyard

Length of output: 841


🌐 Web query:

claude CLI --allowedTools Bash --dangerously-skip-permissions security

💡 Result:

The command “claude CLI --allowedTools Bash --dangerously-skip-permissions” effectively defeats Claude Code’s tool/permission gating and is therefore not meaningfully “secure.” In practice, when bypass mode is enabled, Claude Code can execute Bash even if you attempted to restrict it via --allowedTools, and multiple reports indicate tool allowlists don’t reliably constrain behavior under bypass. What the flags do (security-relevant): 1) --dangerously-skip-permissions enables bypassPermissions / bypassPermissions mode, which skips all permission prompts. Anthropic’s permissions docs state bypassPermissions skips permission prompts and should only be used in isolated environments like containers or VMs; removals targeting / or ~ still prompt as a circuit breaker. 2) --allowedTools is supposed to “allow specific tools without prompting.” However, community-reported bugs show that when bypassPermissions is active, --allowedTools does not restrict tool availability as intended (Bash can run even when not allowlisted). Another report explicitly calls out that bypassPermissions can also bypass sandbox protections. Concrete implications for your exact query: - Allowlisting only “Bash” while also enabling --dangerously-skip-permissions does not provide a safe, non-interactive “Bash-only but constrained” posture. With bypassPermissions, there are reports that tool restrictions via allowlists are ignored, and that sandbox/extra isolation may be reduced. - Multiple bypass-mode issues have been filed, including: a) --allowedTools seemingly ignored with permission-mode bypassPermissions. b) auto-approval of Bash commands even without Bash being in an allow list. c) a general bug report claiming allowedTools has no effect when permission bypass flags are active. Recommended secure usage patterns: - Do not use --dangerously-skip-permissions on a host machine. Use it only inside strong isolation (e.g., a container/VM) as Anthropic explicitly recommends. - Prefer permission modes that do not skip prompts (default/acceptEdits/plan/dontAsk) and use allow/deny rules for policy. - If you need non-interactive automation, use a locked-down allowlist policy (permissions.allow / permissions.deny) plus isolation, and consider additional external enforcement layers rather than relying solely on Claude Code’s bypass behavior (community mitigations describe external approval gates). Practical takeaway: Treat --dangerously-skip-permissions as a “trust the entire environment” switch, not a “trust but restrict to Bash” switch. If you need security, rely on isolation + deny-by-default policies, not bypassPermissions + allowlists.

Citations:


🏁 Script executed:

# Check if review.sh output is used for any further mutations
grep -n "review.sh\|OUTPUT=" scripts/cve/fix-all.sh

Repository: submariner-io/shipyard

Length of output: 359


🏁 Script executed:

# Verify that review-prompt.md doesn't instruct the agent to perform mutations
cat scripts/cve/review-prompt.md

Repository: submariner-io/shipyard

Length of output: 1467


Gate Bash execution behind explicit opt-in; the review phase should be read-only.

The prompt in review-prompt.md (lines 44–50) explicitly instructs the Claude agent to run mutation commands (fix-package.sh, fix-stdlib.sh, ignore.sh), yet --dangerously-skip-permissions with --allowedTools does not safely restrict tool use. Anthropic's documentation and community reports confirm that the bypass flag negates tool allowlists, and Bash can execute even when not explicitly allowlisted. This means the agent can make unvetted changes to the working tree during Phase 2 (review), which happens after Phase 1 deterministic fixes and after the cleanup trap is no longer active to revert changes.

Since the review phase pre-fetches all evidence upfront, the agent does not need write access to produce review output. Remove mutation command invitations from the prompt and disable Bash access by default, or require an explicit --allow-agent-mutations flag if review-phase mutations are genuinely needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/review.sh` around lines 58 - 63, The review phase currently
invokes the Claude agent with Bash execution effectively enabled via the flags
in the claude invocation (the OUTPUT assignment calling claude with
--allowedTools "Bash" and --dangerously-skip-permissions), and the review prompt
invites mutation commands; to fix this remove mutate-inviting commands from
review-prompt.md (the lines that suggest running fix-package.sh, fix-stdlib.sh,
ignore.sh) and change the claude invocation that sets OUTPUT to not permit Bash
by default (remove --allowedTools "Bash" and drop
--dangerously-skip-permissions), and instead require an explicit opt-in flag
(e.g., --allow-agent-mutations) before enabling Bash in the claude call; update
any gating logic that reads that flag so review remains read-only unless
explicitly opted into mutations.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. The review agent has Bash access and can run git log/diff if needed. Pre-fetching commit diffs would add more data to an already information-dense prompt.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, understood — the lazy-fetch pattern makes sense here. Letting the agent pull git diffs on demand avoids bloating the context with evidence that may not be relevant to the specific CVEs under review.

ʕ •ᴥ•ʔ


✏️ Learnings added
Learnt from: dfarrell07
Repo: submariner-io/shipyard PR: 2383
File: scripts/cve/review.sh:59-64
Timestamp: 2026-05-02T04:41:58.453Z
Learning: In `scripts/cve/review.sh` (submariner-io/shipyard), the Claude subagent is intentionally invoked with `--allowedTools "Bash"` and `--dangerously-skip-permissions`. Bash access is kept so the agent can run `git log`/`git diff` on demand during the review phase; evidence is lazily fetched rather than pre-fetched to avoid bloating the prompt context.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@dfarrell07 dfarrell07 force-pushed the cve-fix-skill-redesign branch from 43f1d40 to f77172c Compare May 2, 2026 03:32
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
skills/cve-fix/SKILL.md (1)

50-51: 💤 Low value

Cleanup command kills all matching processes indiscriminately.

The pkill -f fix-all and docker kill $(docker ps -q) commands are aggressive — they will kill all running containers, not just orphaned CVE-related ones. Consider documenting this risk or providing a more targeted cleanup approach.

📝 Suggested improvement
-`pkill -f fix-all; docker kill $(docker ps -q)` before reporting.
+`pkill -f fix-all; docker ps --filter "ancestor=quay.io/submariner/shipyard-dapper-base" -q | xargs -r docker kill` before reporting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@skills/cve-fix/SKILL.md` around lines 50 - 51, The documented cleanup
commands "pkill -f fix-all" and "docker kill $(docker ps -q)" are overly broad;
update SKILL.md to either warn about the risk of killing unrelated
processes/containers or replace with targeted alternatives: recommend using a
specific pkill pattern or storing and killing the exact PIDs for the fix-all
process (reference "pkill -f fix-all"), and for containers suggest filtering by
name, label or image (e.g., use docker ps --filter with a project/name/label and
docker rm -f on that filtered list instead of "docker kill $(docker ps -q)");
include a short example of the safer filter-based approach and a one-line
warning if maintainers keep the global commands.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@skills/cve-fix/SKILL.md`:
- Around line 50-51: The documented cleanup commands "pkill -f fix-all" and
"docker kill $(docker ps -q)" are overly broad; update SKILL.md to either warn
about the risk of killing unrelated processes/containers or replace with
targeted alternatives: recommend using a specific pkill pattern or storing and
killing the exact PIDs for the fix-all process (reference "pkill -f fix-all"),
and for containers suggest filtering by name, label or image (e.g., use docker
ps --filter with a project/name/label and docker rm -f on that filtered list
instead of "docker kill $(docker ps -q)"); include a short example of the safer
filter-based approach and a one-line warning if maintainers keep the global
commands.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 51a4d4d8-ad0f-43fc-b788-c06b1ec26589

📥 Commits

Reviewing files that changed from the base of the PR and between 43f1d40 and f77172c.

📒 Files selected for processing (17)
  • .agents/commit-templates.md
  • .agents/workflows/cve-fix.md
  • .github/workflows/testing.yml
  • Makefile
  • scripts/cve/detect.sh
  • scripts/cve/fix-all.sh
  • scripts/cve/fix-package.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/ignore.sh
  • scripts/cve/lib.sh
  • scripts/cve/locate.sh
  • scripts/cve/review-prompt.md
  • scripts/cve/review.sh
  • scripts/cve/scan.sh
  • scripts/cve/test-lib.sh
  • skills/cve-fix/SKILL.md
  • test/scripts/cve/test.sh
✅ Files skipped from review due to trivial changes (5)
  • .agents/commit-templates.md
  • .agents/workflows/cve-fix.md
  • .github/workflows/testing.yml
  • scripts/cve/locate.sh
  • test/scripts/cve/test.sh
🚧 Files skipped from review as they are similar to previous changes (9)
  • Makefile
  • scripts/cve/review-prompt.md
  • scripts/cve/lib.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/scan.sh
  • scripts/cve/fix-all.sh
  • scripts/cve/ignore.sh
  • scripts/cve/review.sh
  • scripts/cve/test-lib.sh

@dfarrell07 dfarrell07 force-pushed the cve-fix-skill-redesign branch from f77172c to 21978d4 Compare May 2, 2026 04:38
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
scripts/cve/fix-all.sh (1)

87-92: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

jq semver sorting now fails on normal Go module versions.

fixedIn values are typically v-prefixed. map(tonumber) throws on v1, so this whole jq program falls into the || echo "" path, CVE_LINES becomes empty, and the deterministic fixer quietly skips packages that do have available fixes.

Small fix
-    fixedIn: (map(.fixedIn) | sort_by(split(".") | map(tonumber)) | last),
+    fixedIn: (map(.fixedIn) | sort_by(gsub("^v"; "") | split(".") | map(tonumber? // 0)) | last),
#!/bin/bash
set -euo pipefail

printf '%s\n' '[{"fixedIn":"v1.10.0"},{"fixedIn":"v1.9.9"}]' \
  | jq -r 'map(.fixedIn) | sort_by(split(".") | map(tonumber)) | last'

Expected result: the current expression errors on the v prefix. After the fix above, it should return v1.10.0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/fix-all.sh` around lines 87 - 92, The jq semver sort fails
because fixedIn values are v-prefixed (e.g., "v1.10.0"); update the sort
expression so it strips a leading "v" before splitting and converting to
numbers: in the pipeline that builds fixedIn (the map({ pkg: .[0].pkg, type:
.[0].type, fixedIn: (map(.fixedIn) | sort_by(... ) | last), cves: map(.cve) })
block) replace the sort_by argument to first remove a leading "v" (e.g. using
sub("^v";"") on each fixedIn), then split on "." and map(tonumber) so versions
like "v1.10.0" sort correctly and fixedIn returns the expected highest version.
🧹 Nitpick comments (1)
scripts/cve/locate.sh (1)

17-23: ⚡ Quick win

Use a Bash array instead of a space-joined string to collect go.mod paths.

FOUND_IN is built with space separators at line 21 and then iterated with unquoted $FOUND_IN at line 47. Any go.mod path containing a space would be split incorrectly. A Bash array handles arbitrary paths safely.

♻️ Proposed refactor
-FOUND_IN=""
+FOUND_IN=()
 while IFS= read -r GOMOD; do
   if grep -q "$PACKAGE" "$GOMOD" 2>/dev/null; then
-    FOUND_IN="${FOUND_IN:+$FOUND_IN }$GOMOD"
+    FOUND_IN+=("$GOMOD")
   fi
 done < <(find_gomods)

 if [[ -z "$FOUND_IN" ]]; then
+if [[ ${`#FOUND_IN`[@]} -eq 0 ]]; then
   echo "ERROR: $PACKAGE not found in any go.mod" >&2
   exit 1
 fi
-echo "Found in: $FOUND_IN"
+echo "Found in: ${FOUND_IN[*]}"

Then for the dependency graph loop:

-for GOMOD in $FOUND_IN; do
+for GOMOD in "${FOUND_IN[@]}"; do

Also applies to: 47-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/locate.sh` around lines 17 - 23, The script currently builds
FOUND_IN as a space-joined string which breaks on paths containing spaces;
change FOUND_IN to a Bash array (e.g., initialize FOUND_IN=() and append each
match with FOUND_IN+=("$GOMOD") inside the find_gomods read loop) and then
iterate over the results with for GOMOD in "${FOUND_IN[@]}" (also update the
later dependency graph loop that currently iterates over unquoted $FOUND_IN to
use the same "${FOUND_IN[@]}" form); ensure every use of these elements is
quoted to preserve paths with spaces.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/cve/fix-all.sh`:
- Around line 149-152: The script currently ignores `make unit` failures and can
still show a successful PR/branch result when `REVIEW_COUNT` is zero; change the
Verify block so the exit status of `make unit` is captured and propagated: run
`make unit`, save its exit code, and if non-zero either increment `REVIEW_COUNT`
(so the script treats it as needing attention) or set a `VERIFICATION_FAILED`
flag and ensure the final success path checks that flag and exits non-zero;
update the logic that prints the final branch/PR instructions to consider this
new flag or the adjusted `REVIEW_COUNT` so test failures are reflected in the
final status.

In `@scripts/cve/fix-package.sh`:
- Around line 40-41: The script uses GNU-only flags (grep -oP and xargs -r)
which fail on BSD/macOS; update the K8S_BEFORE assignment and the other
occurrences to portable POSIX commands: replace grep -oP 'v0\.\K[0-9]+' with a
pipeline like grep -Eo 'v0\.[0-9]+' | sed 's/^v0\.//' (so in the K8S_BEFORE
assignment that calls find_gomods you still grep for 'k8s.io/client-go' but
extract the digit with the grep|sed combo), and replace any xargs -r usage by
guarding the xargs call with an if test that the input is non-empty (e.g.
capture to a variable and run xargs only if [ -n "$VAR" ]), updating the
occurrences referenced in the diff (K8S_BEFORE and the commands at lines flagged
around 75 and 104) so the script runs on BSD/macOS as well.

In `@scripts/cve/locate.sh`:
- Around line 32-35: The current search uses PKG_BASENAME which yields false
positives; change the grep to search the full module path stored in PACKAGE (not
PKG_BASENAME). Update the while-loop/grep invocation that computes HITS (and any
related variables like GOMOD) to use "$PACKAGE" (properly quoted/escaped) as the
search term (e.g., grep "replace.*${PACKAGE}" "$GOMOD") so replace directives
match the full module path rather than just the basename.

---

Duplicate comments:
In `@scripts/cve/fix-all.sh`:
- Around line 87-92: The jq semver sort fails because fixedIn values are
v-prefixed (e.g., "v1.10.0"); update the sort expression so it strips a leading
"v" before splitting and converting to numbers: in the pipeline that builds
fixedIn (the map({ pkg: .[0].pkg, type: .[0].type, fixedIn: (map(.fixedIn) |
sort_by(... ) | last), cves: map(.cve) }) block) replace the sort_by argument to
first remove a leading "v" (e.g. using sub("^v";"") on each fixedIn), then split
on "." and map(tonumber) so versions like "v1.10.0" sort correctly and fixedIn
returns the expected highest version.

---

Nitpick comments:
In `@scripts/cve/locate.sh`:
- Around line 17-23: The script currently builds FOUND_IN as a space-joined
string which breaks on paths containing spaces; change FOUND_IN to a Bash array
(e.g., initialize FOUND_IN=() and append each match with FOUND_IN+=("$GOMOD")
inside the find_gomods read loop) and then iterate over the results with for
GOMOD in "${FOUND_IN[@]}" (also update the later dependency graph loop that
currently iterates over unquoted $FOUND_IN to use the same "${FOUND_IN[@]}"
form); ensure every use of these elements is quoted to preserve paths with
spaces.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e36ace12-31f7-4fd4-a08b-93c15ee66b23

📥 Commits

Reviewing files that changed from the base of the PR and between f77172c and 21978d4.

📒 Files selected for processing (17)
  • .agents/commit-templates.md
  • .agents/workflows/cve-fix.md
  • .github/workflows/testing.yml
  • Makefile
  • scripts/cve/detect.sh
  • scripts/cve/fix-all.sh
  • scripts/cve/fix-package.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/ignore.sh
  • scripts/cve/lib.sh
  • scripts/cve/locate.sh
  • scripts/cve/review-prompt.md
  • scripts/cve/review.sh
  • scripts/cve/scan.sh
  • scripts/cve/test-lib.sh
  • skills/cve-fix/SKILL.md
  • test/scripts/cve/test.sh
✅ Files skipped from review due to trivial changes (8)
  • scripts/cve/review-prompt.md
  • test/scripts/cve/test.sh
  • .agents/workflows/cve-fix.md
  • .agents/commit-templates.md
  • scripts/cve/test-lib.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/detect.sh
  • scripts/cve/lib.sh
🚧 Files skipped from review as they are similar to previous changes (5)
  • .github/workflows/testing.yml
  • scripts/cve/scan.sh
  • scripts/cve/ignore.sh
  • skills/cve-fix/SKILL.md
  • scripts/cve/review.sh

Comment thread scripts/cve/fix-all.sh Outdated
Comment on lines +40 to +41
# shellcheck disable=SC2046 # word splitting is intentional (multiple file args)
K8S_BEFORE=$(grep -h 'k8s.io/client-go' $(find_gomods) 2>/dev/null | grep -oP 'v0\.\K[0-9]+' | sort -un | tr '\n' ' ')
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot May 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' 'require k8s.io/client-go v0.31.1' | grep -oP 'v0\.\K[0-9]+'
printf '%s\n' foo | xargs -r printf '%s\n'

Repository: submariner-io/shipyard

Length of output: 130


🏁 Script executed:

cat -n scripts/cve/fix-package.sh | head -120

Repository: submariner-io/shipyard

Length of output: 5342


🏁 Script executed:

#!/bin/bash
# Test 1: sed alternative for grep -oP replacement
printf '%s\n' 'require k8s.io/client-go v0.31.1' | sed -nE 's/.*v0\.([0-9]+).*/\1/p'
echo "---"
# Test 2: mapfile alternative for xargs -r
changed_go_files=()
printf '%s\n' 'go.mod' 'go.sum' | mapfile -t changed_go_files
echo "mapfile exit code: $?"
echo "Array size: ${`#changed_go_files`[@]}"

Repository: submariner-io/shipyard

Length of output: 108


GNU-only grep and xargs flags break standalone script on BSD/macOS.

Lines 41, 75 use grep -oP (Perl regex mode) and line 104 uses xargs -r (no-run-if-empty), both GNU-only extensions. On BSD/macOS systems, this causes the script to fail before completing K8s checks or staging updated files, breaking the new non-Dapper cve-fix entrypoint.

Replace with portable POSIX alternatives:

Portable shell-only fixes
-# shellcheck disable=SC2046 # word splitting is intentional (multiple file args)
-K8S_BEFORE=$(grep -h 'k8s.io/client-go' $(find_gomods) 2>/dev/null | grep -oP 'v0\.\K[0-9]+' | sort -un | tr '\n' ' ')
+# shellcheck disable=SC2046 # word splitting is intentional (multiple file args)
+K8S_BEFORE=$(grep -h 'k8s.io/client-go' $(find_gomods) 2>/dev/null | sed -nE 's/.*v0\.([0-9]+).*/\1/p' | sort -un | tr '\n' ' ')-# shellcheck disable=SC2046 # word splitting is intentional (multiple file args)
-K8S_AFTER=$(grep -h 'k8s.io/client-go' $(find_gomods) 2>/dev/null | grep -oP 'v0\.\K[0-9]+' | sort -un | tr '\n' ' ')
+# shellcheck disable=SC2046 # word splitting is intentional (multiple file args)
+K8S_AFTER=$(grep -h 'k8s.io/client-go' $(find_gomods) 2>/dev/null | sed -nE 's/.*v0\.([0-9]+).*/\1/p' | sort -un | tr '\n' ' ')-git diff --name-only | grep -E 'go\.(mod|sum)$' | xargs -r git add || true
+mapfile -t changed_go_files < <(git diff --name-only | grep -E 'go\.(mod|sum)$' || true)
+if ((${`#changed_go_files`[@]})); then
+  git add "${changed_go_files[@]}"
+fi

Also applies to: lines 75, 104

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/cve/fix-package.sh` around lines 40 - 41, The script uses GNU-only
flags (grep -oP and xargs -r) which fail on BSD/macOS; update the K8S_BEFORE
assignment and the other occurrences to portable POSIX commands: replace grep
-oP 'v0\.\K[0-9]+' with a pipeline like grep -Eo 'v0\.[0-9]+' | sed 's/^v0\.//'
(so in the K8S_BEFORE assignment that calls find_gomods you still grep for
'k8s.io/client-go' but extract the digit with the grep|sed combo), and replace
any xargs -r usage by guarding the xargs call with an if test that the input is
non-empty (e.g. capture to a variable and run xargs only if [ -n "$VAR" ]),
updating the occurrences referenced in the diff (K8S_BEFORE and the commands at
lines flagged around 75 and 104) so the script runs on BSD/macOS as well.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Won't fix. Our CI runs on Linux with GNU grep. The -oP flag is standard there. macOS portability isn't a requirement for this project.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@dfarrell07, understood — since the project targets Linux CI with GNU grep, flagging grep -oP and xargs -r as portability issues isn't applicable here. I'll keep that in mind for future reviews.


✏️ Learnings added
Learnt from: dfarrell07
Repo: submariner-io/shipyard PR: 2383
File: scripts/cve/fix-package.sh:40-41
Timestamp: 2026-05-02T14:58:58.278Z
Learning: In submariner-io/shipyard CVE fix scripts (scripts/cve/), GNU-only grep flags such as `grep -oP` (Perl regex) and `xargs -r` (no-run-if-empty) are intentional and acceptable. The project's CI runs exclusively on Linux with GNU grep, and macOS/BSD portability is not a requirement. Do not flag these as portability issues in future reviews.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: dfarrell07
Repo: submariner-io/shipyard PR: 2383
File: scripts/cve/fix-stdlib.sh:0-0
Timestamp: 2026-05-02T04:41:52.237Z
Learning: In Submariner/shipyard-style CVE fix scripts, don’t treat untracked `go.sum` files as a concern: these repos already include a `go.sum` in every Go module directory, and `go mod tidy` only updates existing `go.sum` files (it won’t create new ones). Therefore, for staging changes, it’s sufficient to use `git diff --name-only` (or equivalent) to stage modified `go.mod`/`go.sum` files, and avoid flagging any absence/presence of untracked `go.sum` as a false positive.

Comment thread scripts/cve/locate.sh Outdated
@dfarrell07 dfarrell07 force-pushed the cve-fix-skill-redesign branch from 21978d4 to 0e1ad56 Compare May 2, 2026 15:01
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/cve/fix-package.sh`:
- Around line 63-67: The BREAKING string is being overwritten inside the loop;
change the assignment in the if-block that sets BREAKING for the matching module
(using PAIR, GOMOD, GO_WAS, GO_AFTER) to append the new entry instead of
replacing it — use the existing accumulation idiom like ${BREAKING:+$BREAKING; }
so each match adds "$GOMOD: Go $GO_WAS -> $GO_AFTER" to BREAKING rather than
overwriting previous entries.
- Line 21: The ERR trap only runs "git checkout -- ." which leaves the
index/staged files intact after the script runs (so files added by the later
"git add" remain staged); update the trap command (the line that currently reads
trap 'git checkout -- . 2>/dev/null || true' ERR) to also reset the index by
running a git reset for the working tree before checkout — for example: run "git
reset --quiet -- . 2>/dev/null || true" (or "git reset HEAD -- . 2>/dev/null ||
true") followed by "git checkout -- . 2>/dev/null || true" so failures after the
script's git add/commit steps (see the script's git add and git commit usage)
will unstage and revert files like go.mod/go.sum.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c037ab09-2f3c-4de2-98fc-24e595bb24a2

📥 Commits

Reviewing files that changed from the base of the PR and between 21978d4 and 0e1ad56.

📒 Files selected for processing (17)
  • .agents/commit-templates.md
  • .agents/workflows/cve-fix.md
  • .github/workflows/testing.yml
  • Makefile
  • scripts/cve/detect.sh
  • scripts/cve/fix-all.sh
  • scripts/cve/fix-package.sh
  • scripts/cve/fix-stdlib.sh
  • scripts/cve/ignore.sh
  • scripts/cve/lib.sh
  • scripts/cve/locate.sh
  • scripts/cve/review-prompt.md
  • scripts/cve/review.sh
  • scripts/cve/scan.sh
  • scripts/cve/test-lib.sh
  • skills/cve-fix/SKILL.md
  • test/scripts/cve/test.sh
✅ Files skipped from review due to trivial changes (6)
  • test/scripts/cve/test.sh
  • scripts/cve/scan.sh
  • .agents/workflows/cve-fix.md
  • .agents/commit-templates.md
  • scripts/cve/detect.sh
  • scripts/cve/review.sh
🚧 Files skipped from review as they are similar to previous changes (9)
  • .github/workflows/testing.yml
  • scripts/cve/locate.sh
  • scripts/cve/test-lib.sh
  • scripts/cve/ignore.sh
  • scripts/cve/review-prompt.md
  • scripts/cve/fix-all.sh
  • scripts/cve/fix-stdlib.sh
  • skills/cve-fix/SKILL.md
  • scripts/cve/lib.sh

Comment thread scripts/cve/fix-package.sh Outdated
Comment thread scripts/cve/fix-package.sh
@dfarrell07 dfarrell07 force-pushed the cve-fix-skill-redesign branch from 0e1ad56 to 5295949 Compare May 2, 2026 15:12
Copy link
Copy Markdown
Member

@skitt skitt left a comment

Choose a reason for hiding this comment

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

I’ve started reviewing this but it’s going to take me a while, so I’ll leave comments as I go and let you know once it’s all done.

Comment thread scripts/cve/fix-all.sh Outdated
Comment on lines +42 to +45
SCAN_LOG=$(mktemp)
"$SCRIPT_DIR/scan.sh" "$STATE_FILE" --fresh --json > "$SCAN_LOG" || true
SCAN_JSON=$(cat "$SCAN_LOG")
rm -f "$SCAN_LOG"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
SCAN_LOG=$(mktemp)
"$SCRIPT_DIR/scan.sh" "$STATE_FILE" --fresh --json > "$SCAN_LOG" || true
SCAN_JSON=$(cat "$SCAN_LOG")
rm -f "$SCAN_LOG"
SCAN_JSON=$("$SCRIPT_DIR/scan.sh" "$STATE_FILE" --fresh --json || true)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Done, thanks.

Comment thread scripts/cve/fix-all.sh Outdated
Comment on lines +47 to +52
MATCH_COUNT=$(printf '%s\n' "$SCAN_JSON" | jq '.matches | length' 2>/dev/null) || MATCH_COUNT=""
if [[ -z "$MATCH_COUNT" ]]; then
echo "ERROR: Scan failed or produced invalid output." >&2
echo "Check scanner availability (grype or docker/podman)." >&2
exit 1
fi
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
MATCH_COUNT=$(printf '%s\n' "$SCAN_JSON" | jq '.matches | length' 2>/dev/null) || MATCH_COUNT=""
if [[ -z "$MATCH_COUNT" ]]; then
echo "ERROR: Scan failed or produced invalid output." >&2
echo "Check scanner availability (grype or docker/podman)." >&2
exit 1
fi
if ! MATCH_COUNT=$(printf '%s\n' "$SCAN_JSON" | jq '.matches | length' 2>/dev/null); then
echo "ERROR: Scan failed or produced invalid output." >&2
echo "Check scanner availability (grype or docker/podman)." >&2
exit 1
fi

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Adopted the if ! pattern, thanks. Added || [[ -z "$MATCH_COUNT" ]] because jq exits 0 on empty input with no output, so if ! alone misses the case where scan.sh produces nothing (e.g., no scanner available).

dfarrell07 added 2 commits May 4, 2026 12:23
Extract all inline bash from skills/cve-fix/SKILL.md into
shellcheck-linted scripts. The SKILL.md becomes a thin wrapper that
delegates to fix-all.sh.

The deterministic orchestrator (fix-all.sh) handles the full flow:
detect config, create fix branch, scan with grype, fix each CVE,
verify, commit, run tests. After the deterministic phase, it invokes
a Claude subagent (review.sh) to review all outcomes and handle edge
cases like breaking changes or persistent CVEs.

Add make cve-fix target for standalone use outside the skill.

See SEP-0032 for design details.

Signed-off-by: Daniel Farrell <dfarrell@redhat.com>
Capture scan.sh output directly instead of writing to a temp
file. Use if ! to check jq exit code, with an empty-output
guard since jq exits 0 on empty input.

Signed-off-by: Daniel Farrell <dfarrell@redhat.com>
@dfarrell07 dfarrell07 force-pushed the cve-fix-skill-redesign branch from 5295949 to ccc0ba9 Compare May 4, 2026 16:24
@dfarrell07
Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@dfarrell07
Copy link
Copy Markdown
Member Author

@coderabbitai What of your feedback is unaddressed? Why haven't you approved?

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get all review comments on the PR
gh pr view 2383 --repo submariner-io/shipyard --json reviews,reviewDecision
echo "---COMMENTS---"
gh api repos/submariner-io/shipyard/pulls/2383/comments --paginate | jq '.[] | select(.user.login == "coderabbitai[bot]") | {id: .id, path: .path, body: .body, line: .line, position: .position}'
echo "---REVIEW THREADS---"
gh api repos/submariner-io/shipyard/pulls/2383/reviews --paginate | jq '.[] | select(.user.login == "coderabbitai[bot]") | {id: .id, state: .state, submitted_at: .submitted_at, body: .body}'

Length of output: 141548


@dfarrell07 — here's a full accounting of every comment from my reviews:


✅ Confirmed addressed

File Issue
Makefile Quote forwarded REPO/BRANCH args
scripts/cve/detect.sh Dirty-tree guard before running (implemented in detect.sh line 111)
scripts/cve/fix-all.sh Semver-aware fixedIn sort (gsub("^v";""))
scripts/cve/fix-all.sh make unit failures now increment REVIEW_COUNT
scripts/cve/fix-package.sh K8S_BEFORE/K8S_AFTER scan all go.mod files
scripts/cve/fix-package.sh Pipeline under pipefail (`
scripts/cve/fix-package.sh ERR trap now resets index (git reset HEAD) before git checkout
scripts/cve/fix-package.sh BREAKING accumulates with ${BREAKING:+$BREAKING; }
scripts/cve/lib.sh --fresh pulls the scan image too
scripts/cve/locate.sh Replace directive search uses full $PACKAGE, not basename

🤝 Withdrawn (I accepted your explanation / added learning)

File Issue Reason withdrawn
scripts/cve/detect.sh Shell-escape state file heredoc Values are paths/refs/literals — no real metacharacter risk
scripts/cve/fix-all.sh Post-fix scan exit code Intentional design: exit code tied to deterministic phase only
scripts/cve/fix-package.sh Use go list -json instead of grep Intentional trade-off for speed
scripts/cve/fix-stdlib.sh Stage untracked go.sum All Submariner repos always have go.sum pre-existing
scripts/cve/lib.sh Idempotent insert_grype_ignore Orchestrator prevents duplicate calls
scripts/cve/locate.sh grep -F fixed-string matching Module paths are safe in practice
scripts/cve/review.sh Special-case stdlib in locate.sh loop Agent handles gracefully from FIX_SUMMARY context
scripts/cve/review.sh Gate Bash behind opt-in flag Lazy-fetch design; agent needs git log/git diff
scripts/cve/fix-package.sh GNU-only grep -oP/xargs -r CI is Linux-only; macOS portability not required

⚠️ Still technically open (not confirmed addressed or withdrawn)

  1. scripts/cve/locate.sh lines 17–23FOUND_IN built as a space-joined string; a Bash array would be safer for paths containing spaces. (Nitpick)
  2. skills/cve-fix/SKILL.md lines 50–51pkill -f fix-all; docker kill $(docker ps -q) kills all containers indiscriminately. (Labeled "Low value 💤")

Why no approval yet

The PR review decision is CHANGES_REQUESTED because GitHub's state machine requires a new explicit approval to override it. Additionally, reviewer @skitt posted CHANGES_REQUESTED on 2026-05-04 and indicated they're still reviewing incrementally.

Given the 2 remaining nitpicks above are genuinely low-stakes, I'm happy to do a fresh review pass on the latest commit to check whether anything new was introduced. Would you like me to trigger that, or would you prefer to address those two items first?

Signed-off-by: Daniel Farrell <dfarrell@redhat.com>
@dfarrell07
Copy link
Copy Markdown
Member Author

@coderabbitai Both remaining items addressed:

  1. docker kill $(docker ps -q) kills all containers — Fixed. Added scripts/cve/clean.sh with scoped cleanup that only targets grype:latest and fix-*-cves-* containers. Referenced from SKILL.md and make cve-clean.

  2. FOUND_IN as space-joined string — Won't fix. find_gomods returns paths like go.mod, tools/go.mod — Go module paths can't contain spaces.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

🧩 Analysis chain

Let me verify the clean.sh fix quickly.


🏁 Script executed:

#!/bin/bash
# Check clean.sh content
echo "=== scripts/cve/clean.sh ==="
cat scripts/cve/clean.sh 2>/dev/null || echo "NOT FOUND"

echo ""
echo "=== Makefile cve-clean target ==="
grep -n "cve-clean\|clean.sh" Makefile 2>/dev/null || echo "NOT FOUND"

echo ""
echo "=== SKILL.md references to clean ==="
grep -n "clean\|pkill\|docker kill" skills/cve-fix/SKILL.md 2>/dev/null || echo "NOT FOUND"

Length of output: 673


@dfarrell07 — both items confirmed:

  1. clean.sh scoped cleanup ✅ — scripts/cve/clean.sh correctly filters with grep -E 'grype:latest|fix-.*-cves-' before calling docker kill, so it only targets CVE-fix containers. make cve-clean is wired up and SKILL.md now references the script.

  2. FOUND_IN space-join — Accepted. Go module paths cannot contain spaces per the module spec, so the current string-join approach is safe here.

All of my feedback is now addressed or withdrawn. Triggering a fresh review pass.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

3 participants