Skip to content

feat: workspace-scoped lockfile-refresh commands, section rendering fix, and fix coverage count#451

Merged
sonukapoor merged 5 commits into
mainfrom
feature/issue-450-lockfile-refresh-commands
May 25, 2026
Merged

feat: workspace-scoped lockfile-refresh commands, section rendering fix, and fix coverage count#451
sonukapoor merged 5 commits into
mainfrom
feature/issue-450-lockfile-refresh-commands

Conversation

@sonukapoor
Copy link
Copy Markdown
Collaborator

Extends #450 with workspace awareness and output improvements across all three areas.

Workspace-scoped commands — npm, pnpm, and bun now emit workspace-targeted commands when a lockfile-refresh can fix a transitive vulnerability. For pnpm this means pnpm -C <path> update --no-save <pkg> for a single workspace or pnpm update --recursive --no-save <pkg> when the vulnerable package is declared across multiple workspaces. For npm it means npm update --workspace=<path> or npm update --workspaces. Yarn keeps the generic yarn upgrade <pkg> since its workspace protocol doesn't need path targeting. Workspace paths are collected from all dependency paths (not just the shortest), so every affected workspace is captured.

pnpm-workspace.yaml supportreadDirectDependencyNames now falls back to reading pnpm-workspace.yaml when package.json has no workspaces field. This was blocking correct direct-dependency detection in pnpm monorepos that use the dedicated YAML file (e.g. valibot), which in turn caused simple-git and similar packages to receive no workspace-scoped fix command.

Section rendering fixparent-update targets now get their own titled sections ("Critical severity parent updates within range", "High severity parent updates within range") instead of being merged into the urgent direct-fix sections. This eliminates the two-table rendering issue where a direct-install table and a lockfile-refresh table appeared inside the same section.

Fix coverage count — Both the terminal output and the HTML report now show how many findings the plan covers after all commands: "Running all commands above should fix X of Y findings." The count is computed by checking each finding against the final plan using the existing findSuggestedCommandForFinding logic.

HTML display fix — The HTML report's fix plan target list now uses displayTargetVersion ("within current range") instead of the raw semver for parent-update targets, matching the terminal output.

Closes #450

…ve fixes

When the parent package's declared range already covers the fixed version
of a vulnerable transitive dependency, non-npm package managers can update
the lockfile directly without a parent version bump.

Previously, fix-commands.ts skipped this case for all non-npm package
managers with a message that the fix path was npm-specific. This change
replaces that skip with targeted update commands:

- pnpm: pnpm update <dep>
- yarn: yarn upgrade <dep>
- bun: bun update <dep>

Closes #450
…registry

Extends the transitive remediation scanner to check whether the installed
parent package already declares a version range that covers the fixed
transitive dependency. Previously this check only ran for npm (via the
package-lock graph). For pnpm, yarn, and bun lockfiles the scanner now
fetches the installed parent's published manifest from the npm registry
and checks whether the parent's declared range for the vulnerable child
already allows a safe version.

When a match is found, the finding gets recommendedNpmTransitiveRemediation
set to update-parent-within-range and fix-commands.ts emits the correct
lockfile-refresh command (pnpm update / yarn upgrade / bun update) instead
of skipping the finding.

Closes #450
Plain pnpm update only runs in the root workspace. For monorepos where a
transitive dep is pulled in across multiple importers, --recursive ensures
all workspace lockfile entries are refreshed. --no-save prevents pnpm from
writing the package to any workspace package.json, which is correct since
we are only refreshing a transitive dependency's resolved version.
…ng, add coverage count

- Add workspace map builders for npm (package-lock.json), pnpm (pnpm-lock.yaml),
  and bun (bun.lock) to track which workspaces declare each direct dependency
- Read pnpm-workspace.yaml as fallback when package.json has no workspaces field,
  fixing direct-dependency detection in pnpm monorepos
- Emit workspace-scoped lockfile-refresh commands: npm update --workspace=<path>,
  pnpm -C <path> update --no-save, pnpm update --recursive for multi-workspace
- Collect workspace paths from all dependency paths (not just the shortest),
  ensuring every affected workspace gets the correct scoped command
- Move parent-update targets into their own sections (Critical/High severity
  parent updates within range) to eliminate mixed-table rendering
- Fix HTML report to use displayTargetVersion (within current range) instead
  of raw semver for parent-update targets
- Show fix coverage count after the command plan in both terminal and HTML:
  Running all commands above should fix X of Y findings
- Wrap workspace map builders in try-catch so a parse failure never aborts
  the scan -- workspace scoping is best-effort
…context strings

The previous label and context strings were opaque — 'within current range' gave
no hint to the developer that a lockfile refresh (not a parent upgrade) is what's
needed. Replace with 'lockfile refresh' as the display label and rewrite the reason
strings to state plainly that the parent already permits the safe child version.
@sonukapoor sonukapoor merged commit 7a03495 into main May 25, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: suggest lockfile-refresh commands when parent range already covers the fixed version

1 participant