autoremediator 0.17.0 → 0.18.0
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/README.md +2 -1
- package/dist/api/change-request/index.d.ts +2 -1
- package/dist/api/change-request/index.d.ts.map +1 -1
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/patches/index.d.ts +1 -0
- package/dist/api/patches/index.d.ts.map +1 -1
- package/dist/api/patches/reconcile.d.ts +7 -0
- package/dist/api/patches/reconcile.d.ts.map +1 -0
- package/dist/api/patches/reconcile.test.d.ts +2 -0
- package/dist/api/patches/reconcile.test.d.ts.map +1 -0
- package/dist/api/remediate/validators.d.ts +3 -0
- package/dist/api/remediate/validators.d.ts.map +1 -1
- package/dist/{chunk-U4LIJIGD.js → chunk-FXOUJDQ3.js} +1712 -856
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/runners.d.ts +5 -0
- package/dist/cli/runners.d.ts.map +1 -1
- package/dist/cli/triage.d.ts +7 -0
- package/dist/cli/triage.d.ts.map +1 -0
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli.js +220 -3
- package/dist/index.js +1707 -852
- package/dist/index.js.map +1 -1
- package/dist/intelligence/sources/github-advisory.d.ts.map +1 -1
- package/dist/mcp/server.js +1 -1
- package/dist/openapi/server.js +1 -1
- package/dist/platform/package-manager/index.d.ts +1 -0
- package/dist/platform/package-manager/index.d.ts.map +1 -1
- package/dist/platform/supply-chain.d.ts +10 -0
- package/dist/platform/supply-chain.d.ts.map +1 -0
- package/dist/platform/supply-chain.test.d.ts +2 -0
- package/dist/platform/supply-chain.test.d.ts.map +1 -0
- package/dist/platform/types.d.ts +38 -4
- package/dist/platform/types.d.ts.map +1 -1
- package/dist/platform/workspace.d.ts +28 -0
- package/dist/platform/workspace.d.ts.map +1 -0
- package/dist/platform/workspace.test.d.ts +2 -0
- package/dist/platform/workspace.test.d.ts.map +1 -0
- package/dist/remediation/local/options.d.ts.map +1 -1
- package/dist/remediation/local/primary-strategy.d.ts +3 -1
- package/dist/remediation/local/primary-strategy.d.ts.map +1 -1
- package/dist/remediation/strategies/patch-synthesis-prompt.d.ts.map +1 -1
- package/dist/remediation/tools/apply-patch-file/index.d.ts +1 -0
- package/dist/remediation/tools/apply-patch-file/index.d.ts.map +1 -1
- package/dist/remediation/tools/apply-version-bump.d.ts +1 -0
- package/dist/remediation/tools/apply-version-bump.d.ts.map +1 -1
- package/dist/remediation/tools/check-inventory.d.ts.map +1 -1
- package/dist/remediation/tools/check-reachability.d.ts +6 -1
- package/dist/remediation/tools/check-reachability.d.ts.map +1 -1
- package/dist/remediation/tools/generate-patch/helpers.d.ts +1 -0
- package/dist/remediation/tools/generate-patch/helpers.d.ts.map +1 -1
- package/dist/remediation/tools/generate-patch/index.d.ts +1 -0
- package/dist/remediation/tools/generate-patch/index.d.ts.map +1 -1
- package/dist/scanner/adapters/npm-audit.d.ts.map +1 -1
- package/dist/scanner/adapters/yarn-audit.d.ts.map +1 -1
- package/dist/scanner/delta-scan.d.ts.map +1 -1
- package/dist/scanner/lockfile-diff.d.ts +10 -0
- package/dist/scanner/lockfile-diff.d.ts.map +1 -0
- package/dist/scanner/lockfile-diff.test.d.ts +2 -0
- package/dist/scanner/lockfile-diff.test.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+IpC,wBAAgB,aAAa,IAAI,OAAO,CA+TvC"}
|
package/dist/cli/runners.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { runInteractiveTriage } from "./triage.js";
|
|
2
|
+
export { runInteractiveTriage };
|
|
1
3
|
import type { CommandOptions } from "./types.js";
|
|
2
4
|
export declare function runSingleCve(cveId: string, opts: CommandOptions): Promise<void>;
|
|
3
5
|
export declare function runScanInput(inputPath: string, opts: CommandOptions): Promise<void>;
|
|
@@ -23,4 +25,7 @@ export declare function runDiffAudit(opts: {
|
|
|
23
25
|
outputFormat?: string;
|
|
24
26
|
ci?: boolean;
|
|
25
27
|
}): Promise<void>;
|
|
28
|
+
export declare function runReconcilePatches(opts: Pick<CommandOptions, "cwd" | "patchesDir" | "packageManager" | "runTests" | "outputFormat"> & {
|
|
29
|
+
autoApply?: boolean;
|
|
30
|
+
}): Promise<void>;
|
|
26
31
|
//# sourceMappingURL=runners.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runners.d.ts","sourceRoot":"","sources":["../../src/cli/runners.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runners.d.ts","sourceRoot":"","sources":["../../src/cli/runners.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAGhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAkFjD,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA8IrF;AAED,wBAAsB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2KzF;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,YAAY,GAAG,cAAc,CAAC,GAChE,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,YAAY,GAAG,cAAc,CAAC,GAChE,OAAO,CAAC,IAAI,CAAC,CA4Bf;AAED,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,YAAY,GAAG,gBAAgB,GAAG,cAAc,CAAC,GACnF,OAAO,CAAC,IAAI,CAAC,CAgCf;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA+C3E;AAED,wBAAsB,YAAY,CAAC,eAAe,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA6F/F;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBhB;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE;IACJ,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,GACA,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,EAAE,CAAC,EAAE,OAAO,CAAC;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CAiChB;AAED,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,KAAK,GAAG,YAAY,GAAG,gBAAgB,GAAG,UAAU,GAAG,cAAc,CAAC,GAAG;IAClG,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,GACA,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CommandOptions } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Interactive developer CLI triage workflow.
|
|
4
|
+
* Prompts developer through security findings with actions to apply, skip, suppress, or quit.
|
|
5
|
+
*/
|
|
6
|
+
export declare function runInteractiveTriage(inputPathOrOpts: string | Partial<CommandOptions>, maybeOpts?: Partial<CommandOptions>): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=triage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"triage.d.ts","sourceRoot":"","sources":["../../src/cli/triage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,EACjD,SAAS,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAClC,OAAO,CAAC,IAAI,CAAC,CAyIf"}
|
package/dist/cli/types.d.ts
CHANGED
package/dist/cli/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;AACvE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,eAAe,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;AACvE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,eAAe,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,YAAY,CAAC;IAE3B,WAAW,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,YAAY,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3D,qBAAqB,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7C,2BAA2B,EAAE,OAAO,CAAC;IACrC,iBAAiB,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IACvC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;IACvD,sBAAsB,EAAE,OAAO,CAAC;IAChC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,UAAU,GAAG,gBAAgB,GAAG,eAAe,CAAC;IAC9D,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,EAAE,EAAE,OAAO,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,qBAAqB,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC5C,qBAAqB,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,aAAa,CAAC;IAC1D,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9C"}
|
package/dist/cli.js
CHANGED
|
@@ -10,6 +10,9 @@ import {
|
|
|
10
10
|
evaluatePackage,
|
|
11
11
|
inspectPatchArtifact,
|
|
12
12
|
listPatchArtifacts,
|
|
13
|
+
parseScanInput,
|
|
14
|
+
parseScanInputFromAudit,
|
|
15
|
+
reconcilePatchArtifacts,
|
|
13
16
|
remediate,
|
|
14
17
|
remediateFromScan,
|
|
15
18
|
remediatePortfolio,
|
|
@@ -17,9 +20,10 @@ import {
|
|
|
17
20
|
toCiSummary,
|
|
18
21
|
toCycloneDxVex,
|
|
19
22
|
toSarifOutput,
|
|
23
|
+
uniqueCveIds,
|
|
20
24
|
updateOutdated,
|
|
21
25
|
validatePatchArtifact
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FXOUJDQ3.js";
|
|
23
27
|
|
|
24
28
|
// src/cli/index.ts
|
|
25
29
|
import { fileURLToPath } from "url";
|
|
@@ -28,6 +32,150 @@ import { fileURLToPath } from "url";
|
|
|
28
32
|
import { Command } from "commander";
|
|
29
33
|
import { existsSync } from "fs";
|
|
30
34
|
|
|
35
|
+
// src/cli/triage.ts
|
|
36
|
+
import * as readline from "readline/promises";
|
|
37
|
+
import { stdin as input, stdout as output } from "process";
|
|
38
|
+
async function runInteractiveTriage(inputPathOrOpts, maybeOpts) {
|
|
39
|
+
const inputPath = typeof inputPathOrOpts === "string" ? inputPathOrOpts : inputPathOrOpts.input;
|
|
40
|
+
const opts = (typeof inputPathOrOpts === "object" ? inputPathOrOpts : maybeOpts) ?? {};
|
|
41
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
42
|
+
output.write("\n\u{1F50D} Scanning for security findings to triage...\n");
|
|
43
|
+
let findings = [];
|
|
44
|
+
try {
|
|
45
|
+
if (inputPath) {
|
|
46
|
+
findings = parseScanInput(inputPath, opts.format ?? "auto");
|
|
47
|
+
} else {
|
|
48
|
+
findings = await parseScanInputFromAudit({
|
|
49
|
+
cwd,
|
|
50
|
+
packageManager: opts.packageManager,
|
|
51
|
+
format: opts.format ?? "auto",
|
|
52
|
+
workspace: opts.workspace
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
output.write(
|
|
57
|
+
`Failed to load scan findings: ${err instanceof Error ? err.message : String(err)}
|
|
58
|
+
`
|
|
59
|
+
);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const cveIds = uniqueCveIds(findings);
|
|
63
|
+
if (cveIds.length === 0) {
|
|
64
|
+
output.write("\u2728 No vulnerabilities found to triage!\n\n");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
output.write(`Found ${cveIds.length} unique vulnerability(ies) to triage.
|
|
68
|
+
`);
|
|
69
|
+
const rl = readline.createInterface({ input, output });
|
|
70
|
+
let remediatedCount = 0;
|
|
71
|
+
let skippedCount = 0;
|
|
72
|
+
let suppressedCount = 0;
|
|
73
|
+
try {
|
|
74
|
+
for (let i = 0; i < cveIds.length; i++) {
|
|
75
|
+
const cveId = cveIds[i];
|
|
76
|
+
const matchingFindings = findings.filter(
|
|
77
|
+
(f) => f.cveId.toUpperCase() === cveId.toUpperCase()
|
|
78
|
+
);
|
|
79
|
+
const firstFinding = matchingFindings[0];
|
|
80
|
+
const pkgName = firstFinding?.packageName ?? "unknown package";
|
|
81
|
+
const severity = firstFinding?.severity ?? "UNKNOWN";
|
|
82
|
+
let safeVersion;
|
|
83
|
+
if (pkgName !== "unknown package") {
|
|
84
|
+
try {
|
|
85
|
+
const evalRes = await evaluatePackage(pkgName, { enrichIntelligence: true });
|
|
86
|
+
const matchingVuln = evalRes.vulnerabilities.find(
|
|
87
|
+
(v) => v.cveId.toUpperCase() === cveId.toUpperCase()
|
|
88
|
+
);
|
|
89
|
+
safeVersion = matchingVuln?.safeUpgradeVersion ?? evalRes.vulnerabilities.find((v) => v.safeUpgradeVersion)?.safeUpgradeVersion;
|
|
90
|
+
} catch {
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
output.write("\n" + "=".repeat(60) + "\n");
|
|
94
|
+
output.write(`[${i + 1}/${cveIds.length}] Vulnerability: ${cveId}
|
|
95
|
+
`);
|
|
96
|
+
output.write(` Package: ${pkgName}
|
|
97
|
+
`);
|
|
98
|
+
output.write(` Severity: ${severity}
|
|
99
|
+
`);
|
|
100
|
+
if (safeVersion) {
|
|
101
|
+
output.write(` Safe Upstream Version: ${safeVersion}
|
|
102
|
+
`);
|
|
103
|
+
}
|
|
104
|
+
output.write("=".repeat(60) + "\n");
|
|
105
|
+
let answered = false;
|
|
106
|
+
while (!answered) {
|
|
107
|
+
const answer = await rl.question(
|
|
108
|
+
"Action: [a]pply fix, [s]kip, [x] suppress/vex, [q]uit triage? [a/s/x/q]: "
|
|
109
|
+
);
|
|
110
|
+
const choice = answer.trim().toLowerCase();
|
|
111
|
+
if (choice === "a" || choice === "apply") {
|
|
112
|
+
output.write(`Applying remediation for ${cveId}...
|
|
113
|
+
`);
|
|
114
|
+
try {
|
|
115
|
+
const report = await remediate(cveId, {
|
|
116
|
+
cwd,
|
|
117
|
+
packageManager: opts.packageManager,
|
|
118
|
+
patchesDir: opts.patchesDir,
|
|
119
|
+
policy: opts.policy,
|
|
120
|
+
runTests: opts.runTests,
|
|
121
|
+
constraints: {
|
|
122
|
+
directDependenciesOnly: opts.directDependenciesOnly,
|
|
123
|
+
preferVersionBump: opts.preferVersionBump,
|
|
124
|
+
workspace: opts.workspace
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
const applied = report.results.some((r) => r.applied);
|
|
128
|
+
if (applied) {
|
|
129
|
+
output.write(`\u2705 Successfully applied remediation for ${cveId}!
|
|
130
|
+
`);
|
|
131
|
+
remediatedCount++;
|
|
132
|
+
} else {
|
|
133
|
+
const reason = report.results[0]?.unresolvedReason ?? "unresolved";
|
|
134
|
+
output.write(`\u26A0\uFE0F Remediation could not be applied automatically (${reason}).
|
|
135
|
+
`);
|
|
136
|
+
skippedCount++;
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {
|
|
139
|
+
output.write(
|
|
140
|
+
`\u274C Error remediating ${cveId}: ${err instanceof Error ? err.message : String(err)}
|
|
141
|
+
`
|
|
142
|
+
);
|
|
143
|
+
skippedCount++;
|
|
144
|
+
}
|
|
145
|
+
answered = true;
|
|
146
|
+
} else if (choice === "s" || choice === "skip" || choice === "") {
|
|
147
|
+
output.write(`Skipped ${cveId}.
|
|
148
|
+
`);
|
|
149
|
+
skippedCount++;
|
|
150
|
+
answered = true;
|
|
151
|
+
} else if (choice === "x" || choice === "suppress") {
|
|
152
|
+
output.write(`Marked ${cveId} as suppressed / VEX excluded.
|
|
153
|
+
`);
|
|
154
|
+
suppressedCount++;
|
|
155
|
+
answered = true;
|
|
156
|
+
} else if (choice === "q" || choice === "quit") {
|
|
157
|
+
output.write("Exiting triage session.\n");
|
|
158
|
+
return;
|
|
159
|
+
} else {
|
|
160
|
+
output.write("Invalid option. Please choose 'a', 's', 'x', or 'q'.\n");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
} finally {
|
|
165
|
+
rl.close();
|
|
166
|
+
output.write("\n=== Triage Summary ===\n");
|
|
167
|
+
output.write(`Total evaluated: ${cveIds.length}
|
|
168
|
+
`);
|
|
169
|
+
output.write(`Remediated: ${remediatedCount}
|
|
170
|
+
`);
|
|
171
|
+
output.write(`Suppressed: ${suppressedCount}
|
|
172
|
+
`);
|
|
173
|
+
output.write(`Skipped: ${skippedCount}
|
|
174
|
+
|
|
175
|
+
`);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
31
179
|
// src/cli/runners.ts
|
|
32
180
|
import { readFileSync, writeFileSync } from "fs";
|
|
33
181
|
|
|
@@ -102,6 +250,7 @@ async function runSingleCve(cveId, opts) {
|
|
|
102
250
|
preview: opts.preview,
|
|
103
251
|
simulationMode: opts.simulationMode,
|
|
104
252
|
runTests: opts.runTests,
|
|
253
|
+
typecheck: opts.typecheck,
|
|
105
254
|
patchesDir: opts.patchesDir,
|
|
106
255
|
policy: opts.policy,
|
|
107
256
|
evidence: opts.evidence,
|
|
@@ -220,6 +369,10 @@ async function runSingleCve(cveId, opts) {
|
|
|
220
369
|
}
|
|
221
370
|
}
|
|
222
371
|
async function runScanInput(inputPath, opts) {
|
|
372
|
+
if (opts.interactive) {
|
|
373
|
+
await runInteractiveTriage(inputPath, opts);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
223
376
|
const changeRequest = resolveChangeRequestOptions(opts);
|
|
224
377
|
const report = await remediateFromScan(inputPath, {
|
|
225
378
|
cwd: opts.cwd,
|
|
@@ -232,6 +385,7 @@ async function runScanInput(inputPath, opts) {
|
|
|
232
385
|
preview: opts.preview,
|
|
233
386
|
simulationMode: opts.simulationMode,
|
|
234
387
|
runTests: opts.runTests,
|
|
388
|
+
typecheck: opts.typecheck,
|
|
235
389
|
llmProvider: opts.llmProvider,
|
|
236
390
|
model: opts.model,
|
|
237
391
|
modelPersonality: opts.modelPersonality,
|
|
@@ -704,10 +858,42 @@ Introduced Findings:
|
|
|
704
858
|
process.exitCode = report.netRiskVerdict === "degraded" ? 1 : 0;
|
|
705
859
|
}
|
|
706
860
|
}
|
|
861
|
+
async function runReconcilePatches(opts) {
|
|
862
|
+
const report = await reconcilePatchArtifacts({
|
|
863
|
+
cwd: opts.cwd,
|
|
864
|
+
patchesDir: opts.patchesDir,
|
|
865
|
+
packageManager: opts.packageManager,
|
|
866
|
+
autoApply: opts.autoApply,
|
|
867
|
+
runTests: opts.runTests
|
|
868
|
+
});
|
|
869
|
+
if (opts.outputFormat === "json") {
|
|
870
|
+
logJson(report);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
process.stdout.write(`=== Patch Artifact Reconciliation ===
|
|
874
|
+
`);
|
|
875
|
+
process.stdout.write(`Reconciled (upgraded): ${report.reconciledCount}
|
|
876
|
+
`);
|
|
877
|
+
process.stdout.write(`Retained: ${report.retainedCount}
|
|
878
|
+
|
|
879
|
+
`);
|
|
880
|
+
for (const item of report.reconciled) {
|
|
881
|
+
process.stdout.write(`- [${item.status}] ${item.packageName} (${item.patchFilePath})
|
|
882
|
+
`);
|
|
883
|
+
if (item.safeUpstreamVersion) {
|
|
884
|
+
process.stdout.write(` Safe Upstream Version: ${item.safeUpstreamVersion}
|
|
885
|
+
`);
|
|
886
|
+
}
|
|
887
|
+
if (item.reason) {
|
|
888
|
+
process.stdout.write(` Reason: ${item.reason}
|
|
889
|
+
`);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
707
893
|
|
|
708
894
|
// src/cli/types.ts
|
|
709
895
|
function isCveId(value) {
|
|
710
|
-
return /^CVE-\d{4}-\d{1,7}$/i.test(value);
|
|
896
|
+
return /^CVE-\d{4}-\d{1,7}$/i.test(value) || /^GHSA-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}$/i.test(value);
|
|
711
897
|
}
|
|
712
898
|
|
|
713
899
|
// src/cli/validators.ts
|
|
@@ -749,7 +935,11 @@ function validateOutputFormat(outputFormat, supported, commandName) {
|
|
|
749
935
|
// src/cli/program.ts
|
|
750
936
|
function addSharedOptions(program, includeInput = false, includeSimulationMode = true) {
|
|
751
937
|
const parseBooleanFlag = (value) => value === "true";
|
|
752
|
-
program.option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--package-manager <name>", OPTION_DESCRIPTIONS.packageManager).option("--patches-dir <path>", OPTION_DESCRIPTIONS.patchesDir).option("--dry-run", OPTION_DESCRIPTIONS.dryRun, false).option("--preview", OPTION_DESCRIPTIONS.preview, false).option("--run-tests", OPTION_DESCRIPTIONS.runTests, false).option(
|
|
938
|
+
program.option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--package-manager <name>", OPTION_DESCRIPTIONS.packageManager).option("--patches-dir <path>", OPTION_DESCRIPTIONS.patchesDir).option("--dry-run", OPTION_DESCRIPTIONS.dryRun, false).option("--preview", OPTION_DESCRIPTIONS.preview, false).option("--run-tests", OPTION_DESCRIPTIONS.runTests, false).option(
|
|
939
|
+
"--typecheck",
|
|
940
|
+
"Enable typecheck validation (e.g. tsc --noEmit or npm run typecheck) after patching",
|
|
941
|
+
false
|
|
942
|
+
).option("-i, --interactive", "Launch interactive developer CLI triage workflow", false).option("--llm-provider <provider>", OPTION_DESCRIPTIONS.llmProvider).option("--model <name>", OPTION_DESCRIPTIONS.model).option("--model-personality <profile>", OPTION_DESCRIPTIONS.modelPersonality).option("--provider-safety-profile <profile>", OPTION_DESCRIPTIONS.providerSafetyProfile).option(
|
|
753
943
|
"--require-consensus-for-high-risk",
|
|
754
944
|
OPTION_DESCRIPTIONS.requireConsensusForHighRisk,
|
|
755
945
|
false
|
|
@@ -890,6 +1080,26 @@ function createProgram() {
|
|
|
890
1080
|
await runValidatePatch(patchPath, merged);
|
|
891
1081
|
}
|
|
892
1082
|
);
|
|
1083
|
+
patches.command("reconcile").description(
|
|
1084
|
+
"Reconcile active patch artifacts against upstream registries to retire obsolete patches"
|
|
1085
|
+
).option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--patches-dir <path>", OPTION_DESCRIPTIONS.patchesDir).option(
|
|
1086
|
+
"--auto-apply",
|
|
1087
|
+
"Automatically upgrade packages and remove retired patch artifacts",
|
|
1088
|
+
false
|
|
1089
|
+
).option("--run-tests", OPTION_DESCRIPTIONS.runTests, false).option("--package-manager <name>", OPTION_DESCRIPTIONS.packageManager).option("--output-format <format>", "Output format: text|json", "text").action(
|
|
1090
|
+
async (opts, command) => {
|
|
1091
|
+
const merged = {
|
|
1092
|
+
...command.optsWithGlobals(),
|
|
1093
|
+
...opts
|
|
1094
|
+
};
|
|
1095
|
+
validateOutputFormat(
|
|
1096
|
+
merged.outputFormat ?? "text",
|
|
1097
|
+
["text", "json"],
|
|
1098
|
+
"patches reconcile"
|
|
1099
|
+
);
|
|
1100
|
+
await runReconcilePatches(merged);
|
|
1101
|
+
}
|
|
1102
|
+
);
|
|
893
1103
|
program.command("reachability").description("Perform AST call-graph reachability analysis for a package or vulnerable symbol").requiredOption("--package <name>", "Target package name to search").option("--symbol <name>", "Optional specific vulnerable function or export symbol to check").option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--output-format <format>", "Output format: text|json", "text").action(
|
|
894
1104
|
async (opts) => {
|
|
895
1105
|
validateOutputFormat(
|
|
@@ -931,12 +1141,19 @@ function createProgram() {
|
|
|
931
1141
|
);
|
|
932
1142
|
await runDiffAudit(opts);
|
|
933
1143
|
});
|
|
1144
|
+
program.command("triage [input]").description("Interactively triage discovered vulnerabilities step-by-step").option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--package-manager <name>", OPTION_DESCRIPTIONS.packageManager).option("--patches-dir <path>", OPTION_DESCRIPTIONS.patchesDir).option("--format <format>", OPTION_DESCRIPTIONS.format, "auto").option("--run-tests", OPTION_DESCRIPTIONS.runTests, false).option("--policy <path>", OPTION_DESCRIPTIONS.policy).action(async (inputArg, opts) => {
|
|
1145
|
+
await runInteractiveTriage(inputArg ? inputArg : opts, opts);
|
|
1146
|
+
});
|
|
934
1147
|
addSharedOptions(
|
|
935
1148
|
program.argument("[target]", "Scanner output file path (or CVE ID fallback)").option("--format <type>", OPTION_DESCRIPTIONS.format, "auto").option("--summary-file <path>", "Write machine-readable scan summary JSON to path"),
|
|
936
1149
|
true
|
|
937
1150
|
).action(async (target, opts) => {
|
|
938
1151
|
validateSharedCommandOptions(opts);
|
|
939
1152
|
validateOutputFormat(opts.outputFormat, ["text", "json", "sarif"], "default");
|
|
1153
|
+
if (opts.interactive) {
|
|
1154
|
+
await runInteractiveTriage(opts.input ?? target ?? opts, opts);
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
940
1157
|
if (opts.audit) {
|
|
941
1158
|
await runScanInput(opts.input ?? target ?? "", opts);
|
|
942
1159
|
return;
|