Skip to content

Commit 5efc2ff

Browse files
authored
ci: add audit-dependencies claude skill (#15967)
# Overview Adds a Claude Code skill for fixing dependency audit vulnerabilities, and adds input validation to the audit script. Invoked manually via `/audit-dependencies [severity]` (defaults to `high`). ## Key Changes - **New skill at `.claude/skills/audit-dependencies/SKILL.md`** - User-invocable only (`disable-model-invocation: true`), so Claude won't auto-detect or load it. - Accepts an optional severity argument (`critical|high|moderate|low`), defaults to `high`. - Codifies the workflow: run audit script, trace dependency chains, prefer direct bumps over pnpm overrides, research breaking changes, install/build/verify, look up advisories, commit, and create a PR. - Includes a graphviz decision flowchart for the bump-vs-override decision. - Calls out parallel agent dispatch for breaking change research and advisory lookups. - Uses GHSA links (`github.com/advisories/GHSA-...`) over NVD links in PR bodies. - **Severity validation in `audit-dependencies.sh`** - Validates the severity argument against `low`, `moderate`, `high`, `critical`. Exits with code 2 on invalid input. ## Design Decisions The skill enforces "direct bump first, override as last resort" because overrides hide version mismatches and can silently break when the parent package updates. Each override requires explicit justification (no patched parent version available, high breaking change risk, or user defers to separate PR).
1 parent 395e1ed commit 5efc2ff

2 files changed

Lines changed: 198 additions & 0 deletions

File tree

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
---
2+
name: audit-dependencies
3+
description: Use when fixing dependency vulnerabilities, running pnpm audit, or when the audit-dependencies CI check fails
4+
user-invocable: true
5+
disable-model-invocation: true
6+
argument-hint: "critical|high|moderate|low"
7+
---
8+
9+
# Audit Dependencies
10+
11+
## Overview
12+
13+
Fix dependency vulnerabilities reported by `.github/workflows/audit-dependencies.sh`. Always prefer direct dependency bumps over pnpm overrides. Every override requires justification for why a direct bump isn't feasible.
14+
15+
## Core Workflow
16+
17+
```dot
18+
digraph audit {
19+
"Run audit script" [shape=box];
20+
"Group by package" [shape=box];
21+
"Trace dependency chain" [shape=box];
22+
"Can bump direct dep?" [shape=diamond];
23+
"Research breaking changes" [shape=box];
24+
"Breaking changes acceptable?" [shape=diamond];
25+
"Apply direct bump" [shape=box];
26+
"Apply pnpm override" [shape=box];
27+
"More packages?" [shape=diamond];
28+
"Install and verify" [shape=box];
29+
"Build and verify" [shape=box];
30+
"Commit and create PR" [shape=box];
31+
32+
"Run audit script" -> "Group by package";
33+
"Group by package" -> "Trace dependency chain";
34+
"Trace dependency chain" -> "Can bump direct dep?";
35+
"Can bump direct dep?" -> "Research breaking changes" [label="yes"];
36+
"Can bump direct dep?" -> "Apply pnpm override" [label="no - explain why"];
37+
"Research breaking changes" -> "Breaking changes acceptable?";
38+
"Breaking changes acceptable?" -> "Apply direct bump" [label="yes"];
39+
"Breaking changes acceptable?" -> "Apply pnpm override" [label="no - explain why"];
40+
"Apply direct bump" -> "More packages?";
41+
"Apply pnpm override" -> "More packages?";
42+
"More packages?" -> "Trace dependency chain" [label="yes"];
43+
"More packages?" -> "Install and verify" [label="no"];
44+
"Install and verify" -> "Build and verify";
45+
"Build and verify" -> "Commit and create PR";
46+
}
47+
```
48+
49+
## Step-by-Step
50+
51+
### 1. Run the Audit Script
52+
53+
```bash
54+
./.github/workflows/audit-dependencies.sh $ARGUMENTS
55+
```
56+
57+
`$ARGUMENTS` is the severity passed to the skill (defaults to `high` if omitted). The script runs `pnpm audit --prod --json` and filters for actionable vulnerabilities (those with a patched version available). `high` includes `critical`.
58+
59+
Parse the output to build a deduplicated list of vulnerable packages with:
60+
61+
- Package name and current version
62+
- Fixed version requirement
63+
- Full dependency chain (e.g., `packages/plugin-sentry > @sentry/nextjs > rollup`)
64+
65+
### 2. For Each Vulnerable Package
66+
67+
#### Trace the dependency chain
68+
69+
Identify whether the vulnerable package is:
70+
71+
- **Direct dependency**: Listed in a workspace package's `package.json`
72+
- **Transitive dependency**: Pulled in by another package
73+
74+
#### Try direct bump first
75+
76+
For transitive deps, walk up the chain to find the nearest package you control:
77+
78+
1. Check if bumping the **parent package** resolves the vulnerability
79+
- `pnpm view <parent>@latest dependencies.<vulnerable-pkg>`
80+
- Check intermediate versions too (the fix may exist in a minor bump)
81+
2. If the parent bump resolves it, research breaking changes:
82+
- Check changelogs/release notes
83+
- Search GitHub issues for compatibility problems
84+
- Review the API surface used in this repo (read the source files)
85+
- Check if the version range crosses a major version boundary
86+
3. Present findings to user with risk assessment
87+
88+
**Parallelize research**: When multiple packages need breaking change analysis, dispatch parallel agents (one per package) to research simultaneously.
89+
90+
#### Fall back to override only when justified
91+
92+
Add a scoped pnpm override in root `package.json` only when:
93+
94+
- No version of the parent package fixes the vulnerability
95+
- The parent bump has high breaking change risk (major API changes, no test coverage, requires code changes across many files)
96+
- The user explicitly decides to defer the parent bump to a separate PR
97+
98+
Override format: `"<parent>><vulnerable-pkg>": "<fixed-version>"`
99+
100+
Before adding any override, verify the target version exists:
101+
102+
```bash
103+
pnpm view <pkg>@<version> version
104+
```
105+
106+
### 3. Apply Fixes
107+
108+
- Edit `package.json` files for direct bumps
109+
- Edit root `package.json` `pnpm.overrides` for overrides (keep alphabetical)
110+
- If a direct bump changes behavior, update consuming code (e.g., adding `allowOverwrite: true` when an API default changes)
111+
112+
### 4. Install and Verify
113+
114+
```bash
115+
pnpm install
116+
```
117+
118+
If install fails due to native build errors (e.g., `better-sqlite3`), fall back to:
119+
120+
```bash
121+
pnpm install --ignore-scripts
122+
```
123+
124+
Then re-run the audit script with the same severity:
125+
126+
```bash
127+
./.github/workflows/audit-dependencies.sh $ARGUMENTS
128+
```
129+
130+
The audit script must exit 0. If vulnerabilities remain, check for additional instances of the same dependency in other workspace packages.
131+
132+
### 5. Build and Verify
133+
134+
```bash
135+
pnpm run build:core
136+
```
137+
138+
For packages with changed dependencies, also run their specific build:
139+
140+
```bash
141+
pnpm run build:<package-name>
142+
```
143+
144+
### 6. Look Up CVEs
145+
146+
For each fixed vulnerability, find the GitHub Security Advisory (GHSA):
147+
148+
- Check `https://github.com/<org>/<repo>/security/advisories` for each package
149+
- Search the web for `<package-name> GHSA <fixed-version>`
150+
- Record: GHSA ID, CVE ID, severity, one-line description
151+
- Prefer GHSA links (`https://github.com/advisories/GHSA-xxxx-xxxx-xxxx`) over NVD links
152+
153+
**Parallelize CVE lookups**: Dispatch parallel agents to search for CVEs across all packages simultaneously.
154+
155+
### 7. Commit and Create PR
156+
157+
Commit with conventional commit format:
158+
159+
```
160+
fix(deps): resolve $ARGUMENTS severity audit vulnerabilities
161+
```
162+
163+
Create PR using `gh pr create` with this body structure:
164+
165+
```markdown
166+
# Overview
167+
168+
[What the PR fixes, mention `pnpm audit --prod`]
169+
170+
## Key Changes
171+
172+
- **[Package name] in [workspace path]**
173+
- [old version][new version]. Fixes [GHSA-xxxx-xxxx-xxxx](https://github.com/advisories/GHSA-xxxx-xxxx-xxxx) ([description]).
174+
- [Why this approach: direct bump because X / override because Y]
175+
- [Any code changes required by the bump]
176+
177+
## Design Decisions
178+
179+
[Why direct bumps were preferred, justification for any remaining overrides]
180+
```
181+
182+
## Common Mistakes
183+
184+
| Mistake | Fix |
185+
| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
186+
| Jumping straight to overrides | Always check if bumping the parent resolves it first |
187+
| Not checking all workspace packages | Same dep may appear in multiple `package.json` files (e.g., `changelogen` in both `tools/releaser` and `tools/scripts`) |
188+
| Overriding with a nonexistent version | Verify the target version exists with `pnpm view` before installing |
189+
| Not falling back to `--ignore-scripts` | Pre-existing native build failures block `pnpm install`; use `--ignore-scripts` to get lockfile updated |
190+
| Missing code changes for breaking bumps | If a bump changes API defaults, update the calling code |
191+
| Forgetting advisory links in PR | Always look up and include GHSA links for each vulnerability |

.github/workflows/audit-dependencies.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
#!/bin/bash
22

3+
valid_severities=("low" "moderate" "high" "critical")
34
severity=${1:-"high"}
45
output_file="audit_output.json"
56

7+
if [[ ! " ${valid_severities[*]} " =~ \ ${severity}\ ]]; then
8+
echo "Error: invalid severity '${severity}'"
9+
echo "Valid values: ${valid_severities[*]}"
10+
exit 2
11+
fi
12+
613
echo "Auditing for ${severity} vulnerabilities..."
714

815
audit_json=$(pnpm audit --prod --json)

0 commit comments

Comments
 (0)