Skip to content

feat: add vulnerability quick-fix + hint#39

Merged
9romise merged 11 commits intonpmx-dev:mainfrom
nitodeco:vuln-quick-fix
Feb 18, 2026
Merged

feat: add vulnerability quick-fix + hint#39
9romise merged 11 commits intonpmx-dev:mainfrom
nitodeco:vuln-quick-fix

Conversation

@nitodeco
Copy link
Collaborator

@nitodeco nitodeco commented Feb 9, 2026

Closes #24

marked 16 1 1, This version has 1 high, 2 moderate vulnerabilities  Upgrade to 16 1 5 to

@nitodeco nitodeco requested a review from 9romise February 9, 2026 23:24
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a vulnerability code-action provider that offers quick-fix actions to update vulnerable dependencies to safer versions. It adds a new VulnerabilityCodeActionProvider that scans vulnerability diagnostics and extracts "fixed in" version information, then emits preferred quick-fix code actions to replace affected versions in documents. The diagnostic rule is enhanced to parse and surface this fixed-in version in diagnostic messages and target URLs. Supporting changes include expanded mock exports for testing and a new module alias for test configuration.

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description references the related issue #24 and includes screenshots demonstrating the vulnerability quick-fix feature, directly relating to the changeset.
Linked Issues check ✅ Passed All code changes fully address issue #24 requirements: the vulnerability rule now extracts fixed-in versions, the code action provider offers quick fixes to update vulnerable packages, and messages display the earliest safe version.
Out of Scope Changes check ✅ Passed All changes are directly scoped to implementing the vulnerability quick-fix feature: diagnostic enhancements, code action provider, supporting utilities, tests, and configuration updates are all required for the feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/providers/code-actions/vulnerability.ts (1)

47-51: Minor: Redundant parseVersion call on fixedInVersion.

The fixedInVersion extracted from the diagnostic code is already a raw semver string (e.g., "16.1.5"), so parseVersion(fixedInVersion)?.semver will return the same value. While this works correctly, it's slightly redundant.

♻️ Optional simplification
       const currentVersion = document.getText(diagnostic.range)
       const currentSemver = parseVersion(currentVersion)?.semver
-      const fixedSemver = parseVersion(fixedInVersion)?.semver ?? fixedInVersion
-      if (currentSemver && currentSemver === fixedSemver)
+      if (currentSemver && currentSemver === fixedInVersion)
         return []

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/providers/diagnostics/rules/vulnerability.ts (1)

75-103: ⚠️ Potential issue | 🟠 Major

Guard vulnerablePackages to avoid runtime crashes.
If the API omits vulnerablePackages, Line 94 will throw, breaking diagnostics for the file. Default to an empty list before filtering.

🔧 Suggested fix
-  const { totalCounts, vulnerablePackages } = result
+  const { totalCounts, vulnerablePackages = [] } = result
@@
-  const rootVulnerabilitiesFixedIn = vulnerablePackages
+  const rootVulnerabilitiesFixedIn = vulnerablePackages
     .filter((vulnerablePackage) => vulnerablePackage.depth === 'root')

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/providers/diagnostics/rules/vulnerability.ts (2)

15-20: Clarify function intent: this finds the maximum (not earliest) fixedIn version.

The reduce logic returns the maximum version from the list (since lt(best, current) keeps the larger value). This is correct when you need to fix all vulnerabilities simultaneously—the user must upgrade to at least the highest fixedIn version. However, the PR objective references "earliest safe version," which could cause confusion.

Consider renaming to getMinimumRequiredFixVersion or adding a brief comment explaining why the maximum is chosen.

📝 Suggested clarification
+/**
+ * Returns the highest fixedIn version, ensuring all vulnerabilities are addressed.
+ */
 function getBestFixedInVersion(fixedInVersions: string[]): string | undefined {
   if (!fixedInVersions.length)
     return

-  return fixedInVersions.reduce((best, current) => lt(best, current) ? current : best)
+  return fixedInVersions.reduce((best, current) => lt(best, current) ? current : best)
 }

62-64: Reconsider preserving the version prefix in the upgrade message.

Using parsed.prefix (e.g., ^ or ~) in the message produces output like "Upgrade to ^16.1.5 to fix." This could be confusing because:

  1. The prefix implies a range, not a specific version.
  2. If the user's current range (e.g., ^16.0.0) already technically includes 16.1.5, the message may seem contradictory.

Consider showing the exact version without a prefix in the message, or clarifying that the version number is the minimum required.

💡 Suggested fix
   const fixedInVersion = getBestFixedInVersion(rootVulnerabilitiesFixedIn)
   const messageSuffix = fixedInVersion
-    ? ` Upgrade to ${parsed.prefix}${fixedInVersion} to fix.`
+    ? ` Upgrade to ${fixedInVersion} to fix.`
     : ''

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@nitodeco nitodeco requested a review from 9romise February 16, 2026 14:16
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/code-actions/vulnerability.test.ts (1)

45-50: Consider also asserting the WorkspaceEdit replacement and CodeActionKind.

The test only checks title and isPreferred via objectContaining. Verifying that edit contains the correct replacement text (e.g. ^1.2.3) and that kind === CodeActionKind.QuickFix would catch regressions in the actual fix logic, not just the label.

src/providers/diagnostics/rules/vulnerability.ts (1)

55-61: Guard against duplicate fixedIn values before selecting the best.

If multiple root-level vulnerabilities report the same fixedIn version, rootVulnerabilitiesFixedIn will contain duplicates. This is harmless for correctness (the reduce still picks the minimum), but deduplicating avoids redundant comparisons and makes intent clearer.

Proposed change
  const rootVulnerabilitiesFixedIn = vulnerablePackages
    .flatMap(({ depth, vulnerabilities }) => {
      if (depth !== 'root')
        return []

      return vulnerabilities.flatMap(({ fixedIn }) => fixedIn ? [fixedIn] : [])
    })

- const fixedInVersion = getBestFixedInVersion(rootVulnerabilitiesFixedIn)
+ const fixedInVersion = getBestFixedInVersion([...new Set(rootVulnerabilitiesFixedIn)])

@9romise 9romise merged commit f34f4ac into npmx-dev:main Feb 18, 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.

Display earliest safe version for vulnurability check

2 participants