autoremediator 0.16.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/delta-scan/delta-scan.test.d.ts +2 -0
- package/dist/api/delta-scan/delta-scan.test.d.ts.map +1 -0
- package/dist/api/delta-scan/index.d.ts +5 -0
- package/dist/api/delta-scan/index.d.ts.map +1 -0
- package/dist/api/evaluate/evaluate.test.d.ts +2 -0
- package/dist/api/evaluate/evaluate.test.d.ts.map +1 -0
- package/dist/api/evaluate/index.d.ts +5 -0
- package/dist/api/evaluate/index.d.ts.map +1 -0
- package/dist/api/index.d.ts +5 -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/reachability/index.d.ts +3 -0
- package/dist/api/reachability/index.d.ts.map +1 -0
- package/dist/api/reachability/reachability.test.d.ts +2 -0
- package/dist/api/reachability/reachability.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/api/reporting.d.ts.map +1 -1
- package/dist/api/vex/index.d.ts +1 -1
- package/dist/api/vex/index.d.ts.map +1 -1
- package/dist/{chunk-CQXNIRHT.js → chunk-FXOUJDQ3.js} +2003 -756
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/runners.d.ts +22 -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 +365 -3
- package/dist/index.js +1967 -721
- package/dist/index.js.map +1 -1
- package/dist/intelligence/index.d.ts +1 -1
- package/dist/intelligence/index.d.ts.map +1 -1
- package/dist/intelligence/sources/github-advisory.d.ts +8 -0
- package/dist/intelligence/sources/github-advisory.d.ts.map +1 -1
- package/dist/intelligence/sources/osv.d.ts +4 -0
- package/dist/intelligence/sources/osv.d.ts.map +1 -1
- package/dist/mcp/server.d.ts +106 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +100 -1
- package/dist/openapi/rbac.d.ts +2 -2
- package/dist/openapi/rbac.d.ts.map +1 -1
- package/dist/openapi/server.d.ts.map +1 -1
- package/dist/openapi/server.js +13 -6
- 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 +121 -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/evaluate-package.d.ts +3 -0
- package/dist/remediation/evaluate-package.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/runtime-tools.d.ts +1 -1
- package/dist/remediation/runtime-tools.d.ts.map +1 -1
- package/dist/remediation/strategies/patch-synthesis-prompt.d.ts.map +1 -1
- package/dist/remediation/tools/apply-patch-file/helpers.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 +3 -0
- package/dist/scanner/delta-scan.d.ts.map +1 -0
- 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 +7 -9
|
@@ -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>;
|
|
@@ -6,4 +8,24 @@ export declare function runInspectPatch(patchPath: string, opts: Pick<CommandOpt
|
|
|
6
8
|
export declare function runValidatePatch(patchPath: string, opts: Pick<CommandOptions, "cwd" | "patchesDir" | "packageManager" | "outputFormat">): Promise<void>;
|
|
7
9
|
export declare function runUpdateOutdated(opts: CommandOptions): Promise<void>;
|
|
8
10
|
export declare function runPortfolio(targetsFilePath: string, opts: CommandOptions): Promise<void>;
|
|
11
|
+
export declare function runReachability(opts: {
|
|
12
|
+
cwd?: string;
|
|
13
|
+
package: string;
|
|
14
|
+
symbol?: string;
|
|
15
|
+
outputFormat?: string;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
export declare function runEvaluate(packageName: string, opts: {
|
|
18
|
+
cwd?: string;
|
|
19
|
+
version?: string;
|
|
20
|
+
outputFormat?: string;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
export declare function runDiffAudit(opts: {
|
|
23
|
+
cwd?: string;
|
|
24
|
+
base?: string;
|
|
25
|
+
outputFormat?: string;
|
|
26
|
+
ci?: boolean;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
export declare function runReconcilePatches(opts: Pick<CommandOptions, "cwd" | "patchesDir" | "packageManager" | "runTests" | "outputFormat"> & {
|
|
29
|
+
autoApply?: boolean;
|
|
30
|
+
}): Promise<void>;
|
|
9
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":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -5,18 +5,25 @@ import {
|
|
|
5
5
|
buildDependencyScopeCounts,
|
|
6
6
|
buildSlaBreachSummary,
|
|
7
7
|
buildStrategyCounts,
|
|
8
|
+
checkReachability,
|
|
8
9
|
ciExitCode,
|
|
10
|
+
evaluatePackage,
|
|
9
11
|
inspectPatchArtifact,
|
|
10
12
|
listPatchArtifacts,
|
|
13
|
+
parseScanInput,
|
|
14
|
+
parseScanInputFromAudit,
|
|
15
|
+
reconcilePatchArtifacts,
|
|
11
16
|
remediate,
|
|
12
17
|
remediateFromScan,
|
|
13
18
|
remediatePortfolio,
|
|
19
|
+
scanDelta,
|
|
14
20
|
toCiSummary,
|
|
15
21
|
toCycloneDxVex,
|
|
16
22
|
toSarifOutput,
|
|
23
|
+
uniqueCveIds,
|
|
17
24
|
updateOutdated,
|
|
18
25
|
validatePatchArtifact
|
|
19
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FXOUJDQ3.js";
|
|
20
27
|
|
|
21
28
|
// src/cli/index.ts
|
|
22
29
|
import { fileURLToPath } from "url";
|
|
@@ -25,6 +32,150 @@ import { fileURLToPath } from "url";
|
|
|
25
32
|
import { Command } from "commander";
|
|
26
33
|
import { existsSync } from "fs";
|
|
27
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
|
+
|
|
28
179
|
// src/cli/runners.ts
|
|
29
180
|
import { readFileSync, writeFileSync } from "fs";
|
|
30
181
|
|
|
@@ -99,6 +250,7 @@ async function runSingleCve(cveId, opts) {
|
|
|
99
250
|
preview: opts.preview,
|
|
100
251
|
simulationMode: opts.simulationMode,
|
|
101
252
|
runTests: opts.runTests,
|
|
253
|
+
typecheck: opts.typecheck,
|
|
102
254
|
patchesDir: opts.patchesDir,
|
|
103
255
|
policy: opts.policy,
|
|
104
256
|
evidence: opts.evidence,
|
|
@@ -217,6 +369,10 @@ async function runSingleCve(cveId, opts) {
|
|
|
217
369
|
}
|
|
218
370
|
}
|
|
219
371
|
async function runScanInput(inputPath, opts) {
|
|
372
|
+
if (opts.interactive) {
|
|
373
|
+
await runInteractiveTriage(inputPath, opts);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
220
376
|
const changeRequest = resolveChangeRequestOptions(opts);
|
|
221
377
|
const report = await remediateFromScan(inputPath, {
|
|
222
378
|
cwd: opts.cwd,
|
|
@@ -229,6 +385,7 @@ async function runScanInput(inputPath, opts) {
|
|
|
229
385
|
preview: opts.preview,
|
|
230
386
|
simulationMode: opts.simulationMode,
|
|
231
387
|
runTests: opts.runTests,
|
|
388
|
+
typecheck: opts.typecheck,
|
|
232
389
|
llmProvider: opts.llmProvider,
|
|
233
390
|
model: opts.model,
|
|
234
391
|
modelPersonality: opts.modelPersonality,
|
|
@@ -600,10 +757,143 @@ async function runPortfolio(targetsFilePath, opts) {
|
|
|
600
757
|
process.exitCode = report.failedCount > 0 ? 1 : 0;
|
|
601
758
|
}
|
|
602
759
|
}
|
|
760
|
+
async function runReachability(opts) {
|
|
761
|
+
const result = await checkReachability({
|
|
762
|
+
cwd: opts.cwd,
|
|
763
|
+
packageName: opts.package,
|
|
764
|
+
symbol: opts.symbol
|
|
765
|
+
});
|
|
766
|
+
if (opts.outputFormat === "json") {
|
|
767
|
+
logJson(result);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
process.stdout.write(`Package: ${result.packageName}
|
|
771
|
+
`);
|
|
772
|
+
process.stdout.write(`Status: ${result.status}
|
|
773
|
+
`);
|
|
774
|
+
process.stdout.write(`Reason: ${result.reason}
|
|
775
|
+
`);
|
|
776
|
+
if (result.evidence && result.evidence.length > 0) {
|
|
777
|
+
process.stdout.write(`Evidence files (${result.evidence.length}):
|
|
778
|
+
`);
|
|
779
|
+
for (const ev of result.evidence) {
|
|
780
|
+
process.stdout.write(
|
|
781
|
+
` - ${ev.filePath} [${ev.matchType}] (invoked: ${ev.invoked ?? false})
|
|
782
|
+
`
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
async function runEvaluate(packageName, opts) {
|
|
788
|
+
const report = await evaluatePackage(packageName, {
|
|
789
|
+
version: opts.version,
|
|
790
|
+
cwd: opts.cwd,
|
|
791
|
+
enrichIntelligence: true
|
|
792
|
+
});
|
|
793
|
+
if (opts.outputFormat === "json") {
|
|
794
|
+
logJson(report);
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
process.stdout.write(
|
|
798
|
+
`Package: ${report.packageName}${report.evaluatedVersion ? `@${report.evaluatedVersion}` : ""}
|
|
799
|
+
`
|
|
800
|
+
);
|
|
801
|
+
process.stdout.write(`Verdict: ${report.verdict.toUpperCase()}
|
|
802
|
+
`);
|
|
803
|
+
process.stdout.write(`Summary: ${report.summary}
|
|
804
|
+
`);
|
|
805
|
+
if (report.recommendedVersion) {
|
|
806
|
+
process.stdout.write(`Recommended Version: ${report.recommendedVersion}
|
|
807
|
+
`);
|
|
808
|
+
}
|
|
809
|
+
if (report.vulnerabilities.length > 0) {
|
|
810
|
+
process.stdout.write(`Known Vulnerabilities (${report.vulnerabilities.length}):
|
|
811
|
+
`);
|
|
812
|
+
for (const vuln of report.vulnerabilities) {
|
|
813
|
+
process.stdout.write(` - [${vuln.cveId}] (${vuln.severity}) ${vuln.summary}
|
|
814
|
+
`);
|
|
815
|
+
if (vuln.safeUpgradeVersion) {
|
|
816
|
+
process.stdout.write(` Safe upgrade: ${vuln.safeUpgradeVersion}
|
|
817
|
+
`);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
async function runDiffAudit(opts) {
|
|
823
|
+
const report = await scanDelta({
|
|
824
|
+
cwd: opts.cwd,
|
|
825
|
+
baseRef: opts.base
|
|
826
|
+
});
|
|
827
|
+
if (opts.outputFormat === "json") {
|
|
828
|
+
logJson(report);
|
|
829
|
+
if (opts.ci) {
|
|
830
|
+
process.exitCode = report.netRiskVerdict === "degraded" ? 1 : 0;
|
|
831
|
+
}
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
process.stdout.write(`Delta scan against base: ${report.baseRef}
|
|
835
|
+
`);
|
|
836
|
+
process.stdout.write(`Net Risk Verdict: ${report.netRiskVerdict.toUpperCase()}
|
|
837
|
+
`);
|
|
838
|
+
process.stdout.write(`Dependency Changes: ${report.dependencyChanges.length}
|
|
839
|
+
`);
|
|
840
|
+
process.stdout.write(`Newly Introduced CVEs: ${report.introducedFindings.length}
|
|
841
|
+
`);
|
|
842
|
+
process.stdout.write(`Resolved CVEs: ${report.resolvedFindings.length}
|
|
843
|
+
`);
|
|
844
|
+
process.stdout.write(`Summary: ${report.summary}
|
|
845
|
+
`);
|
|
846
|
+
if (report.introducedFindings.length > 0) {
|
|
847
|
+
process.stdout.write(`
|
|
848
|
+
Introduced Findings:
|
|
849
|
+
`);
|
|
850
|
+
for (const f of report.introducedFindings) {
|
|
851
|
+
process.stdout.write(
|
|
852
|
+
` - [${f.cveId}] ${f.packageName}@${f.installedVersion ?? "unknown"} (${f.severity}): ${f.summary}
|
|
853
|
+
`
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
if (opts.ci) {
|
|
858
|
+
process.exitCode = report.netRiskVerdict === "degraded" ? 1 : 0;
|
|
859
|
+
}
|
|
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
|
+
}
|
|
603
893
|
|
|
604
894
|
// src/cli/types.ts
|
|
605
895
|
function isCveId(value) {
|
|
606
|
-
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);
|
|
607
897
|
}
|
|
608
898
|
|
|
609
899
|
// src/cli/validators.ts
|
|
@@ -645,7 +935,11 @@ function validateOutputFormat(outputFormat, supported, commandName) {
|
|
|
645
935
|
// src/cli/program.ts
|
|
646
936
|
function addSharedOptions(program, includeInput = false, includeSimulationMode = true) {
|
|
647
937
|
const parseBooleanFlag = (value) => value === "true";
|
|
648
|
-
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(
|
|
649
943
|
"--require-consensus-for-high-risk",
|
|
650
944
|
OPTION_DESCRIPTIONS.requireConsensusForHighRisk,
|
|
651
945
|
false
|
|
@@ -786,12 +1080,80 @@ function createProgram() {
|
|
|
786
1080
|
await runValidatePatch(patchPath, merged);
|
|
787
1081
|
}
|
|
788
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
|
+
);
|
|
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(
|
|
1104
|
+
async (opts) => {
|
|
1105
|
+
validateOutputFormat(
|
|
1106
|
+
opts.outputFormat ?? "text",
|
|
1107
|
+
["text", "json"],
|
|
1108
|
+
"reachability"
|
|
1109
|
+
);
|
|
1110
|
+
await runReachability(opts);
|
|
1111
|
+
}
|
|
1112
|
+
);
|
|
1113
|
+
program.command("evaluate <package>").description(
|
|
1114
|
+
"Pre-flight security evaluator for npm packages before installation (e.g. evaluate express@4.18.2)"
|
|
1115
|
+
).option("--pkg-version <version>", "Package version to evaluate").option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--output-format <format>", "Output format: text|json", "text").action(
|
|
1116
|
+
async (pkg, opts) => {
|
|
1117
|
+
validateOutputFormat(
|
|
1118
|
+
opts.outputFormat ?? "text",
|
|
1119
|
+
["text", "json"],
|
|
1120
|
+
"evaluate"
|
|
1121
|
+
);
|
|
1122
|
+
let targetName = pkg;
|
|
1123
|
+
let targetVersion = opts.pkgVersion;
|
|
1124
|
+
const lastAt = pkg.lastIndexOf("@");
|
|
1125
|
+
if (lastAt > 0 && !targetVersion) {
|
|
1126
|
+
targetName = pkg.slice(0, lastAt);
|
|
1127
|
+
targetVersion = pkg.slice(lastAt + 1);
|
|
1128
|
+
}
|
|
1129
|
+
await runEvaluate(targetName, {
|
|
1130
|
+
cwd: opts.cwd,
|
|
1131
|
+
version: targetVersion,
|
|
1132
|
+
outputFormat: opts.outputFormat
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
);
|
|
1136
|
+
program.command("diff").description("Git-aware delta vulnerability scan against base git reference or working tree").option("--base <ref>", "Git base reference (default: HEAD)", "HEAD").option("--cwd <path>", OPTION_DESCRIPTIONS.cwd, process.cwd()).option("--ci", "Enable CI exit code behavior on degraded security posture", false).option("--output-format <format>", "Output format: text|json", "text").action(async (opts) => {
|
|
1137
|
+
validateOutputFormat(
|
|
1138
|
+
opts.outputFormat ?? "text",
|
|
1139
|
+
["text", "json"],
|
|
1140
|
+
"diff"
|
|
1141
|
+
);
|
|
1142
|
+
await runDiffAudit(opts);
|
|
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
|
+
});
|
|
789
1147
|
addSharedOptions(
|
|
790
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"),
|
|
791
1149
|
true
|
|
792
1150
|
).action(async (target, opts) => {
|
|
793
1151
|
validateSharedCommandOptions(opts);
|
|
794
1152
|
validateOutputFormat(opts.outputFormat, ["text", "json", "sarif"], "default");
|
|
1153
|
+
if (opts.interactive) {
|
|
1154
|
+
await runInteractiveTriage(opts.input ?? target ?? opts, opts);
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
795
1157
|
if (opts.audit) {
|
|
796
1158
|
await runScanInput(opts.input ?? target ?? "", opts);
|
|
797
1159
|
return;
|