Skip to content

Commit a5f06c0

Browse files
authored
chore(skills): bump-transitive skill (#2367)
2 parents 0b35ff9 + 06ad7ba commit a5f06c0

2 files changed

Lines changed: 106 additions & 1 deletion

File tree

.agents/skills/README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ This directory contains all Claude Code skills for the web-widgets repository.
1818
├── openspec-onboard/ # Guided OpenSpec onboarding
1919
├── openspec-propose/ # Propose new change with all artifacts
2020
├── openspec-sync-specs/ # Sync delta specs to main specs
21-
└── openspec-verify-change/ # Verify implementation matches artifacts
21+
├── openspec-verify-change/ # Verify implementation matches artifacts
22+
└── bump-transitive/ # Surgically bump a vulnerable transitive dependency
2223
```
2324

2425
## Usage
@@ -28,6 +29,7 @@ Skills are automatically loaded by Claude Code. Users can invoke them via slash
2829
- `/code-review` — Review current PR
2930
- `/debug-widget` — Debug widget runtime issues
3031
- `/openspec-*` or `/opsx:*` — OpenSpec workflow commands
32+
- `/bump-transitive` — Bump a vulnerable transitive dep to its latest safe patch per major
3133

3234
## Skill Format
3335

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
---
2+
name: bump-transitive
3+
description: Surgically bump a vulnerable transitive dependency to its latest patch per major using pnpm.overrides, then clean up without leaving override traces in package.json.
4+
---
5+
6+
# Fix Vulnerable Transitive Dependency
7+
8+
Use when a security advisory identifies a vulnerable transitive package (one not directly in any `package.json`) and you need to force it to a safe version across the monorepo without bumping unrelated packages.
9+
10+
The user will provide the package name and the fixed versions from the advisory.
11+
12+
## Process
13+
14+
### 1. Discover all versions in use
15+
16+
Run `pnpm why -r` to see every resolved version and the full dependency chain explaining why each exists:
17+
18+
```sh
19+
pnpm why -r <package>
20+
```
21+
22+
Each top-level line (`<package>@x.y.z`) is a distinct version in the graph. The tree below it shows which packages pull it in — useful for understanding whether a version can be collapsed or must stay separate.
23+
24+
To extract just the version list:
25+
26+
```sh
27+
pnpm why -r <package> | grep '^<package>@'
28+
```
29+
30+
### 2. Find latest safe version per major
31+
32+
For each major currently in the lockfile, find the latest available version on npm:
33+
34+
```sh
35+
npm view <package> versions --json | node -e "
36+
const v = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
37+
const majors = {};
38+
v.forEach(ver => {
39+
const m = parseInt(ver.split('.')[0]);
40+
if (!majors[m]) majors[m] = [];
41+
majors[m].push(ver);
42+
});
43+
Object.entries(majors).forEach(([m, vers]) => {
44+
console.log('Major', m, '— latest:', vers[vers.length-1]);
45+
});
46+
"
47+
```
48+
49+
Cross-reference with the advisory's "Fixed in" versions — use whichever is higher.
50+
51+
### 3. Add overrides to root package.json
52+
53+
In the `pnpm.overrides` section of the root `package.json`, add one entry per major using the `@major` selector syntax:
54+
55+
```json
56+
"pnpm": {
57+
"overrides": {
58+
"<package>@1": "1.x.y",
59+
"<package>@2": "2.x.y",
60+
"<package>@5": "5.x.y"
61+
}
62+
}
63+
```
64+
65+
Only add majors that are actually present in the lockfile.
66+
67+
### 4. First pnpm install — update the lockfile
68+
69+
```sh
70+
pnpm install
71+
```
72+
73+
This writes the pinned versions into `pnpm-lock.yaml`.
74+
75+
### 5. Remove the overrides from package.json
76+
77+
Delete the entries added in step 3. The lockfile now has the correct versions recorded and will enforce them on its own.
78+
79+
### 6. Second pnpm install — clean up
80+
81+
```sh
82+
pnpm install
83+
```
84+
85+
This removes the override snapshot from the lockfile's config block and leaves a clean state: no trace of the rewrite in `package.json`, no stale override metadata in the lockfile.
86+
87+
### 7. Verify
88+
89+
Check that the lockfile diff is surgical — only the target package versions changed:
90+
91+
```sh
92+
git diff pnpm-lock.yaml | grep '^[-+]' | grep -v '^---\|^+++' | grep -v '<package>'
93+
```
94+
95+
The only non-target lines should be inconsequential formatting shuffles (identical values on both sides of the diff). If other packages were bumped, investigate before proceeding.
96+
97+
## Rules
98+
99+
- **Never run `pnpm update` or `pnpm upgrade`** — these re-resolve the entire dependency graph.
100+
- **Never delete `pnpm-lock.yaml`** — regenerating it from scratch bumps everything within semver ranges.
101+
- **Never use `--frozen-lockfile`** on either install — the first install must update the lockfile, the second must reconcile the config snapshot.
102+
- Only add overrides for majors actually present in the lockfile — do not add speculative entries.
103+
- If the package is a **direct** dependency (appears in a `package.json` `dependencies`/`devDependencies`), edit that file directly instead of using overrides.

0 commit comments

Comments
 (0)