fix(npm): lockfileVersion 2+ transitiveRemediation only if package.json changes (#14173)

This commit is contained in:
Rhys Arkins 2022-02-11 14:20:55 +01:00 committed by GitHub
parent 0786775005
commit b2183a30c5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 398 additions and 2 deletions

View file

@ -2638,7 +2638,9 @@ Please see the above link for valid timezone names.
When enabled, Renovate will attempt to remediate vulnerabilities even if they exist only in transitive dependencies.
Applicable only for GitHub platform (with vulnerability alerts enabled), `npm` manager, and when a `package-lock.json` v1 format is present.
Applicable only for GitHub platform (with vulnerability alerts enabled) and `npm` manager.
When the `lockfileVersion` is higher than `1` in `package-lock.json`, remediations are only possible when changes are made to `package.json`.
This is considered a feature flag with the aim to remove it and default to this behavior once it has been more widely tested.
## unicodeEmoji

View file

@ -6,6 +6,7 @@ import { updateLockedDependency } from '.';
const packageFileContent = loadFixture('package.json', './package-lock');
const lockFileContent = loadFixture('package-lock.json', './package-lock');
const lockFileV2Content = loadFixture('package-lock-v2.json', './package-lock');
const acceptsJson = JSON.parse(loadFixture('accepts.json', './package-lock'));
const expressJson = JSON.parse(loadFixture('express.json', './common'));
const mimeJson = JSON.parse(loadFixture('mime.json', './package-lock'));
@ -92,6 +93,16 @@ describe('manager/npm/update/locked-dependency/index', () => {
JSON.parse(res.files['package-lock.json']).dependencies.mime.version
).toBe('1.2.12');
});
it('rejects in-range remediation if lockfile v2+', async () => {
const res = await updateLockedDependency({
...config,
lockFileContent: lockFileV2Content,
depName: 'mime',
currentVersion: '1.2.11',
newVersion: '1.2.12',
});
expect(res.status).toBe('unsupported');
});
it('fails to remediate if parent dep cannot support', async () => {
const acceptsModified = clone(acceptsJson);
acceptsModified.versions['2.0.0'] = {};
@ -120,6 +131,16 @@ describe('manager/npm/update/locked-dependency/index', () => {
const packageLock = JSON.parse(res.files['package-lock.json']);
expect(packageLock.dependencies.express.version).toBe('4.1.0');
});
it('remediates lock file v2 express', async () => {
config.depName = 'express';
config.currentVersion = '4.0.0';
config.newVersion = '4.1.0';
config.lockFileContent = lockFileV2Content;
const res = await updateLockedDependency(config);
expect(res.files['package.json']).toContain('"express": "4.1.0"');
const packageLock = JSON.parse(res.files['package-lock.json']);
expect(packageLock.dependencies.express.version).toBe('4.1.0');
});
it('returns already-updated if already remediated exactly', async () => {
config.depName = 'mime';
config.currentVersion = '1.2.10';
@ -127,6 +148,14 @@ describe('manager/npm/update/locked-dependency/index', () => {
const res = await updateLockedDependency(config);
expect(res.status).toBe('already-updated');
});
it('returns already-updated if already v2 remediated exactly', async () => {
config.depName = 'mime';
config.currentVersion = '1.2.10';
config.newVersion = '1.2.11';
config.lockFileContent = lockFileV2Content;
const res = await updateLockedDependency(config);
expect(res.status).toBe('already-updated');
});
it('returns already-updated if already remediated higher', async () => {
config.depName = 'mime';
config.currentVersion = '1.2.9';

View file

@ -0,0 +1,359 @@
{
"name": "npm90",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "npm90",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"express": "4.0.0"
}
},
"node_modules/accepts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.0.0.tgz",
"integrity": "sha1-NgTHZVhsO5z3h3tpN829RYf5R9w=",
"dependencies": {
"mime": "~1.2.11",
"negotiator": "~0.3.0"
}
},
"node_modules/buffer-crc32": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz",
"integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w=",
"engines": {
"node": "*"
}
},
"node_modules/cookie": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz",
"integrity": "sha1-kOtGndzpBchm3mh+/EMTHYgB+dA=",
"engines": {
"node": "*"
}
},
"node_modules/cookie-signature": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.3.tgz",
"integrity": "sha1-kc2ZfMUftkFZVzjGnNoCAyj1D/k="
},
"node_modules/debug": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz",
"integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA=",
"engines": {
"node": "*"
}
},
"node_modules/escape-html": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz",
"integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A="
},
"node_modules/express": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.0.0.tgz",
"integrity": "sha1-J03IKTPJ9XTMOKDOXqgXK+nGsJQ=",
"dependencies": {
"accepts": "1.0.0",
"buffer-crc32": "0.2.1",
"cookie": "0.1.0",
"cookie-signature": "1.0.3",
"debug": ">= 0.7.3 < 1",
"escape-html": "1.0.1",
"fresh": "0.2.2",
"merge-descriptors": "0.0.2",
"methods": "0.1.0",
"parseurl": "1.0.1",
"path-to-regexp": "0.1.2",
"qs": "0.6.6",
"range-parser": "1.0.0",
"send": "0.2.0",
"serve-static": "1.0.1",
"type-is": "1.0.0",
"utils-merge": "1.0.0"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/fresh": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.2.tgz",
"integrity": "sha1-lzHc9WeMf660T7kDxPct9VGH+nc="
},
"node_modules/merge-descriptors": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-0.0.2.tgz",
"integrity": "sha1-w2pSp4FDdRPFcnXzndnTF1FKyMc="
},
"node_modules/methods": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz",
"integrity": "sha1-M11Cnu/SG3us8unJIqjSvRSjDk8="
},
"node_modules/mime": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
},
"node_modules/negotiator": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.3.0.tgz",
"integrity": "sha1-cG1pLv7d9XTVfqn7GriaT6fuj2A=",
"engines": {
"node": "*"
}
},
"node_modules/parseurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.0.1.tgz",
"integrity": "sha1-Llfc5u/dN8NRhwEDCUTCK/OIt7Q="
},
"node_modules/path-to-regexp": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.2.tgz",
"integrity": "sha1-mysVH5zDAYye6lDKlXKeBXgXErQ="
},
"node_modules/qs": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz",
"integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc=",
"engines": {
"node": "*"
}
},
"node_modules/range-parser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.0.tgz",
"integrity": "sha1-pLJkz+C+XONqvjdlrJwqJIdG28A="
},
"node_modules/send": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.2.0.tgz",
"integrity": "sha1-Bnq/Rc/4v/spy9t0OXJbMjiKLFg=",
"dependencies": {
"debug": "*",
"fresh": "~0.2.1",
"mime": "~1.2.9",
"range-parser": "~1.0.0"
}
},
"node_modules/serve-static": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.0.1.tgz",
"integrity": "sha1-ENy/1Es+ApGhMfyatKslqfWnikI=",
"dependencies": {
"send": "0.1.4"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/serve-static/node_modules/fresh": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz",
"integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc="
},
"node_modules/serve-static/node_modules/range-parser": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz",
"integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs=",
"engines": {
"node": "*"
}
},
"node_modules/serve-static/node_modules/send": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz",
"integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=",
"dependencies": {
"debug": "*",
"fresh": "0.2.0",
"mime": "~1.2.9",
"range-parser": "0.0.4"
}
},
"node_modules/type-is": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.0.0.tgz",
"integrity": "sha1-T/Qk6XNJoe4ZELS/xIhZXs3EQ/w=",
"dependencies": {
"mime": "~1.2.11"
}
},
"node_modules/utils-merge": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
"integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=",
"engines": {
"node": ">= 0.4.0"
}
}
},
"dependencies": {
"accepts": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.0.0.tgz",
"integrity": "sha1-NgTHZVhsO5z3h3tpN829RYf5R9w=",
"requires": {
"mime": "~1.2.11",
"negotiator": "~0.3.0"
}
},
"buffer-crc32": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz",
"integrity": "sha1-vj5TgvwCttYySVasGvmKqYsIU0w="
},
"cookie": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz",
"integrity": "sha1-kOtGndzpBchm3mh+/EMTHYgB+dA="
},
"cookie-signature": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.3.tgz",
"integrity": "sha1-kc2ZfMUftkFZVzjGnNoCAyj1D/k="
},
"debug": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-0.8.1.tgz",
"integrity": "sha1-IP9NJvXkIstoobrLu2EDmtjBwTA="
},
"escape-html": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz",
"integrity": "sha1-GBoobq05ejmpKFfPsdQwUuNWv/A="
},
"express": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/express/-/express-4.0.0.tgz",
"integrity": "sha1-J03IKTPJ9XTMOKDOXqgXK+nGsJQ=",
"requires": {
"accepts": "1.0.0",
"buffer-crc32": "0.2.1",
"cookie": "0.1.0",
"cookie-signature": "1.0.3",
"debug": ">= 0.7.3 < 1",
"escape-html": "1.0.1",
"fresh": "0.2.2",
"merge-descriptors": "0.0.2",
"methods": "0.1.0",
"parseurl": "1.0.1",
"path-to-regexp": "0.1.2",
"qs": "0.6.6",
"range-parser": "1.0.0",
"send": "0.2.0",
"serve-static": "1.0.1",
"type-is": "1.0.0",
"utils-merge": "1.0.0"
}
},
"fresh": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.2.tgz",
"integrity": "sha1-lzHc9WeMf660T7kDxPct9VGH+nc="
},
"merge-descriptors": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-0.0.2.tgz",
"integrity": "sha1-w2pSp4FDdRPFcnXzndnTF1FKyMc="
},
"methods": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/methods/-/methods-0.1.0.tgz",
"integrity": "sha1-M11Cnu/SG3us8unJIqjSvRSjDk8="
},
"mime": {
"version": "1.2.11",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz",
"integrity": "sha1-WCA+7Ybjpe8XrtK32evUfwpg3RA="
},
"negotiator": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.3.0.tgz",
"integrity": "sha1-cG1pLv7d9XTVfqn7GriaT6fuj2A="
},
"parseurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.0.1.tgz",
"integrity": "sha1-Llfc5u/dN8NRhwEDCUTCK/OIt7Q="
},
"path-to-regexp": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.2.tgz",
"integrity": "sha1-mysVH5zDAYye6lDKlXKeBXgXErQ="
},
"qs": {
"version": "0.6.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-0.6.6.tgz",
"integrity": "sha1-bgFQmP9RlouKPIGQAdXyyJvEsQc="
},
"range-parser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.0.tgz",
"integrity": "sha1-pLJkz+C+XONqvjdlrJwqJIdG28A="
},
"send": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/send/-/send-0.2.0.tgz",
"integrity": "sha1-Bnq/Rc/4v/spy9t0OXJbMjiKLFg=",
"requires": {
"debug": "*",
"fresh": "~0.2.1",
"mime": "~1.2.9",
"range-parser": "~1.0.0"
}
},
"serve-static": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.0.1.tgz",
"integrity": "sha1-ENy/1Es+ApGhMfyatKslqfWnikI=",
"requires": {
"send": "0.1.4"
},
"dependencies": {
"fresh": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.2.0.tgz",
"integrity": "sha1-v9lALPPfEsSkwxDHn5mj3eE9NKc="
},
"range-parser": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz",
"integrity": "sha1-wEJ//vUcEKy6B4KkbJYC50T/Ygs="
},
"send": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/send/-/send-0.1.4.tgz",
"integrity": "sha1-vnDY0b4B3mGCGvE3gLUDRaT3Gr0=",
"requires": {
"debug": "*",
"fresh": "0.2.0",
"mime": "~1.2.9",
"range-parser": "0.0.4"
}
}
}
},
"type-is": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.0.0.tgz",
"integrity": "sha1-T/Qk6XNJoe4ZELS/xIhZXs3EQ/w=",
"requires": {
"mime": "~1.2.11"
}
},
"utils-merge": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
"integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
}
}
}

View file

@ -39,6 +39,7 @@ export async function updateLockedDependency(
logger.warn({ err }, 'Failed to parse files');
return { status: 'update-failed' };
}
const { lockfileVersion } = packageLockJson;
const lockedDeps = getLockedDependencies(
packageLockJson,
depName,
@ -63,7 +64,7 @@ export async function updateLockedDependency(
);
status = 'already-updated';
} else {
if (packageLockJson.lockfileVersion !== 1) {
if (lockfileVersion !== 1) {
logger.debug(
`Found lockfileVersion ${packageLockJson.lockfileVersion}`
);
@ -240,6 +241,11 @@ export async function updateLockedDependency(
}
if (newPackageJsonContent) {
files[packageFile] = newPackageJsonContent;
} else if (lockfileVersion !== 1) {
logger.debug(
'Remediations which change package-lock.json only are not supported unless lockfileVersion=1'
);
return { status: 'unsupported' };
}
return { status: 'updated', files };
} catch (err) /* istanbul ignore next */ {