diff --git a/.claude/commands/_TEMPLATE.md b/.claude/commands/_TEMPLATE.md new file mode 100644 index 0000000000..f8d8bf51f9 --- /dev/null +++ b/.claude/commands/_TEMPLATE.md @@ -0,0 +1,169 @@ +# /command-name - Brief Description + +## Purpose +[Clear statement of what this command does and why] + +## Prerequisites +- [List all requirements] +- [Dependencies, permissions needed] +- [Tools or configuration required] + +## Usage + +``` +/command-name [arguments] +``` + +## MANDATORY EXECUTION REQUIREMENTS + +**⚠️ CRITICAL: This command specification MUST be followed exactly. NO shortcuts allowed.** + +When executing this command, you MUST: + +1. **Execute ALL steps sequentially** - Steps are numbered 1-N. Execute every single one. +2. **Perform ALL actions listed** - Each step has an "Actions:" section. Execute every action listed. +3. **Display ALL required output** - Each step has "Expected Output" sections. Display the exact format shown. +4. **Make ALL checks specified** - If a step says "check for X, Y, and Z", check all three, not just one. +5. **Use ALL specified tools** - If a step says "Use tool X to do Y", use that exact tool. +6. **Handle ALL error cases** - Follow the error handling instructions in each step. +7. **Generate ALL artifacts** - Create all files, directories, and reports specified. + +**Verification Checklist - MUST complete before marking command as done:** +- [ ] All N steps executed +- [ ] All tools called as specified +- [ ] All files/directories created as specified +- [ ] All output displayed in the exact format shown +- [ ] All reports/artifacts generated + +**If you find yourself thinking "I'll skip this" or "this is similar enough":** +- STOP immediately +- Go back and execute the step exactly as written +- Remember: The user created this specification for a reason + +## Execution Policy + +**Permission Model:** +- **Read-only commands:** Execute without asking permission (`ls`, `cat`, `less`, `head`, `tail`, file reads, directory browsing) +- **Exception:** Ask permission only when reading potentially sensitive files (credentials, tokens, private keys, `.env` files, secrets) +- **Write operations:** Always ask permission for file modifications, deletions, or destructive commands + +## Process + +**Total Steps: N** + +Before starting, acknowledge that you will execute all N steps completely. As you complete each step, mark it in your response with: ✅ Step X/N Complete + +### 1. [Step Name] + +**Objective:** [What this step achieves] + +**Actions:** +- [Specific action to perform] +- [Another specific action] +- [Tool to use: `tool_name` with parameters X, Y] + +**Expected Output:** +``` +[Exact output format to display] +✓ Item 1: Value +✓ Item 2: Value +``` + +**Error Handling:** +- If [condition], then [action] +- Common error: [error message] → Solution: [fix] + +### 2. [Next Step] + +[Continue pattern...] + +## Output + +The command produces: + +1. **Console Output:** [What user sees in real-time] +2. **Files Created:** [List of files] +3. **Artifacts:** [List of artifacts] + +## Success Criteria + +Command is successful when: +- ✓ [Criterion 1] +- ✓ [Criterion 2] +- ✓ [All steps completed] + +## Error Handling + +### Error: [Error Name] + +**Symptom:** +``` +[Error message or indication] +``` + +**Common Causes:** +- [Cause 1] +- [Cause 2] + +**Solution:** +1. [Step 1 to fix] +2. [Step 2 to fix] +3. [Verification step] + +## Examples + +### Successful Execution + +``` +Running /command-name... + +[1/N] [Step name]... +✓ [Output line 1] +✓ [Output line 2] + +[2/N] [Next step]... +✓ [Output] + +... + +✅ Command Complete! + +Next Steps: +1. [Recommended action 1] +2. [Recommended action 2] +``` + +### Execution with Warnings + +``` +Running /command-name... + +[1/N] [Step name]... +⚠ [Warning message] +ℹ️ [Information] + +... +``` + +## Integration with Other Commands + +**Before this command:** +- [Prerequisites] + +**After this command:** +- [Next steps] +- [Related commands] + +## Tips + +1. **[Tip category]:** + - [Specific tip] + - [Usage pattern] + +2. **[Another category]:** + - [Guidance] + +## See Also + +- `/related-command` - [Brief description] +- `file.md` - [Documentation reference] diff --git a/.claude/commands/fix-cve.md b/.claude/commands/fix-cve.md new file mode 100644 index 0000000000..fe6933ac87 --- /dev/null +++ b/.claude/commands/fix-cve.md @@ -0,0 +1,276 @@ +--- +description: Fix CVE vulnerabilities in the Notebooks repository +--- + +# /fix-cve - CVE Resolution Command + +## Purpose + +Execute the **complete CVE resolution workflow** autonomously — from assignment through fix, PR creation, Jira updates, logging, and Slack summary. **No questions asked.** + +## Prerequisites + +- Jira MCP configured — see [docs/claude-mcp.md](../../docs/claude-mcp.md) +- GitHub access for PR creation +- Write access to the notebooks repository +- Full guide: [docs/cves/cve-developer-guide.md](../../docs/cves/cve-developer-guide.md) + +## Usage + +``` +/fix-cve # Full workflow - assign AND fix top CVEs +/fix-cve plan # Same as above - full workflow +/fix-cve # Fix a specific CVE ticket +/fix-cve status # Show status of assigned CVEs +``` + +--- + +## ⚠️ CRITICAL: FULLY AUTONOMOUS EXECUTION + +**THIS IS THE MOST IMPORTANT SECTION. FOLLOW EXACTLY.** + +### NEVER Ask Questions - Just Execute + +When this command is invoked, execute the **ENTIRE workflow** without stopping: + +❌ **NEVER ASK:** +- "Would you like me to proceed?" +- "Should I assign these tickets?" +- "Would you like me to create a PR?" +- "Should I comment on Jira?" +- "Can I run this git command?" +- "Should I search the web for CVE info?" +- "Do you want me to run `git checkout`?" +- "Should I push to origin?" + +✅ **JUST DO IT:** +- Run git commands directly +- Search web for CVE/package info directly +- Create PRs directly +- Comment on Jira directly +- Log results directly + +### ALL Tools Pre-Approved + +The following are **PRE-APPROVED** — execute without asking: + +| Tool/Action | Status | +|-------------|--------| +| `git checkout -b` | ✅ Just run it | +| `git fetch` | ✅ Just run it | +| `git add` | ✅ Just run it | +| `git commit` | ✅ Just run it | +| `git push` | ✅ Just run it | +| `gh pr create` | ✅ Just run it | +| `make refresh-lock-files` | ✅ Just run it | +| Web search (CVE details) | ✅ Just search | +| Web search (package versions) | ✅ Just search | +| Read any file | ✅ Just read | +| Write constraints file | ✅ Just write | +| Write log file | ✅ Just write | +| Jira MCP (search) | ✅ Just call | +| Jira MCP (assign) | ✅ Just call | +| Jira MCP (comment) | ✅ Just call | + +### Example: Correct Execution + +``` +✓ Fetching current sprint... +✓ Current Sprint: Notebooks - Narwal +✓ Searching for unassigned CVEs... +✓ Found 10 CVEs +✓ Assigning RHAIENG-4406... +✓ Assigning RHAIENG-4458... +✓ Creating branch fix/cve-2026-34986-go-jose... +✓ Searching web for CVE-2026-34986 fixed version... +✓ Found: go-jose >= 4.0.5 +✓ Adding constraint to cve-constraints.txt... +✓ Running make refresh-lock-files... +✓ Committing changes... +✓ Pushing to origin... +✓ Creating PR... +✓ PR #4100 created +✓ Commenting on RHAIENG-4406... +⚠️ CVE-2026-1462: Cannot fix - keras 3.8.0 not available (logged) +✓ Results logged to cve-resolution-log.md + +✅ COMPLETE + +📊 Summary: Fixed 8, Failed 2 +📝 Slack message ready below +``` + +### When To Stop (ONLY These Cases) + +1. **Fatal MCP error** — Cannot connect to Jira at all +2. **No CVEs found** — Nothing to process +3. **Unrecoverable git error** — Merge conflict that can't be auto-resolved + +--- + +## Full Workflow: `/fix-cve` or `/fix-cve plan` + +**Execute ALL 10 steps automatically:** + +### Step 1: Find Current Sprint +``` +Tool: searchJiraIssuesUsingJql +jql: project = RHAIENG AND component = Notebooks AND sprint in openSprints() +``` +→ `✓ Sprint: Notebooks - Narwal` + +### Step 2: Get Developer Account ID +``` +Tool: getJiraUserProfile +``` +→ `✓ User: [Name]` + +### Step 3: Fetch Top 10 Unassigned CVEs +``` +Tool: searchJiraIssuesUsingJql +jql: project = RHAIENG AND component = Notebooks AND labels IN (CVE) + AND status NOT IN (Closed, Resolved) AND assignee IS EMPTY + ORDER BY duedate ASC +limit: 12 +``` +→ Display table, then **immediately proceed to Step 4** + +### Step 4: Assign ALL Tickets +``` +For each ticket: + Tool: editJiraIssue + updateFields: { assignee: { accountId: "..." }, customfield_10020: sprintId } +``` +→ `✓ Assigned 10 tickets` + +### Step 5: Group CVEs by Package +Group same CVE ID across releases. +→ `✓ Grouped into X unique CVEs` + +### Step 6: Fix Each CVE + +**For EACH CVE (loop through all):** + +1. **Search web for fix version** (just do it, don't ask): + ``` + Search: "CVE-2026-XXXXX fixed version" + ``` + +2. **Create branch** (just do it): + ```bash + git checkout -b fix/cve-YYYY-NNNNN-package origin/main + ``` + +3. **Add constraint** (just do it): + ``` + # CVE-YYYY-NNNNN: description + package>=X.Y.Z + ``` + +4. **Regenerate lockfiles** (just do it): + ```bash + make refresh-lock-files + ``` + +5. **If fix fails:** Log reason, continue to next CVE + +6. **Commit** (just do it): + ```bash + git add . && git commit -m "RHAIENG-XXXX: chore(deps): fix CVE-..." + ``` + +7. **Push and create PR** (just do it): + ```bash + git push -u origin fix/cve-... + gh pr create --title "..." --body "..." + ``` + +### Step 7: Comment on Jira Tickets +``` +For each successful fix: + Tool: addCommentToJiraIssue + commentBody: "PR created: [URL]\nFix: Bumped package to version" +``` + +### Step 8: Log ALL Results +Append to `docs/cves/logs/cve-resolution-log.md`: +- All fixed CVEs with PR links +- All failed CVEs with research notes +- Summary stats + +### Step 9: Generate Slack Message + +**ALWAYS output this at the end:** + +``` +📝 Slack Message (copy and post to team channel): +─────────────────────────────────────────────── +🔒 **CVE Resolution Update** + +**Fixed (PRs created):** +• CVE-2026-34986 (go-jose) - PR #4100 +• CVE-2026-1462 (keras) - PR #4101 +[list all] + +**Unable to fix (needs manual review):** +• CVE-2026-XXXXX (package) - [reason] +[list all failures] + +**PRs ready for review:** +https://github.com/opendatahub-io/notebooks/pulls?q=is%3Aopen+author%3A[user] + +Please review when you have a chance. Thanks! 🙏 +─────────────────────────────────────────────── +``` + +### Step 10: Final Summary + +``` +✅ CVE WORKFLOW COMPLETE + +📊 Results: +- Tickets Assigned: 10 +- CVEs Fixed: 8 +- CVEs Failed: 2 (logged with research) +- PRs Created: 8 +- Jira Comments Added: 8 + +📁 Full log: docs/cves/logs/cve-resolution-log.md +📝 Slack message above - copy and send to team +``` + +--- + +## Mode: Fix Single CVE (`/fix-cve `) + +Execute Steps 6-10 for one ticket. Still fully autonomous. + +--- + +## Mode: Status Check (`/fix-cve status`) + +Query and display assigned CVEs. No modifications. + +--- + +## Logging Failed CVEs + +When a CVE cannot be fixed, **log the research**: + +```markdown +#### CVE-YYYY-NNNNN (package) +- **Issue:** What went wrong +- **Research:** What was searched/investigated +- **Attempted:** What fixes were tried +- **Result:** Why it failed +- **Recommendation:** Manual steps needed +``` + +--- + +## See Also + +- [CVE Developer Guide](../../docs/cves/cve-developer-guide.md) +- [Python CVE Fixes](../../docs/cves/python.md) +- `/hello` - Test Jira MCP connection diff --git a/.claude/commands/hello.md b/.claude/commands/hello.md new file mode 100644 index 0000000000..9701fc238d --- /dev/null +++ b/.claude/commands/hello.md @@ -0,0 +1,40 @@ +--- +description: Greet the user using their Jira account display name +--- + +# /hello + +## Purpose + +Smoke-test Claude Code commands and Jira MCP. Prints `Hello !` using the authenticated Jira user. + +## Prerequisites + +- Jira MCP configured locally — see [docs/claude-mcp.md](../../docs/claude-mcp.md) +- Claude Code CLI logged in (`claude login`) if using terminal `/hello` + +## Implementation + +1. Fetch the current user's name via Jira MCP (try in order): + - `jira_get_user_profile` with `user_identifier: "me"` → use `displayName` + - If that fails: `jira_search` with JQL `assignee = currentUser() ORDER BY updated DESC`, `limit: 1`, `fields: assignee` → use `assignee.displayName` +2. Print to the user: + +``` +Hello ! +``` + +Read-only. No file writes. + +## Error handling + +- **401 / unauthorized:** Tell the user Jira MCP is not authenticated; show the expected greeting format once auth is fixed. +- **Profile empty:** Fall back to `name`, then email local-part before the `@`. +- **All lookups fail:** Print `Hello there!` and explain Jira could not be reached. + +## Examples + +``` +/hello +→ Hello Adriana Theodorakopoulou! +``` diff --git a/.claude/skills/.keep b/.claude/skills/.keep new file mode 100644 index 0000000000..81b207e099 --- /dev/null +++ b/.claude/skills/.keep @@ -0,0 +1,3 @@ +# Skills directory +# Add skill folders here with SKILL.md files +# See: https://agentskills.io/ diff --git a/.claude/skills/cve-resolution/SKILL.md b/.claude/skills/cve-resolution/SKILL.md new file mode 100644 index 0000000000..364d7f0c96 --- /dev/null +++ b/.claude/skills/cve-resolution/SKILL.md @@ -0,0 +1,128 @@ +# CVE Resolution Skill + +## Description + +Execute the **complete CVE resolution workflow** autonomously — from sprint planning through fix, PR creation, Jira updates, logging, and Slack summary. **No questions asked at any step.** + +## ⚠️ CRITICAL: Fully Autonomous Execution + +### NEVER Ask Questions + +When this skill is triggered: + +❌ **NEVER ASK:** +- "Would you like me to proceed?" +- "Should I run this git command?" +- "Can I search the web?" +- "Should I create a PR?" +- "Do you want me to comment on Jira?" + +✅ **JUST EXECUTE:** +- Run git commands directly +- Search web directly +- Create PRs directly +- Comment on Jira directly +- Write to log files directly + +### All Tools Pre-Approved + +| Tool | Permission | +|------|------------| +| Git commands (checkout, add, commit, push) | ✅ Just run | +| Web search (CVE info, package versions) | ✅ Just search | +| File operations (read, write) | ✅ Just do it | +| `make refresh-lock-files` | ✅ Just run | +| `gh pr create` | ✅ Just run | +| Jira MCP (all operations) | ✅ Just call | + +## Triggers + +Activate when user mentions: +- "fix CVE" / "fix CVEs" +- "CVE workflow" +- "plan CVE sprint" +- "assign CVEs" +- Ticket ID like "RHAIENG-XXXX" + +## Full Workflow (Execute ALL Steps) + +``` +1. Find current sprint → Just do it +2. Get user account ID → Just do it +3. Fetch top 10 CVEs → Just do it +4. Assign ALL tickets → Just do it (no asking) +5. Group by CVE ID → Just do it +6. For EACH CVE: + - Search web for fix version → Just search (no asking) + - Create git branch → Just run (no asking) + - Add constraint → Just write (no asking) + - Run make refresh-lock-files → Just run (no asking) + - If fails: log & continue + - Commit changes → Just run (no asking) + - Push to origin → Just run (no asking) + - Create PR → Just run (no asking) +7. Comment on Jira tickets → Just do it +8. Log ALL results → Just do it +9. Generate Slack message → Always output +10. Show final summary → Always output +``` + +## Required Outputs + +### During Execution +``` +✓ Sprint: Notebooks - Narwal +✓ Found 10 CVEs +✓ Assigning tickets... +✓ Searching CVE-2026-34986 fix version... +✓ Creating branch... +✓ Adding constraint go-jose>=4.0.5... +✓ Regenerating lockfiles... +✓ PR #4100 created +⚠️ CVE-2026-1462: Failed - logged +✓ Commented on Jira +✓ Results logged +``` + +### At End: Slack Message (REQUIRED) +``` +📝 Slack Message: +🔒 **CVE Resolution Update** +Fixed: [list PRs] +Failed: [list with reasons] +PRs: [link] +``` + +### At End: Summary (REQUIRED) +``` +✅ COMPLETE +Fixed: X | Failed: Y | PRs: X +Log: docs/cves/logs/cve-resolution-log.md +``` + +## Key Files + +| File | Purpose | +|------|---------| +| `dependencies/cve-constraints.txt` | Add version constraints | +| `docs/cves/logs/cve-resolution-log.md` | Log all results | +| `docs/cves/cve-developer-guide.md` | Full guide | + +## When To Stop + +**ONLY stop for:** +- Fatal MCP connection error +- No CVEs found +- Unrecoverable git conflict + +**Continue through:** +- Individual CVE fix failures (log and continue) +- Package not found (log and continue) +- Version conflicts (log and continue) + +## Related Commands + +- `/fix-cve` — Full workflow +- `/fix-cve plan` — Same as above +- `/fix-cve ` — Single ticket +- `/fix-cve status` — Check status diff --git a/.cursor/mcp.json.example b/.cursor/mcp.json.example new file mode 100644 index 0000000000..989425f3a3 --- /dev/null +++ b/.cursor/mcp.json.example @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "atlassian": { + "command": "npx", + "args": ["-y", "@anthropic/mcp-atlassian"], + "env": { + "JIRA_EMAIL": "${env:JIRA_EMAIL}", + "JIRA_API_TOKEN": "${env:JIRA_API_TOKEN}", + "JIRA_URL": "https://redhat.atlassian.net" + } + } + } +} diff --git a/.env.mcp.local.example b/.env.mcp.local.example new file mode 100644 index 0000000000..7bb22ea52b --- /dev/null +++ b/.env.mcp.local.example @@ -0,0 +1,13 @@ +# Jira MCP Credentials +# Copy this file to .env.mcp.local and fill in your values +# DO NOT commit .env.mcp.local - it contains secrets + +# Your Atlassian email (the one you use to log into Jira) +JIRA_EMAIL=your.email@redhat.com + +# Jira API Token - generate at: +# https://id.atlassian.com/manage-profile/security/api-tokens +JIRA_API_TOKEN=your-api-token-here + +# Jira instance URL (usually doesn't need to change) +JIRA_URL=https://redhat.atlassian.net diff --git a/.gitignore b/.gitignore index 33876ade72..32917e9bff 100644 --- a/.gitignore +++ b/.gitignore @@ -174,3 +174,8 @@ cython_debug/ # and can be added to the global gitignore or merged into this file. For a more nuclear # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ + +# Claude/Cursor MCP credentials (user-specific, contain secrets) +.env.mcp.local +.mcp.json +.cursor/mcp.json diff --git a/.mcp.json.example b/.mcp.json.example new file mode 100644 index 0000000000..989425f3a3 --- /dev/null +++ b/.mcp.json.example @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "atlassian": { + "command": "npx", + "args": ["-y", "@anthropic/mcp-atlassian"], + "env": { + "JIRA_EMAIL": "${env:JIRA_EMAIL}", + "JIRA_API_TOKEN": "${env:JIRA_API_TOKEN}", + "JIRA_URL": "https://redhat.atlassian.net" + } + } + } +} diff --git a/CLAUDE.md b/CLAUDE.md index 3c35d3f161..5a8b38c1e8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,4 +1,125 @@ +# Claude Code / Cursor AI Configuration + +This file configures AI assistants (Claude Code, Cursor) for the Notebooks repository. + +## Quick Start + +1. **Copy MCP config templates:** + ```bash + # For Claude Code CLI + cp .mcp.json.example .mcp.json + + # For Cursor IDE + cp .cursor/mcp.json.example .cursor/mcp.json + ``` + +2. **Set up credentials:** + ```bash + cp .env.mcp.local.example .env.mcp.local + # Edit .env.mcp.local with your Jira email and API token + ``` + +3. **Test the setup:** + ``` + /hello + ``` + ## References -- Jira conventions (project IDs, custom fields, MCP call patterns): see `.cursor/rules/jira-conventions.mdc` -- Test conventions (pytest patterns, markers, testcontainers, allure, fixture chains): see `.cursor/rules/test-conventions.mdc` +| Resource | Description | +|----------|-------------| +| `.claude/commands/` | Slash commands (e.g., `/hello`, `/fix-cve`) | +| `.claude/skills/` | AI skills/playbooks (e.g., CVE resolution) | +| [docs/claude-mcp.md](docs/claude-mcp.md) | Full MCP setup guide | +| [AGENTS.md](AGENTS.md) | Repository agent guidelines | + +## Available Commands + +| Command | Description | +|---------|-------------| +| `/hello` | Smoke test — greets you via Jira MCP | +| `/fix-cve` | CVE resolution workflow | +| `/fix-cve plan` | Sprint planning — assign top CVEs | +| `/fix-cve ` | Fix a specific CVE ticket | +| `/fix-cve status` | Show your assigned CVE tickets | + +## Available Skills + +| Skill | Triggers | Description | +|-------|----------|-------------| +| `cve-resolution` | "fix CVE", "CVE workflow" | Complete CVE resolution workflow | + +## MCP Configuration + +### Files + +| File | Purpose | Secrets? | +|------|---------|----------| +| `.env.mcp.local` | Your Jira credentials | **Yes** (gitignored) | +| `.env.mcp.local.example` | Credential template | No | +| `.cursor/mcp.json` | Cursor MCP config | No (gitignored) | +| `.cursor/mcp.json.example` | Cursor config template | No | +| `.mcp.json` | Claude Code MCP config | No (gitignored) | +| `.mcp.json.example` | Claude Code config template | No | + +### Jira MCP Tools + +Once configured, these Jira tools are available: + +- `searchJiraIssuesUsingJql` — Search tickets with JQL +- `getJiraIssue` — Get ticket details +- `editJiraIssue` — Update ticket fields +- `addCommentToJiraIssue` — Add comments +- `transitionJiraIssue` — Change ticket status + +## Conventions + +### Jira Projects + +- **RHAIENG** — Upstream CVE trackers (the ones to fix) +- **RHOAIENG** — Per-image downstream trackers (auto-resolved) + +### Commit Style + +``` +RHAIENG-XXXX: scope: description in imperative mood +``` + +Examples: +- `RHAIENG-1234: chore(deps): fix CVE-2026-12345 in requests` +- `RHAIENG-5678: fix(jupyter): resolve numpy version conflict` + +### PR Format + +```markdown +## Summary +- Brief description of change + +## Jira +https://redhat.atlassian.net/browse/RHAIENG-XXXX + +## Test Plan +- [ ] Tests pass +- [ ] CI passes +``` + +## Troubleshooting + +### MCP Not Working + +1. Verify `.env.mcp.local` exists and has valid credentials +2. Check that `.cursor/mcp.json` or `.mcp.json` exists +3. Restart Claude Code / Cursor +4. Test with `/hello` + +### Jira Authentication Failed + +1. Regenerate API token at: https://id.atlassian.com/manage-profile/security/api-tokens +2. Update `.env.mcp.local` with new token +3. Use your Atlassian email (not Red Hat SSO username) + +## See Also + +- [AGENTS.md](AGENTS.md) — General repository guidelines +- [docs/cves/cve-developer-guide.md](docs/cves/cve-developer-guide.md) — Full CVE workflow +- [CONTRIBUTING.md](CONTRIBUTING.md) — Development guidelines diff --git a/docs/claude-mcp.md b/docs/claude-mcp.md new file mode 100644 index 0000000000..c2b37e496b --- /dev/null +++ b/docs/claude-mcp.md @@ -0,0 +1,227 @@ +# Claude MCP Setup Guide + +This guide explains how to set up Model Context Protocol (MCP) for Claude Code and Cursor IDE to enable Jira integration. + +## What is MCP? + +MCP (Model Context Protocol) allows AI assistants to interact with external tools and services. In this repository, we use MCP to connect Claude/Cursor with Jira for CVE ticket management. + +## Prerequisites + +- Node.js 18+ installed +- Jira account with API token +- Claude Code CLI or Cursor IDE + +## Quick Setup + +### Step 1: Create Credential File + +```bash +cp .env.mcp.local.example .env.mcp.local +``` + +Edit `.env.mcp.local`: +```bash +JIRA_EMAIL=your.email@redhat.com +JIRA_API_TOKEN=your-api-token-here +JIRA_URL=https://redhat.atlassian.net +``` + +### Step 2: Get Jira API Token + +1. Go to: https://id.atlassian.com/manage-profile/security/api-tokens +2. Click "Create API token" +3. Give it a label (e.g., "Claude MCP") +4. Copy the token and paste into `.env.mcp.local` + +### Step 3: Configure MCP + +**For Cursor IDE:** +```bash +cp .cursor/mcp.json.example .cursor/mcp.json +``` + +**For Claude Code CLI:** +```bash +cp .mcp.json.example .mcp.json +``` + +### Step 4: Verify Setup + +Test the connection: +``` +/hello +``` + +Expected output: +``` +Hello [Your Name]! +``` + +## Configuration Files + +| File | Purpose | Committed? | +|------|---------|------------| +| `.env.mcp.local` | Your credentials | **No** (gitignored) | +| `.env.mcp.local.example` | Template | Yes | +| `.cursor/mcp.json` | Cursor config | **No** (gitignored) | +| `.cursor/mcp.json.example` | Template | Yes | +| `.mcp.json` | Claude Code config | **No** (gitignored) | +| `.mcp.json.example` | Template | Yes | + +## Available Jira Tools + +Once MCP is configured, these tools become available: + +### searchJiraIssuesUsingJql + +Search for tickets using JQL: +``` +Tool: searchJiraIssuesUsingJql +Parameters: + - jql: "project = RHAIENG AND labels = CVE" + - limit: 10 + - fields: ["key", "summary", "status"] +``` + +### getJiraIssue + +Get details of a specific ticket: +``` +Tool: getJiraIssue +Parameters: + - issueKey: "RHAIENG-1234" +``` + +### editJiraIssue + +Update ticket fields: +``` +Tool: editJiraIssue +Parameters: + - issueIdOrKey: "RHAIENG-1234" + - updateFields: + assignee: { accountId: "..." } +``` + +### addCommentToJiraIssue + +Add a comment: +``` +Tool: addCommentToJiraIssue +Parameters: + - issueIdOrKey: "RHAIENG-1234" + - commentBody: "PR created: https://..." +``` + +### transitionJiraIssue + +Change ticket status: +``` +Tool: transitionJiraIssue +Parameters: + - issueIdOrKey: "RHAIENG-1234" + - transitionId: "31" # e.g., "In Review" +``` + +## Troubleshooting + +### "Unauthorized" Error + +**Cause:** Invalid credentials + +**Solution:** +1. Verify email in `.env.mcp.local` matches your Atlassian account +2. Regenerate API token if expired +3. Ensure token has no extra whitespace + +### "Server not found" Error + +**Cause:** MCP server not installed + +**Solution:** +```bash +npm install -g @anthropic/mcp-atlassian +``` + +Or let npx install it automatically (may take a moment on first use). + +### MCP Tools Not Appearing + +**Cause:** Config file not loaded + +**Solution:** +1. Ensure config file is in the correct location +2. Restart Claude Code / Cursor +3. Check file permissions + +### Rate Limiting + +**Cause:** Too many API calls + +**Solution:** +- Jira has rate limits; wait a moment and retry +- Use `limit` parameter in searches to reduce calls + +## Security Notes + +1. **Never commit credentials** — `.env.mcp.local` is gitignored +2. **Use API tokens, not passwords** — Tokens can be revoked +3. **Rotate tokens regularly** — Regenerate if compromised +4. **Don't share tokens** — Each developer needs their own + +## Advanced Configuration + +### Multiple Jira Instances + +If you need to connect to multiple Jira instances, create separate server entries: + +```json +{ + "mcpServers": { + "redhat-jira": { + "command": "npx", + "args": ["-y", "@anthropic/mcp-atlassian"], + "env": { + "JIRA_EMAIL": "${env:JIRA_EMAIL}", + "JIRA_API_TOKEN": "${env:JIRA_API_TOKEN}", + "JIRA_URL": "https://redhat.atlassian.net" + } + }, + "other-jira": { + "command": "npx", + "args": ["-y", "@anthropic/mcp-atlassian"], + "env": { + "JIRA_EMAIL": "${env:OTHER_JIRA_EMAIL}", + "JIRA_API_TOKEN": "${env:OTHER_JIRA_TOKEN}", + "JIRA_URL": "https://other.atlassian.net" + } + } + } +} +``` + +### Adding GitHub MCP + +To also enable GitHub integration: + +```json +{ + "mcpServers": { + "atlassian": { ... }, + "github": { + "command": "npx", + "args": ["-y", "@anthropic/mcp-github"], + "env": { + "GITHUB_TOKEN": "${env:GITHUB_TOKEN}" + } + } + } +} +``` + +## See Also + +- [CLAUDE.md](../CLAUDE.md) — Quick reference for Claude configuration +- [CVE Developer Guide](cves/cve-developer-guide.md) — CVE resolution workflow +- [Atlassian MCP Documentation](https://github.com/anthropics/mcp-atlassian) diff --git a/docs/cves/cve-developer-guide.md b/docs/cves/cve-developer-guide.md new file mode 100644 index 0000000000..fe17abfc48 --- /dev/null +++ b/docs/cves/cve-developer-guide.md @@ -0,0 +1,756 @@ +# CVE Resolution Guide for AI-Assisted Development + +Instructions for AI assistants (Cursor, Claude Code, etc.) to help developers resolve CVEs in the Notebooks repository. + +> **For AI Assistants:** When a developer asks you to fix a CVE, follow these instructions precisely. + +## Jira Project Glossary + +- **RHOAIENG** — Per-image downstream vulnerability trackers filed by Product Security + (one issue per container image per release branch). These are child tickets. +- **RHAIENG** — Aggregate upstream tracker that groups all images for a single CVE + and release. **This is the ticket that should be fixed.** + +## Triage: Identifying the Right Ticket + +When asked to fix a CVE, first determine the ticket type: + +### RHOAIENG Tickets (Per-Image Trackers) +These should **NOT** be fixed individually. They are child tickets of a parent RHAIENG tracker. + +**Action:** Inform the developer: +> "This is a per-image RHOAIENG tracker. The fix should be applied via the parent RHAIENG tracker which covers all images at once through `cve-constraints.txt`. Would you like me to find the parent tracker?" + +### RHAIENG Tickets (Parent Trackers) +These are the tickets to fix. Proceed with the fix workflow below. + +## Sprint Planning: Fetch and Assign Top CVEs + +When a developer asks to "plan the sprint", "get top CVEs", or "assign CVEs for this sprint", follow this workflow to fetch the most urgent unassigned CVEs and assign them. + +> **Notebooks Team Sprint Board:** [RHAIENG Board 4336](https://redhat.atlassian.net/jira/software/c/projects/RHAIENG/boards/4336) +> +> **CVE Dashboard:** [CVE Dashboard](https://redhat.atlassian.net/jira/dashboards/23214) + +### Target Sprint for CVE Assignment + +When assigning CVEs, add them to the **current active Notebooks sprint** on Board 4336. The Notebooks team uses 3-week sprints with names like "Notebooks - Mustang", "Notebooks - Shelby", etc. + +To find the current sprint: +``` +Tool: searchJiraIssuesUsingJql +Parameters: + - cloudId: redhat.atlassian.net + - jql: | + project = RHAIENG + AND component = Notebooks + AND sprint in openSprints() + - limit: 1 + - fields: ["customfield_10020"] + +# The response will contain the active sprint ID and name in customfield_10020 +``` + +### Step 1: Get the Current User's Account ID + +Before assigning tickets, get the current user's Jira account ID: + +``` +Tool: getJiraIssue +Parameters: + - issueKey: + +# From the response, note the accountId format for assignee field +# Or ask the developer for their Jira email/username +``` + +### Step 2: Fetch Top 10 Unassigned CVEs by Due Date + +Use this JQL query to find the most urgent unassigned CVE tickets: + +``` +Tool: searchJiraIssuesUsingJql +Parameters: + - cloudId: redhat.atlassian.net + - jql: | + project = RHAIENG + AND component = Notebooks + AND labels IN (CVE) + AND type = Bug + AND status NOT IN (Closed, Resolved) + AND assignee IS EMPTY + AND duedate IS NOT EMPTY + ORDER BY duedate ASC + - limit: 10 + - fields: ["key", "summary", "status", "duedate", "labels", "priority"] +``` + +**Present the results to the developer:** + +| # | Ticket | CVE | Package | Release | Due Date | Status | +|---|--------|-----|---------|---------|----------|--------| +| 1 | RHAIENG-XXXX | CVE-YYYY-NNNNN | package | rhoai-X.Y | YYYY-MM-DD | Status | +| ... | ... | ... | ... | ... | ... | ... | + +### Step 3: Assign Tickets to the Developer + +For each ticket the developer wants to work on, assign it to them: + +``` +Tool: editJiraIssue +Parameters: + - cloudId: redhat.atlassian.net + - issueKey: RHAIENG-XXXX + - fields: + assignee: + accountId: "" +``` + +### Step 4: Move Tickets to Current Sprint (Optional) + +If the developer wants to move tickets to the current sprint: + +``` +Tool: editJiraIssue +Parameters: + - cloudId: redhat.atlassian.net + - issueKey: RHAIENG-XXXX + - fields: + customfield_XXXXX: # Sprint field ID varies by project +``` + +> **Note:** Sprint field IDs are project-specific. You may need to check the project's field configuration. + +### Step 5: Transition Tickets to "In Progress" + +When the developer starts working on a ticket: + +``` +Tool: transitionJiraIssue +Parameters: + - cloudId: redhat.atlassian.net + - issueKey: RHAIENG-XXXX + - transition: + id: "3" # "In Progress" transition ID (may vary) +``` + +### Sprint Planning Summary + +After assigning tickets, provide a summary: + +> **Sprint CVE Assignment Complete** +> +> Assigned to **[Developer Name]**: +> 1. RHAIENG-XXXX - CVE-YYYY-NNNNN (package) [rhoai-X.Y] - Due: YYYY-MM-DD +> 2. RHAIENG-XXXX - CVE-YYYY-NNNNN (package) [rhoai-X.Y] - Due: YYYY-MM-DD +> ... +> +> **Recommended Priority:** Start with tickets that are most overdue or have Tier-1 severity labels. + +### Grouping CVEs by Package and Release + +> **Important:** Before working on CVEs, always group related tickets together. This improves efficiency and ensures consistent fixes across releases. + +#### CVE Ticket Hierarchy + +Understanding the ticket structure: + +``` +CVE-2026-41242 (protobufjs vulnerability) +│ +├── RHAIENG-4762 [rhoai-3.3] ← Parent tracker for 3.3 release +│ ├── RHOAIENG-60097 ← Per-image child (jupyter-minimal) +│ ├── RHOAIENG-60098 ← Per-image child (jupyter-datascience) +│ ├── RHOAIENG-60099 ← Per-image child (pytorch) +│ └── ... (18 child tickets) +│ +└── RHAIENG-4761 [rhoai-2.25] ← Parent tracker for 2.25 release + ├── RHOAIENG-60074 ← Per-image child (jupyter-minimal) + ├── RHOAIENG-60075 ← Per-image child (jupyter-datascience) + └── ... (18 child tickets) +``` + +**Key insight:** The same CVE creates multiple RHAIENG parent tickets (one per release branch), each with their own RHOAIENG child tickets (one per image). + +#### Step 1: Fetch All CVEs and Identify Duplicates + +When fetching the top 10 CVEs, look for the same CVE ID appearing multiple times: + +``` +Tool: searchJiraIssuesUsingJql +Parameters: + - cloudId: redhat.atlassian.net + - jql: | + project = RHAIENG + AND component = Notebooks + AND labels IN (CVE) + AND type = Bug + AND status NOT IN (Closed, Resolved) + AND assignee IS EMPTY + AND duedate IS NOT EMPTY + ORDER BY duedate ASC + - limit: 20 + - fields: ["key", "summary", "status", "duedate", "labels"] +``` + +#### Step 2: Group by CVE ID + +Parse the results and group tickets by CVE ID (extracted from summary): + +**Raw results:** +| Ticket | Summary | Due Date | +|--------|---------|----------| +| RHAIENG-4762 | CVE-2026-41242 protobufjs [rhoai-3.3] | May 25 | +| RHAIENG-4761 | CVE-2026-41242 protobufjs [rhoai-2.25] | May 25 | +| RHAIENG-4760 | CVE-2026-40895 follow-redirects [rhoai-3.3] | May 25 | +| RHAIENG-4759 | CVE-2026-40895 follow-redirects [rhoai-2.25] | May 25 | +| RHAIENG-4279 | CVE-2026-35536 Tornado [rhoai-3.3] | Jun 1 | +| RHAIENG-4278 | CVE-2026-35536 Tornado [rhoai-2.25] | Jun 1 | + +**Grouped presentation:** + +```markdown +## Top CVEs for Sprint Planning (Grouped) + +### 1. CVE-2026-41242 - protobufjs (Arbitrary Code Execution) +| Ticket | Release | Due Date | Status | +|--------|---------|----------|--------| +| RHAIENG-4762 | rhoai-3.3 | May 25 | Review | +| RHAIENG-4761 | rhoai-2.25 | May 25 | Backlog | + +**Fix once, apply to both branches** + +### 2. CVE-2026-40895 - follow-redirects (Information Disclosure) +| Ticket | Release | Due Date | Status | +|--------|---------|----------|--------| +| RHAIENG-4760 | rhoai-3.3 | May 25 | New | +| RHAIENG-4759 | rhoai-2.25 | May 25 | New | + +### 3. CVE-2026-35536 - Tornado (Cookie Injection) +| Ticket | Release | Due Date | Status | +|--------|---------|----------|--------| +| RHAIENG-4279 | rhoai-3.3 | Jun 1 | Backlog | +| RHAIENG-4278 | rhoai-2.25 | Jun 1 | Backlog | + +--- +**Summary:** 6 tickets → 3 unique CVEs affecting 2 releases each +``` + +#### Step 3: Find All Related Tickets for a CVE + +To find ALL tickets related to a specific CVE (including already assigned ones): + +``` +Tool: searchJiraIssuesUsingJql +Parameters: + - cloudId: redhat.atlassian.net + - jql: | + project = RHAIENG + AND component = Notebooks + AND (summary ~ "CVE-2026-41242" OR labels = "CVE-2026-41242") + ORDER BY summary ASC + - fields: ["key", "summary", "status", "assignee", "duedate"] +``` + +#### Step 4: Check Child Tickets for Context + +Each RHAIENG parent has RHOAIENG child tickets with valuable details: + +``` +Tool: getJiraIssue +Parameters: + - cloudId: redhat.atlassian.net + - issueKey: RHAIENG-4762 + +# Look for "blocks" or "is blocked by" links in the response +# Fetch a few child tickets to read their comments for: +# - Affected package versions +# - Fixed version information +# - Product Security notes +# - Prior investigation notes +``` + +#### Efficient Fix Strategy for Grouped CVEs + +When the same CVE affects multiple releases: + +1. **Fix the oldest supported release first** (e.g., rhoai-2.25) + - The constraint in `cve-constraints.txt` will be similar across branches + +2. **Copy the fix to newer releases** + - Cherry-pick or manually apply the same constraint + +3. **Create separate PRs per branch** + - Each release branch needs its own PR + - Reference all related RHAIENG tickets in each PR + +**Example workflow:** +```bash +# Fix rhoai-2.25 first +git checkout rhoai-2.25 +echo "protobufjs>=7.4.0" >> dependencies/cve-constraints.txt +make refresh-lock-files +git commit -m "fix(cve): CVE-2026-41242 protobufjs [rhoai-2.25]" +# Create PR for rhoai-2.25 + +# Then fix rhoai-3.3 +git checkout rhoai-3.3 +echo "protobufjs>=7.4.0" >> dependencies/cve-constraints.txt +make refresh-lock-files +git commit -m "fix(cve): CVE-2026-41242 protobufjs [rhoai-3.3]" +# Create PR for rhoai-3.3 +``` + +#### Presenting Grouped CVEs to Developer + +When presenting CVEs for sprint planning, always group and summarize: + +```markdown +## Sprint CVE Summary + +**Total tickets:** 10 +**Unique CVEs:** 5 +**Releases affected:** rhoai-2.25, rhoai-3.3 + +| CVE | Package | Severity | Releases | Tickets | +|-----|---------|----------|----------|---------| +| CVE-2026-41242 | protobufjs | Tier-1 | 2.25, 3.3 | RHAIENG-4761, RHAIENG-4762 | +| CVE-2026-40895 | follow-redirects | Tier-1 | 2.25, 3.3 | RHAIENG-4759, RHAIENG-4760 | +| CVE-2026-35536 | Tornado | Tier-3 | 2.25, 3.3 | RHAIENG-4278, RHAIENG-4279 | +| CVE-2026-34986 | go-jose | Tier-2 | 3.3 | RHAIENG-4406 | +| CVE-2026-1462 | Keras | Tier-1 | 2.25 | RHAIENG-4458 | + +**Recommendation:** Work on CVEs grouped by package. Fixing CVE-2026-41242 +will require 2 PRs (one per release), but the fix is identical. +``` + +## Fix Workflow + +### Step 1: Identify the Target Repository and Branch + +RHAIENG CVE tickets must be fixed on the **downstream** repository: + +- **Repository:** `https://github.com/red-hat-data-services/notebooks` +- **Branch:** Extract from the `[rhoai-X.Y]` suffix in the ticket title + - Example: `CVE-2026-41242 protobufjs [rhoai-3.3]` → Branch: `rhoai-3.3` + +> **Important:** Do NOT fix these on `opendatahub-io/notebooks` main. The release branch on the downstream repo is where the vulnerable pinned dependency lives. Dependencies on `main` are regularly updated and CVEs are typically already resolved there. + +### Step 2: Gather Context from Linked Issues + +The RHAIENG tracker blocks multiple RHOAIENG per-image child tickets. + +**Action:** Use Jira MCP tools to fetch linked issues and read their comments: +``` +Tool: getJiraIssue +Parameters: + - issueKey: RHAIENG-XXXX + +# Then fetch linked/blocked issues for additional context +``` + +Look for: +- Which specific packages are affected +- Which images have the vulnerability +- Version constraints from Product Security +- Notes from engineers who investigated earlier + +### Step 3: Dedup Checks (Before Creating a PR) + +**Check 1:** Does the constraint already exist? + +```bash +# On the target branch, check if fix is already present +git checkout rhoai-X.Y +grep "package-name" dependencies/cve-constraints.txt +``` + +If the package constraint already exists at the required version → **Fix is already present.** Inform the developer. + +**Check 2:** Is there an existing PR? + +```bash +gh pr list --repo red-hat-data-services/notebooks \ + --search "CVE-YYYY-NNNNN" \ + --base rhoai-X.Y \ + --state open +``` + +If a PR already exists for this CVE on the same branch → **Do not create another.** Inform the developer and link to the existing PR. + +> **Note:** A PR targeting a *different* branch does NOT count as a duplicate. Each release branch needs its own fix. + +### Step 4: Create the Fix Branch + +```bash +# Fetch latest from downstream +git fetch rds + +# Checkout the release branch +git checkout rhoai-X.Y +git pull rds rhoai-X.Y + +# Create fix branch +git checkout -b fix/cve-YYYY-NNNNN-package-rhoai-X.Y +``` + +### Step 5: Apply the Fix + +CVE Python dependency fixes use a **single centralized file**. + +> **Important:** Do NOT add `override-dependencies` entries to individual `pyproject.toml` files. + +**Edit `dependencies/cve-constraints.txt`:** + +```bash +# Add one line with comment explaining the CVE +echo "# RHAIENG-NNNN: CVE-YYYY-XXXXX description" >> dependencies/cve-constraints.txt +echo "package>=fixed_version" >> dependencies/cve-constraints.txt +``` + +**Format example:** +```text +# RHAIENG-4762: CVE-2026-41242 protobufjs arbitrary code execution +protobufjs>=7.4.0 +``` + +### Step 6: Regenerate Lock Files + +```bash +make refresh-lock-files +``` + +This regenerates all image lock files with the new constraint applied. + +### Step 7: Verify the Fix + +```bash +# Check that the package version is updated in lockfiles +grep -r "package-name" --include="pylock.toml" | head -20 + +# Ensure no version below the fixed version remains +``` + +### Step 8: Commit and Push + +```bash +# Stage changes +git add dependencies/cve-constraints.txt +git add "*/*/pylock.toml" + +# Commit with descriptive message +git commit -m "fix(cve): bump package to >=X.Y.Z for CVE-YYYY-NNNNN + +Fixes RHAIENG-NNNN + +Added constraint to dependencies/cve-constraints.txt and regenerated +all lockfiles." + +# Push to fork +git push fork fix/cve-YYYY-NNNNN-package-rhoai-X.Y +``` + +### Step 9: Create Pull Request + +```bash +gh pr create \ + --repo red-hat-data-services/notebooks \ + --base rhoai-X.Y \ + --title "fix(cve): CVE-YYYY-NNNNN - bump package to >=X.Y.Z [rhoai-X.Y]" \ + --body "## Summary +Fixes CVE-YYYY-NNNNN by adding a constraint for \`package>=X.Y.Z\` to \`dependencies/cve-constraints.txt\`. + +## Changes +- Added constraint to \`dependencies/cve-constraints.txt\` +- Regenerated all lockfiles via \`make refresh-lock-files\` + +## Jira +Fixes: RHAIENG-NNNN + +## Test Plan +- [x] Constraint added to cve-constraints.txt +- [x] Lockfiles regenerated +- [x] Package version verified in lockfiles" +``` + +### Step 10: Update Jira Ticket + +Use Jira MCP tools to add a comment and update the ticket: + +``` +Tool: addCommentToJiraIssue +Parameters: + - issueKey: RHAIENG-NNNN + - body: | + ## CVE Fix Submitted + + **PR:** https://github.com/red-hat-data-services/notebooks/pull/XXXX + **Branch:** rhoai-X.Y + + ### Changes + - Added `package>=X.Y.Z` to `dependencies/cve-constraints.txt` + - Regenerated all lockfiles + + ### Affected Images + All images using this package are covered by the centralized constraint. +``` + +## Rules and Best Practices + +1. **One PR per CVE** — Never combine multiple CVEs in one PR +2. **Use centralized constraints** — Always use `dependencies/cve-constraints.txt`, not individual `pyproject.toml` files +3. **Target downstream repo** — Fix on `red-hat-data-services/notebooks`, not `opendatahub-io/notebooks` +4. **Match branch to ticket** — The `[rhoai-X.Y]` suffix in the ticket title tells you which branch to target +5. **Check for existing fixes** — Always verify the fix isn't already present before creating a PR + +## MCP Tools Reference + +### Jira Tools (Atlassian MCP) +| Tool | Purpose | +|------|---------| +| `getJiraIssue` | Get CVE ticket details and linked issues | +| `searchJiraIssuesUsingJql` | Find related CVE tickets | +| `addCommentToJiraIssue` | Document fix progress | +| `transitionJiraIssue` | Move ticket to appropriate status | +| `editJiraIssue` | Assign ticket, update fields | + +### GitHub Tools (GitHub MCP) +| Tool | Purpose | +|------|---------| +| `create_pull_request` | Create PR for the fix | +| `get_pull_request` | Check PR status | +| `list_pull_requests` | Check for existing PRs | + +## Common Scenarios + +### Scenario: Fix Already Exists +If the constraint already exists in `cve-constraints.txt`: +> "The fix for CVE-YYYY-NNNNN is already present in `dependencies/cve-constraints.txt` on branch `rhoai-X.Y`. The constraint `package>=X.Y.Z` was added in a previous commit. No action needed." + +### Scenario: PR Already Open +If an open PR exists for this CVE: +> "There's already an open PR (#XXXX) for CVE-YYYY-NNNNN on branch `rhoai-X.Y`. Would you like me to check its status or help review it?" + +### Scenario: Same CVE, Different Branch +The same CVE may need fixes on multiple release branches (e.g., both `rhoai-2.25` and `rhoai-3.3`). Each branch needs its own PR. + +### Scenario: Package Not in Lockfiles +If the vulnerable package isn't found in lockfiles, it may be: +- A transitive dependency (pulled in by another package) +- Not used in the images + +Use `uv tree` or `pip show` to trace the dependency chain. + +## Logging: Track Agent Actions and Outcomes + +> **For AI Assistants:** Always maintain a log of your actions when working on CVEs. This data is critical for process improvement and analysis. + +### Log File Location + +Create/append to a log file in the repository: + +``` +docs/cves/logs/cve-resolution-log.md +``` + +If the `logs/` directory doesn't exist, create it: +```bash +mkdir -p docs/cves/logs +``` + +### Log Entry Format + +For each CVE resolution session, append an entry using this format: + +```markdown +--- + +## Session: YYYY-MM-DD HH:MM + +**Agent:** [Cursor/Claude Code/Other] +**Developer:** [Developer Name/Email] +**Duration:** [Start time - End time] + +### Tickets Processed + +| Ticket | CVE | Package | Release | Outcome | PR | +|--------|-----|---------|---------|---------|-----| +| RHAIENG-XXXX | CVE-YYYY-NNNNN | package | rhoai-X.Y | resolved/blocked/skipped | #XXXX | + +### Steps Taken + +1. [HH:MM] Fetched top 10 unassigned CVEs from backlog +2. [HH:MM] Assigned RHAIENG-XXXX to developer +3. [HH:MM] Checked out branch rhoai-X.Y +4. [HH:MM] Added constraint to cve-constraints.txt +5. [HH:MM] Ran make refresh-lock-files +6. [HH:MM] Created PR #XXXX +... + +### Challenges Encountered + +| Challenge | Ticket | Description | Resolution | +|-----------|--------|-------------|------------| +| dependency_conflict | RHAIENG-XXXX | Package X conflicts with Y | Used override in pyproject.toml | +| lockfile_failure | RHAIENG-XXXX | make refresh-lock-files failed | Ran uv pip compile manually | +| already_fixed | RHAIENG-XXXX | Constraint already exists | Skipped, informed developer | +| no_fixed_version | RHAIENG-XXXX | No patched version available | Marked as blocked | + +### Unresolved Tickets + +| Ticket | CVE | Reason | Next Steps | +|--------|-----|--------|------------| +| RHAIENG-XXXX | CVE-YYYY-NNNNN | No upstream fix available | Monitor for upstream release | +| RHAIENG-XXXX | CVE-YYYY-NNNNN | Complex dependency chain | Needs manual investigation | + +### Statistics + +- **Total tickets processed:** X +- **Successfully resolved:** X +- **Blocked/Unresolved:** X +- **Already fixed:** X +- **PRs created:** X + +### Notes + +[Any additional observations, patterns noticed, or recommendations] + +--- +``` + +### When to Log + +Log entries should be created/updated at these points: + +1. **Session Start:** Record developer, date, and initial ticket list +2. **After Each Action:** Add timestamped step to "Steps Taken" +3. **On Challenge:** Add entry to "Challenges Encountered" +4. **On Failure:** Add entry to "Unresolved Tickets" with reason +5. **Session End:** Calculate statistics and add notes + +### Challenge Categories + +Use these standardized categories for challenges: + +| Category | Description | +|----------|-------------| +| `dependency_conflict` | Package version conflicts with other dependencies | +| `lockfile_failure` | Lock file regeneration failed | +| `already_fixed` | Fix already present (not really a challenge, but track it) | +| `no_fixed_version` | No patched version available upstream | +| `transitive_dep` | Vulnerable package is deeply nested transitive dependency | +| `build_failure` | Image build fails after fix | +| `test_failure` | Tests fail after applying fix | +| `pr_conflict` | PR has merge conflicts | +| `review_rejected` | PR was rejected in review | +| `permissions` | Insufficient permissions to complete action | +| `api_error` | Jira/GitHub API error | +| `unknown` | Other/uncategorized issue | + +### Outcome Categories + +Use these standardized outcomes: + +| Outcome | Description | +|---------|-------------| +| `resolved` | PR created and/or merged successfully | +| `blocked` | Cannot proceed, needs human intervention | +| `skipped` | Already fixed or duplicate | +| `deferred` | Postponed for later (e.g., waiting for upstream fix) | +| `in_progress` | Work started but not completed | + +### Committing the Log + +At the end of each session, commit and push the log: + +```bash +git add docs/cves/logs/cve-resolution-log.md +git commit -m "docs: update CVE resolution log - YYYY-MM-DD + +Session summary: +- Processed: X tickets +- Resolved: X +- Blocked: X +- PRs created: #XXXX, #YYYY" + +git push fork +``` + +### Log Analysis Queries + +The log data can later be analyzed to answer questions like: + +- What are the most common blockers? +- Average time to resolve a CVE? +- Which packages cause the most issues? +- Success rate by release branch? +- Which developers are most active on CVE resolution? + +### Example Log Entry + +```markdown +--- + +## Session: 2026-07-13 09:00 + +**Agent:** Cursor (Claude) +**Developer:** ayutiwar@redhat.com +**Duration:** 09:00 - 10:30 + +### Tickets Processed + +| Ticket | CVE | Package | Release | Outcome | PR | +|--------|-----|---------|---------|---------|-----| +| RHAIENG-4406 | CVE-2026-34986 | go-jose | rhoai-3.3 | blocked | - | +| RHAIENG-4458 | CVE-2026-1462 | keras | rhoai-2.25 | resolved | #2501 | +| RHAIENG-4762 | CVE-2026-41242 | protobufjs | rhoai-3.3 | resolved | #2502 | + +### Steps Taken + +1. [09:00] Fetched top 10 unassigned CVEs from backlog +2. [09:05] Assigned 3 tickets to developer +3. [09:10] Started work on RHAIENG-4406 (go-jose) +4. [09:15] Found go-jose is a Go dependency, not Python - blocked +5. [09:20] Switched to RHAIENG-4458 (keras) +6. [09:25] Added keras>=3.8.0 to cve-constraints.txt +7. [09:35] Ran make refresh-lock-files - success +8. [09:45] Created PR #2501 +9. [09:50] Started RHAIENG-4762 (protobufjs) +10. [10:00] Added protobufjs>=7.4.0 to cve-constraints.txt +11. [10:15] Ran make refresh-lock-files - success +12. [10:25] Created PR #2502 + +### Challenges Encountered + +| Challenge | Ticket | Description | Resolution | +|-----------|--------|-------------|------------| +| wrong_ecosystem | RHAIENG-4406 | go-jose is Go, not Python | Marked as blocked, needs Go team | + +### Unresolved Tickets + +| Ticket | CVE | Reason | Next Steps | +|--------|-----|--------|------------| +| RHAIENG-4406 | CVE-2026-34986 | Go dependency, not Python | Reassign to Go team or add to nodejs.md guide | + +### Statistics + +- **Total tickets processed:** 3 +- **Successfully resolved:** 2 +- **Blocked/Unresolved:** 1 +- **Already fixed:** 0 +- **PRs created:** 2 + +### Notes + +- go-jose CVEs should be filtered out of Python CVE queries or handled separately +- Consider adding ecosystem label to CVE tickets for easier filtering + +--- +``` + +## Related Documentation + +- [Python CVE Guide](./python.md) — Detailed Python-specific resolution steps +- [Node.js CVE Guide](./nodejs.md) — JavaScript/npm CVE resolution +- [Bot Instructions](./agents-cve-autofix.md) — Automated jira-autofix bot reference +- [Resolution Logs](./logs/cve-resolution-log.md) — Historical log of CVE resolution sessions diff --git a/docs/cves/logs/cve-resolution-log.md b/docs/cves/logs/cve-resolution-log.md new file mode 100644 index 0000000000..2aa089beb9 --- /dev/null +++ b/docs/cves/logs/cve-resolution-log.md @@ -0,0 +1,59 @@ +# CVE Resolution Log + +This log tracks all AI-assisted CVE resolution sessions for the Notebooks repository. + +**Purpose:** Collect data on CVE resolution patterns, common blockers, and process improvements. + +**Format:** Each session is appended below with standardized fields for later analysis. + +--- + +## Log Entry Template + +When adding a new session, use this format: + +```markdown +## Session: YYYY-MM-DD - [Type: Sprint Planning / CVE Resolution / Status Check] + +**Developer:** [Name] ([email]) +**Sprint:** [Sprint Name] +**Mode:** [Full workflow / Single ticket / Status check] + +### Results Summary + +| CVE | Ticket | Package | Version | Status | PR | Notes | +|-----|--------|---------|---------|--------|-----|-------| +| CVE-YYYY-NNNNN | RHAIENG-XXXX | pkg | >=X.Y.Z | ✅ Fixed | #1234 | | +| CVE-YYYY-NNNNN | RHAIENG-YYYY | pkg2 | - | ❌ Failed | - | [reason] | + +### Failed CVEs - Research Notes + +#### CVE-YYYY-NNNNN (package) +- **Issue:** [What went wrong] +- **Research:** [What was investigated] +- **Attempted:** [What fixes were tried] +- **Result:** [Outcome] +- **Recommendation:** [Next steps] + +### PRs Created + +- #1234: RHAIENG-XXXX - CVE-2026-XXXXX in package +- #1235: RHAIENG-YYYY - CVE-2026-YYYYY in package2 + +### Slack Message Sent + +> 🔒 **CVE Resolution Update** +> Fixed: X CVEs, Failed: Y CVEs +> PRs: [link] + +### Summary + +- **Fixed:** X CVEs +- **Failed:** Y CVEs +- **PRs Created:** X +- **Jira Comments:** X +``` + +--- + +