From 60ca33cee57261e059591684f0712810a6f1b023 Mon Sep 17 00:00:00 2001 From: Amrit Krishnan Date: Tue, 24 Mar 2026 12:47:49 -0400 Subject: [PATCH 1/3] Add skill for security failures --- .claude/skills/fix-security-failures/SKILL.md | 148 ++++++++++++++++++ src/aieng_bot/agent_fixer/prompts.py | 3 +- tests/agent_fixer/test_fixer.py | 1 + 3 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 .claude/skills/fix-security-failures/SKILL.md diff --git a/.claude/skills/fix-security-failures/SKILL.md b/.claude/skills/fix-security-failures/SKILL.md new file mode 100644 index 0000000..cf28930 --- /dev/null +++ b/.claude/skills/fix-security-failures/SKILL.md @@ -0,0 +1,148 @@ +--- +name: fix-security-failures +description: Fix pip-audit security vulnerability failures. Use when CI fails due to pip-audit findings (CVE/GHSA). Handles both fixable and unfixable (upstream-only) vulnerabilities with graceful exit. +--- + +# Fix Security Failures (pip-audit) + +## Step 1: Parse the Vulnerability Report + +Search the failure logs for pip-audit findings: + +```bash +grep -i "CVE-\|GHSA-\|vulnerability\|Found.*vulnerabilit\|pip-audit" .failure-logs.txt | head -100 +``` + +Extract for each finding: +- **Package name** (e.g., `requests`) +- **Installed version** (e.g., `2.28.0`) +- **Vulnerability ID** (e.g., `GHSA-xxxx-xxxx-xxxx` or `CVE-2024-xxxxx`) +- **Fix version** if listed (pip-audit often states `Fix versions: X.Y.Z`) + +pip-audit output format to recognize: +``` +requests 2.28.0 GHSA-xxxx Fix versions: 2.31.0 +filelock 3.12.0 CVE-2024-x Fix versions: (none) +``` + +## Step 2: For Each Vulnerable Package — Check PyPI for a Patched Version + +### 2a. If pip-audit already lists fix versions + +Use those directly — skip to Step 3. + +### 2b. If no fix version is listed, check PyPI + +```bash +# Check all available versions on PyPI +pip index versions 2>/dev/null | head -5 + +# Or query the PyPI JSON API directly +curl -s "https://pypi.org/pypi//json" | python3 -c " +import sys, json +data = json.load(sys.stdin) +versions = sorted(data['releases'].keys()) +print('Available versions:', versions[-10:]) +print('Latest:', data['info']['version']) +" +``` + +### 2c. Determine if a patch exists + +A patch exists if there is **any published version higher than the installed version** that is NOT listed in the vulnerability's `fixed_in` exclusions. + +**No patch exists** if: +- pip-audit explicitly states `Fix versions: (none)` or `No fix available` +- The PyPI API shows no newer releases +- The vulnerability advisory (GHSA/CVE) states the fix requires changes in a **dependency of the package** (i.e., the vulnerable code is in a transitive dependency that the package author hasn't yet updated) +- The latest PyPI version is the same as or older than the installed version + +## Step 3: Apply the Fix (only if a patch version exists) + +Update the version constraint in `pyproject.toml`: + +```bash +# Find current constraint +grep -n "" pyproject.toml +``` + +Edit `pyproject.toml` to require the patched minimum version: +- Change `"package>=1.0"` → `"package>="` +- Or add a lower bound: `"package"` → `"package>="` + +Then regenerate the lock file: + +```bash +uv lock +uv sync +``` + +Verify pip-audit now passes locally: + +```bash +uv run pip-audit +``` + +If clean, commit: + +```bash +git add pyproject.toml uv.lock +git commit -m "chore: bump to to fix + +Co-authored-by: aieng-bot " +``` + +## Step 4: Graceful Exit When No Patch Is Available + +**This is the critical path.** If ANY vulnerability has no patched version available, do NOT attempt to fix it. The fix must come from the upstream library maintainers. + +### Identify unfixable vulnerabilities + +A vulnerability is unfixable if Step 2 confirms no patch version exists on PyPI. + +### Post a PR comment explaining the situation + +```bash +PR_NUMBER=$(cat .pr-context.json | python3 -c "import sys,json; print(json.load(sys.stdin)['pr_number'])") +REPO=$(cat .pr-context.json | python3 -c "import sys,json; print(json.load(sys.stdin)['repo'])") + +gh pr comment "$PR_NUMBER" --repo "$REPO" --body "## Security Vulnerability — No Patch Available Yet + +aieng-bot found the following security vulnerabilities reported by pip-audit, but **cannot fix them automatically** because no patched version has been released to PyPI yet: + +| Package | Version | Vulnerability | Status | +|---------|---------|---------------|--------| +| | | | No fix available on PyPI | + +### Why this cannot be auto-fixed + +The vulnerability exists in \`\` itself (or one of its dependencies). A fix requires the upstream maintainers to release a new version. Once a patched release is published to PyPI, aieng-bot can re-run and apply the update automatically. + +### Recommended next steps + +1. Monitor the vulnerability advisory for a patch release +2. Check if a \`pip-audit\` ignore/exception can be added temporarily with justification (requires human review) +3. Consider whether this dependency can be replaced with an alternative + +_This PR will not be auto-merged until the vulnerability is resolved._" +``` + +### Exit without making any changes + +Do **not** modify `pyproject.toml`, `uv.lock`, or any other file. Do **not** commit anything. Stop here and let the human team handle it. + +## Step 5: Mixed Case — Some Fixable, Some Not + +If a PR has multiple vulnerabilities where some have patches and some don't: + +1. Fix all the patchable ones (Step 3) +2. Post a comment listing the unfixable ones (Step 4 comment template) +3. Do NOT merge the PR — leave it for human review +4. Push the partial fixes so CI can re-run and confirm the remaining vulnerabilities + +## Common Mistakes to Avoid + +- **Do not pin to an exact version** (e.g., `==2.31.0`) — use a minimum bound (`>=2.31.0`) to allow future patch upgrades +- **Do not ignore or suppress pip-audit findings** with `--ignore-vuln` unless a human has explicitly approved it +- **Do not assume transitive dependency bumps are safe** — always run `uv sync` and check that tests still pass after bumping +- **Do not mark the PR as fixed** if an unfixable vulnerability remains — the CI will still fail diff --git a/src/aieng_bot/agent_fixer/prompts.py b/src/aieng_bot/agent_fixer/prompts.py index b70f958..270c3b7 100644 --- a/src/aieng_bot/agent_fixer/prompts.py +++ b/src/aieng_bot/agent_fixer/prompts.py @@ -54,6 +54,7 @@ Skills provide conventions and context - use them for reference when needed: - `/python-conventions` - uv, ruff, mypy conventions - `/merge-resolution` - How to resolve merge conflicts +- `/fix-security-failures` - pip-audit vulnerability triage: bump fixable packages, gracefully exit when no patch exists upstream **You handle ALL workflow steps directly** - skills don't do git operations. @@ -98,7 +99,7 @@ ```bash grep -i "error\|fail\|exception" .failure-logs.txt | head -50 ``` -3. Fix the issues (use `/python-conventions` for guidance) +3. Fix the issues (use `/python-conventions` for general guidance; use `/fix-security-failures` for pip-audit/CVE failures) 4. Commit and go to Step 2: ```bash git add -A diff --git a/tests/agent_fixer/test_fixer.py b/tests/agent_fixer/test_fixer.py index 7a35b6c..582ff9c 100644 --- a/tests/agent_fixer/test_fixer.py +++ b/tests/agent_fixer/test_fixer.py @@ -487,6 +487,7 @@ def test_build_agentic_prompt(self, agentic_request): assert "Skills (Context Only)" in prompt assert "/python-conventions" in prompt assert "/merge-resolution" in prompt + assert "/fix-security-failures" in prompt assert ".pr-context.json" in prompt assert ".failure-logs.txt" in prompt assert "gh pr checks" in prompt From 67e933e89223112ca5d6bafdcefb8fed9d085d6a Mon Sep 17 00:00:00 2001 From: Amrit Krishnan Date: Tue, 24 Mar 2026 12:49:36 -0400 Subject: [PATCH 2/3] Update dashboard with small fixes --- dashboard/components/failure-analysis.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dashboard/components/failure-analysis.tsx b/dashboard/components/failure-analysis.tsx index b23e38a..e4a273e 100644 --- a/dashboard/components/failure-analysis.tsx +++ b/dashboard/components/failure-analysis.tsx @@ -66,7 +66,7 @@ export default function FailureAnalysis({ failure }: FailureAnalysisProps) { case 'lint': return 'Code style and linting issues detected. The bot automatically reformatted and fixed code quality issues.' case 'security': - return 'Security vulnerabilities detected. The bot analyzed and resolved security issues in dependencies.' + return 'Security vulnerabilities detected. The bot analyzed dependencies for CVE/GHSA findings. If a patched version was available on PyPI, the bot bumped the version constraint and regenerated the lock file. If no patch exists yet, the bot left a PR comment explaining the issue and exited without changes.' case 'build': return 'Build compilation errors detected. The bot fixed configuration and code issues to restore builds.' case 'merge_conflict': @@ -200,15 +200,15 @@ export default function FailureAnalysis({ failure }: FailureAnalysisProps) { <>
  • - Identified vulnerable dependencies + Parsed pip-audit output for CVE/GHSA IDs and affected package versions
  • - Updated to patched versions or applied workarounds + Checked PyPI for a patched release; bumped version constraint in pyproject.toml and regenerated uv.lock if a fix was available
  • - Verified security scans pass + If no patch exists upstream, left a PR comment listing the unresolved CVEs and exited without modifying files — requires human review
  • )} From fcee771cab26b6715ac496e5ff568d781166826e Mon Sep 17 00:00:00 2001 From: Amrit Krishnan Date: Tue, 24 Mar 2026 12:52:14 -0400 Subject: [PATCH 3/3] Small typo fix --- .claude/skills/fix-security-failures/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.claude/skills/fix-security-failures/SKILL.md b/.claude/skills/fix-security-failures/SKILL.md index cf28930..21fadb6 100644 --- a/.claude/skills/fix-security-failures/SKILL.md +++ b/.claude/skills/fix-security-failures/SKILL.md @@ -10,7 +10,7 @@ description: Fix pip-audit security vulnerability failures. Use when CI fails du Search the failure logs for pip-audit findings: ```bash -grep -i "CVE-\|GHSA-\|vulnerability\|Found.*vulnerabilit\|pip-audit" .failure-logs.txt | head -100 +grep -i "CVE-\|GHSA-\|vulnerability\|Found.*vulnerability\|pip-audit" .failure-logs.txt | head -100 ``` Extract for each finding: