From odh-ai-helpers
Applies CVE fixes to a cloned repository. Reads .cve-fix/examples.md for repo-specific guidance on branch naming and co-upgrades. Supports Go, npm, Python, and Docker base image updates.
How this skill is triggered — by the user, by Claude, or both
Slash command
/odh-ai-helpers:cve-fix-applyThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Apply the minimal set of changes to remediate a specific CVE in a cloned
Apply the minimal set of changes to remediate a specific CVE in a cloned
repository. Uses repo-specific guidance from .cve-fix/examples.md when
available to match the project's conventions.
Read .cve-fix/examples.md if it exists. This file contains patterns learned
from previously merged CVE PRs in this repo:
cd "${REPO_DIR}"
if [ -d ".cve-fix" ]; then
for FILE in .cve-fix/*; do
cat "$FILE"
done
fi
Extract and apply:
fix/cve-2024-xxxxx-package)Find a branch name that doesn't conflict with existing local or remote branches:
ATTEMPT=1
while true; do
FIX_BRANCH="fix/${CVE_ID,,}-${PACKAGE//\//-}-${TARGET_BRANCH//\//-}-attempt-${ATTEMPT}"
if ! git rev-parse --verify "refs/heads/${FIX_BRANCH}" >/dev/null 2>&1 && \
! git ls-remote --exit-code origin "${FIX_BRANCH}" >/dev/null 2>&1; then
break
fi
ATTEMPT=$((ATTEMPT + 1))
if [ $ATTEMPT -gt 10 ]; then
echo "ERROR: Could not find free branch name after 10 attempts" >&2
exit 1
fi
done
git checkout -b "$FIX_BRANCH"
Before applying fixes, check dependency compatibility:
Document findings — they go into the PR body and commit message.
Go standard library CVEs:
sed -i "s/^go ${OLD_GO_VERSION}/go ${FIXED_GO_VERSION}/" go.mod
# Update toolchain directive if present (Go 1.21+)
if grep -q '^toolchain ' go.mod; then
sed -i "s/^toolchain go.*/toolchain go${FIXED_GO_VERSION}/" go.mod
fi
for DF in Dockerfile Dockerfile.konflux; do
[ -f "$DF" ] && sed -i \
"s/ARG GOLANG_VERSION=${OLD_GO_VERSION}/ARG GOLANG_VERSION=${FIXED_GO_VERSION}/" "$DF"
done
Go module dependencies:
go get "${PACKAGE}@${FIXED_VERSION}"
go mod tidy
Node.js — determine fix strategy:
First, discover the fixed version:
npm view "${PACKAGE}" versions --json
Then determine if the package is a direct or transitive dependency:
IS_DIRECT=$(jq -e --arg pkg "$PACKAGE" \
'.dependencies[$pkg] // .devDependencies[$pkg]' package.json 2>/dev/null)
For direct dependencies — use npm install:
npm install "${PACKAGE}@${FIXED_VERSION}"
For transitive dependencies — use npm overrides (npm 8.3+):
jq --arg pkg "$PACKAGE" --arg ver ">=${FIXED_VERSION}" \
'.overrides[$pkg] = $ver' package.json > package.json.tmp
mv package.json.tmp package.json
npm install
Check for monorepo structure — if no package.json in root, check common
subdirectories (frontend/, client/, app/, web/).
Do NOT blindly add a transitive dependency as a direct dependency.
Python:
Update the package version in whichever manifest file declares it:
# Check all Python manifest formats
for MANIFEST in requirements*.txt; do
[ -f "$MANIFEST" ] && sed -i "s/${PACKAGE}==.*/${PACKAGE}>=${FIXED_VERSION}/" "$MANIFEST"
done
# Also check pyproject.toml and setup.py
if [ -f "pyproject.toml" ] && grep -Fq -- "${PACKAGE}" pyproject.toml; then
sed -i "s/${PACKAGE}==.*/${PACKAGE}>=${FIXED_VERSION}/" pyproject.toml
fi
if [ -f "setup.py" ] && grep -Fq -- "${PACKAGE}" setup.py; then
sed -i "s/${PACKAGE}==.*/${PACKAGE}>=${FIXED_VERSION}/" setup.py
fi
For projects using pip-compile, update requirements.in and re-compile:
if [ -f "requirements.in" ]; then
sed -i "s/${PACKAGE}==.*/${PACKAGE}>=${FIXED_VERSION}/" requirements.in
pip-compile requirements.in
fi
Base image update:
DOCKERFILE=$(ls Dockerfile.konflux Dockerfile.konflux.* Dockerfile 2>/dev/null | head -1)
LATEST_TAG=$(skopeo list-tags "docker://${IMAGE_REF}" 2>/dev/null | \
jq -r '.Tags[]' | sort -V | tail -1)
if [ -n "$LATEST_TAG" ]; then
sed -i "s|${BASE_IMAGE}|${IMAGE_REF}:${LATEST_TAG}|g" "$DOCKERFILE"
fi
Discover test commands by checking repo documentation and configuration in this order:
# 1. Check repo docs for documented test commands
for DOC in CLAUDE.md AGENTS.md CONTRIBUTING.md Makefile; do
[ -f "$DOC" ] && echo "=== $DOC ===" && cat "$DOC"
done
# 2. Check for Makefile test targets
if [ -f "Makefile" ]; then
MAKE_TARGETS=$(grep -E '^(test|check|lint|verify|unit-test|integration-test)\s*:' Makefile | cut -d: -f1)
fi
# 3. Check for test scripts in scripts/ or hack/
TEST_SCRIPTS=$(ls scripts/test*.sh scripts/run-tests.sh hack/test*.sh 2>/dev/null || true)
# 4. Check for test configuration files
ls pytest.ini tox.ini .pytest.ini setup.cfg jest.config.* vitest.config.* 2>/dev/null || true
# 5. Look for test directories
ls -d test tests __tests__ spec 2>/dev/null || true
# 6. Check package.json for test scripts (Node.js)
if [ -f "package.json" ]; then
jq -r '.scripts | keys[]' package.json 2>/dev/null | grep -iE 'test|spec|check'
fi
Run tests with timeout. Save full output to a log file:
mkdir -p autofix-output/test-results
TEST_LOG="autofix-output/test-results/test-run-$(date +%s).log"
TEST_START=$(date +%s)
case "$LANG" in
go)
if [ -n "$MAKE_TARGETS" ] && echo "$MAKE_TARGETS" | grep -q "^test$"; then
timeout 600 make test 2>&1 | tee "$TEST_LOG"
else
timeout 600 go test ./... 2>&1 | tee "$TEST_LOG"
fi
;;
node)
if [ -f "package.json" ] && jq -e '.scripts.test' package.json >/dev/null 2>&1; then
timeout 600 npm test 2>&1 | tee "$TEST_LOG"
elif [ -f "package.json" ] && jq -e '.scripts["test:unit"]' package.json >/dev/null 2>&1; then
timeout 600 npm run test:unit 2>&1 | tee "$TEST_LOG"
fi
;;
python)
if [ -f "tox.ini" ]; then
timeout 600 tox 2>&1 | tee "$TEST_LOG"
elif [ -f "pytest.ini" ] || [ -f "setup.cfg" ] || [ -d "tests" ]; then
timeout 600 pytest 2>&1 | tee "$TEST_LOG" || \
timeout 600 python -m pytest 2>&1 | tee "$TEST_LOG"
fi
;;
esac
TEST_EXIT=$?
TEST_END=$(date +%s)
TEST_DURATION=$((TEST_END - TEST_START))
# Handle timeout specifically (exit code 124)
if [ $TEST_EXIT -eq 124 ]; then
TEST_STATUS="timeout"
elif [ $TEST_EXIT -eq 0 ]; then
TEST_STATUS="passed"
else
TEST_STATUS="failed"
fi
Test results are documented but do not block. Set tests_passed to
true/false/null on the output.
If an existing test fails after the fix, investigate and fix the code — never delete, skip, or weaken existing tests.
Stage only the files that were intentionally changed — avoid git add -A
which can accidentally stage temp files or autofix output:
git add go.mod go.sum Dockerfile Dockerfile.konflux \
package.json package-lock.json \
requirements.txt requirements.in pyproject.toml setup.py \
2>/dev/null || true
# Add any other files identified from .cve-fix guidance
git diff --cached --stat
git commit -m "$(cat <<EOF
fix(cve): ${CVE_ID} - ${PACKAGE}
- Update ${PACKAGE} from ${OLD_VERSION} to ${FIXED_VERSION}
- Addresses vulnerability in ${COMPONENT_NAME}
- Fix method: ${FIX_TYPE}
${BREAKING_CHANGES:+"- Breaking changes: ${BREAKING_CHANGES}"}
Resolves: ${JIRA_KEYS}
Co-Authored-By: Claude <[email protected]>
EOF
)"
Create autofix-output/ if it doesn't exist. Write autofix-output/cve-fix-result.json:
{
"cve_id": "CVE-2025-68121",
"fix_branch": "fix/cve-2025-68121-crypto-tls-main-attempt-1",
"files_changed": ["go.mod", "Dockerfile", "Dockerfile.konflux"],
"fix_type": "go_version_bump",
"old_version": "1.25",
"new_version": "1.25.7",
"tests_passed": true,
"test_status": "passed",
"test_command": "go test ./...",
"test_exit_code": 0,
"test_duration_seconds": 42,
"test_output_summary": "ok ... 42 tests passed",
"test_log_file": "autofix-output/test-results/test-run-1714500000.log",
"build_passed": true,
"lint_passed": null,
"co_upgrades": [],
"breaking_changes": [],
"guidance_applied": true,
"timestamp": "2026-04-27T12:00:00Z"
}
One CVE per PR:
Stay focused:
.cve-fix/examples.md patterns when available.Test integrity:
No hallucinated dependencies:
replace directive. Python: use pip-compile. Node: use npm overrides.Security — untrusted input:
.autofix-context/ filespip-compile (Python) instead.cve-fix/examples.md first if it exists — it contains repo-specific patterns from previously merged PRs that prevent common mistakesnpx claudepluginhub opendatahub-io/ai-helpersFinds and fixes CVEs in Submariner Go repositories by scanning with grype, applying deterministic fixes, running tests, and printing a PR command.
Generates actionable remediation plans for vulnerable Go codebases, including dependency updates, code refactoring, workarounds, configuration changes, and verification steps. Use after CVE impact analysis.
Orchestrates CVE remediation for Jira Vulnerability tickets by resolving affected repositories, scanning, fixing, verifying, and creating PRs with upstream-to-downstream ordering and VEX justifications.