diff --git a/.agents/skills/README.md b/.agents/skills/README.md index a69b29cb87..d53facec3b 100644 --- a/.agents/skills/README.md +++ b/.agents/skills/README.md @@ -18,7 +18,8 @@ This directory contains all Claude Code skills for the web-widgets repository. ├── openspec-onboard/ # Guided OpenSpec onboarding ├── openspec-propose/ # Propose new change with all artifacts ├── openspec-sync-specs/ # Sync delta specs to main specs -└── openspec-verify-change/ # Verify implementation matches artifacts +├── openspec-verify-change/ # Verify implementation matches artifacts +└── bump-transitive/ # Surgically bump a vulnerable transitive dependency ``` ## Usage @@ -28,6 +29,7 @@ Skills are automatically loaded by Claude Code. Users can invoke them via slash - `/code-review` — Review current PR - `/debug-widget` — Debug widget runtime issues - `/openspec-*` or `/opsx:*` — OpenSpec workflow commands +- `/bump-transitive` — Bump a vulnerable transitive dep to its latest safe patch per major ## Skill Format diff --git a/.agents/skills/bump-transitive/SKILL.md b/.agents/skills/bump-transitive/SKILL.md new file mode 100644 index 0000000000..5487a24f02 --- /dev/null +++ b/.agents/skills/bump-transitive/SKILL.md @@ -0,0 +1,103 @@ +--- +name: bump-transitive +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. +--- + +# Fix Vulnerable Transitive Dependency + +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. + +The user will provide the package name and the fixed versions from the advisory. + +## Process + +### 1. Discover all versions in use + +Run `pnpm why -r` to see every resolved version and the full dependency chain explaining why each exists: + +```sh +pnpm why -r +``` + +Each top-level line (`@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. + +To extract just the version list: + +```sh +pnpm why -r | grep '^@' +``` + +### 2. Find latest safe version per major + +For each major currently in the lockfile, find the latest available version on npm: + +```sh +npm view versions --json | node -e " +const v = JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')); +const majors = {}; +v.forEach(ver => { + const m = parseInt(ver.split('.')[0]); + if (!majors[m]) majors[m] = []; + majors[m].push(ver); +}); +Object.entries(majors).forEach(([m, vers]) => { + console.log('Major', m, '— latest:', vers[vers.length-1]); +}); +" +``` + +Cross-reference with the advisory's "Fixed in" versions — use whichever is higher. + +### 3. Add overrides to root package.json + +In the `pnpm.overrides` section of the root `package.json`, add one entry per major using the `@major` selector syntax: + +```json +"pnpm": { + "overrides": { + "@1": "1.x.y", + "@2": "2.x.y", + "@5": "5.x.y" + } +} +``` + +Only add majors that are actually present in the lockfile. + +### 4. First pnpm install — update the lockfile + +```sh +pnpm install +``` + +This writes the pinned versions into `pnpm-lock.yaml`. + +### 5. Remove the overrides from package.json + +Delete the entries added in step 3. The lockfile now has the correct versions recorded and will enforce them on its own. + +### 6. Second pnpm install — clean up + +```sh +pnpm install +``` + +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. + +### 7. Verify + +Check that the lockfile diff is surgical — only the target package versions changed: + +```sh +git diff pnpm-lock.yaml | grep '^[-+]' | grep -v '^---\|^+++' | grep -v '' +``` + +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. + +## Rules + +- **Never run `pnpm update` or `pnpm upgrade`** — these re-resolve the entire dependency graph. +- **Never delete `pnpm-lock.yaml`** — regenerating it from scratch bumps everything within semver ranges. +- **Never use `--frozen-lockfile`** on either install — the first install must update the lockfile, the second must reconcile the config snapshot. +- Only add overrides for majors actually present in the lockfile — do not add speculative entries. +- If the package is a **direct** dependency (appears in a `package.json` `dependencies`/`devDependencies`), edit that file directly instead of using overrides.