Skip to content

Commit 974870a

Browse files
authored
chore(claude): update audit-dependencies skill with lockfile strategy and override rules (#16106)
# Overview Updates the audit-dependencies skill to include a lockfile-update strategy as an intermediate fix between direct dependency bumps and pnpm overrides. Also adds documentation for common pnpm override pitfalls learned from recent audit work. ## Key Changes - **Added lockfile update as a fix strategy** - When a transitive dependency's parent uses a semver range that already includes the fixed version, `pnpm update --recursive` is enough. No `package.json` changes needed. The workflow now checks pinned vs ranged before falling back to overrides. - **Documented pnpm override syntax rules** - Added guidance on using `^` ranges instead of `>=` (which can cross major versions), single-level parent scoping limitations, unsupported version selectors in keys, and risks of global overrides across multiple major versions. - **Added user confirmation step before applying fixes** - The workflow now requires presenting a summary table of proposed fixes and getting user confirmation before making changes. This prevents wasted effort from incorrect fix strategies. ## Design Decisions The fix priority order is now: direct bump > lockfile update > override. The lockfile update step was added because several audit vulnerabilities were resolvable without any `package.json` changes — the parent's semver range already covered the fix, but the lockfile had a stale resolution. Recognizing this case avoids unnecessary overrides that add long-term maintenance burden. The override syntax rules were added because pnpm's override behavior has non-obvious edge cases (e.g., `>=` crossing majors, no nested scoping) that caused issues in practice. ## Overall Flow ```mermaid flowchart TD A[Run audit script] --> B[Group by package] B --> C[Trace dependency chain] C --> D{Can bump direct dep?} D -->|yes| E[Research breaking changes] D -->|no| F{Pinned or ranged?} E --> G{Breaking changes ok?} G -->|yes| H[Apply direct bump] G -->|no| F F -->|ranged, fix in range| I[Lockfile update] F -->|pinned| J[Apply pnpm override] H --> K{More packages?} I --> K J --> K K -->|yes| C K -->|no| L[Present plan to user] L --> M[Install and verify] M --> N[Build and verify] N --> O[Commit and create PR] ```
1 parent 0f79eed commit 974870a

1 file changed

Lines changed: 64 additions & 21 deletions

File tree

  • .claude/skills/audit-dependencies

.claude/skills/audit-dependencies/SKILL.md

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ name: audit-dependencies
33
description: Use when fixing dependency vulnerabilities, running pnpm audit, or when the audit-dependencies CI check fails
44
user-invocable: true
55
disable-model-invocation: true
6-
argument-hint: "critical|high|moderate|low"
6+
argument-hint: 'critical|high|moderate|low'
77
---
88

99
# Audit Dependencies
1010

1111
## Overview
1212

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.
13+
Fix dependency vulnerabilities reported by `.github/workflows/audit-dependencies.sh`. Prefer fixes in this order: direct dependency bump > lockfile update > pnpm override. Every override requires justification for why simpler approaches aren't feasible.
1414

1515
## Core Workflow
1616

@@ -23,8 +23,11 @@ digraph audit {
2323
"Research breaking changes" [shape=box];
2424
"Breaking changes acceptable?" [shape=diamond];
2525
"Apply direct bump" [shape=box];
26+
"Is version pinned or ranged?" [shape=diamond];
27+
"Lockfile update" [shape=box];
2628
"Apply pnpm override" [shape=box];
2729
"More packages?" [shape=diamond];
30+
"Present plan to user" [shape=box];
2831
"Install and verify" [shape=box];
2932
"Build and verify" [shape=box];
3033
"Commit and create PR" [shape=box];
@@ -33,14 +36,18 @@ digraph audit {
3336
"Group by package" -> "Trace dependency chain";
3437
"Trace dependency chain" -> "Can bump direct dep?";
3538
"Can bump direct dep?" -> "Research breaking changes" [label="yes"];
36-
"Can bump direct dep?" -> "Apply pnpm override" [label="no - explain why"];
39+
"Can bump direct dep?" -> "Is version pinned or ranged?" [label="no"];
3740
"Research breaking changes" -> "Breaking changes acceptable?";
3841
"Breaking changes acceptable?" -> "Apply direct bump" [label="yes"];
39-
"Breaking changes acceptable?" -> "Apply pnpm override" [label="no - explain why"];
42+
"Breaking changes acceptable?" -> "Is version pinned or ranged?" [label="no"];
43+
"Is version pinned or ranged?" -> "Lockfile update" [label="ranged - fix is in range"];
44+
"Is version pinned or ranged?" -> "Apply pnpm override" [label="pinned - explain why"];
4045
"Apply direct bump" -> "More packages?";
46+
"Lockfile update" -> "More packages?";
4147
"Apply pnpm override" -> "More packages?";
4248
"More packages?" -> "Trace dependency chain" [label="yes"];
43-
"More packages?" -> "Install and verify" [label="no"];
49+
"More packages?" -> "Present plan to user" [label="no"];
50+
"Present plan to user" -> "Install and verify";
4451
"Install and verify" -> "Build and verify";
4552
"Build and verify" -> "Commit and create PR";
4653
}
@@ -87,29 +94,59 @@ For transitive deps, walk up the chain to find the nearest package you control:
8794

8895
**Parallelize research**: When multiple packages need breaking change analysis, dispatch parallel agents (one per package) to research simultaneously.
8996

97+
#### Check if a lockfile update is sufficient
98+
99+
Before reaching for an override, check whether the parent's version specifier is **pinned** (exact version like `3.10.3`) or **ranged** (like `^2.3.1`, `~4.0.3`):
100+
101+
```bash
102+
pnpm view <parent> dependencies.<vulnerable-pkg>
103+
```
104+
105+
If the range already includes the fixed version, a lockfile update is all that's needed:
106+
107+
```bash
108+
pnpm update <vulnerable-pkg> --recursive
109+
```
110+
111+
No `package.json` changes required — the lockfile was just stale.
112+
90113
#### Fall back to override only when justified
91114

92-
Add a scoped pnpm override in root `package.json` only when:
115+
Add a pnpm override in root `package.json` only when:
93116

117+
- The parent pins an exact version that doesn't satisfy the fix
94118
- No version of the parent package fixes the vulnerability
95119
- The parent bump has high breaking change risk (major API changes, no test coverage, requires code changes across many files)
96120
- The user explicitly decides to defer the parent bump to a separate PR
97121

98-
Override format: `"<parent>><vulnerable-pkg>": "<fixed-version>"`
122+
Override format: `"<parent>><vulnerable-pkg>": "^<fixed-version>"`
123+
124+
**Override syntax rules:**
125+
126+
- Use `^` ranges, not `>=`. `>=` can cross major versions and cause unexpected resolutions (e.g., `"picomatch": ">=2.3.2"` can resolve to 4.x).
127+
- pnpm only supports single-level parent scoping: `"parent>pkg"` works, `"grandparent>parent>pkg"` does not.
128+
- pnpm does not support version selectors in override keys: `"pkg@^2"` does not work.
129+
- If the same vulnerable package appears through many transitive paths, a global override may be needed. Be careful that it doesn't affect unrelated consumers on a different major version — use parent-scoped overrides when the package spans multiple major versions across the tree.
130+
- pnpm only honors `overrides` in the root workspace `package.json`. Overrides in workspace packages are ignored.
99131

100132
Before adding any override, verify the target version exists:
101133

102134
```bash
103135
pnpm view <pkg>@<version> version
104136
```
105137

106-
### 3. Apply Fixes
138+
### 3. Present Plan to User
139+
140+
Before applying fixes, present a summary table to the user showing each vulnerability, the proposed fix strategy (direct bump / lockfile update / override), and justification. Get confirmation before proceeding.
141+
142+
### 4. Apply Fixes
107143

108144
- Edit `package.json` files for direct bumps
145+
- Run `pnpm update <pkg> --recursive` for lockfile-only fixes
109146
- Edit root `package.json` `pnpm.overrides` for overrides (keep alphabetical)
110147
- If a direct bump changes behavior, update consuming code (e.g., adding `allowOverwrite: true` when an API default changes)
111148

112-
### 4. Install and Verify
149+
### 5. Install and Verify
113150

114151
```bash
115152
pnpm install
@@ -129,7 +166,7 @@ Then re-run the audit script with the same severity:
129166

130167
The audit script must exit 0. If vulnerabilities remain, check for additional instances of the same dependency in other workspace packages.
131168

132-
### 5. Build and Verify
169+
### 6. Build and Verify
133170

134171
```bash
135172
pnpm run build:core
@@ -141,7 +178,7 @@ For packages with changed dependencies, also run their specific build:
141178
pnpm run build:<package-name>
142179
```
143180

144-
### 6. Look Up CVEs
181+
### 7. Look Up CVEs
145182

146183
For each fixed vulnerability, find the GitHub Security Advisory (GHSA):
147184

@@ -152,7 +189,7 @@ For each fixed vulnerability, find the GitHub Security Advisory (GHSA):
152189

153190
**Parallelize CVE lookups**: Dispatch parallel agents to search for CVEs across all packages simultaneously.
154191

155-
### 7. Commit and Create PR
192+
### 8. Commit and Create PR
156193

157194
Commit with conventional commit format:
158195

@@ -171,7 +208,7 @@ Create PR using `gh pr create` with this body structure:
171208

172209
- **[Package name] in [workspace path]**
173210
- [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]
211+
- [Why this approach: direct bump because X / lockfile update because Y / override because Z]
175212
- [Any code changes required by the bump]
176213

177214
## Design Decisions
@@ -181,11 +218,17 @@ Create PR using `gh pr create` with this body structure:
181218

182219
## Common Mistakes
183220

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 |
221+
| Mistake | Fix |
222+
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
223+
| Jumping straight to overrides | Check: can you bump the parent? If not, does the semver range already allow the fix (lockfile update)? Only then override. |
224+
| Using `>=` in override ranges | Use `^` to stay within the same major version. `>=2.3.2` can resolve to 4.x. |
225+
| Not checking pinned vs ranged | `pnpm view <parent> dependencies.<pkg>` — if ranged and the fix is in range, just `pnpm update`. |
226+
| Nested override scoping (`a>b>c`) | pnpm only supports single-level: `"parent>pkg"`. For deeper chains, override the direct parent or use a global override. |
227+
| Version selectors in override keys (`pkg@^2`) | Not supported by pnpm. Use parent-scoped or global overrides instead. |
228+
| Global override affecting multiple major versions | `"picomatch": ">=4.0.4"` forces all picomatch to 4.x, breaking consumers that need 2.x. Scope overrides to the parent when a package spans multiple majors. |
229+
| Not checking all workspace packages | Same dep may appear in multiple `package.json` files (e.g., `changelogen` in both `tools/releaser` and `tools/scripts`) |
230+
| Overriding with a nonexistent version | Verify the target version exists with `pnpm view` before installing |
231+
| Not falling back to `--ignore-scripts` | Pre-existing native build failures block `pnpm install`; use `--ignore-scripts` to get lockfile updated |
232+
| Missing code changes for breaking bumps | If a bump changes API defaults, update the calling code |
233+
| Forgetting advisory links in PR | Always look up and include GHSA links for each vulnerability |
234+
| Applying fixes without user confirmation | Present the full plan (strategy per vuln + justification) and get confirmation before making changes |

0 commit comments

Comments
 (0)