@nuxtjp/dependency-security 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-deepmerge +21 -0
- package/NOTICE +3 -1
- package/README.md +24 -9
- package/advisories.mjs +42 -0
- package/dependency-security.check.cjs +27 -2
- package/dependency-versions.json +2 -1
- package/index.mjs +1 -0
- package/package.json +3 -2
- package/patches/deepmerge-4.3.1.patch +78 -0
- package/project.mjs +11 -2
- package/types/index.d.mts +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2012 James Halliday, Josh Duff, and other contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/NOTICE
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
NuxtJP dependency-security
|
|
2
2
|
Apache-2.0 applies to the configuration and verification tool.
|
|
3
3
|
Third-party patch inputs retain the included LICENSE-braces, LICENSE-node-forge
|
|
4
|
-
|
|
4
|
+
LICENSE-simple-git and LICENSE-deepmerge notices; these do not relicense the upstream packages.
|
|
5
|
+
The deepmerge 4.3.1 backport rejects prototype-sensitive keys in both inputs;
|
|
6
|
+
see https://github.com/TehShrike/deepmerge/issues/273 and CVE-2026-93753.
|
package/README.md
CHANGED
|
@@ -15,10 +15,10 @@ pnpm exec nuxtjp-security-check --project-root .
|
|
|
15
15
|
pnpm audit --json
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
The preset requires an installed Nuxt host with the selected braces
|
|
19
|
-
|
|
20
|
-
active.
|
|
21
|
-
|
|
18
|
+
The preset requires an installed Nuxt host with the selected braces target. The
|
|
19
|
+
node-forge and simple-git patches apply only when their exact reviewed targets are
|
|
20
|
+
active. Node-forge 1.4.2 uses its upstream implementation and is checked by the
|
|
21
|
+
same RSA regressions; 1.4.0 still needs the backport. Absence is not a reason to install an unused package. Present targets still require the reviewed fixed
|
|
22
22
|
versions and malformed/escaping graphs fail closed. A bare core-only library
|
|
23
23
|
graph does not need these backports.
|
|
24
24
|
Use an initial install with `--ignore-scripts` before configuring a new host.
|
|
@@ -26,12 +26,21 @@ Use an initial install with `--ignore-scripts` before configuring a new host.
|
|
|
26
26
|
Commit the generated `.nuxtjp-security` patches, manifest and lockfile. Run the
|
|
27
27
|
check after every locked install. Configuration refuses conflicting patches,
|
|
28
28
|
symlink storage and concurrent manifest changes; unrelated settings are retained.
|
|
29
|
-
The check loads the explicitly installed braces
|
|
30
|
-
exercises bounded recursion and malformed RSA signature cases. It creates a
|
|
29
|
+
The check loads the explicitly installed braces implementation and, when present,
|
|
30
|
+
node-forge, and exercises bounded recursion and malformed RSA signature cases. It creates a
|
|
31
31
|
never-issued ephemeral test key in memory and never reads an account key.
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
When deepmerge 4.3.1 is present, the reviewed backport rejects `__proto__`,
|
|
34
|
+
`constructor`, and `prototype` keys in both merge inputs. This deliberately
|
|
35
|
+
excludes those keys from merged output. Regression tests check both distributed
|
|
36
|
+
entry points against poisoned prototypes and ordinary nested and array merges.
|
|
37
|
+
The reported issue and proposed remediation are documented at
|
|
38
|
+
https://github.com/TehShrike/deepmerge/issues/273. The patch is omitted when
|
|
39
|
+
deepmerge is absent, and a different installed version requires review.
|
|
40
|
+
|
|
41
|
+
The following upstream advisories have no recorded fixed registry version:
|
|
42
|
+
GHSA-vfj7-8cjw-p6xm (braces 3.0.3), GHSA-86w9-cpqp-85rv (node-forge 1.4.0)
|
|
43
|
+
and GHSA-gcqx-w48m-w2h4 (deepmerge 4.3.1).
|
|
35
44
|
Version-only audit findings remain visible. Tested patches supplement those
|
|
36
45
|
releases; every other advisory blocks validation. Exact fixed override versions
|
|
37
46
|
for simple-git, its argument parser and esbuild live in `dependency-versions.json`.
|
|
@@ -47,13 +56,19 @@ applySecurityPatches('/explicit/application')
|
|
|
47
56
|
const active = installedDependencies('/explicit/application', 'braces', '3.0.3')
|
|
48
57
|
```
|
|
49
58
|
|
|
59
|
+
`verifyAuditedAdvisories(project, ids)` rejects unrelated advisories and reported
|
|
60
|
+
backports with no active target, then runs the installed dependency regressions.
|
|
61
|
+
This binds version-only audit exceptions to the implementations actually tested.
|
|
62
|
+
`verifyAuditReport(project, report)` additionally checks every severity total,
|
|
63
|
+
rejects unaccounted findings and preserves zero critical/moderate thresholds.
|
|
64
|
+
|
|
50
65
|
A missing target or an installed dependency resolving outside the selected project
|
|
51
66
|
is an error. The API does not execute installs or inspected application scripts.
|
|
52
67
|
The caller must own and explicitly select the project; this is not an OS sandbox
|
|
53
68
|
against another process with the same user privileges.
|
|
54
69
|
|
|
55
70
|
[LICENSE](LICENSE) and [NOTICE](NOTICE) describe this tool's license. The unchanged
|
|
56
|
-
LICENSE-braces, LICENSE-node-forge
|
|
71
|
+
LICENSE-braces, LICENSE-node-forge, LICENSE-simple-git and LICENSE-deepmerge files retain upstream
|
|
57
72
|
patch-input attribution and redistribution terms.
|
|
58
73
|
|
|
59
74
|
## Version policy 2
|
package/advisories.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Bind accepted version-only audit findings to actual tested dependency targets. */
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { verifyProject } from './checks.mjs'
|
|
4
|
+
import resolver from './resolved-dependency.cjs'
|
|
5
|
+
|
|
6
|
+
const targets = Object.freeze({
|
|
7
|
+
'GHSA-vfj7-8cjw-p6xm': 'braces',
|
|
8
|
+
'GHSA-86w9-cpqp-85rv': 'node-forge',
|
|
9
|
+
'GHSA-gcqx-w48m-w2h4': 'deepmerge',
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export function verifyAuditedAdvisories(project, advisories, options = {}) {
|
|
13
|
+
if (!Array.isArray(advisories)) throw new Error('Expected an advisory identifier array')
|
|
14
|
+
const policy = JSON.parse(readFileSync(new URL('./dependency-versions.json', import.meta.url)))
|
|
15
|
+
for (const id of advisories) {
|
|
16
|
+
const target = targets[id]
|
|
17
|
+
if (!target || !policy.backportedAdvisories.includes(id)) throw new Error(`Unremediated advisory: ${id}`)
|
|
18
|
+
if (!resolver.installedDependencies(project, target, undefined, { ...options, allowMissing: true }).length) {
|
|
19
|
+
throw new Error(`Reported advisory has no active regression target: ${id}`)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const result = verifyProject(project, options)
|
|
23
|
+
if (result.exitCode !== 0) throw new Error('Installed dependency regressions failed')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Verify audit totals as well as each advisory against the tested active graph. */
|
|
27
|
+
export function verifyAuditReport(project, report, options = {}) {
|
|
28
|
+
if (!report || typeof report !== 'object' || !report.advisories || typeof report.advisories !== 'object') {
|
|
29
|
+
throw new Error('Invalid audit report')
|
|
30
|
+
}
|
|
31
|
+
const findings = Object.values(report.advisories)
|
|
32
|
+
const totals = report.metadata?.vulnerabilities
|
|
33
|
+
for (const severity of ['info', 'low', 'moderate', 'high', 'critical']) {
|
|
34
|
+
const total = totals?.[severity]
|
|
35
|
+
if (!Number.isSafeInteger(total) || total < 0) throw new Error(`Invalid ${severity} audit total`)
|
|
36
|
+
if (['critical', 'moderate'].includes(severity) && total !== 0) throw new Error(`Unexpected ${severity} vulnerabilities`)
|
|
37
|
+
if (total > findings.filter(item => item?.severity === severity).length) {
|
|
38
|
+
throw new Error(`Unaccounted ${severity} vulnerabilities`)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
verifyAuditedAdvisories(project, findings.map(item => item?.github_advisory_id), options)
|
|
42
|
+
}
|
|
@@ -13,7 +13,8 @@ function dependency(name, version) {
|
|
|
13
13
|
return createRequire(matches[0])(name);
|
|
14
14
|
}
|
|
15
15
|
const braces = dependency('braces', '3.0.3');
|
|
16
|
-
const
|
|
16
|
+
const forgeManifests = require('./resolved-dependency.cjs').installedDependencies(process.cwd(), 'node-forge', undefined, { ...graphOptions, allowMissing: true });
|
|
17
|
+
const deepmergeManifests = require('./resolved-dependency.cjs').installedDependencies(process.cwd(), 'deepmerge', '4.3.1', { ...graphOptions, allowMissing: true });
|
|
17
18
|
test('brace compilation, expansion and stringification retain ordinary behavior', () => {
|
|
18
19
|
assert.equal(braces.compile('src/{a,b}.vue'), 'src/(a|b).vue');
|
|
19
20
|
assert.deepEqual(braces.expand('src/{a,b}.vue'), ['src/a.vue', 'src/b.vue']);
|
|
@@ -30,7 +31,11 @@ test('deep brace, parenthesis and caller AST inputs reject before stack exhausti
|
|
|
30
31
|
const cyclic = { type: 'root', nodes: [] }; cyclic.nodes.push(cyclic);
|
|
31
32
|
assert.throws(() => braces.compile(cyclic), SyntaxError);
|
|
32
33
|
});
|
|
33
|
-
test('RSA verifier accepts standard signatures and rejects extra or malformed DigestAlgorithm elements',
|
|
34
|
+
test('RSA verifier accepts standard signatures and rejects extra or malformed DigestAlgorithm elements', context => {
|
|
35
|
+
if (!forgeManifests.length) { context.skip('No active node-forge: RSA regression is not applicable'); return; }
|
|
36
|
+
for (const manifest of forgeManifests) {
|
|
37
|
+
assert.ok(['1.4.0', '1.4.2'].includes(JSON.parse(fs.readFileSync(manifest, 'utf8')).version), 'Unreviewed node-forge version');
|
|
38
|
+
const forge = createRequire(manifest)('node-forge');
|
|
34
39
|
const keys = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
|
35
40
|
const publicKey = forge.pki.publicKeyFromPem(keys.publicKey.export({ type: 'spki', format: 'pem' }));
|
|
36
41
|
const data = Buffer.from('never-issued security regression fixture');
|
|
@@ -48,6 +53,7 @@ test('RSA verifier accepts standard signatures and rejects extra or malformed Di
|
|
|
48
53
|
try { accepted = publicKey.verify(digest, signature); } catch { /* Rejection is the expected result for a malformed signature. */ }
|
|
49
54
|
assert.equal(accepted, false, 'Malformed algorithm must not verify');
|
|
50
55
|
}
|
|
56
|
+
}
|
|
51
57
|
});
|
|
52
58
|
|
|
53
59
|
test('active dependency graph uses every required upstream security version', () => {
|
|
@@ -55,6 +61,25 @@ test('active dependency graph uses every required upstream security version', ()
|
|
|
55
61
|
require('./version-policy.cjs').verifyInstalledPolicy(process.cwd(), policy, graphOptions);
|
|
56
62
|
});
|
|
57
63
|
|
|
64
|
+
test('deepmerge rejects prototype keys in both inputs and preserves ordinary merges', context => {
|
|
65
|
+
if (!deepmergeManifests.length) { context.skip('No active deepmerge: prototype regression is not applicable'); return; }
|
|
66
|
+
for (const manifest of deepmergeManifests) {
|
|
67
|
+
for (const entry of ['dist/cjs.js', 'dist/umd.js']) {
|
|
68
|
+
const merge = require(path.join(path.dirname(manifest), entry));
|
|
69
|
+
const malicious = JSON.parse('{"session":{"__proto__":{"admin":true}},"__proto__":{"admin":true}}');
|
|
70
|
+
for (const target of [{ session: null }, Object.create(null), JSON.parse('{"__proto__":{"admin":true}}')]) {
|
|
71
|
+
const result = merge(target, malicious);
|
|
72
|
+
assert.equal(result.admin, undefined);
|
|
73
|
+
assert.equal(result.session?.admin, undefined);
|
|
74
|
+
assert.equal(Object.getPrototypeOf(result), Object.prototype);
|
|
75
|
+
assert.equal(Object.getPrototypeOf(result.session), Object.prototype);
|
|
76
|
+
}
|
|
77
|
+
const result = merge({ nested: { a: 1 }, list: [1] }, { nested: { b: 2 }, list: [2] });
|
|
78
|
+
assert.deepEqual(result, { nested: { a: 1, b: 2 }, list: [1, 2] });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
58
83
|
// Preserve the ESM entry point expected by current Nuxt devtools without downgrading Git protections.
|
|
59
84
|
test('fixed simple-git retains named and legacy ESM factory exports', async context => {
|
|
60
85
|
const { pathToFileURL } = require('node:url');
|
package/dependency-versions.json
CHANGED
package/index.mjs
CHANGED
|
@@ -5,3 +5,4 @@ import { applySecurityPatches as configure } from './project.mjs'
|
|
|
5
5
|
export { installedDependencies } from './resolved-dependency.cjs'
|
|
6
6
|
export function applySecurityPatches(project) { configure(project, dirname(fileURLToPath(import.meta.url))) }
|
|
7
7
|
export { verifyProject } from './checks.mjs'
|
|
8
|
+
export { verifyAuditedAdvisories, verifyAuditReport } from './advisories.mjs'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nuxtjp/dependency-security",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "Explicit pnpm backport configuration and active dependency regression checks without Nuxt peers",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
"LICENSE-braces",
|
|
29
29
|
"LICENSE-node-forge",
|
|
30
30
|
"LICENSE-simple-git",
|
|
31
|
+
"LICENSE-deepmerge",
|
|
31
32
|
"README.md"
|
|
32
33
|
],
|
|
33
34
|
"exports": {
|
|
@@ -59,7 +60,7 @@
|
|
|
59
60
|
"nuxt"
|
|
60
61
|
],
|
|
61
62
|
"scripts": {
|
|
62
|
-
"build": "node --check index.mjs && node --check project.mjs && node --check apply.mjs && node --check check.mjs && node --check resolved-dependency.cjs && node --check version-policy.cjs",
|
|
63
|
+
"build": "node --check index.mjs && node --check project.mjs && node --check apply.mjs && node --check check.mjs && node --check advisories.mjs && node --check resolved-dependency.cjs && node --check version-policy.cjs",
|
|
63
64
|
"test": "node --test test/*.test.mjs",
|
|
64
65
|
"typecheck": "tsc --strict --noEmit --module NodeNext --moduleResolution NodeNext --target ES2022 test/public-types.mts"
|
|
65
66
|
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
diff --git a/index.js b/index.js
|
|
2
|
+
index 77968ae..ea40fd2 100644
|
|
3
|
+
--- a/index.js
|
|
4
|
+
+++ b/index.js
|
|
5
|
+
@@ -51,15 +51,20 @@ function propertyIsUnsafe(target, key) {
|
|
6
|
+
&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
+function keyIsForbidden(key) {
|
|
10
|
+
+ return key === '__proto__' || key === 'constructor' || key === 'prototype'
|
|
11
|
+
+}
|
|
12
|
+
+
|
|
13
|
+
function mergeObject(target, source, options) {
|
|
14
|
+
var destination = {}
|
|
15
|
+
if (options.isMergeableObject(target)) {
|
|
16
|
+
getKeys(target).forEach(function(key) {
|
|
17
|
+
+ if (keyIsForbidden(key)) return
|
|
18
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options)
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
getKeys(source).forEach(function(key) {
|
|
22
|
+
- if (propertyIsUnsafe(target, key)) {
|
|
23
|
+
+ if (keyIsForbidden(key) || propertyIsUnsafe(target, key)) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
diff --git a/dist/cjs.js b/dist/cjs.js
|
|
28
|
+
index 7c36cbd..3f743f1 100644
|
|
29
|
+
--- a/dist/cjs.js
|
|
30
|
+
+++ b/dist/cjs.js
|
|
31
|
+
@@ -76,15 +76,20 @@ function propertyIsUnsafe(target, key) {
|
|
32
|
+
&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
+function keyIsForbidden(key) {
|
|
36
|
+
+ return key === '__proto__' || key === 'constructor' || key === 'prototype'
|
|
37
|
+
+}
|
|
38
|
+
+
|
|
39
|
+
function mergeObject(target, source, options) {
|
|
40
|
+
var destination = {};
|
|
41
|
+
if (options.isMergeableObject(target)) {
|
|
42
|
+
getKeys(target).forEach(function(key) {
|
|
43
|
+
+ if (keyIsForbidden(key)) return
|
|
44
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
getKeys(source).forEach(function(key) {
|
|
48
|
+
- if (propertyIsUnsafe(target, key)) {
|
|
49
|
+
+ if (keyIsForbidden(key) || propertyIsUnsafe(target, key)) {
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
diff --git a/dist/umd.js b/dist/umd.js
|
|
54
|
+
index 4071e7c..6a6ab99 100644
|
|
55
|
+
--- a/dist/umd.js
|
|
56
|
+
+++ b/dist/umd.js
|
|
57
|
+
@@ -80,15 +80,20 @@
|
|
58
|
+
&& Object.propertyIsEnumerable.call(target, key)) // and also unsafe if they're nonenumerable.
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
+ function keyIsForbidden(key) {
|
|
62
|
+
+ return key === '__proto__' || key === 'constructor' || key === 'prototype'
|
|
63
|
+
+ }
|
|
64
|
+
+
|
|
65
|
+
function mergeObject(target, source, options) {
|
|
66
|
+
var destination = {};
|
|
67
|
+
if (options.isMergeableObject(target)) {
|
|
68
|
+
getKeys(target).forEach(function(key) {
|
|
69
|
+
+ if (keyIsForbidden(key)) return
|
|
70
|
+
destination[key] = cloneUnlessOtherwiseSpecified(target[key], options);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
getKeys(source).forEach(function(key) {
|
|
74
|
+
- if (propertyIsUnsafe(target, key)) {
|
|
75
|
+
+ if (keyIsForbidden(key) || propertyIsUnsafe(target, key)) {
|
|
76
|
+
return
|
|
77
|
+
}
|
|
78
|
+
|
package/project.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { randomUUID } from 'node:crypto'
|
|
|
5
5
|
import resolver from './resolved-dependency.cjs'
|
|
6
6
|
import versionPolicy from './version-policy.cjs'
|
|
7
7
|
|
|
8
|
-
const patches = ['braces@3.0.3', 'node-forge@1.4.0', 'simple-git@4.0.2']
|
|
8
|
+
const patches = ['braces@3.0.3', 'node-forge@1.4.0', 'simple-git@4.0.2', 'deepmerge@4.3.1']
|
|
9
9
|
function regular(path) {
|
|
10
10
|
const stat = lstatSync(path)
|
|
11
11
|
if (stat.isSymbolicLink() || !stat.isFile() || stat.size > 1024 * 1024) {
|
|
@@ -49,6 +49,13 @@ export function applySecurityPatches(project, source) {
|
|
|
49
49
|
throw new Error('Security patch directory must be a real directory')
|
|
50
50
|
}
|
|
51
51
|
const activeSimpleGit = resolver.installedDependencies(root, 'simple-git', undefined, { allowMissing: true }).length > 0
|
|
52
|
+
const forge = resolver.installedDependencies(root, 'node-forge', undefined, { allowMissing: true })
|
|
53
|
+
const forgeVersions = forge.map(path => parseJson(regular(path)).version)
|
|
54
|
+
if (forgeVersions.some(version => !['1.4.0', '1.4.2'].includes(version))) {
|
|
55
|
+
throw new Error('Dependency version changed; review its security patch')
|
|
56
|
+
}
|
|
57
|
+
const activeForge = forgeVersions.includes('1.4.0')
|
|
58
|
+
const activeDeepmerge = resolver.installedDependencies(root, 'deepmerge', '4.3.1', { allowMissing: true }).length > 0
|
|
52
59
|
const inputs = patches.map(name => {
|
|
53
60
|
const relative = `.nuxtjp-security/${name.replace('@', '-')}.patch`
|
|
54
61
|
if (existing[name] !== undefined && existing[name] !== relative) {
|
|
@@ -59,7 +66,9 @@ export function applySecurityPatches(project, source) {
|
|
|
59
66
|
if (existsSync(target) && !regular(target).equals(bytes)) {
|
|
60
67
|
throw new Error('An existing patch differs; no files were overwritten')
|
|
61
68
|
}
|
|
62
|
-
return { name, relative, bytes, target, required:
|
|
69
|
+
return { name, relative, bytes, target, required:
|
|
70
|
+
(name !== 'simple-git@4.0.2' || activeSimpleGit) && (name !== 'node-forge@1.4.0' || activeForge) &&
|
|
71
|
+
(name !== 'deepmerge@4.3.1' || activeDeepmerge) }
|
|
63
72
|
})
|
|
64
73
|
if (!readFileSync(manifest).equals(original)) throw new Error('Manifest changed during preparation')
|
|
65
74
|
mkdirSync(dir, { recursive: true })
|
package/types/index.d.mts
CHANGED
|
@@ -5,3 +5,7 @@ export function applySecurityPatches(project: string): void;
|
|
|
5
5
|
export function installedDependencies(root: string, target: string, version?: string, options?: GraphOptions & { allowMissing?: boolean }): string[];
|
|
6
6
|
/** Run the known dependency regressions, returning bounded local output and exit status. */
|
|
7
7
|
export function verifyProject(project: string, options?: GraphOptions): { exitCode: number; stdout: string; stderr: string };
|
|
8
|
+
/** Accept only reported advisories with installed targets whose regressions pass. */
|
|
9
|
+
export function verifyAuditedAdvisories(project: string, advisories: string[], options?: GraphOptions): void;
|
|
10
|
+
/** Check audit totals and bind each advisory to an active, regression-tested target. */
|
|
11
|
+
export function verifyAuditReport(project: string, report: unknown, options?: GraphOptions): void;
|