CVE Fix
Automated CVE remediation for Python dependencies. Queries Jira for CVEs, updates Pipfile and Pipfile.lock, creates MRs, and updates Jira.
Critical Lessons Learned
These are hard-won from production use. Follow them strictly:
- Dependency cascade: Upgrading one package often breaks others (e.g., aiohttp 3.13+ broke gql, urllib3 2.x broke boto3). Always check compatibility.md BEFORE updating.
- Both files must update: Always update Pipfile AND Pipfile.lock together. Missing Pipfile changes causes CI failures.
- Branch isolation: Always create branches from
origin/main, never from another feature branch. Cross-contamination has caused multiple MR issues.
- Error handling: Use
isinstance() checks before .get() on variables that might be error strings instead of dicts (e.g., when pipenv lock fails).
- Local validation: Build container + run
pytest --collect-only to catch import errors from missing transitive dependencies before CI.
- Rebase conflicts: When multiple CVE fixes are in flight, document which packages were modified to help resolve conflicts.
Required MCP Tools
Load the developer persona first:
persona_load("developer")
Tools used: jira_search, jira_view_issue, jira_assign, jira_transition, jira_add_comment, git_fetch, git_branch_list, git_branch_create, git_checkout, git_add, git_commit, git_push, gitlab_mr_list, gitlab_mr_create, podman_build, podman_run, memory_session_log, jira_attach_session
Workflow
Phase 1: Discovery and Filtering
Query Jira for CVEs:
jira_search(jql='"Downstream Component Name" ~ "<component>" AND type = Vulnerability AND resolution = Unresolved ORDER BY created DESC', max_results=50)
Default component: automation-analytics-backend
Fetch latest from origin with prune to get up-to-date refs.
Check git log on origin/main (last 500 commits) to find already-merged fixes.
Check all branches for in-progress CVE work.
Check open MRs for existing CVE fix MRs.
Classify each CVE into one of:
- Merged to main - skip (already fixed)
- Has open MR - skip (fix in review)
- Has branch, no MR - resumable (prioritize these)
- Unfixed - needs work from scratch
Select CVEs to process: Prioritize resumable CVEs over new ones. Default: process 1 at a time.
Phase 2: CVE Details and Validation
Get CVE details from Jira using jira_view_issue.
Extract CVE info - see cve-parsing.md for detailed extraction strategies. Need:
- CVE ID (e.g.,
CVE-2024-12345)
- Affected package name (normalized to lowercase with hyphens)
- Summary, CVSS score, severity
Validate the CVE:
- Must have both CVE ID and affected package
- Reject non-pip packages (python, linux, glibc, java, nodejs, gcc, etc.) - these need different remediation (base image update)
Check compatibility requirements - consult compatibility.md for known breaking changes when upgrading the affected package.
Phase 3: Resume Logic (for existing branches)
If resuming a CVE that already has a branch:
- Find the existing branch name by searching branch list for the issue key.
- Check it out (try local first, then
origin/<branch>).
- Check commits ahead of
origin/main to detect what's already done.
- Check if Pipfile/Pipfile.lock are already committed.
- Check if branch is already pushed to remote.
- Skip completed steps in subsequent phases.
Phase 4: Jira Updates
- Resolve Jira username from config (must be email format, e.g.,
user@redhat.com).
- Assign issue to current user.
- Set acceptance criteria if not already present:
* CVE-XXXX vulnerability in <package> is remediated
* <package> is updated to a version that fixes CVE-XXXX
* Pipfile and Pipfile.lock are updated with the new version
* No regressions in existing functionality
* CI pipeline passes
- Transition to In Progress.
Phase 5: Branch Creation
Skip this phase if resuming (already on feature branch).
- Verify working directory is clean - abort if uncommitted changes exist.
- Checkout main and hard reset to
origin/main (critical for branch isolation).
- Create feature branch:
<ISSUE_KEY>-<cve-id>-<package> (e.g., AAP-12345-cve-2025-69223-aiohttp).
- Verify branch base matches
origin/main exactly (merge-base check).
Phase 6: Update Pipfile and Pipfile.lock
Skip if already committed (resume case).
This uses a container-based approach to resolve package versions with the correct Python version:
Read Python version from the project's Pipfile [requires] section.
Map to UBI container image:
| Python |
Image |
| 3.9 |
registry.access.redhat.com/ubi9/python-39 |
| 3.11 |
registry.access.redhat.com/ubi9/python-311 |
| 3.12 |
registry.access.redhat.com/ubi9/python-312 |
Create temp workspace in /tmp/cve-fix-* with:
- Minimal Pipfile containing just the target package (and any companion packages)
- Containerfile based on the UBI image
Build container with podman_build (installs pip + pipenv).
Run pipenv lock inside the container with the temp dir volume-mounted.
Extract new version and hashes from the generated Pipfile.lock.
Update project Pipfile:
- If package exists: update to
>= <new_version> with CVE comment
- If package missing: add after
[packages] header
- Update companion packages too if needed
Update project Pipfile.lock:
- Update version and hashes for main package
- Update companion packages
- Preserve all other packages unchanged
Clean up temp directory.
Phase 7: Commit and Push
- Build commit message using format:
<ISSUE_KEY> - fix(deps): update <package> <old> -> <new> to fix <CVE-ID>
- Stage Pipfile and Pipfile.lock.
- Commit the changes.
- Push branch to origin with
--set-upstream.
Phase 8: Create MR
Build MR title: <ISSUE_KEY> - fix(security): fix <CVE-ID> in <package>
Build MR description with sections:
- Summary (security fix for CVE in package)
- CVE Details (ID, package, severity, CVSS with NVD link)
- Changes (Pipfile and Pipfile.lock updates, companion packages)
- Compatibility Notes (if applicable)
- Jira link
- Testing checklist
- Completion checklist
Create MR via gitlab_mr_create (not draft).
Phase 9: Post-MR Actions
- Add Jira comment with MR link and change summary.
- Notify team via Slack using the
notify_team skill with cve_fix template.
- Log to session memory.
- Attach session context to the Jira issue for audit trail.
- Scan fixed image via
scan_vulnerabilities skill (if commit SHA available).
- Restore developer persona after scan.
Dry Run Mode
When dry_run is true, show what would be done without making any changes. Display the CVE status summary table and planned steps.
Output Summary
Present results as a markdown table:
| Status |
Count |
Issues |
| Merged to main |
N |
AAP-... |
| Has Open MR |
N |
AAP-... |
| Resumable |
N |
AAP-... |
| Needs Work |
N |
AAP-... |
For each processed CVE, show:
- Issue key, CVE ID, package, severity, CVSS
- Branch name, Python version
- Pipfile changes (old version -> new version)
- Companion package updates
- MR link
Additional Resources
- Package compatibility requirements: See references/compatibility.md for known breaking changes between packages
- CVE info extraction from Jira: See references/cve-parsing.md for multi-strategy parsing of CVE IDs and affected packages from Jira issue text
1---2name: cve-fix3description: Automatically fix CVE vulnerabilities in Python dependencies for downstream projects. Queries Jira for unresolved CVEs, filters already-fixed issues, updates Pipfile and Pipfile.lock using container-based pipenv lock, creates MRs, and updates Jira. Use when the user mentions CVEs, vulnerabilities, security fixes, CVE remediation, dependency security updates, or asks to fix CVEs.4---56# CVE Fix78Automated CVE remediation for Python dependencies. Queries Jira for CVEs, updates Pipfile and Pipfile.lock, creates MRs, and updates Jira.910## Critical Lessons Learned1112These are hard-won from production use. Follow them strictly:13141. **Dependency cascade**: Upgrading one package often breaks others (e.g., aiohttp 3.13+ broke gql, urllib3 2.x broke boto3). Always check [compatibility.md](references/compatibility.md) BEFORE updating.152. **Both files must update**: Always update Pipfile AND Pipfile.lock together. Missing Pipfile changes causes CI failures.163. **Branch isolation**: Always create branches from `origin/main`, never from another feature branch. Cross-contamination has caused multiple MR issues.174. **Error handling**: Use `isinstance()` checks before `.get()` on variables that might be error strings instead of dicts (e.g., when pipenv lock fails).185. **Local validation**: Build container + run `pytest --collect-only` to catch import errors from missing transitive dependencies before CI.196. **Rebase conflicts**: When multiple CVE fixes are in flight, document which packages were modified to help resolve conflicts.2021## Required MCP Tools2223Load the **developer** persona first:2425```26persona_load("developer")27```2829Tools used: `jira_search`, `jira_view_issue`, `jira_assign`, `jira_transition`, `jira_add_comment`, `git_fetch`, `git_branch_list`, `git_branch_create`, `git_checkout`, `git_add`, `git_commit`, `git_push`, `gitlab_mr_list`, `gitlab_mr_create`, `podman_build`, `podman_run`, `memory_session_log`, `jira_attach_session`3031## Workflow3233### Phase 1: Discovery and Filtering34351. **Query Jira for CVEs**:36 ```37 jira_search(jql='"Downstream Component Name" ~ "<component>" AND type = Vulnerability AND resolution = Unresolved ORDER BY created DESC', max_results=50)38 ```39 Default component: `automation-analytics-backend`40412. **Fetch latest from origin** with prune to get up-to-date refs.42433. **Check git log on `origin/main`** (last 500 commits) to find already-merged fixes.44454. **Check all branches** for in-progress CVE work.46475. **Check open MRs** for existing CVE fix MRs.48496. **Classify each CVE** into one of:50 - **Merged to main** - skip (already fixed)51 - **Has open MR** - skip (fix in review)52 - **Has branch, no MR** - resumable (prioritize these)53 - **Unfixed** - needs work from scratch54557. **Select CVEs to process**: Prioritize resumable CVEs over new ones. Default: process 1 at a time.5657### Phase 2: CVE Details and Validation58591. **Get CVE details** from Jira using `jira_view_issue`.60612. **Extract CVE info** - see [cve-parsing.md](references/cve-parsing.md) for detailed extraction strategies. Need:62 - CVE ID (e.g., `CVE-2024-12345`)63 - Affected package name (normalized to lowercase with hyphens)64 - Summary, CVSS score, severity65663. **Validate the CVE**:67 - Must have both CVE ID and affected package68 - Reject non-pip packages (python, linux, glibc, java, nodejs, gcc, etc.) - these need different remediation (base image update)69704. **Check compatibility requirements** - consult [compatibility.md](references/compatibility.md) for known breaking changes when upgrading the affected package.7172### Phase 3: Resume Logic (for existing branches)7374If resuming a CVE that already has a branch:75761. Find the existing branch name by searching branch list for the issue key.772. Check it out (try local first, then `origin/<branch>`).783. Check commits ahead of `origin/main` to detect what's already done.794. Check if Pipfile/Pipfile.lock are already committed.805. Check if branch is already pushed to remote.816. Skip completed steps in subsequent phases.8283### Phase 4: Jira Updates84851. **Resolve Jira username** from config (must be email format, e.g., `user@redhat.com`).862. **Assign issue** to current user.873. **Set acceptance criteria** if not already present:88 ```89 * CVE-XXXX vulnerability in <package> is remediated90 * <package> is updated to a version that fixes CVE-XXXX91 * Pipfile and Pipfile.lock are updated with the new version92 * No regressions in existing functionality93 * CI pipeline passes94 ```954. **Transition to In Progress**.9697### Phase 5: Branch Creation9899Skip this phase if resuming (already on feature branch).1001011. **Verify working directory is clean** - abort if uncommitted changes exist.1022. **Checkout main** and **hard reset to `origin/main`** (critical for branch isolation).1033. **Create feature branch**: `<ISSUE_KEY>-<cve-id>-<package>` (e.g., `AAP-12345-cve-2025-69223-aiohttp`).1044. **Verify branch base** matches `origin/main` exactly (merge-base check).105106### Phase 6: Update Pipfile and Pipfile.lock107108Skip if already committed (resume case).109110This uses a **container-based approach** to resolve package versions with the correct Python version:1111121. **Read Python version** from the project's Pipfile `[requires]` section.1131142. **Map to UBI container image**:115 | Python | Image |116 |--------|-------|117 | 3.9 | `registry.access.redhat.com/ubi9/python-39` |118 | 3.11 | `registry.access.redhat.com/ubi9/python-311` |119 | 3.12 | `registry.access.redhat.com/ubi9/python-312` |1201213. **Create temp workspace** in `/tmp/cve-fix-*` with:122 - Minimal Pipfile containing just the target package (and any companion packages)123 - Containerfile based on the UBI image1241254. **Build container** with `podman_build` (installs pip + pipenv).1261275. **Run `pipenv lock`** inside the container with the temp dir volume-mounted.1281296. **Extract new version and hashes** from the generated Pipfile.lock.1301317. **Update project Pipfile**:132 - If package exists: update to `>= <new_version>` with CVE comment133 - If package missing: add after `[packages]` header134 - Update companion packages too if needed1351368. **Update project Pipfile.lock**:137 - Update version and hashes for main package138 - Update companion packages139 - Preserve all other packages unchanged1401419. **Clean up** temp directory.142143### Phase 7: Commit and Push1441451. **Build commit message** using format: `<ISSUE_KEY> - fix(deps): update <package> <old> -> <new> to fix <CVE-ID>`1462. **Stage** Pipfile and Pipfile.lock.1473. **Commit** the changes.1484. **Push branch** to origin with `--set-upstream`.149150### Phase 8: Create MR1511521. **Build MR title**: `<ISSUE_KEY> - fix(security): fix <CVE-ID> in <package>`1531542. **Build MR description** with sections:155 - Summary (security fix for CVE in package)156 - CVE Details (ID, package, severity, CVSS with NVD link)157 - Changes (Pipfile and Pipfile.lock updates, companion packages)158 - Compatibility Notes (if applicable)159 - Jira link160 - Testing checklist161 - Completion checklist1621633. **Create MR** via `gitlab_mr_create` (not draft).164165### Phase 9: Post-MR Actions1661671. **Add Jira comment** with MR link and change summary.1682. **Notify team** via Slack using the `notify_team` skill with `cve_fix` template.1693. **Log to session memory**.1704. **Attach session context** to the Jira issue for audit trail.1715. **Scan fixed image** via `scan_vulnerabilities` skill (if commit SHA available).1726. **Restore developer persona** after scan.173174## Dry Run Mode175176When `dry_run` is true, show what would be done without making any changes. Display the CVE status summary table and planned steps.177178## Output Summary179180Present results as a markdown table:181182| Status | Count | Issues |183|--------|-------|--------|184| Merged to main | N | AAP-... |185| Has Open MR | N | AAP-... |186| Resumable | N | AAP-... |187| Needs Work | N | AAP-... |188189For each processed CVE, show:190- Issue key, CVE ID, package, severity, CVSS191- Branch name, Python version192- Pipfile changes (old version -> new version)193- Companion package updates194- MR link195196## Additional Resources197198- **Package compatibility requirements**: See [references/compatibility.md](references/compatibility.md) for known breaking changes between packages199- **CVE info extraction from Jira**: See [references/cve-parsing.md](references/cve-parsing.md) for multi-strategy parsing of CVE IDs and affected packages from Jira issue text