diff --git a/workflows/cve-fixer/.ambient/ambient.json b/workflows/cve-fixer/.ambient/ambient.json new file mode 100644 index 00000000..3d1d324d --- /dev/null +++ b/workflows/cve-fixer/.ambient/ambient.json @@ -0,0 +1,10 @@ +{ + "name": "CVE Fixer", + "description": "Automate remediation of CVE issues reported by ProdSec team in Jira by creating pull requests with dependency updates and patches", + "systemPrompt": "You are a CVE remediation assistant for the Ambient Code Platform. Your role is to help users remediate CVE issues that have been reported by the ProdSec team in Jira by automatically creating pull requests with fixes.\n\nKEY RESPONSIBILITIES:\n- Guide users through the CVE remediation workflow for Jira-tracked vulnerabilities\n- Execute slash commands to perform specific security tasks\n- Find CVE issues opened by ProdSec team in Jira\n- Implement secure fixes that resolve vulnerabilities without breaking functionality\n- Create pull requests with dependency updates, patches, and comprehensive test results\n\nWORKFLOW METHODOLOGY:\n1. FIND - Find CVEs already reported in Jira for a component\n2. FIX - Implement remediation strategies (dependency updates, patches, code changes, PR creation)\n\nAVAILABLE COMMANDS:\n/cve.find - Find CVEs reported in Jira for a specific component\n/cve.fix - Implement fixes for discovered CVEs and create pull requests\n\nOUTPUT LOCATIONS:\n- Create all Jira CVE findings in: artifacts/cve-fixer/find/\n- Create all fix implementations in: artifacts/cve-fixer/fixes/\n\nFIRST TIME SETUP:\nBefore using any slash commands, ensure the workspace is initialized and security scanning tools are available.", + "startupPrompt": "Welcome! I'm your CVE Remediation assistant.\n\nšŸŽÆ WHAT I DO:\nI help you remediate CVE issues reported by the ProdSec team in Jira by automatically creating pull requests with dependency updates, patches, and code changes.\n\nšŸ“‹ WORKFLOW PHASES:\n1. **Find** - Discover CVE issues opened by ProdSec in Jira for a component\n2. **Fix** - Implement secure remediations and create pull requests\n\nšŸš€ AVAILABLE COMMANDS:\n/cve.find - Find CVE issues reported by ProdSec in Jira\n/cve.fix - Implement security fixes and create PRs\n\nšŸ’” GETTING STARTED:\nRun /cve.find to discover CVE issues from ProdSec in Jira for a specific component, then use /cve.fix to automatically remediate them with pull requests.\n\n**Note:** This workflow is designed for CVE issues tracked in Jira by your Product Security team.\n\nWhat would you like to accomplish today?", + "results": { + "Jira CVE Issues": "artifacts/cve-fixer/find/**/*.md", + "Fix Implementations": "artifacts/cve-fixer/fixes/**/*" + } +} diff --git a/workflows/cve-fixer/.claude/CLAUDE.md b/workflows/cve-fixer/.claude/CLAUDE.md new file mode 100644 index 00000000..e67d6486 --- /dev/null +++ b/workflows/cve-fixer/.claude/CLAUDE.md @@ -0,0 +1,264 @@ +# CVE Fixer Workflow - Agent Guidelines + +This document defines the rules, guardrails, and quality standards for the CVE Fixer workflow. These are **hard requirements** that must be followed in all workflow executions. + +--- + +## 🚫 Hard Limits (NEVER Do These) + +### Git Operations +- **NEVER force-push** (`git push --force`, `git push -f`, `git push --force-with-lease`) +- **NEVER commit directly to protected branches** (main, master, rhoai-release, odh-release, or any branch listed in `protected_branches`) +- **NEVER skip git hooks** (`--no-verify`, `--no-gpg-sign`, `-n`) +- **NEVER use `git reset --hard`** without explicit user instruction +- **NEVER delete remote branches** without explicit user instruction +- **NEVER modify git history** of pushed commits (no rebase, amend, or squash on pushed branches) + +### Branch Safety +- **ALWAYS create feature branches** for fixes (never work directly on main/protected branches) +- **ALWAYS check if branch is protected** before pushing +- **ALWAYS use branch naming convention**: `fix/cve-YYYY-XXXXX--attempt-N` + +### Pull Request Creation +- **ALWAYS create separate PRs** for each CVE (never combine multiple CVE fixes in one PR) +- **ALWAYS verify CVE exists** in vulnerability scan before creating PR (skip if already fixed) +- **ALWAYS check for existing open PRs** before creating new ones (prevent duplicates) +- **ALWAYS include test results** in PR description (even if tests failed or couldn't run) + +### Repository Operations +- **NEVER delete user's working directories** or files +- **ONLY clone repositories to `/tmp`** (never to user's workspace) +- **ALWAYS clean up `/tmp` clones** after workflow completes +- **NEVER run `rm -rf` on paths outside `/tmp`** (this is denied in settings.json) + +--- + +## āœ… Safety Rules + +### Before Making Changes +1. **Verify CVE presence** - Always scan the repository to confirm the CVE actually exists before attempting to fix it +2. **Check for existing work** - Look for open PRs that might already address the CVE +3. **Understand the scope** - Know which repositories need fixes (upstream, downstream, or both) +4. **Validate mappings** - If component not in mapping file, ask user for repository information + +### During Execution +1. **Use version-matched scanning** - For Go projects, use `GOTOOLCHAIN` to match repository's Go version +2. **Test before PR** - Always attempt to discover and run tests before creating PRs +3. **Document everything** - Save detailed reports to `artifacts/cve-fixer/` for every action +4. **Handle errors gracefully** - If a step fails, document the failure and continue with next CVE/repo + +### Communication +1. **Be concise** - Brief status updates during execution, detailed summary at end +2. **Show confidence** - Indicate certainty level when making recommendations +3. **Full URLs in output** - Always print complete PR URLs (e.g., `https://github.com/org/repo/pull/123`) +4. **Clear status indicators** - Use āœ…, āŒ, āš ļø to show success, failure, warnings + +--- + +## šŸ“‹ Quality Standards + +### Test Execution +**Required:** Always attempt to discover and run tests before creating PRs. + +**Test Failure Handling:** +- **If tests PASS** āœ… - Proceed with PR creation, note success in PR description +- **If tests FAIL** āŒ - **Still create PR** but: + - Include failure details in PR description + - Add warning labels if possible + - Document which tests failed and error messages + - Include note: "āš ļø Tests failed - manual review required before merge" +- **If NO tests found** āš ļø - Create PR with note: "No automated tests discovered - manual testing required" +- **If tests can't run** āš ļø - Create PR with error details: "Tests could not execute: [reason]" + +**Rationale:** PRs should always be created so users can review the fix. Test failures don't mean the fix is wrong - they provide valuable information for review. + +### Commit Standards +- **Use conventional commits** format: + ``` + fix(cve): CVE-YYYY-XXXXX - + + - Update from X.X.X to Y.Y.Y + - Addresses vulnerability in + - Breaking changes: [if any] + + Resolves: JIRA-123, JIRA-456 + ``` +- **Include Co-authored-by** for AI assistance: + ``` + Co-Authored-By: Claude Sonnet 4.6 (1M context) + ``` + +### PR Description Standards +Every PR must include: +1. **CVE Details** - ID, severity, CVSS score, affected versions +2. **Fix Summary** - What changed and why +3. **Test Results** - Status, command, output (even if failed) +4. **Breaking Changes** - Analysis of compatibility impacts +5. **Jira References** - Plain text issue IDs (no hyperlinks) +6. **Verification Steps** - Checklist for reviewers +7. **Risk Assessment** - Low/Medium/High with justification + +--- + +## šŸŽÆ Workflow-Specific Rules + +### CVE Verification +1. **Never apply fixes blindly** - Always verify CVE exists in current code +2. **Use correct toolchain** - For Go stdlib CVEs, use `GOTOOLCHAIN=go` matching repo's go.mod +3. **Check all repositories** - If component maps to multiple repos, verify and fix each independently + +### Duplicate Prevention +1. **Check for existing PRs** with: `gh pr list --repo X --state open --base Y --search "CVE-ID"` +2. **Use `--base` parameter** to scope search to specific target branch +3. **Skip if PR exists** - Document in `artifacts/cve-fixer/fixes/existing-pr-CVE-*.md` + +### Multi-Repository Handling +1. **Process independently** - Each repository gets its own clone, branch, scan, fix, test, and PR +2. **Upstream first** - When fixing both upstream and downstream, process upstream first +3. **Track separately** - Maintain separate artifacts and reports per repository + +### Ignored CVEs +Respect ignore patterns in Jira comments: +- `cve-automation-ignore` +- `skip-cve-automation` +- `ignore-cve-automation` +- `automation-ignore-cve` + +When found, skip the CVE and document why. + +--- + +## šŸ”§ Automation Support + +### Scheduled/Unattended Runs +This workflow is designed for scheduled automation (GitHub Actions, Ambient scheduled sessions). + +**Automation Mode Behavior:** +- āœ… Automatic PR creation (no manual approval gates) +- āœ… Continue on test failures (create PR anyway with failure details) +- āœ… Skip CVEs that are already fixed or have open PRs +- āœ… Save all output to artifacts (user reviews PRs, not logs) +- āœ… Clean up `/tmp` after completion + +**Why No Manual Approval Gate:** +1. PRs are the review mechanism - user approves by merging +2. Scheduled runs require unattended operation +3. Bad PRs can simply be closed (no harm done) +4. All context is in PR description for informed review + +### Interactive Runs +When user runs `/cve.fix` interactively: +- āœ… Same behavior as automated runs (consistency) +- āœ… Print PR URLs to console for easy access +- āœ… Show summary of created/skipped PRs +- āœ… User can review PRs immediately if desired + +--- + +## šŸ“Š Success Criteria + +A successful workflow execution means: + +1. āœ… **All CVEs processed** - None skipped due to errors +2. āœ… **Correct PRs created** - Only for CVEs that actually exist and have no open PRs +3. āœ… **Tests attempted** - Even if they fail, results are documented +4. āœ… **Complete artifacts** - Reports saved for every action taken +5. āœ… **Clean state** - `/tmp` directories cleaned up +6. āœ… **Clear output** - User knows exactly what happened and what to review + +--- + +## šŸ›”ļø Error Handling + +### When Things Go Wrong + +**Git authentication fails:** +- Try all available credential methods (gh auth, GITHUB_TOKEN, SSH) +- If all fail, document the issue and skip that repository +- DO NOT prompt for credentials in automated runs + +**CVE scan fails:** +- Document the error in artifacts +- Skip that CVE/repository +- Continue with next CVE + +**Test execution fails:** +- Document test failures +- **Create PR anyway** with failure details +- Let user decide whether to merge + +**PR creation fails:** +- Log the error +- Save the branch name and changes +- Include in final summary so user can manually create PR + +**Component not in mapping:** +- In interactive mode: Ask user for repository information +- In automated mode: Skip and document in artifacts + +--- + +## šŸ“ Documentation Requirements + +### Artifacts to Generate +For every CVE processed, create: + +1. **Fix implementation report** - `artifacts/cve-fixer/fixes/fix-implementation-CVE-*.md` + - Changes made + - Test results + - PR URL + +2. **Already-fixed report** - `artifacts/cve-fixer/fixes/already-fixed-CVE-*.md` (if CVE not present) + - Scan results + - Timestamp + +3. **Existing PR report** - `artifacts/cve-fixer/fixes/existing-pr-CVE-*.md` (if duplicate) + - Existing PR details + - Timestamp + +4. **PR summary** - `artifacts/cve-fixer/fixes/pr-creation-summary.md` + - All PRs created + - All CVEs skipped (with reasons) + - Test status per PR + +--- + +## šŸ” Review Checklist + +Before completing workflow execution, verify: + +- [ ] No force-pushes attempted +- [ ] No direct commits to protected branches +- [ ] All feature branches follow naming convention +- [ ] Every CVE has corresponding artifact (fix/skip/existing) +- [ ] Test results documented (pass/fail/none/error) +- [ ] PRs created only for actual fixes (not already-fixed CVEs) +- [ ] No duplicate PRs created +- [ ] `/tmp` directories cleaned up +- [ ] Final summary shows all PR URLs +- [ ] Conventional commit format used +- [ ] PR descriptions include all required sections + +--- + +## šŸŽ“ Learning from the Bugfix Workflow + +This workflow draws inspiration from the [bugfix workflow](https://github.com/ambient-code/workflows/tree/main/workflows/bugfix) best practices: + +- Clear hard limits on dangerous operations +- Safety-first approach to git operations +- Comprehensive documentation requirements +- Support for both interactive and automated execution +- Quality standards that don't block automation + +--- + +## šŸ“ž Questions or Issues? + +If you encounter situations not covered by these guidelines: +1. Err on the side of caution +2. Document the situation in artifacts +3. Continue with other CVEs +4. Include the question in the final summary + +**Remember:** The goal is to help users remediate CVEs safely and efficiently, whether running interactively or on a schedule. When in doubt, create the PR with all available information and let the user decide. diff --git a/workflows/cve-fixer/.claude/commands/cve.find.md b/workflows/cve-fixer/.claude/commands/cve.find.md new file mode 100644 index 00000000..013db7d8 --- /dev/null +++ b/workflows/cve-fixer/.claude/commands/cve.find.md @@ -0,0 +1,494 @@ +# /cve.find - Find CVEs in Jira + +## Purpose +Find and catalog CVEs that have been reported in Jira for a specific component. This command queries your Jira instance to discover existing CVE-related issues, allowing you to track known vulnerabilities that may already be documented in your issue tracking system. + +## Execution Style + +**Be concise. Brief status + final summary only.** + +Example: + +```text +Querying Jira... Found 2 CVEs + +Results: +- RHOAIENG-49745: CVE-2025-68121 +- RHOAIENG-48536: CVE-2025-61726 + +Report: artifacts/cve-fixer/find/cve-issues-20260226-145018.md +``` + +## Prerequisites + +- **JIRA_API_TOKEN environment variable must be set** (API token from Jira Cloud) +- **JIRA_EMAIL environment variable must be set** (your Jira account email, e.g. user@redhat.com) +- curl must be available (pre-installed on most systems) +- **jq must be installed** for JSON payload creation and parsing (required) +- Access to the Jira project containing CVE issues +- Internet connection for Jira API access + +## Process + +1. **Parse Arguments and Flags** + - Parse the command arguments for both the component name and optional flags + - **Supported flags:** + - `--ignore-resolved` — Exclude issues with Jira status "Resolved" from results + - The component name is any argument that is not a flag + - If component is not provided, ask the user to type the component name + - **IMPORTANT**: Let the user type the component name freely as text input + - **DO NOT** provide multiple-choice options or suggestions + - **DO NOT** use AskUserQuestion tool with predefined options + - Simply ask: "What is the component name?" and wait for user's text response + - Store the `--ignore-resolved` flag as a boolean for use in step 3 + +2. **Check JIRA API Token (REQUIRED - User Setup)** + - **This is the ONLY thing the user must configure manually before proceeding** + + - Check if JIRA_API_TOKEN and JIRA_EMAIL are set: + ```bash + if [ -z "$JIRA_API_TOKEN" ]; then + echo "ERROR: JIRA_API_TOKEN is not set" + else + echo "JIRA_API_TOKEN is set" + fi + if [ -z "$JIRA_EMAIL" ]; then + echo "ERROR: JIRA_EMAIL is not set" + else + echo "JIRA_EMAIL is set" + fi + ``` + + - **If JIRA_API_TOKEN or JIRA_EMAIL is NOT set or empty**: + - **STOP here and inform the user they need to set up both variables first** + - Provide instructions: + + **Step 1: Generate a Jira API Token** + - Go to https://id.atlassian.com/manage-profile/security/api-tokens + - Click "Create API token" + - Give it a name and copy the token + + **Step 2: Export both environment variables** + ```bash + export JIRA_API_TOKEN="your-token-here" + export JIRA_EMAIL="your-email@redhat.com" + ``` + To make it persistent, add to `~/.bashrc` or `~/.zshrc`: + ```bash + echo 'export JIRA_API_TOKEN="your-token-here"' >> ~/.bashrc + echo 'export JIRA_EMAIL="your-email@redhat.com"' >> ~/.bashrc + source ~/.bashrc + ``` + + - **After user sets the variables, verify they're exported correctly** using the check script above + - Should output: "JIRA_API_TOKEN is set" and "JIRA_EMAIL is set" + + - **Only proceed to the next steps if both JIRA_API_TOKEN and JIRA_EMAIL are set** + +3. **Query Jira for CVE Issues** + + a. Set up variables: + ```bash + COMPONENT_NAME="[from step 1]" + JIRA_BASE_URL="https://redhat.atlassian.net" + JIRA_EMAIL="${JIRA_EMAIL}" + JIRA_API_TOKEN="${JIRA_API_TOKEN}" + # Jira Cloud uses Basic Auth: base64(email:api-token) + AUTH=$(echo -n "${JIRA_EMAIL}:${JIRA_API_TOKEN}" | base64) + ``` + + b. Construct JQL query and execute API call: + ```bash + # Build JQL query + JQL="project = RHOAIENG AND component = \"${COMPONENT_NAME}\" AND summary ~ \"CVE*\"" + + # Append resolved filter if --ignore-resolved flag was provided + if [ "$IGNORE_RESOLVED" = "true" ]; then + JQL="${JQL} AND status not in (\"Resolved\")" + fi + + # URL-encode the JQL query for the GET request + ENCODED_JQL=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''${JQL}'''))") + + # Execute API call with Basic Auth against the v3 search/jql endpoint + RESPONSE=$(curl -s -w "\n%{http_code}" -X GET \ + --connect-timeout 10 \ + --max-time 30 \ + --retry 3 \ + --retry-delay 2 \ + -H "Content-Type: application/json" \ + -H "Authorization: Basic ${AUTH}" \ + "${JIRA_BASE_URL}/rest/api/3/search/jql?jql=${ENCODED_JQL}&fields=key,summary,status,priority,created,components&maxResults=100&startAt=0") + + # Extract HTTP status code + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | sed '$d') + + # Check for errors + if [ "$HTTP_CODE" != "200" ]; then + echo "ERROR: Jira API request failed with HTTP ${HTTP_CODE}" + echo "$BODY" | jq -r '.errorMessages[]? // .errors? // .' + exit 1 + fi + + # Get issue count (v3 API uses cursor-based pagination, no 'total' field) + ISSUE_COUNT=$(echo "$BODY" | jq '.issues | length') + IS_LAST=$(echo "$BODY" | jq -r '.isLast') + + echo "Found ${ISSUE_COUNT} CVE issues on first page for component: ${COMPONENT_NAME}" + + # Handle 0 results gracefully + if [ "$ISSUE_COUNT" -eq 0 ]; then + echo "No CVE issues found for component: ${COMPONENT_NAME}" + echo "This may mean: no CVEs have been filed, the component name is misspelled, or the project has no matching issues." + exit 0 + fi + + # Save initial results + echo "$BODY" > /tmp/jira-cve-response.json + ``` + + c. Handle pagination using cursor-based nextPageToken (v3 API): + ```bash + # The v3 search/jql endpoint uses cursor-based pagination: + # - isLast: boolean indicating if this is the last page + # - nextPageToken: opaque token to pass for the next page + # Note: Both jql and nextPageToken must be included in subsequent requests + + PAGE=1 + while [ "$IS_LAST" != "true" ]; do + PAGE=$((PAGE + 1)) + echo "Fetching page ${PAGE}..." + + # Extract nextPageToken from previous response + NEXT_TOKEN=$(echo "$BODY" | jq -r '.nextPageToken') + ENCODED_TOKEN=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''${NEXT_TOKEN}'''))") + + RESPONSE=$(curl -s -w "\n%{http_code}" -X GET \ + --connect-timeout 10 \ + --max-time 30 \ + --retry 3 \ + --retry-delay 2 \ + -H "Content-Type: application/json" \ + -H "Authorization: Basic ${AUTH}" \ + "${JIRA_BASE_URL}/rest/api/3/search/jql?jql=${ENCODED_JQL}&fields=key,summary,status,priority,created,components&maxResults=100&nextPageToken=${ENCODED_TOKEN}") + + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | sed '$d') + + if [ "$HTTP_CODE" != "200" ]; then + echo "Warning: Pagination failed on page ${PAGE}" + break + fi + + PAGE_COUNT=$(echo "$BODY" | jq '.issues | length') + IS_LAST=$(echo "$BODY" | jq -r '.isLast') + echo " Page ${PAGE}: ${PAGE_COUNT} issues (isLast: ${IS_LAST})" + + # Append page to results file + echo "$BODY" > /tmp/jira-cve-response-page-${PAGE}.json + done + + # Merge all paginated results into the main response + if ls /tmp/jira-cve-response-page-*.json 1>/dev/null 2>&1; then + jq -s '{issues: [.[].issues[]]}' \ + /tmp/jira-cve-response.json /tmp/jira-cve-response-page-*.json > /tmp/jira-cve-merged.json + mv /tmp/jira-cve-merged.json /tmp/jira-cve-response.json + rm -f /tmp/jira-cve-response-page-*.json + fi + + TOTAL=$(jq '.issues | length' /tmp/jira-cve-response.json) + echo "Total CVE issues found: ${TOTAL}" + ``` + +4. **Filter Issues with Ignore Comments** + - Check each issue for comments containing ignore patterns + - Filter out issues marked to be ignored by automation + + **Ignore Patterns (case-insensitive):** + - "cve-automation-ignore" + - "cve automation ignore" + - "skip-cve-automation" + - "ignore-cve-automation" + - "automation-ignore-cve" + + ```bash + # Initialize arrays for tracking + echo "Checking for ignored issues..." + + # Create temporary files for filtered results + cp /tmp/jira-cve-response.json /tmp/jira-cve-response-original.json + + # Get all issue keys + ISSUE_KEYS=($(jq -r '.issues[].key' /tmp/jira-cve-response-original.json)) + IGNORED_ISSUES=() + IGNORED_REASONS=() + + # Check each issue for ignore comments + for KEY in "${ISSUE_KEYS[@]}"; do + echo " Checking $KEY for ignore comments..." + + # Fetch comments for this issue (using Basic Auth and v3 API) + COMMENTS_RESPONSE=$(curl -s -w "\n%{http_code}" -X GET \ + --connect-timeout 10 \ + --max-time 30 \ + --retry 3 \ + --retry-delay 2 \ + -H "Content-Type: application/json" \ + -H "Authorization: Basic ${AUTH}" \ + "${JIRA_BASE_URL}/rest/api/3/issue/${KEY}/comment") + + COMMENTS_HTTP_CODE=$(echo "$COMMENTS_RESPONSE" | tail -n1) + COMMENTS_BODY=$(echo "$COMMENTS_RESPONSE" | sed '$d') + + if [ "$COMMENTS_HTTP_CODE" = "200" ]; then + # Check if any comment contains ignore patterns (case-insensitive) + IGNORE_MATCH=$(echo "$COMMENTS_BODY" | jq -r '.comments[]?.body' | \ + grep -iE 'cve.{0,1}automation.{0,1}ignore|skip.{0,1}cve.{0,1}automation|ignore.{0,1}cve.{0,1}automation|automation.{0,1}ignore.{0,1}cve' || true) + + if [ -n "$IGNORE_MATCH" ]; then + echo " āš ļø Issue $KEY has ignore comment - will be filtered out" + IGNORED_ISSUES+=("$KEY") + # Get first matching comment for reason + REASON=$(echo "$IGNORE_MATCH" | head -n1 | cut -c1-100) + IGNORED_REASONS+=("$REASON") + fi + else + echo " Warning: Could not fetch comments for $KEY (HTTP $COMMENTS_HTTP_CODE)" + fi + done + + # Filter out ignored issues from the response + if [ ${#IGNORED_ISSUES[@]} -gt 0 ]; then + echo "" + echo "Filtered out ${#IGNORED_ISSUES[@]} ignored issue(s)" + + # Build JSON array of ignored keys and filter safely using jq --argjson (no string interpolation) + IGNORED_JSON=$(printf '%s\n' "${IGNORED_ISSUES[@]}" | jq -R . | jq -s .) + jq --argjson ignored "$IGNORED_JSON" \ + '{issues: [.issues[] | select(.key as $k | ($ignored | index($k)) == null)], total: 0} | + .total = (.issues | length)' \ + /tmp/jira-cve-response-original.json > /tmp/jira-cve-response.json + + # Save ignored issues for reporting + echo "${IGNORED_ISSUES[@]}" > /tmp/jira-cve-ignored-keys.txt + printf "%s\n" "${IGNORED_REASONS[@]}" > /tmp/jira-cve-ignored-reasons.txt + else + echo "No issues with ignore comments found" + fi + + # Update TOTAL count + TOTAL=$(jq '.issues | length' /tmp/jira-cve-response.json) + echo "Remaining issues after filtering: $TOTAL" + ``` + +5. **Extract Issue Information** + - Parse output from either MCP server or curl API response + - Extract issue keys and metadata + + **If using curl with jq available:** + ```bash + # Parse all pages (if multiple exist) + if [ -f /tmp/jira-cve-response.json ]; then + # Combine all pages into single array if pagination occurred + ALL_JSON=/tmp/jira-cve-response.json + + # Extract issues to array + if command -v jq &> /dev/null; then + jq -r '.issues[] | + "KEY: \(.key)\n" + + "SUMMARY: \(.fields.summary)\n" + + "STATUS: \(.fields.status.name)\n" + + "PRIORITY: \(.fields.priority.name // "None")\n" + + "CREATED: \(.fields.created)\n" + + "---"' "$ALL_JSON" + fi + fi + ``` + +6. **Generate Issue List** + - Create markdown file with structured output + - Include all metadata and statistics + - Report ignored issues separately for transparency + + ```bash + # Set output file + TIMESTAMP=$(date +"%Y%m%d-%H%M%S") + OUTPUT_FILE="artifacts/cve-fixer/find/cve-issues-${TIMESTAMP}.md" + + # Count ignored issues + IGNORED_COUNT=0 + if [ -f /tmp/jira-cve-ignored-keys.txt ]; then + IGNORED_COUNT=$(wc -w < /tmp/jira-cve-ignored-keys.txt) + fi + + # Create header + cat > "$OUTPUT_FILE" < /dev/null; then + INDEX=1 + jq -r '.issues[] | @json' /tmp/jira-cve-response.json | while read -r issue; do + KEY=$(echo "$issue" | jq -r '.key') + SUMMARY=$(echo "$issue" | jq -r '.fields.summary') + STATUS=$(echo "$issue" | jq -r '.fields.status.name') + PRIORITY=$(echo "$issue" | jq -r '.fields.priority.name // "None"') + CREATED=$(echo "$issue" | jq -r '.fields.created') + + cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" <> "$OUTPUT_FILE" + + cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" + + # Extract CVE IDs + cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" + + # Add ignored issues section if any were filtered + if [ -f /tmp/jira-cve-ignored-keys.txt ] && [ -s /tmp/jira-cve-ignored-keys.txt ]; then + cat >> "$OUTPUT_FILE" <> "$OUTPUT_FILE" <&2 + grep -o '"key":"[^"]*"' /tmp/jira-cve-response.json | cut -d'"' -f4 | while read -r key; do + echo "- ${key}" >> "$OUTPUT_FILE" + done + fi + + cat >> "$OUTPUT_FILE" < /dev/null; then + jq -r '.issues[0:10][] | " • \(.key): \(.fields.summary)"' /tmp/jira-cve-response.json + fi + ``` + +## Output + - **CVE Issues List**: `artifacts/cve-fixer/find/cve-issues-[timestamp].md` + - The folder already exists, do not run mkdir commands to create it + - List of Jira issue numbers/keys for CVEs matching the component (excluding ignored issues) + - Separate section for ignored issues (if any) with reasons for transparency + - Pretty print the first 10 or so issues to the console as well + - Summary includes both total issues found and count of ignored issues + +## Usage Examples + +Basic usage (will prompt for component): + +```bash +/cve.find +``` + +With component specified as argument: + +```bash +/cve.find backend-api +``` + +With component and ignore resolved issues: + +```bash +/cve.find backend-api --ignore-resolved +``` + +Ignore resolved without specifying component (will prompt): + +```bash +/cve.find --ignore-resolved +``` + +## Success Criteria + +After running this command, you should have: +- [ ] Complete list of Jira CVE issues for the specified component +- [ ] Issues with ignore comments filtered out automatically +- [ ] Ignored issues documented separately for transparency +- [ ] Issue numbers (keys) extracted and documented +- [ ] Issue metadata (summary, priority, status) captured +- [ ] Results saved to artifacts/cve-fixer/find/ + +## Next Steps + +After completing this phase: +1. Review the discovered Jira issues to understand already-documented CVEs +2. Run `/cve.fix` to fix the issues that have been found +3. Cross-reference Jira issues with scan results to identify gaps diff --git a/workflows/cve-fixer/.claude/commands/cve.fix.md b/workflows/cve-fixer/.claude/commands/cve.fix.md new file mode 100644 index 00000000..4de528a6 --- /dev/null +++ b/workflows/cve-fixer/.claude/commands/cve.fix.md @@ -0,0 +1,1101 @@ +# /cve.fix - Implement CVE Fixes + +## Purpose +Implement secure remediations for prioritized CVEs through dependency updates, patches, code changes, or compensating controls. This command executes the actual fixes that eliminate vulnerabilities. + +## Execution Style + +**Be concise. Brief status + final summary only.** + +Example: +``` +Loading CVEs... 2 found +Cloning repos... Done + +Upstream (main): Go 1.25.7 → Already fixed āœ… +Downstream (rhoai-3.0): Existing PR #1 → Skipped + +Summary: +- No new PRs created +- Upstream already fixed +- Downstream: https://github.com/org/repo/pull/1 +``` + +## Prerequisites +- Component-repository mapping file: `component-repository-mappings.json` +- Version control system initialized (git) +- GitHub CLI (`gh`) installed and authenticated +- Test suite available to verify fixes don't break functionality +- Latest `/cve.find` output with CVE list +- (Optional) `.cve-fix/` folder in target repositories for fix guidance + +## Process + +1. **Load CVEs from Find Output or User-Specified Jira Issue** + + **Option A: User specifies one or more Jira issues** + - If user provides one or more Jira issue IDs (e.g., `/cve.fix RHOAIENG-4973` or `/cve.fix RHOAIENG-4973 RHOAIENG-5821`): + - Process each issue independently -- extract CVE ID and component from each + - Use the provided Jira issue ID(s) directly + - Fetch the issue details from Jira API + - Extract CVE ID from the issue summary + - Extract component name from the issue + - Proceed with this single CVE + - Skip the `/cve.find` output lookup + + **Option B: Use /cve.find output (default)** + - If no specific Jira issue provided: + - Read the latest `/cve.find` output from `artifacts/cve-fixer/find/` + - Extract CVE IDs with their status from the markdown file + - Filter for CVEs where `Status: Open` (unfixed vulnerabilities) + - Extract component name from the find output (e.g., "AI Core Dashboard") + - Collect ALL open CVEs (no filtering) + - Proceed with all open CVEs found + + **Result**: A list of CVEs to fix with their associated Jira issues and components + +2. **Load Component-Repository Mapping** + - Use `component-repository-mappings.json` from workspace root + - Look up the component from the CVE find output + - Extract repository information for the component: + - Container to repository mappings + - Repository details (default_branch, github_url, active_release_branches, etc.) + - Branch strategy and CVE fix workflow + + **2.1: If Component NOT Found in Mapping** + + If the component is not in the mapping file, **ask the user** to provide: + + - **Repository URL**: GitHub repository URL (e.g., `https://github.com/org/repo`) + - **Target Branch**: Primary branch to apply the fix (e.g., `main`, `rhoai-3.0`) + - **Additional Branches** (optional): Other branches to backport the fix to (e.g., `rhoai-2.5`, `v2.28.0-fixes`) + - **Build Location** (optional): Subdirectory where the code lives (e.g., `maas-api/` for monorepos) + + Example prompt to user: + ``` + Component "Example Component" not found in component-repository-mappings.json. + + Please provide the following information: + 1. Repository URL (e.g., https://github.com/org/repo): + 2. Target branch to fix (e.g., main): + 3. Additional branches for backports (optional, comma-separated): + 4. Build location subdirectory (optional, leave blank if root): + ``` + + Once the user provides this information: + - Create a temporary mapping structure for this session + - Use the provided repository and branches for the fix + - **Optionally**: Ask user if they want to add this mapping to `component-repository-mappings.json` for future use + + **2.2: If Component Found in Mapping** + + - Proceed with mapped repository as documented below + +3. **Identify Target Repositories** + - Get list of ALL repositories from the mapping for the component + - **IMPORTANT**: A single component may map to MULTIPLE repositories (e.g., an upstream repo and one or more downstream repos) + - Each repository entry may have a `repo_type` field indicating `"upstream"` or `"downstream"` + - For each repository, gather: + - Repository name (e.g., "opendatahub-io/odh-dashboard") + - Default branch (e.g., "main") + - Active release branches (e.g., ["v2.29.0-fixes", "v2.28.0-fixes", "rhoai-3.0"]) + - Primary target branch for CVE fixes (from `cve_fix_workflow.primary_target`) + - Backport targets from cve_fix_workflow + - Repository type (monorepo vs single package) + - Repo type: upstream or downstream (from `repo_type` field, defaults to upstream if absent) + - Create initial list of ALL candidate repositories for the fix + - **Multi-repo strategy**: When a component has both upstream and downstream repos: + - Fix upstream first, then apply the same fix to downstream repos + - Each repo gets its own clone, branch, PR, and verification cycle + - The fix in downstream repos may be a cherry-pick or re-application of the upstream fix + - Steps 4 through 11 are repeated for EACH repository in the list + +4. **Clone or Use Existing Repository** + - Always use `/tmp` for repository operations with unique dirs per repo + - For each repo, extract `REPO_ORG` and `REPO_NAME` from `github_url`, set `REPO_DIR="/tmp/${REPO_ORG}/${REPO_NAME}"` + - If `$REPO_DIR` exists, `cd` into it; otherwise `mkdir -p "/tmp/${REPO_ORG}"`, `git clone` the URL, `cd` in, and `git checkout` the target branch + - **Configure git credentials** immediately after clone (needed for push): + 1. `gh auth setup-git` (if `gh` is authenticated) + 2. Else set `credential.helper` using `$GITHUB_TOKEN` or `$GH_TOKEN` + 3. Else switch remote to SSH if `~/.ssh/id_rsa` or `id_ed25519` exists + 4. Else warn: no credentials configured, push will fail + - **Multi-repo example**: + ```bash + # Upstream: /tmp/opendatahub-io/models-as-a-service (branch: main) + # Downstream: /tmp/red-hat-data-services/models-as-a-service (branch: rhoai-3.0) + ``` + +4.5. **Load Global Fix Guidance from `.cve-fix/` Folder** + - Runs ONCE after all repos are cloned, BEFORE any fixes. Builds a global knowledge base from `.cve-fix/` folders across all cloned repos. + - Check every cloned repo for `.cve-fix/`, read ALL files (e.g., `examples.md`, `config.json`, `dependencies.md`, `pitfalls.md`), and merge into a single context. + - Extract: dependency co-upgrades, lock file requirements, version upgrade patterns, branch-specific instructions, known working fix versions, testing requirements, common pitfalls. + - Apply this guidance to ALL subsequent steps (5-11). Guidance from any repo applies globally; when conflicts exist, prefer the repo-specific instruction. + - If no `.cve-fix/` folders exist, proceed with default strategy. + +--- +> **Steps 5-11 repeat for EACH repository identified in Step 3.** +> Each repo gets its own clone, branch, verification, fix, test run, and PR. +--- + +5. **Verify CVE Presence in Repository** + - **CRITICAL**: Don't blindly apply fixes to all repositories in the mapping + - **CRITICAL**: Only fix CVEs that exist as UNFIXED vulnerabilities in the current branch + - **CRITICAL**: Use the correct Go/language version for vulnerability scanning (see below) + + **5.1: Version-Matched Vulnerability Scanning** + + - **Problem**: Running vulnerability scanners (e.g., govulncheck) with a local toolchain that is NEWER than the repo's target version produces **false negatives**. govulncheck does symbol-level analysis by compiling against the local stdlib. If the local Go 1.26 stdlib already has security fixes, govulncheck won't detect CVEs that affect Go 1.25 or 1.24. + - **Solution**: Use the `GOTOOLCHAIN` environment variable to force govulncheck to download and use the exact Go toolchain version the repository targets. Go's toolchain management will automatically fetch the correct version. + + **For Go projects (govulncheck with GOTOOLCHAIN — REQUIRED):** + + ```bash + # Change to build location to read go.mod (important for monorepos) + cd "$BUILD_LOCATION" || { + echo "ERROR: Cannot access build location: $BUILD_LOCATION" + exit 1 + } + + # Extract the Go version from go.mod + GO_VERSION=$(grep '^go ' go.mod | awk '{print $2}') + # If there's a toolchain directive, extract that version too + TOOLCHAIN_VERSION=$(grep '^toolchain ' go.mod | sed 's/toolchain go//') + + # Use the toolchain version if present, otherwise use go directive version + TARGET_GO_VERSION="${TOOLCHAIN_VERSION:-$GO_VERSION}" + + # IMPORTANT: GOTOOLCHAIN requires a full patch version (e.g., go1.25.0, not go1.25) + # If the version has no patch component, append .0 + if [[ "$TARGET_GO_VERSION" =~ ^[0-9]+\.[0-9]+$ ]]; then + TARGET_GO_VERSION="${TARGET_GO_VERSION}.0" + fi + + echo "Repo targets Go version: $TARGET_GO_VERSION" + echo "Local Go: $(go version)" + echo "Running govulncheck with GOTOOLCHAIN=go${TARGET_GO_VERSION}..." + + # Run govulncheck with the matching toolchain + # Go will automatically download the correct toolchain version + GOTOOLCHAIN="go${TARGET_GO_VERSION}" govulncheck -show verbose ./... 2>&1 + ``` + + **Why GOTOOLCHAIN?** + - Forces govulncheck to compile and analyze against the EXACT Go stdlib version the repo targets + - Go automatically downloads the matching toolchain if not already installed locally + - No Docker dependency required — uses Go's built-in toolchain management + - Produces accurate results for stdlib CVEs (crypto/tls, net/url, crypto/x509, etc.) + - **Without this**: A local Go 1.26 would show 0-1 stdlib CVEs. **With this**: the same repo shows 12+ stdlib CVEs correctly + + **Example of the difference:** + ``` + # WITHOUT GOTOOLCHAIN (local Go 1.26.0, repo targets Go 1.25): + # → "Your code is affected by 1 vulnerability" (only module-level, misses all stdlib CVEs) + + # WITH GOTOOLCHAIN=go1.25.0: + # → "Your code is affected by 14 vulnerabilities" (correctly detects all stdlib CVEs) + # → Includes: crypto/tls, crypto/x509, net/url, net/http, encoding/asn1, etc. + ``` + + **For Go projects — build_location support:** + ```bash + # If the mapping specifies a build_location (e.g., "maas-api/"), cd into it first + BUILD_LOCATION="${BUILD_LOCATION:-.}" # Default to root if not specified + cd "$BUILD_LOCATION" + + # Then run govulncheck with matching toolchain + GOTOOLCHAIN="go${TARGET_GO_VERSION}" govulncheck -show verbose ./... + ``` + + **For Node.js projects:** + ```bash + # npm audit uses the lockfile and doesn't depend on local Node version + # GOTOOLCHAIN is not needed for Node.js + npm audit --json 2>/dev/null | grep -i "CVE-YYYY-XXXXX" + ``` + + **For Python projects:** + ```bash + # pip-audit checks against the vulnerability database + pip-audit -r requirements.txt 2>/dev/null | grep -i "CVE-YYYY-XXXXX" + ``` + + **Fallback (if GOTOOLCHAIN download fails):** + ```bash + # If GOTOOLCHAIN fails (e.g., network issues, unavailable version), fall back to local + if ! GOTOOLCHAIN="go${TARGET_GO_VERSION}" govulncheck -show verbose ./... 2>/tmp/govulncheck-err.txt; then + echo "āš ļø WARNING: GOTOOLCHAIN=go${TARGET_GO_VERSION} failed. Falling back to local Go toolchain." + echo "āš ļø Results may have false negatives for stdlib CVEs." + echo "āš ļø Error: $(cat /tmp/govulncheck-err.txt | head -3)" + echo "āš ļø Local Go: $(go version) | Repo target: go${TARGET_GO_VERSION}" + govulncheck -show verbose ./... 2>&1 + fi + ``` + + **5.2: Analyze Scan Results** + + - Check if the target CVE appears in the scan results + - **If CVE has already been fixed (not present in scan results)**: + - **DO NOT create a PR** — the vulnerability is already resolved + - **Print to stdout**: "āœ… CVE-YYYY-XXXXX is already fixed in [repository] ([branch]). No action needed." + - **Document in artifacts**: Create a brief note in `artifacts/cve-fixer/fixes/already-fixed-CVE-YYYY-XXXXX.md` with: + - CVE ID + - Repository and branch checked + - Scan results showing CVE is not present + - Timestamp of verification + - Note that Jira ticket may need manual closure + - **Move to next CVE**: Skip all remaining steps for this CVE and proceed to the next one + - **Note**: The Jira ticket may still be open — this is an issue management task, not a code fix task + - Only proceed with remaining steps for CVEs that are confirmed as current vulnerabilities in the scan + + **5.3: Check for Existing Open PRs** + + - **CRITICAL**: Before creating a new fix, check if someone (or a previous automation run) has already opened a PR that addresses this CVE + - **Why**: Duplicate PRs waste reviewer time and create confusion. If a PR already exists, the work is in progress — skip to the next CVE. + - **This check runs AFTER the vulnerability scan** (Step 5.2), because if the CVE is already fixed in the branch, there's no need to check for PRs at all + - **IMPORTANT**: Use `--base` to scope the search to the specific target branch to avoid false positives from PRs targeting other branches + + **How to check:** + + ```bash + REPO_FULL="opendatahub-io/models-as-a-service" # org/repo from mapping + CVE_ID="CVE-YYYY-XXXXX" + TARGET_BRANCH="main" # from mapping or user input + + # Search open PRs for this specific CVE ID targeting this branch + EXISTING_PR=$(gh pr list --repo "$REPO_FULL" --state open --base "$TARGET_BRANCH" --search "$CVE_ID" --json number,title,url,headRefName,baseRefName --jq '.[0]' 2>/dev/null) + + if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then + PR_NUMBER=$(echo "$EXISTING_PR" | jq -r '.number') + PR_TITLE=$(echo "$EXISTING_PR" | jq -r '.title') + PR_URL=$(echo "$EXISTING_PR" | jq -r '.url') + echo "ā­ļø Skipping $CVE_ID — existing open PR found:" + echo " PR #${PR_NUMBER}: ${PR_TITLE}" + echo " URL: ${PR_URL}" + + # Document the skip + cat > "artifacts/cve-fixer/fixes/existing-pr-$CVE_ID-$TARGET_BRANCH.md" <" + - **Document in artifacts**: Create a brief note in `artifacts/cve-fixer/fixes/existing-pr-CVE-YYYY-XXXXX-$TARGET_BRANCH.md` + - **Move to next CVE**: Skip all remaining steps for this CVE in this repository + - **If NO open PR is found:** + - Proceed with the fix (Step 6 onwards) + + **Search strategy:** + - Search by exact CVE ID first (e.g., `CVE-2025-61726`) — this is the most reliable match + - The `gh pr list --search` command searches PR titles and bodies + - A single PR may address multiple CVEs (e.g., "fix: cve-2025-61726 and cve-2025-68121") — if ANY of the target CVEs appear in an existing PR, consider all CVEs in that PR as already handled + - **IMPORTANT: Only skip for OPEN PRs.** Closed or merged PRs should be ignored — if a previous PR was closed without merging (e.g., it was incorrect or superseded), it is valid to create a new fix PR for the same CVE. The `--state open` flag in the `gh pr list` command ensures only open PRs are checked. + - **Stale remote branches**: A previous automation run may have left a remote branch with the same name (e.g., `fix/cve-YYYY-XXXXX-attempt-1`) from a closed PR. If push fails due to a conflicting remote branch, increment the attempt number (e.g., `attempt-2`) or delete the stale remote branch with `git push origin --delete ` before pushing. + + **Example output when PR exists:** + ``` + ā­ļø Skipping CVE-2025-61726 — existing open PR found: + PR #227: fix: cve-2025-61726 and cve-2025-68121 in go stdlib + URL: https://github.com/red-hat-data-services/models-as-a-service/pull/227 + + ā­ļø Skipping CVE-2025-68121 — existing open PR found: + PR #227: fix: cve-2025-61726 and cve-2025-68121 in go stdlib + URL: https://github.com/red-hat-data-services/models-as-a-service/pull/227 + ``` + +6. **Analyze Breaking Changes & Dependency Compatibility** + - **CRITICAL**: Before applying fixes, analyze dependency compatibility + - Check if security fix version is compatible with current dependencies + - Example: If fixing Starlette CVE, check FastAPI compatibility + - Use AI agent or manual research to identify: + - Dependency version conflicts + - Required co-upgrades (e.g., upgrading both FastAPI and Starlette) + - Breaking API changes in new versions + - Migration guides or changelogs + - Document all breaking changes and compatibility issues found + - Determine the minimal set of changes needed to resolve conflicts + +7. **Create Feature Branches** + - **CRITICAL**: Create a SEPARATE branch for EACH CVE (not a single combined branch) + - Use consistent naming: `fix/cve-YYYY-XXXXX--attempt-1` + - Where: + - `YYYY-XXXXX` is the CVE ID (e.g., `2023-26115`) + - `` is the affected package name (e.g., `word-wrap`, `cross-spawn`) + - Each branch should contain ONLY the fix for its specific CVE + +8. **Apply Remediations** + + **8.1: Node.js Dependency Updates (PREFERRED: npm Overrides Approach)** + + For Node.js projects with transitive dependency vulnerabilities, use npm `overrides` to create minimal, reviewable PRs: + + **Step 8.1.1: Determine latest fixed version** + ```bash + # Get latest version that fixes the CVE + npm view versions --json | jq -r '.[-1]' + + # Or get latest version in a specific major version range + npm view @^4.0.0 version # Latest 4.x + + # Examples: + npm view form-data@^4.0.0 version # Output: 4.0.4 + npm view word-wrap version # Output: 1.2.5 + npm view cross-spawn@^7.0.0 version # Output: 7.0.6 + ``` + + **Step 8.1.2: Add or update override in package.json** + ```bash + # Check if package.json exists (monorepos may have frontend/ or backend/ subdirs) + if [ -f "package.json" ]; then + PACKAGE_JSON="package.json" + elif [ -f "frontend/package.json" ]; then + PACKAGE_JSON="frontend/package.json" + fi + + # Add override using jq (recommended) + jq '.overrides[""] = "^"' "$PACKAGE_JSON" > "${PACKAGE_JSON}.tmp" && mv "${PACKAGE_JSON}.tmp" "$PACKAGE_JSON" + + # Example: Add form-data override to upgrade to 4.0.4 + jq '.overrides["form-data"] = "^4.0.4"' package.json > package.json.tmp && mv package.json.tmp package.json + ``` + + **Step 8.1.3: Install dependencies** + ```bash + # Install dependencies to apply the override + npm install + ``` + + **Step 8.1.4: Verify the fix** + ```bash + # Check that the override was applied + npm list + + # Verify CVE is resolved + npm audit | grep -i "" || echo "CVE resolved" + ``` + + **8.2: Alternative - Direct npm update (Use only if overrides not suitable)** + + Use direct update ONLY when: + - Updating direct dependencies (not transitive) + - npm version < 8.3 (overrides not available) + - Major version upgrade has breaking changes + + ```bash + npm update + ``` + + āš ļø **WARNING**: This may trigger lockfile format upgrades and create large diffs + + **8.3: Python Dependency Updates** + - **Dependency Updates**: Update package versions to patched releases + - Update primary dependency (e.g., `starlette==0.49.1`) + - Update incompatible dependencies (e.g., `fastapi>=0.120.0`) + - Document reason for each change + + **8.4: Go Dependency Updates** + + For Go projects with CVEs in the standard library or dependencies: + + **8.4.1: Go Standard Library CVEs (crypto/tls, net/http, etc.)** + + When fixing CVEs in Go's standard library, update the Go version itself: + + **PREFERRED APPROACH - Direct Version Update**: + ```bash + # Update go.mod to specify the patched Go version directly + # Example: Fixing CVE-2025-68121 (requires Go 1.25.7+) + + # Before: + # go 1.25 + + # After: + # go 1.25.7 + ``` + + **Files to Update**: + 1. **go.mod**: Change `go X.Y` to `go X.Y.Z` (e.g., `go 1.25` → `go 1.25.7`) + 2. **Dockerfile**: Update `ARG GOLANG_VERSION=X.Y` to `ARG GOLANG_VERSION=X.Y.Z` + 3. **Dockerfile.konflux** (if exists): Update `ARG GOLANG_VERSION=X.Y.Z` + + **Example**: + ```bash + # 1. Update go.mod + sed -i 's/^go 1.25$/go 1.25.7/' go.mod + + # 2. Update Dockerfile + sed -i 's/ARG GOLANG_VERSION=1.25$/ARG GOLANG_VERSION=1.25.7/' Dockerfile + + # 3. Update Dockerfile.konflux (if exists) + sed -i 's/ARG GOLANG_VERSION=1.25$/ARG GOLANG_VERSION=1.25.7/' Dockerfile.konflux + ``` + + **Alternative Approach - Toolchain Directive** (NOT RECOMMENDED): + ```go + // Less preferred - more verbose + go 1.25 + toolchain go1.25.7 + ``` + + āš ļø **Use toolchain directive ONLY when**: + - You need to keep language version separate from compiler version + - Project has specific requirements for language version pinning + - Otherwise, use the direct version approach (simpler and clearer) + + **8.4.2: Go Module Dependencies** + + For CVEs in third-party Go modules: + + ```bash + # Update specific dependency to patched version + go get github.com/vulnerable/package@v1.2.3 + + # Update all dependencies + go get -u ./... + + # Tidy dependencies + go mod tidy + ``` + + **8.5: Other Remediation Types** + - **Code Patches**: Apply vendor-provided patches or security fixes + - **Code Refactoring**: Rewrite vulnerable code patterns securely + - **Configuration Changes**: Adjust settings to mitigate vulnerabilities + - **Compensating Controls**: Add input validation, sanitization, or access controls + +9. **Document Changes & Breaking Change Report** + - Create comprehensive fix implementation document + - **Breaking Change Analysis Section**: + - List all dependency version changes + - Document compatibility issues found and resolved + - Explain why each dependency was upgraded + - Note any API breaking changes in upgraded dependencies + - Provide migration guidance if needed + - Record which CVEs each change addresses + - List all Jira issues resolved by this fix + - Document testing performed to validate the fix + - **If using npm overrides approach**: + - Note that package.json overrides section was updated + - Explain that this forces all transitive dependencies to use the fixed version + - Document why this approach was chosen over direct update + - Create detailed commit message with: + - CVE ID and description + - Fix method (npm overrides vs direct update) + - Version upgrade details (e.g., "3.0.1 → 4.0.4 via npm overrides") + - Breaking changes summary + - Jira issue references + - Co-authored-by for AI assistance + +10. **Discover and Run Tests** + - Run existing tests before creating PRs to verify fixes don't break functionality + - Always attempt test discovery and execution. Results are documented in the PR but do not block PR creation. + - If tests can't run (missing tools, version mismatch, etc.), document the actual error message + + **Step 10.1: Discover Test Configuration** + + Look for common test indicators in the repository: + + ```bash + # Check for test scripts in package.json (Node.js) + if [ -f "package.json" ]; then + jq -r '.scripts | keys[] | select(test("test|spec|check"))' package.json + fi + + # Check for Python test configurations + find . -maxdepth 2 -name "pytest.ini" -o -name "tox.ini" -o -name ".pytest.ini" + + # Check for test directories + find . -maxdepth 3 -type d -name "test" -o -name "tests" -o -name "__tests__" -o -name "spec" + + # Check for common test files + find . -name "*test*.py" -o -name "test_*.py" -o -name "*_test.py" | head -n 5 + find . -name "*.test.js" -o -name "*.spec.js" -o -name "*.test.ts" | head -n 5 + + # Check for CI configuration (may indicate test commands) + ls .github/workflows/*.yml .gitlab-ci.yml Makefile 2>/dev/null + ``` + + **Step 10.2: Identify Test Commands** + + Based on project type and configuration, identify test commands: + + **Node.js/JavaScript:** + ```bash + npm test # Most common + npm run test:unit + yarn test + pnpm test + ``` + + **Python:** + ```bash + pytest + pytest tests/ + python -m pytest + python -m unittest discover + tox + make test + ``` + + **Go:** + ```bash + go test ./... + make test + ``` + + **Ruby:** + ```bash + bundle exec rspec + rake test + ``` + + **Rust:** + ```bash + cargo test + ``` + + **Step 10.3: Run Tests (with timeout and failure handling)** + + - Set reasonable timeout (e.g., 10 minutes for unit tests) + - Capture stdout and stderr + - Don't fail the workflow if tests fail - document it instead + + ```bash + # Create test results directory + mkdir -p artifacts/cve-fixer/fixes/test-results + + # Run tests with timeout and capture output + TEST_OUTPUT_FILE="artifacts/cve-fixer/fixes/test-results/test-run-$(date +%Y%m%d-%H%M%S).log" + + # Example: Node.js + timeout 600 npm test > "$TEST_OUTPUT_FILE" 2>&1 + TEST_EXIT_CODE=$? + + # Example: Go + go test ./... > "$TEST_OUTPUT_FILE" 2>&1 + TEST_EXIT_CODE=$? + + # Capture results + if [ $TEST_EXIT_CODE -eq 0 ]; then + echo "āœ… Tests passed" | tee -a "$TEST_OUTPUT_FILE" + TEST_STATUS="PASSED" + elif [ $TEST_EXIT_CODE -eq 124 ]; then + echo "ā±ļø Tests timed out after 10 minutes" | tee -a "$TEST_OUTPUT_FILE" + TEST_STATUS="TIMEOUT" + else + echo "āŒ Tests failed with exit code $TEST_EXIT_CODE" | tee -a "$TEST_OUTPUT_FILE" + # Check if it's a version mismatch + if grep -q "go.mod requires go >=" "$TEST_OUTPUT_FILE"; then + echo "ā„¹ļø Version mismatch detected - this validates the fix" | tee -a "$TEST_OUTPUT_FILE" + TEST_STATUS="VERSION_MISMATCH" + else + TEST_STATUS="FAILED" + fi + fi + ``` + + **Step 10.4: Handle Test Results** + + Document the outcome and proceed to PR creation regardless of result: + + | Result | Action | + |--------|--------| + | **PASSED** | Note success in PR description | + | **FAILED** | Include failure summary in PR with warning | + | **NO_TESTS** | Add "manual testing required" to PR checklist | + | **COULD_NOT_RUN** | Document the error in PR description | + | **VERSION_MISMATCH** | Note this validates the fix -- version enforcement works | + + All outcomes proceed to PR creation. Test results are informational, not blocking. + + **Step 10.5: Generate Test Summary** + + Create a test summary section for the PR: + + ```markdown + ## Test Results + + **Status**: āœ… PASSED | āŒ FAILED | āš ļø NO TESTS FOUND | āš ļø COULD NOT RUN + + **Tests discovered**: Yes/No + **Test command**: `npm test` | `pytest` | etc. + **Exit code**: 0 (success) | non-zero (failure) + **Duration**: 2m 34s + + ### Summary + - Total tests: X + - Passed: Y + - Failed: Z + - Skipped: W + + ### Details + [Brief summary or link to full test output] + + **Note**: Full test output available in CI/CD pipeline after PR creation. + ``` + + **Step 10.6: Document in Fix Implementation Report** + + Add test results to the fix implementation report: + + ```markdown + ## Pre-PR Test Execution + + **Test Discovery**: Tests found in `tests/` directory + **Test Framework**: pytest + **Test Command**: `pytest tests/` + **Execution Time**: 2m 34s + **Result**: PASSED āœ… + + **Test Output** (last 50 lines): + ``` + [test output] + ``` + + **Full test log**: `artifacts/cve-fixer/fixes/test-results/test-run-20260218-143022.log` + ``` + +11. **Create Pull Requests** + - **CRITICAL**: You MUST actually CREATE the PRs using `gh pr create` command + - **CRITICAL**: Create a SEPARATE PR for EACH CVE (NOT combined) + - **CRITICAL**: Only create PRs for CVEs that were ACTUALLY FIXED (not for CVEs that were already fixed in Step 5) + - For each CVE fix that was successfully committed and pushed: + - Generate PR title: `Security: Fix CVE-YYYY-XXXXX ()` + - **Extract Jira issue IDs for this CVE:** + - **If Jira issue IDs were provided explicitly in Step 1 (Option A)**: + - Use the Jira issue IDs that were already extracted from user input in Step 1 + - Do NOT re-read or re-parse the `/cve.find` output + - These IDs were already associated with the CVE during initial processing + - **If using `/cve.find` output (Option B)**: + - Read the latest `/cve.find` output from `artifacts/cve-fixer/find/` + - Search for all Jira issues that mention this specific CVE ID in their summary + - Extract the issue IDs (e.g., RHOAIENG-17794, RHOAIENG-16619, etc.) + - Collect all issue IDs for this CVE + - Generate comprehensive PR description with: + - CVE details and severity + - **Test execution results** (from Step 9) + - Breaking change analysis + - Testing recommendations + - Verification steps checklist + - Risk assessment table + - Links to CVE advisories + - **Jira issue references**: List the extracted Jira issue IDs as plain text WITHOUT hyperlinks + - āœ… Correct: `Resolves: RHOAIENG-17794, RHOAIENG-16619, RHOAIENG-16616` + - āŒ Wrong: `Resolves: [RHOAIENG-17794](https://redhat.atlassian.net/browse/RHOAIENG-17794)` + - āŒ Wrong: `Multiple RHOAIENG issues for CVE-2024-21538 across different release branches` + - Do NOT create markdown links for Jira issues + - Do NOT use generic descriptions - list the ACTUAL issue IDs + - Just list the issue IDs separated by commas + - **CREATE** the PR using GitHub CLI (with fallback to GitHub API): + ```bash + # Prepare PR body + PR_BODY=$(cat <<'EOF' +## Summary + +This PR fixes **CVE-YYYY-XXXXX** by upgrading from X.X.X to Y.Y.Y. + +### CVE Details +- **CVE ID**: CVE-YYYY-XXXXX +- **Package**: +- **Severity**: CRITICAL/HIGH/MEDIUM/LOW (CVSS X.X) +- **Impact**: [Description] +- **Vulnerable versions**: X.X.X - X.X.X +- **Fixed version**: Y.Y.Y +- **Jira Issues**: RHOAIENG-XXXXX, RHOAIENG-YYYYY + +### Test Results + +**Status**: āœ… All tests passed | āŒ Some tests failed | āš ļø No tests found + +**Tests discovered**: Yes/No +**Test command**: \`npm test\` | \`pytest\` | \`N/A\` +**Result**: PASSED/FAILED/NOT_RUN +**Duration**: Xm Ys + +
+Test Summary + +- Total: X tests +- Passed: Y +- Failed: Z +- Skipped: W + +
+ + +āš ļø **Note**: Tests failed during pre-PR validation. Review failures before merging. + + +āš ļø **Note**: No automated tests found. Manual testing required. + +### Breaking Changes +[Breaking change details] + +### Testing Checklist + +- [x] Pre-PR automated tests executed +- [ ] Verify CVE is resolved with security scan +- [ ] Test affected functionality manually +- [ ] Review test failures (if any) + +### Risk Assessment +[Risk assessment table] + +--- + +šŸ¤– Generated by CVE Fixer Workflow +EOF +) + + gh pr create \ + --base \ + --title "Security: Fix CVE-YYYY-XXXXX ()" \ + --body "$PR_BODY" + ``` + - Capture the PR URL from the command output + - Save PR URL to fix implementation report + - Create summary of all PRs created in `artifacts/cve-fixer/fixes/pr-creation-summary.md` + - **VERIFY**: Confirm all PRs were successfully created by listing them (use `gh pr list --repo ` if available, or check via GitHub web interface) + - **CRITICAL - Console Output**: When printing PR URLs to the user (in the final summary or anywhere in stdout), ALWAYS use the full URL (e.g., `https://github.com/org/repo/pull/123`), NOT just the PR number or a markdown link. The user needs to be able to click or copy the full URL directly from the terminal. + +--- +> **END per-repository loop. Return to Step 5 for next repository.** +--- + +12. **Cleanup Temporary Repositories** + - After all repository/CVE processing completes, remove temporary clone directories created under `/tmp/` + - This cleanup must be non-blocking: log failures and continue final reporting + - Include a summary line showing cleaned vs failed cleanup paths + + **Implementation:** + ```bash + echo "=== Cleaning up temporary repositories ===" + CLEANED_COUNT=0 + FAILED_COUNT=0 + CLEANED_PATHS=() + FAILED_PATHS=() + + # Find all cloned repositories in /tmp with .git directories + for REPO_DIR in /tmp/*/*/.git; do + if [ -d "$REPO_DIR" ]; then + PARENT_DIR=$(dirname "$REPO_DIR") + echo "Removing $PARENT_DIR..." + if rm -rf "$PARENT_DIR" 2>/dev/null; then + CLEANED_COUNT=$((CLEANED_COUNT + 1)) + CLEANED_PATHS+=("$PARENT_DIR") + else + echo " āš ļø Failed to remove $PARENT_DIR" + FAILED_COUNT=$((FAILED_COUNT + 1)) + FAILED_PATHS+=("$PARENT_DIR") + fi + fi + done + + echo "" + echo "Cleanup complete: $CLEANED_COUNT directories removed, $FAILED_COUNT failures" + if [ ${#CLEANED_PATHS[@]} -gt 0 ]; then + echo "Cleaned:" + printf ' - %s\n' "${CLEANED_PATHS[@]}" + fi + if [ ${#FAILED_PATHS[@]} -gt 0 ]; then + echo "Failed to clean:" + printf ' - %s\n' "${FAILED_PATHS[@]}" + fi + ``` + +13. **Prepare for Testing** + - **Note**: Basic automated tests have already been run (see Step 10) + - This section is for additional validation and comprehensive testing + - Stage all remediation changes + - Generate fix summary showing before/after state + - Create test plan focusing on: + - Affected functionality not covered by existing tests + - Breaking changes validation + - Integration testing + - Security verification (re-scan for CVE) + - Manual testing scenarios (if automated tests unavailable) + - Document any known risks or rollback procedures + +## Output +- **Fix Implementation Report**: `artifacts/cve-fixer/fixes/fix-implementation-CVE-YYYY-XXXXX.md` + - Detailed log of all changes made + - Breaking change analysis with dependency compatibility details + - Complete list of files changed + - Pre-PR test execution results + - Testing recommendations + - Risk assessment + - Jira issue references + - PR URL for the created pull request + +- **Already Fixed Report**: `artifacts/cve-fixer/fixes/already-fixed-CVE-YYYY-XXXXX.md` (if CVE was already fixed) + - CVE ID and repository checked + - Scan results showing CVE is not present + - Timestamp of verification + - Note about Jira ticket requiring manual closure + +- **Existing PR Report**: `artifacts/cve-fixer/fixes/existing-pr-CVE-YYYY-XXXXX.md` (if an open PR already exists) + - CVE ID, repository, and branch + - Existing PR number, title, and URL + - Timestamp of check + - Note that fix is already in progress + +- **Test Results**: `artifacts/cve-fixer/fixes/test-results/test-run-TIMESTAMP.log` + - Full test execution output + - Test framework output (pytest, jest, etc.) + - Success/failure details + - Execution duration + +- **PR Summary**: `artifacts/cve-fixer/fixes/pr-creation-summary.md` + - List of all PRs created (one per CVE per repository) + - PR URLs, branch names, and target repositories + - Indication of upstream vs downstream PRs + - Test status for each PR + - Quick reference for tracking fixes across all repositories + - Note of any CVEs skipped because they were already fixed or have existing open PRs + +- **Updated Code**: Changes applied directly to codebase in feature branch + - Modified dependency files (pyproject.toml, package.json, etc.) + - Updated dependency lock files as needed + +- **Created Pull Requests**: One PR per CVE per repository on GitHub + - Separate PR for each CVE fix in each repository + - PRs created on all target repositories (upstream and downstream) + - Each PR contains comprehensive description with test results and testing checklist + +- **Console Summary**: Print a final summary to the user with: + - Full PR URLs (e.g., `https://github.com/org/repo/pull/123`) — NOT shortened markdown links + - Already-fixed CVEs and why they were skipped + - CVEs skipped due to existing open PRs (with the existing PR URL) + - Test results per repository + - The user must be able to copy/click PR URLs directly from the terminal output + +## Usage Examples + +Fix all open CVEs from /cve.find output (default): +``` +/cve.fix +``` + +Fix specific Jira issue: +``` +/cve.fix RHOAIENG-4973 +``` + +Fix multiple specific Jira issues: +``` +/cve.fix RHOAIENG-4973 RHOAIENG-5821 +``` + +Fix with custom message: +``` +/cve.fix Fix open CVEs found in latest scan +``` + +**How it works**: +- If you provide Jira issue IDs (e.g., RHOAIENG-XXXXX), the workflow will fix those specific issues +- If you don't provide Jira IDs, the workflow will: + 1. Read the latest `/cve.find` output + 2. Extract all CVEs with `Status: Open` + 3. Create separate PRs for each open CVE + 4. Verify each CVE actually exists in the repository before fixing + +## Detailed Workflow Example + +### Example: Fixing Go stdlib CVEs for "Model as a Service" + +1. **Load**: Read latest `/cve.find` output -- 2 CVEs (CVE-2025-61729, CVE-2025-68121) +2. **Map**: Look up "Model as a Service" in `component-repository-mappings.json` -- 2 repos (upstream: opendatahub-io/models-as-a-service, downstream: red-hat-data-services/models-as-a-service) +3. **Clone**: Clone both repos to `/tmp/opendatahub-io/...` and `/tmp/red-hat-data-services/...` +4. **Load guidance**: Read `.cve-fix/` from both repos +5. **For each repo**: + - Scan with `GOTOOLCHAIN=go1.25.0 govulncheck ./...` -- confirms CVEs present + - Check for existing PRs with `gh pr list --search "CVE-2025-68121"` + - Fix: update `go 1.25` to `go 1.25.7` in go.mod + Dockerfiles + - Run `go test ./...` + - Commit, push branch `fix/cve-2025-68121-go-stdlib-attempt-1` + - Create PR with `gh pr create` +6. **Summary**: 2 PRs created (one per repo), test results documented + +## Success Criteria + +After running this command, you should have: +- [ ] Component-repository mapping loaded and repositories identified +- [ ] CVE presence verified in each repository (not applied blindly) +- [ ] Already-fixed CVEs identified and documented (no PRs created for these) +- [ ] Existing open PRs checked — CVEs with in-progress PRs skipped (no duplicates created) +- [ ] Repository-specific fix guidance loaded if `.cve-fix/examples.md` exists +- [ ] Feature branches created for each CVE that needs fixing +- [ ] Breaking change analysis completed and documented +- [ ] Dependency compatibility issues identified and resolved +- [ ] Code changes that remediate targeted CVEs +- [ ] Updated dependencies to non-vulnerable versions +- [ ] Tests discovered and executed (if available) +- [ ] Test results documented in fix reports +- [ ] Comprehensive fix implementation report created for each CVE that was fixed +- [ ] Already-fixed reports created for CVEs that were already resolved +- [ ] Commits created with detailed CVE fix messages +- [ ] Changes pushed to feature branches +- [ ] **Pull requests created on GitHub with test results (one PR per CVE that was fixed)** +- [ ] PR URLs saved to fix implementation reports +- [ ] PR summary file generated with all created PRs, skipped CVEs, and existing open PRs + +## Next Steps + +After completing this phase: +1. Run `/cve.verify` to test that fixes work and CVEs are resolved +2. Or review the fix implementation in `artifacts/cve-fixer/fixes/` + +## Notes + +### Component-Repository Mapping File +- **Location**: `component-repository-mappings.json` in workspace root +- **Purpose**: Maps Jira components to GitHub repositories and their branch strategies +- **CRITICAL**: Always verify CVE presence in repositories before applying fixes + - Don't blindly apply fixes to all repositories in a component mapping + - Clone and search each repository for the vulnerable dependency + - Filter the repository list to only those that contain the CVE +- **Multi-Repository Support**: A single component can map to MULTIPLE repositories + - Common pattern: an **upstream** repo (e.g., `opendatahub-io/models-as-a-service`) and one or more **downstream** repos (e.g., `red-hat-data-services/models-as-a-service`) + - Each repository has its own `default_branch`, `cve_fix_workflow`, and `repo_type` + - The `repo_type` field can be `"upstream"` or `"downstream"` to indicate the relationship + - When fixing CVEs, iterate through ALL repositories for the component and apply fixes to each one independently + - Downstream repos often track different branches (e.g., `rhoai-3.0`) than upstream (`main`) + - Each repository gets its own clone directory, feature branch, verification, test run, and PR +- **Mapping File Structure**: + ```json + { + "components": { + "Component Name": { + "container_to_repo_mapping": { ... }, + "repositories": { + "org/repo-upstream": { + "default_branch": "main", + "active_release_branches": [...], + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "..." + }, + "repo_type": "upstream" + }, + "org/repo-downstream": { + "default_branch": "rhoai-3.0", + "active_release_branches": ["rhoai-3.0"], + "cve_fix_workflow": { + "primary_target": "rhoai-3.0", + "backport_targets": "rhoai-3.0" + }, + "repo_type": "downstream" + } + } + } + } + } + ``` +- **If Component Not in Mapping**: + - Ask user to provide repository information manually + - Optionally offer to update the mapping file with the new component + +### npm Overrides Approach (Recommended for Node.js) +- **PREFERRED** method for fixing transitive dependency CVEs in Node.js projects +- Uses npm's `overrides` feature (requires npm 8.3+) to force specific versions +- **Benefits**: + - Minimal, reviewable PRs (only package.json + dependency updates) + - Upgrades to latest fixed version (not just patch) + - Forces consistent version across entire dependency tree + - Easier to review than direct dependency updates +- **When to use**: + - āœ… Fixing transitive (indirect) dependencies + - āœ… Want minimal, clean PRs + - āœ… npm version >= 8.3 + - āœ… Latest major version is safe to use +- **When NOT to use**: + - āŒ Updating direct dependencies (use normal package.json update) + - āŒ npm version < 8.3 (use `npm update` instead) + - āŒ Latest major version has breaking changes (use specific version override) +- **Example**: + ```json + // package.json + "overrides": { + "form-data": "^4.0.4", // Forces ALL transitive uses to 4.0.4+ + "word-wrap": "^1.2.5" // Fixes CVE-2023-26115 + } + ``` +### Pre-PR Testing Strategy +- **Automatic test discovery**: Workflow attempts to find and run tests automatically +- **Non-blocking**: Test failures don't prevent PR creation +- **Why run tests before PR?** + - Catch obvious breaking changes early + - Provide immediate feedback to reviewers + - Reduce CI/CD iteration time + - Show test impact directly in PR description + +- **Test discovery order**: + 1. Check package.json scripts (Node.js) + 2. Look for test configuration files (pytest.ini, etc.) + 3. Scan for test directories (tests/, __tests__, spec/) + 4. Check CI/CD configs for test commands + +- **Handling test failures**: + - Document failures clearly in PR + - Still create PR (CVE fix may be correct, tests may have pre-existing issues) + - Add warning in PR description + - Let reviewers decide if failures are related to fix + +- **No tests found**: + - Document this clearly + - Request manual testing in PR + - Not uncommon for some repositories + +- **Test execution limits**: + - 10-minute timeout for test runs + - Only run quick unit/integration tests + - Skip slow E2E or performance tests + - Full test suite runs in CI/CD after PR creation + +### Breaking Change Analysis +- **ALWAYS** analyze dependency compatibility before applying fixes +- Security patches may require co-upgrading dependent packages +- Use AI agents to research compatibility when uncertain +- Document ALL breaking changes, even if minor +- Examples of common breaking changes: + - Starlette 0.49.1 requires FastAPI 0.120+ (incompatible with 0.115.x) + - Django security patches may require database migrations + - Node.js package updates may require TypeScript type updates + +### Dependency Conflicts +- If a security fix creates a dependency conflict, you MUST upgrade other packages +- Example: Upgrading Starlette to fix CVE requires upgrading FastAPI +- Document the dependency chain that required the upgrade +- Explain in the PR why additional packages were upgraded + +### Testing Strategy +- Always test fixes in non-production environment first +- Some fixes may require application code changes beyond dependency updates +- Watch for breaking changes when upgrading major versions +- Consider backward compatibility requirements for APIs +- Keep fixes focused; batch related CVEs but avoid mixing unrelated changes + +### Commit Messages +- Include CVE ID in commit title +- Document breaking changes in commit body +- Reference Jira issues being resolved (plain text IDs, no hyperlinks) + - Example: `Resolves RHOAIENG-17794, RHOAIENG-427` +- Add Co-Authored-By for AI agent assistance diff --git a/workflows/cve-fixer/.claude/settings.json b/workflows/cve-fixer/.claude/settings.json new file mode 100644 index 00000000..b8c99b8f --- /dev/null +++ b/workflows/cve-fixer/.claude/settings.json @@ -0,0 +1,15 @@ +{ + "permissions": { + "allow": [ + "Bash", + "Read", + "Write", + "Edit", + "WebSearch", + "WebFetch" + ], + "deny": [ + "Bash(rm)" + ] + } +} diff --git a/workflows/cve-fixer/.gitignore b/workflows/cve-fixer/.gitignore new file mode 100644 index 00000000..46c76b6d --- /dev/null +++ b/workflows/cve-fixer/.gitignore @@ -0,0 +1,2 @@ +# CVE Fixer Artifacts - generated output, not tracked in repo +artifacts/cve-fixer/ diff --git a/workflows/cve-fixer/FIELD_REFERENCE.md b/workflows/cve-fixer/FIELD_REFERENCE.md new file mode 100644 index 00000000..e45dc14c --- /dev/null +++ b/workflows/cve-fixer/FIELD_REFERENCE.md @@ -0,0 +1,212 @@ +# CVE Fixer - Field Reference + +This document provides detailed information about the configuration fields in `.ambient/ambient.json`. + +## Required Fields + +### name +- **Type:** string +- **Purpose:** Display name shown in ACP UI +- **Current Value:** "CVE Fixer" +- **Guidelines:** Keep concise (2-5 words), use title case + +### description +- **Type:** string +- **Purpose:** Explains workflow purpose in UI +- **Current Value:** "Automate remediation of CVE issues reported by ProdSec team in Jira by creating pull requests with dependency updates and patches" +- **Guidelines:** 1-3 sentences, clear and specific about workflow capabilities + +### systemPrompt +- **Type:** string +- **Purpose:** Defines AI agent's role and behavior throughout the workflow +- **Current Value:** See `.ambient/ambient.json` +- **Guidelines:** + - Start with clear role definition (e.g., "You are a CVE remediation assistant...") + - List key responsibilities using bullet points + - Document workflow methodology with numbered phases + - Reference all available slash commands with brief descriptions + - Specify exact output locations for artifacts + - Include first-time setup instructions + +### startupPrompt +- **Type:** string +- **Purpose:** Initial message shown when workflow activates +- **Current Value:** See `.ambient/ambient.json` +- **Guidelines:** + - Greet user warmly and introduce the workflow purpose + - List available commands with brief descriptions + - Provide clear call-to-action for getting started + - Keep concise but informative + +## Optional Fields + +### results +- **Type:** object with string values +- **Purpose:** Maps artifact types to file path patterns +- **Current Value:** See `.ambient/ambient.json` +- **Guidelines:** + - Use glob patterns to match multiple files + - Organize by artifact type for easy discovery + - Ensure paths match those referenced in commands and systemPrompt + +**Current Mappings:** +```json +{ + "Jira CVE Issues": "artifacts/cve-fixer/find/**/*.md", + "Fix Implementations": "artifacts/cve-fixer/fixes/**/*" +} +``` + +### version +- **Type:** string +- **Example:** "1.0.0" +- **Purpose:** Track workflow configuration version for updates and compatibility + +### author +- **Type:** string or object +- **Example:** `{"name": "Your Name", "email": "security@example.com"}` +- **Purpose:** Identify workflow creator and maintainer + +### tags +- **Type:** array of strings +- **Example:** `["security", "cve", "vulnerability", "remediation"]` +- **Purpose:** Categorize workflow for discovery and organization + +### icon +- **Type:** string (emoji) +- **Example:** "šŸ”’" +- **Purpose:** Visual identifier in workflow selection UI + +## Customization Examples + +### Adding a new output type + +If you want to track additional artifacts (e.g., "Test Results"): + +```json +"results": { + "Jira CVE Issues": "artifacts/cve-fixer/find/**/*.md", + "Fix Implementations": "artifacts/cve-fixer/fixes/**/*", + "Test Results": "artifacts/cve-fixer/tests/**/*.log" +} +``` + +### Changing artifact location + +To use a different base directory (e.g., `security-artifacts/`): + +1. Update `systemPrompt` OUTPUT LOCATIONS section: +``` +OUTPUT LOCATIONS: +- Create all Jira CVE findings in: security-artifacts/cve-fixer/find/ +- Create all fix implementations in: security-artifacts/cve-fixer/fixes/ +``` + +2. Update `results` paths: +```json +"results": { + "Jira CVE Issues": "security-artifacts/cve-fixer/find/**/*.md", + "Fix Implementations": "security-artifacts/cve-fixer/fixes/**/*" +} +``` + +3. Update all command files in `.claude/commands/` to reference new paths in their ## Output sections + +### Adding environment configuration + +```json +"environment": { + "ARTIFACTS_DIR": "artifacts/cve-fixer", + "SCAN_TOOLS": "snyk,npm-audit,trivy", + "LOG_LEVEL": "info" +} +``` + +### Customizing for specific compliance frameworks + +Modify `systemPrompt` to emphasize compliance: + +``` +KEY RESPONSIBILITIES: +- Guide users through the CVE remediation workflow +- Execute slash commands to perform specific security tasks +- Ensure remediations meet SOC2 and PCI-DSS requirements +- Generate audit-ready compliance documentation +... +``` + +## Command Files + +Slash command files are located in `.claude/commands/` and follow this structure: + +```markdown +# /{command-name} - {Description} +## Purpose +## Prerequisites +## Process +## Output +## Usage Examples +## Success Criteria +## Next Steps +## Notes +``` + +**Current Commands:** +- `cve.find.md` - Find CVEs reported in Jira for a component +- `cve.fix.md` - Implement CVE fixes and create pull requests + +## File Naming Conventions + +- **Workflow directory:** `workflows/cve-fixer/` +- **Command files:** `{workflow-prefix}.{phase}.md` (e.g., `cve.find.md`, `cve.fix.md`) +- **Artifacts:** `artifacts/cve-fixer/{category}/{files}` + +## Validation Checklist + +Before using this workflow, verify: + +- [ ] `.ambient/ambient.json` is valid JSON (no comments, no trailing commas) +- [ ] All required fields (name, description, systemPrompt, startupPrompt) are present +- [ ] All command files have unique names and follow naming convention +- [ ] Output paths in `results` match those referenced in `systemPrompt` +- [ ] Output paths in `results` match those in command files' ## Output sections +- [ ] README.md accurately describes the workflow and implemented commands +- [ ] All file references use correct absolute or relative paths + +## Configuration Best Practices + +1. **Keep prompts focused:** systemPrompt should be comprehensive but not overwhelming. Focus on workflow-specific guidance. + +2. **Be specific about outputs:** Always specify exact artifact paths so users know where to find results. + +3. **Maintain consistency:** Ensure artifact paths are identical across ambient.json, systemPrompt, and command files. + +4. **Version your workflow:** Update version field when making significant changes to track evolution. + +5. **Document customizations:** If you modify the workflow, update this FIELD_REFERENCE.md to reflect changes. + +## Troubleshooting Configuration Issues + +**Problem:** Workflow doesn't load in ACP +**Solution:** Validate JSON syntax in `.ambient/ambient.json`. Remove any comments or trailing commas. + +**Problem:** Artifacts aren't being found +**Solution:** Verify paths in `results` match actual output locations. Use glob patterns correctly (`**/*.md` for recursive). + +**Problem:** Commands don't appear +**Solution:** Ensure command files are in `.claude/commands/` and follow naming convention `{prefix}.{phase}.md`. + +## References + +- [ACP Documentation](https://ambient-code.github.io/vteam) +- [Template Workflow](https://github.com/ambient-code/workflows/tree/main/workflows/template-workflow) +- [Workflow Best Practices](https://ambient-code.github.io/vteam/guides/workflows) +- [JSON Schema Validation](https://jsonlint.com/) + +## Support + +For configuration questions or issues: +1. Validate JSON syntax using a JSON linter +2. Review this field reference for proper field usage +3. Check ACP documentation for workflow requirements +4. Open an issue in the repository if problems persist diff --git a/workflows/cve-fixer/README.md b/workflows/cve-fixer/README.md new file mode 100644 index 00000000..04b58855 --- /dev/null +++ b/workflows/cve-fixer/README.md @@ -0,0 +1,238 @@ +# CVE Fixer + +Automate remediation of CVE issues reported by ProdSec team in Jira by creating pull requests with dependency updates and patches. + +## Overview + +This workflow helps you remediate CVE vulnerabilities that have been reported by your Product Security team in Jira. It provides automated tools to: + +1. **Find** - Discover CVE issues already reported in Jira for a specific component +2. **Fix** - Implement remediations and create pull requests automatically + +The workflow is designed for both interactive use and scheduled automation (GitHub Actions, Ambient scheduled sessions). + +## Getting Started + +### Prerequisites + +- **Required:** + - JIRA_API_TOKEN environment variable (for Jira access) + - JIRA_EMAIL environment variable (your Jira account email) + - Git and GitHub CLI (`gh`) installed + - Component-to-repository mapping configured in `component-repository-mappings.json` + +- **Optional:** + - Test suite for regression testing (workflow auto-discovers and runs tests) + - Security scanning tools (govulncheck, npm audit, etc. - auto-installed when needed) + +### Installation + +1. Load this workflow in your ACP session +2. Set up Jira credentials: + ```bash + export JIRA_API_TOKEN="your-token-here" + export JIRA_EMAIL="your-email@redhat.com" + ``` +3. Run `/cve.find` to discover CVE issues from Jira + +## Available Commands + +### `/cve.find` - Find CVEs in Jira + +Discover and catalog CVEs that have been reported by ProdSec team in Jira for a specific component. + +**Usage:** +```bash +/cve.find # Will prompt for component name +/cve.find backend-api # Find CVEs for specific component +/cve.find backend-api --ignore-resolved # Exclude resolved issues +``` + +**Prerequisites:** +- JIRA_API_TOKEN and JIRA_EMAIL environment variables +- Access to Jira instance (https://redhat.atlassian.net) +- jq installed (for JSON parsing) + +**Output:** +- `artifacts/cve-fixer/find/cve-issues-[timestamp].md` - List of Jira CVE issues with metadata + +**Features:** +- Automatically filters out issues marked with ignore patterns in comments +- Supports pagination for components with many CVEs +- Extracts issue metadata (summary, status, priority, created date) +- Groups results by status and priority + +### `/cve.fix` - Implement CVE Fixes + +Implement remediations for CVEs discovered in Jira by creating pull requests with fixes. + +**Usage:** +```bash +/cve.fix # Will prompt for component and Jira issues +/cve.fix RHOAIENG-12345 # Fix specific Jira issue +/cve.fix RHOAIENG-12345,RHOAIENG-12346 # Fix multiple issues +``` + +**What it does:** +1. Maps Jira components to GitHub repositories (upstream/downstream) +2. Clones repositories to `/tmp` (keeps your workspace clean) +3. Verifies CVE presence with version-matched scanning (GOTOOLCHAIN for Go) +4. Checks for existing PRs to avoid duplicates +5. Applies fixes automatically (dependency updates, stdlib upgrades, patches) +6. Discovers and runs tests before creating PRs +7. Creates separate PRs per CVE with comprehensive descriptions +8. Cleans up `/tmp` clones after completion + +**Output:** +- `artifacts/cve-fixer/fixes/fix-implementation-CVE-*.md` - Detailed change logs +- `artifacts/cve-fixer/fixes/pr-creation-summary.md` - Executive summary +- Pull requests created in target repositories + +**Features:** +- **Multi-repository support** - Handles upstream and downstream repos independently +- **Test execution** - Auto-discovers and runs tests (creates PR even if tests fail) +- **Duplicate prevention** - Checks for existing PRs before creating new ones +- **CVE verification** - Only fixes CVEs that actually exist in current code +- **Breaking change analysis** - Documents compatibility impacts in PR description +- **Conventional commits** - Uses standardized commit message format +- **Safety guardrails** - Never force-pushes or commits to protected branches + +## Component-to-Repository Mapping + +The workflow uses `component-repository-mappings.json` to map Jira components to GitHub repositories. Example: + +```json +{ + "Model as a Service": { + "repositories": { + "opendatahub-io/models-as-a-service": { + "github_url": "https://github.com/opendatahub-io/models-as-a-service", + "repo_type": "upstream", + "primary_target": "main", + "build_location": "." + }, + "red-hat-data-services/models-as-a-service": { + "github_url": "https://github.com/red-hat-data-services/models-as-a-service", + "repo_type": "downstream", + "primary_target": "rhoai-2.19", + "build_location": "." + } + } + } +} +``` + +If a component is not mapped, the workflow will prompt you for repository information interactively. + +## Output Artifacts + +All workflow outputs are saved in the `artifacts/cve-fixer/` directory: + +``` +artifacts/cve-fixer/ +ā”œā”€ā”€ find/ # Jira CVE issues found for components +└── fixes/ # Fix implementations, test results, and PR summaries +``` + +## Example Workflow + +```bash +# Step 1: Find CVEs reported by ProdSec in Jira +/cve.find backend-api + +# Step 2: Review the discovered issues in artifacts/cve-fixer/find/ + +# Step 3: Implement fixes and create PRs +/cve.fix RHOAIENG-12345,RHOAIENG-12346 + +# Step 4: Review the created PRs and merge when ready +``` + +## Automation Support + +This workflow is designed for both interactive and automated use: + +### Scheduled Runs (GitHub Actions, Ambient Sessions) +- āœ… Runs fully unattended (no manual approval gates) +- āœ… Creates PRs automatically with comprehensive context +- āœ… Continues on test failures (documents failures in PR) +- āœ… Skips already-fixed CVEs and duplicate PRs +- āœ… Cleans up temporary files automatically + +### Interactive Runs +- āœ… Same behavior as automated runs (consistency) +- āœ… Prints PR URLs to console for easy access +- āœ… Shows summary of created/skipped PRs + +**Why no manual approval?** PRs are the review mechanism - you approve by merging. Bad PRs can simply be closed with no harm done. + +## Safety Guardrails + +See `.claude/CLAUDE.md` for comprehensive safety rules. Key protections: + +- **Never force-pushes** or modifies git history +- **Never commits to protected branches** (main, master, release branches) +- **Only clones to `/tmp`** (never touches your workspace) +- **Always verifies CVE exists** before creating PR +- **Always checks for duplicate PRs** before creating new ones +- **Always attempts test execution** before creating PR +- **Respects ignore patterns** in Jira comments + +## Best Practices + +1. **Run /cve.find periodically** - Track new Jira CVE reports from ProdSec +2. **Review PRs carefully** - Each PR includes test results and breaking change analysis +3. **Keep mappings updated** - Maintain `component-repository-mappings.json` with your repositories +4. **Monitor for ignored CVEs** - Workflow respects ignore patterns like `cve-automation-ignore` +5. **Check artifacts** - All actions are logged in `artifacts/cve-fixer/` for transparency + +## Troubleshooting + +**Problem:** JIRA_API_TOKEN not set +**Solution:** Generate token at https://id.atlassian.com/manage-profile/security/api-tokens and export it + +**Problem:** Component not found in mappings +**Solution:** Workflow will prompt for repository info. Update `component-repository-mappings.json` for future runs + +**Problem:** Tests fail in created PR +**Solution:** This is expected behavior - PR is created with failure details so you can review the fix manually + +**Problem:** CVE not present in scan +**Solution:** Workflow automatically skips and documents in `artifacts/cve-fixer/fixes/already-fixed-CVE-*.md` + +**Problem:** Duplicate PR exists +**Solution:** Workflow automatically detects and skips, documented in `artifacts/cve-fixer/fixes/existing-pr-CVE-*.md` + +## Configuration + +The workflow is configured via `.ambient/ambient.json`: + +- **Name:** CVE Fixer +- **Description:** Automate remediation of CVE issues reported by ProdSec team in Jira +- **Artifact Paths:** + - Jira CVE Issues: `artifacts/cve-fixer/find/**/*.md` + - Fix Implementations: `artifacts/cve-fixer/fixes/**/*` + +## Contributing + +To improve this workflow: +1. Fork the repository +2. Make your changes +3. Test thoroughly with real CVEs +4. Submit a pull request + +## License + +MIT + +## Support + +For issues or questions: +- Open an issue in the repository +- Refer to the [ACP documentation](https://docs.ambient-code.com) + +--- + +**Created with:** ACP Workflow Creator +**Workflow Type:** CVE Remediation +**Version:** 1.0.0 diff --git a/workflows/cve-fixer/component-repository-mappings.json b/workflows/cve-fixer/component-repository-mappings.json new file mode 100644 index 00000000..2f72bdc9 --- /dev/null +++ b/workflows/cve-fixer/component-repository-mappings.json @@ -0,0 +1,387 @@ +{ + "components": { + "AI Core Dashboard": { + "container_to_repo_mapping": { + "odh-dashboard-container": "opendatahub-io/odh-dashboard", + "rhoai/odh-dashboard-rhel8": "opendatahub-io/odh-dashboard", + "rhoai/odh-dashboard-rhel9": "opendatahub-io/odh-dashboard", + "rhoai/odh-mod-arch-gen-ai-rhel9": "opendatahub-io/odh-dashboard", + "rhoai/odh-mod-arch-model-registry-rhel9": "opendatahub-io/odh-dashboard", + "mod-arch-maas": "opendatahub-io/odh-dashboard" + }, + "repositories": { + "opendatahub-io/odh-dashboard": { + "github_url": "https://github.com/opendatahub-io/odh-dashboard", + "default_branch": "main", + "protected_branches": [ + "main", + "rhoai-release", + "odh-release" + ], + "active_release_branches": [ + "v2.29.0-fixes", + "v2.28.0-fixes", + "v2.27.0-fixes" + ], + "branch_strategy": "Fix in main → auto-propagates to stable → rhoai (every 2 hours). Manual cherry-pick to release branches during code freeze.", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "Active vX.X.X-fixes branches for released versions", + "automation": "Auto-sync every 2 hours (main → stable → rhoai)", + "manual_intervention": "Cherry-pick during code freeze or for patch releases" + }, + "repository_type": "monorepo", + "monorepo_packages": { + "packages/gen-ai": "Builds odh-mod-arch-gen-ai container", + "packages/model-registry": "Builds odh-mod-arch-modular-architecture container", + "packages/maas": "Builds mod-arch-maas container", + "packages/kserve": "KServe UI module", + "packages/model-serving": "Model serving UI module" + } + } + } + }, + "Model as a Service": { + "container_to_repo_mapping": { + "rhoai/odh-maas-api-rhel9": "opendatahub-io/models-as-a-service" + }, + "repositories": { + "opendatahub-io/models-as-a-service": { + "github_url": "https://github.com/opendatahub-io/models-as-a-service", + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "build_location": "maas-api/", + "notes": "Upstream repository. Contains maas-api Go application. Builds using Dockerfile.konflux for Red Hat builds.", + "repo_type": "upstream" + }, + "red-hat-data-services/models-as-a-service": { + "github_url": "https://github.com/red-hat-data-services/models-as-a-service", + "default_branch": "rhoai-3.0", + "protected_branches": [], + "active_release_branches": [ + "rhoai-3.0" + ], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "rhoai-3.0", + "backport_targets": "rhoai-3.0", + "automation": "Manual backport from upstream", + "manual_intervention": "Cherry-pick or re-apply fixes from upstream repo" + }, + "build_location": "maas-api/", + "notes": "Downstream Red Hat release repository for maas-api. Fixes from upstream should be backported to rhoai-3.0 branch.", + "repo_type": "downstream" + } + } + }, + "Model Serving": { + "container_to_repo_mapping": { + "odh-modelmesh-runtime-adapter": "opendatahub-io/modelmesh-runtime-adapter", + "rhoai/odh-modelmesh-runtime-adapter-rhel8": "opendatahub-io/modelmesh-runtime-adapter", + "rhoai/odh-modelmesh-runtime-adapter-rhel9": "opendatahub-io/modelmesh-runtime-adapter", + "odh-model-controller": "opendatahub-io/odh-model-controller", + "odh-mm-rest-proxy": "opendatahub-io/odh-model-controller", + "rhoai/odh-model-controller-rhel8": "opendatahub-io/odh-model-controller", + "rhoai/odh-model-controller-rhel9": "opendatahub-io/odh-model-controller", + "rhoai/odh-kserve-controller-rhel9": "opendatahub-io/kserve", + "rhoai/odh-kserve-storage-initializer-rhel9": "opendatahub-io/kserve", + "rhoai/odh-kserve-agent-rhel9": "opendatahub-io/kserve-agent", + "rhoai/odh-kserve-router-rhel9": "opendatahub-io/kserve-router", + "rhoai/odh-llm-d-inference-scheduler-rhel9": "opendatahub-io/llm-d-inference-scheduler", + "rhoai/odh-modelmesh-serving-controller-rhel8": "opendatahub-io/modelmesh" + }, + "repositories": { + "opendatahub-io/modelmesh-runtime-adapter": { + "github_url": "https://github.com/opendatahub-io/modelmesh-runtime-adapter", + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + } + }, + "opendatahub-io/odh-model-controller": { + "github_url": "https://github.com/opendatahub-io/odh-model-controller", + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + } + }, + "opendatahub-io/kserve": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/kserve" + }, + "opendatahub-io/kserve-agent": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/kserve-agent" + }, + "opendatahub-io/kserve-router": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/kserve-router" + }, + "opendatahub-io/llm-d-inference-scheduler": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/llm-d-inference-scheduler" + }, + "opendatahub-io/modelmesh": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/modelmesh" + } + } + }, + "Notebooks Images": { + "container_to_repo_mapping": { + "rhoai/odh-pipeline-runtime-tensorflow-cuda-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-pipeline-runtime-tensorflow-rocm-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-tensorflow-cuda-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-tensorflow-rocm-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-pytorch-cuda-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-pipeline-runtime-pytorch-cuda-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-pytorch-rocm-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-pipeline-runtime-pytorch-rocm-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-codeserver-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-datascience-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-pipeline-runtime-datascience-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-minimal-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-workbench-jupyter-trustyai-py312-rhel9": "opendatahub-io/workbench-images", + "rhoai/odh-pipeline-runtime-minimal-py312-rhel9": "opendatahub-io/workbench-images" + }, + "repositories": { + "opendatahub-io/workbench-images": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/workbench-images" + } + } + }, + "AI Pipelines": { + "container_to_repo_mapping": { + "odh-ml-pipelines-driver-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-api-server-v2-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-launcher-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-persistenceagent-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-scheduledworkflow-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-cache-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-api-server-container": "opendatahub-io/data-science-pipelines", + "odh-data-science-pipelines-runtime-container": "opendatahub-io/data-science-pipelines", + "odh-data-science-pipelines-runtime-generic-container": "opendatahub-io/data-science-pipelines", + "odh-ml-pipelines-viewercontroller-argoworkflow-container": "opendatahub-io/data-science-pipelines", + "rhoai/odh-data-science-pipelines-operator-controller-rhel8": "opendatahub-io/data-science-pipelines-operator", + "odh-data-science-pipelines-argo-argoexec-container": "argoproj/argo-workflows", + "odh-data-science-pipelines-argo-workflowcontroller-container": "argoproj/argo-workflows" + }, + "repositories": { + "opendatahub-io/data-science-pipelines": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/data-science-pipelines" + }, + "opendatahub-io/data-science-pipelines-operator": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/data-science-pipelines-operator" + }, + "argoproj/argo-workflows": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "External dependency - not managed by OpenDataHub", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "N/A", + "automation": "N/A", + "excluded_from_automation": true, + "manual_intervention": "Monitor upstream releases and update dependency version" + }, + "notes": "Third-party dependency managed by Argo project. Excluded from automation - track upstream fixes only.", + "github_url": "https://github.com/argoproj/argo-workflows" + } + } + }, + "Notebooks Server": { + "container_to_repo_mapping": { + "rhoai/odh-notebook-controller-rhel8": "opendatahub-io/kubeflow", + "rhoai/odh-kf-notebook-controller-rhel8": "opendatahub-io/kubeflow", + "rhoai/odh-kf-notebook-controller-rhel9": "opendatahub-io/kubeflow", + "rhoai/odh-notebook-controller-rhel9": "opendatahub-io/kubeflow" + }, + "repositories": { + "opendatahub-io/kubeflow": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/kubeflow" + } + } + }, + "Training Kubeflow": { + "container_to_repo_mapping": { + "rhoai/odh-training-operator-rhel8": "opendatahub-io/training-operator", + "rhoai/odh-training-operator-rhel9": "opendatahub-io/training-operator", + "rhoai/odh-notebook-controller-rhel8": "opendatahub-io/notebooks", + "rhoai/odh-kf-notebook-controller-rhel8": "opendatahub-io/notebooks", + "rhoai/odh-notebook-controller-rhel9": "opendatahub-io/notebooks", + "rhoai/odh-kf-notebook-controller-rhel9": "opendatahub-io/notebooks", + "rhoai/odh-kuberay-operator-controller-rhel9": "opendatahub-io/kuberay-operator-controller", + "rhoai/odh-codeflare-operator-rhel8": "opendatahub-io/codeflare-operator", + "rhoai/odh-codeflare-operator-rhel9": "opendatahub-io/codeflare-operator" + }, + "repositories": { + "opendatahub-io/training-operator": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/training-operator" + }, + "opendatahub-io/notebooks": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/notebooks" + }, + "opendatahub-io/kuberay-operator-controller": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/kuberay-operator-controller" + }, + "opendatahub-io/codeflare-operator": { + "default_branch": "main", + "protected_branches": [], + "active_release_branches": [], + "branch_strategy": "TBD - needs investigation", + "cve_fix_workflow": { + "primary_target": "main", + "backport_targets": "TBD", + "automation": "Unknown", + "manual_intervention": "Unknown" + }, + "github_url": "https://github.com/opendatahub-io/codeflare-operator" + } + } + } + }, + "metadata": { + "description": "Component to repository and branch mappings for CVE fix workflow automation", + "purpose": "Maps RHOAI Jira components to GitHub repositories and their branch strategies for automated CVE patching", + "last_updated": "2026-03-16", + "components_analyzed": 7, + "components_with_branch_info": 1, + "components_pending_branch_analysis": 6 + } +}