From f34d395fa525f75a75e2d60d4df963461417f6f0 Mon Sep 17 00:00:00 2001
From: Rhys Arkins <rhys@arkins.net>
Date: Sun, 15 Jan 2023 10:24:19 +0100
Subject: [PATCH] fix(npm): augment constraints less aggressively (#19850)

---
 .../npm/extract/locked-versions.spec.ts       | 74 +++++++++++++++++++
 .../manager/npm/extract/locked-versions.ts    |  6 +-
 2 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/lib/modules/manager/npm/extract/locked-versions.spec.ts b/lib/modules/manager/npm/extract/locked-versions.spec.ts
index 64aec7d91c..fec0bd9a0e 100644
--- a/lib/modules/manager/npm/extract/locked-versions.spec.ts
+++ b/lib/modules/manager/npm/extract/locked-versions.spec.ts
@@ -344,6 +344,39 @@ describe('modules/manager/npm/extract/locked-versions', () => {
       ]);
     });
 
+    it('skips augmenting v2 lock file constraint', async () => {
+      npm.getNpmLock.mockReturnValue({
+        lockedVersions: { a: '1.0.0', b: '2.0.0', c: '3.0.0' },
+        lockfileVersion: 2,
+      });
+      const packageFiles = [
+        {
+          npmLock: 'package-lock.json',
+          constraints: {
+            npm: '>=9.0.0',
+          },
+          deps: [
+            { depName: 'a', currentValue: '1.0.0' },
+            { depName: 'b', currentValue: '2.0.0' },
+          ],
+        },
+      ];
+      await getLockedVersions(packageFiles);
+      expect(packageFiles).toEqual([
+        {
+          constraints: {
+            npm: '>=9.0.0',
+          },
+          deps: [
+            { currentValue: '1.0.0', depName: 'a', lockedVersion: '1.0.0' },
+            { currentValue: '2.0.0', depName: 'b', lockedVersion: '2.0.0' },
+          ],
+          lockFiles: ['package-lock.json'],
+          npmLock: 'package-lock.json',
+        },
+      ]);
+    });
+
     it('appends <7 to npm constraints', async () => {
       npm.getNpmLock.mockReturnValue({
         lockedVersions: {
@@ -385,6 +418,47 @@ describe('modules/manager/npm/extract/locked-versions', () => {
       ]);
     });
 
+    it('skips appending <7 to npm constraints', async () => {
+      npm.getNpmLock.mockReturnValue({
+        lockedVersions: {
+          a: '1.0.0',
+          b: '2.0.0',
+          c: '3.0.0',
+        },
+        lockfileVersion: 1,
+      });
+      const packageFiles = [
+        {
+          npmLock: 'package-lock.json',
+          constraints: {
+            npm: '^8.0.0',
+          },
+          deps: [
+            {
+              depName: 'a',
+              currentValue: '1.0.0',
+            },
+            {
+              depName: 'b',
+              currentValue: '2.0.0',
+            },
+          ],
+        },
+      ];
+      await getLockedVersions(packageFiles);
+      expect(packageFiles).toEqual([
+        {
+          constraints: { npm: '^8.0.0' },
+          deps: [
+            { currentValue: '1.0.0', depName: 'a', lockedVersion: '1.0.0' },
+            { currentValue: '2.0.0', depName: 'b', lockedVersion: '2.0.0' },
+          ],
+          lockFiles: ['package-lock.json'],
+          npmLock: 'package-lock.json',
+        },
+      ]);
+    });
+
     it('ignores pnpm', async () => {
       const packageFiles = [
         {
diff --git a/lib/modules/manager/npm/extract/locked-versions.ts b/lib/modules/manager/npm/extract/locked-versions.ts
index 4ddece56b4..770177fff5 100644
--- a/lib/modules/manager/npm/extract/locked-versions.ts
+++ b/lib/modules/manager/npm/extract/locked-versions.ts
@@ -60,7 +60,7 @@ export async function getLockedVersions(
       if (lockfileVersion === 1) {
         if (packageFile.constraints?.npm) {
           // Add a <7 constraint if it's not already a fixed version
-          if (!semver.valid(packageFile.constraints.npm)) {
+          if (semver.satisfies('6.14.18', packageFile.constraints.npm)) {
             packageFile.constraints.npm += ' <7';
           }
         } else {
@@ -68,8 +68,8 @@ export async function getLockedVersions(
         }
       } else if (lockfileVersion === 2) {
         if (packageFile.constraints?.npm) {
-          // Add a <9 constraint if it's not already a fixed version
-          if (!semver.valid(packageFile.constraints.npm)) {
+          // Add a <9 constraint if the latest 8.x is compatible
+          if (semver.satisfies('8.19.3', packageFile.constraints.npm)) {
             packageFile.constraints.npm += ' <9';
           }
         } else {
-- 
GitLab