autoremediator 0.13.0 → 0.14.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/dist/{chunk-4CVVRAQM.js → chunk-3NNNFJLV.js} +371 -108
- package/dist/chunk-3NNNFJLV.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.js +368 -105
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +3 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/openapi/server.js +1 -1
- package/llms.txt +1 -1
- package/package.json +1 -1
- package/dist/chunk-4CVVRAQM.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/api/options-schema.ts
|
|
2
|
-
var PACKAGE_MANAGER_VALUES = ["npm", "pnpm", "yarn"];
|
|
2
|
+
var PACKAGE_MANAGER_VALUES = ["npm", "pnpm", "yarn", "bun", "deno"];
|
|
3
3
|
var LLM_PROVIDER_VALUES = ["remote", "local"];
|
|
4
4
|
var PROVENANCE_SOURCE_VALUES = ["cli", "sdk", "mcp", "openapi", "unknown"];
|
|
5
5
|
var OPTION_DESCRIPTIONS = {
|
|
@@ -296,21 +296,26 @@ function createUpdateOutdatedOptionSchemaProperties() {
|
|
|
296
296
|
// src/api/patches/inspection.ts
|
|
297
297
|
import { existsSync as existsSync4 } from "fs";
|
|
298
298
|
import { readdir, readFile as readFile2, stat } from "fs/promises";
|
|
299
|
-
import { join as
|
|
299
|
+
import { join as join4 } from "path";
|
|
300
300
|
|
|
301
301
|
// src/remediation/strategies/patch-utils.ts
|
|
302
|
-
import { existsSync as existsSync2, mkdirSync, writeFileSync, readFileSync } from "fs";
|
|
303
|
-
import { join as
|
|
302
|
+
import { existsSync as existsSync2, mkdirSync, writeFileSync, readFileSync as readFileSync2 } from "fs";
|
|
303
|
+
import { join as join3 } from "path";
|
|
304
304
|
import { execa as execa2 } from "execa";
|
|
305
305
|
|
|
306
306
|
// src/platform/package-manager/index.ts
|
|
307
307
|
import { existsSync } from "fs";
|
|
308
|
-
import { join } from "path";
|
|
308
|
+
import { join as join2 } from "path";
|
|
309
309
|
import { execa } from "execa";
|
|
310
310
|
|
|
311
311
|
// src/platform/package-manager/list-parser.ts
|
|
312
|
+
import { readFileSync } from "fs";
|
|
313
|
+
import { join } from "path";
|
|
312
314
|
function parsePackageManagerListOutput(pm, stdout) {
|
|
313
315
|
const versions = /* @__PURE__ */ new Map();
|
|
316
|
+
if (pm === "bun") {
|
|
317
|
+
return parseBunListOutput(stdout, versions);
|
|
318
|
+
}
|
|
314
319
|
if (!stdout.trim()) return versions;
|
|
315
320
|
if (pm === "yarn") {
|
|
316
321
|
return parseYarnListOutput(stdout, versions);
|
|
@@ -360,6 +365,61 @@ function collectDependencyTree(tree, versions) {
|
|
|
360
365
|
collectDependencyTree(entry.dependencies, versions);
|
|
361
366
|
}
|
|
362
367
|
}
|
|
368
|
+
function parseBunListOutput(stdout, versions) {
|
|
369
|
+
const lines = stdout.split("\n").map((line) => line.replace(/^[\s│├└─]+/, "").trim()).filter(Boolean);
|
|
370
|
+
for (const line of lines) {
|
|
371
|
+
const at = line.lastIndexOf("@");
|
|
372
|
+
if (at <= 0) continue;
|
|
373
|
+
const name = line.slice(0, at);
|
|
374
|
+
const version = line.slice(at + 1);
|
|
375
|
+
if (name && version) {
|
|
376
|
+
versions.set(name, version);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return versions;
|
|
380
|
+
}
|
|
381
|
+
function resolveDenoInventory(cwd) {
|
|
382
|
+
const versions = /* @__PURE__ */ new Map();
|
|
383
|
+
let raw;
|
|
384
|
+
try {
|
|
385
|
+
raw = readFileSync(join(cwd, "deno.lock"), "utf8");
|
|
386
|
+
} catch {
|
|
387
|
+
return versions;
|
|
388
|
+
}
|
|
389
|
+
let lock;
|
|
390
|
+
try {
|
|
391
|
+
lock = JSON.parse(raw);
|
|
392
|
+
} catch {
|
|
393
|
+
return versions;
|
|
394
|
+
}
|
|
395
|
+
if (!lock || typeof lock !== "object") return versions;
|
|
396
|
+
const lockObj = lock;
|
|
397
|
+
const packages = lockObj["packages"];
|
|
398
|
+
if (packages && typeof packages === "object") {
|
|
399
|
+
const pkgsObj = packages;
|
|
400
|
+
const npmMap = pkgsObj["npm"];
|
|
401
|
+
if (npmMap && typeof npmMap === "object") {
|
|
402
|
+
for (const key of Object.keys(npmMap)) {
|
|
403
|
+
extractNameVersion(key, versions);
|
|
404
|
+
}
|
|
405
|
+
return versions;
|
|
406
|
+
}
|
|
407
|
+
for (const key of Object.keys(pkgsObj)) {
|
|
408
|
+
const stripped = key.startsWith("npm:") ? key.slice(4) : key;
|
|
409
|
+
extractNameVersion(stripped, versions);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return versions;
|
|
413
|
+
}
|
|
414
|
+
function extractNameVersion(spec, versions) {
|
|
415
|
+
const at = spec.lastIndexOf("@");
|
|
416
|
+
if (at <= 0) return;
|
|
417
|
+
const name = spec.slice(0, at);
|
|
418
|
+
const version = spec.slice(at + 1);
|
|
419
|
+
if (name && version) {
|
|
420
|
+
versions.set(name, version);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
363
423
|
|
|
364
424
|
// src/platform/package-manager/index.ts
|
|
365
425
|
async function getYarnMajorVersion(cwd) {
|
|
@@ -372,8 +432,10 @@ async function getYarnMajorVersion(cwd) {
|
|
|
372
432
|
}
|
|
373
433
|
}
|
|
374
434
|
function detectPackageManager(cwd) {
|
|
375
|
-
if (existsSync(
|
|
376
|
-
if (existsSync(
|
|
435
|
+
if (existsSync(join2(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
436
|
+
if (existsSync(join2(cwd, "yarn.lock"))) return "yarn";
|
|
437
|
+
if (existsSync(join2(cwd, "bun.lockb")) || existsSync(join2(cwd, "bun.lock"))) return "bun";
|
|
438
|
+
if (existsSync(join2(cwd, "deno.lock"))) return "deno";
|
|
377
439
|
return "npm";
|
|
378
440
|
}
|
|
379
441
|
function withWorkspace(command, pm, workspace) {
|
|
@@ -390,6 +452,20 @@ function resolveInstallCommand(pm, constraints, yarnMajor) {
|
|
|
390
452
|
const installMode = constraints?.installMode ?? "deterministic";
|
|
391
453
|
const preferOfflineOverride = constraints?.installPreferOffline;
|
|
392
454
|
const frozenOverride = constraints?.enforceFrozenLockfile;
|
|
455
|
+
if (pm === "bun") {
|
|
456
|
+
const frozen = frozenOverride ?? installMode === "deterministic";
|
|
457
|
+
const command2 = ["bun", "install"];
|
|
458
|
+
if (frozen) command2.push("--frozen-lockfile");
|
|
459
|
+
return withWorkspace(command2, pm, constraints?.workspace);
|
|
460
|
+
}
|
|
461
|
+
if (pm === "deno") {
|
|
462
|
+
const frozen = frozenOverride ?? installMode === "deterministic";
|
|
463
|
+
const preferOffline = preferOfflineOverride ?? installMode === "prefer-offline";
|
|
464
|
+
const command2 = ["deno", "install"];
|
|
465
|
+
if (frozen) command2.push("--frozen");
|
|
466
|
+
if (preferOffline && !frozen) command2.push("--cache-only");
|
|
467
|
+
return withWorkspace(command2, pm, constraints?.workspace);
|
|
468
|
+
}
|
|
393
469
|
const includePreferOffline = pm !== "yarn" && (preferOfflineOverride ?? installMode !== "standard");
|
|
394
470
|
let includeFrozenLockfile = pm !== "npm" && (frozenOverride ?? installMode === "deterministic");
|
|
395
471
|
if (frozenOverride === false) {
|
|
@@ -410,22 +486,36 @@ function resolveInstallCommand(pm, constraints, yarnMajor) {
|
|
|
410
486
|
return withWorkspace(command, pm, constraints?.workspace);
|
|
411
487
|
}
|
|
412
488
|
function resolveListCommand(pm, constraints) {
|
|
413
|
-
|
|
489
|
+
if (pm === "deno") {
|
|
490
|
+
return [];
|
|
491
|
+
}
|
|
492
|
+
const base = pm === "pnpm" ? ["pnpm", "list", "--json", "--depth", "99"] : pm === "yarn" ? ["yarn", "list", "--json"] : pm === "bun" ? ["bun", "pm", "ls", "--all"] : ["npm", "list", "--json", "--all"];
|
|
414
493
|
return withWorkspace(base, pm, constraints?.workspace);
|
|
415
494
|
}
|
|
416
495
|
function resolveTestCommand(pm, constraints) {
|
|
417
|
-
const base = pm === "pnpm" ? ["pnpm", "test"] : pm === "yarn" ? ["yarn", "test"] : ["npm", "test"];
|
|
496
|
+
const base = pm === "pnpm" ? ["pnpm", "test"] : pm === "yarn" ? ["yarn", "test"] : pm === "bun" ? ["bun", "test"] : pm === "deno" ? ["deno", "test"] : ["npm", "test"];
|
|
418
497
|
return withWorkspace(base, pm, constraints?.workspace);
|
|
419
498
|
}
|
|
420
499
|
function resolveAuditCommand(pm, constraints) {
|
|
500
|
+
if (pm === "deno") {
|
|
501
|
+
throw new Error(
|
|
502
|
+
"Deno does not support a native audit command. Use --input with a SARIF or npm-audit scan file instead."
|
|
503
|
+
);
|
|
504
|
+
}
|
|
421
505
|
const base = pm === "yarn" ? ["yarn", "audit", "--json"] : [pm, "audit", "--json"];
|
|
422
506
|
return withWorkspace(base, pm, constraints?.workspace);
|
|
423
507
|
}
|
|
424
508
|
function resolveWhyCommand(pm, packageName, constraints) {
|
|
509
|
+
if (pm === "deno") return [];
|
|
510
|
+
if (pm === "bun") {
|
|
511
|
+
const base2 = ["bun", "pm", "why", packageName];
|
|
512
|
+
return withWorkspace(base2, pm, constraints?.workspace);
|
|
513
|
+
}
|
|
425
514
|
const base = pm === "npm" ? ["npm", "explain", packageName] : [pm, "why", packageName];
|
|
426
515
|
return withWorkspace(base, pm, constraints?.workspace);
|
|
427
516
|
}
|
|
428
517
|
function resolveDedupeCommand(pm, constraints) {
|
|
518
|
+
if (pm === "bun" || pm === "deno") return [];
|
|
429
519
|
const base = [pm, "dedupe"];
|
|
430
520
|
return withWorkspace(base, pm, constraints?.workspace);
|
|
431
521
|
}
|
|
@@ -452,6 +542,28 @@ function getPackageManagerCommands(pm) {
|
|
|
452
542
|
lockfileName: "yarn.lock"
|
|
453
543
|
};
|
|
454
544
|
}
|
|
545
|
+
if (pm === "bun") {
|
|
546
|
+
return {
|
|
547
|
+
install: ["bun", "install"],
|
|
548
|
+
installPreferOffline: ["bun", "install"],
|
|
549
|
+
installDeterministic: resolveInstallCommand("bun", { installMode: "deterministic" }),
|
|
550
|
+
installDev: (pkg) => ["bun", "add", "-d", pkg],
|
|
551
|
+
test: ["bun", "test"],
|
|
552
|
+
list: ["bun", "pm", "ls", "--all"],
|
|
553
|
+
lockfileName: "bun.lockb"
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (pm === "deno") {
|
|
557
|
+
return {
|
|
558
|
+
install: ["deno", "install"],
|
|
559
|
+
installPreferOffline: ["deno", "install", "--cache-only"],
|
|
560
|
+
installDeterministic: resolveInstallCommand("deno", { installMode: "deterministic" }),
|
|
561
|
+
installDev: (pkg) => ["deno", "add", pkg],
|
|
562
|
+
test: ["deno", "test"],
|
|
563
|
+
list: [],
|
|
564
|
+
lockfileName: "deno.lock"
|
|
565
|
+
};
|
|
566
|
+
}
|
|
455
567
|
return {
|
|
456
568
|
install: ["npm", "install"],
|
|
457
569
|
installPreferOffline: ["npm", "install", "--prefer-offline"],
|
|
@@ -555,7 +667,7 @@ async function listPatchArtifacts(options = {}) {
|
|
|
555
667
|
return [];
|
|
556
668
|
}
|
|
557
669
|
const entries = await readdir(patchesDirPath, { withFileTypes: true });
|
|
558
|
-
const patchFiles = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".patch")).map((entry) =>
|
|
670
|
+
const patchFiles = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".patch")).map((entry) => join4(patchesDirPath, entry.name)).sort((left, right) => left.localeCompare(right));
|
|
559
671
|
const summaries = await Promise.all(
|
|
560
672
|
patchFiles.map(async (patchFilePath) => {
|
|
561
673
|
const inspection = await inspectPatchArtifact(patchFilePath, options);
|
|
@@ -616,13 +728,13 @@ function defineTool(config) {
|
|
|
616
728
|
|
|
617
729
|
// src/remediation/tools/check-inventory.ts
|
|
618
730
|
import { z } from "zod";
|
|
619
|
-
import { readFileSync as
|
|
620
|
-
import { join as
|
|
731
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
732
|
+
import { join as join6 } from "path";
|
|
621
733
|
import { execa as execa3 } from "execa";
|
|
622
734
|
|
|
623
735
|
// src/platform/policy.ts
|
|
624
|
-
import { existsSync as existsSync5, readFileSync as
|
|
625
|
-
import { join as
|
|
736
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
737
|
+
import { join as join5 } from "path";
|
|
626
738
|
import { parse as yamlParse } from "yaml";
|
|
627
739
|
var DEFAULT_POLICY = {
|
|
628
740
|
allowMajorBumps: false,
|
|
@@ -653,10 +765,10 @@ var DEFAULT_POLICY = {
|
|
|
653
765
|
escalationGraph: void 0
|
|
654
766
|
};
|
|
655
767
|
function loadPolicy(cwd, explicitPath) {
|
|
656
|
-
const candidate = explicitPath ??
|
|
768
|
+
const candidate = explicitPath ?? join5(cwd, ".github", "autoremediator.yml");
|
|
657
769
|
if (!existsSync5(candidate)) return DEFAULT_POLICY;
|
|
658
770
|
try {
|
|
659
|
-
const parsed = yamlParse(
|
|
771
|
+
const parsed = yamlParse(readFileSync3(candidate, "utf8"));
|
|
660
772
|
return {
|
|
661
773
|
allowMajorBumps: parsed.allowMajorBumps ?? DEFAULT_POLICY.allowMajorBumps,
|
|
662
774
|
denyPackages: parsed.denyPackages ?? DEFAULT_POLICY.denyPackages,
|
|
@@ -717,7 +829,7 @@ function isActiveSuppression(suppression) {
|
|
|
717
829
|
}
|
|
718
830
|
function loadSuppressionsFile(filePath) {
|
|
719
831
|
try {
|
|
720
|
-
const content =
|
|
832
|
+
const content = readFileSync3(filePath, "utf8");
|
|
721
833
|
const parsed = yamlParse(content);
|
|
722
834
|
return Array.isArray(parsed?.suppressions) ? parsed.suppressions : [];
|
|
723
835
|
} catch {
|
|
@@ -748,14 +860,14 @@ var checkInventoryTool = defineTool({
|
|
|
748
860
|
description: "Read the project's package.json and installed dependencies to list packages and exact versions. Must be called before checking version matches.",
|
|
749
861
|
parameters: z.object({
|
|
750
862
|
cwd: z.string().describe("Absolute path to the consumer project's root directory"),
|
|
751
|
-
packageManager: z.enum(["npm", "pnpm", "yarn"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
863
|
+
packageManager: z.enum(["npm", "pnpm", "yarn", "bun", "deno"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
752
864
|
policy: z.string().optional().describe("Optional path to .github/autoremediator.yml policy file"),
|
|
753
865
|
workspace: z.string().optional().describe("Optional workspace/package selector for monorepos")
|
|
754
866
|
}),
|
|
755
867
|
execute: async ({ cwd, packageManager, policy, workspace }) => {
|
|
756
868
|
let pkgJson;
|
|
757
869
|
try {
|
|
758
|
-
pkgJson = JSON.parse(
|
|
870
|
+
pkgJson = JSON.parse(readFileSync4(join6(cwd, "package.json"), "utf8"));
|
|
759
871
|
} catch {
|
|
760
872
|
return {
|
|
761
873
|
packages: [],
|
|
@@ -769,15 +881,21 @@ var checkInventoryTool = defineTool({
|
|
|
769
881
|
workspace: workspace ?? loadedPolicy.constraints?.workspace
|
|
770
882
|
});
|
|
771
883
|
let installedVersions = /* @__PURE__ */ new Map();
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
884
|
+
if (pm === "deno") {
|
|
885
|
+
installedVersions = resolveDenoInventory(cwd);
|
|
886
|
+
} else {
|
|
887
|
+
try {
|
|
888
|
+
const [cmd, ...args] = listCommand;
|
|
889
|
+
if (cmd) {
|
|
890
|
+
const listResult = await execa3(cmd, args, {
|
|
891
|
+
cwd,
|
|
892
|
+
stdio: "pipe",
|
|
893
|
+
reject: false
|
|
894
|
+
});
|
|
895
|
+
installedVersions = parseListOutput(pm, listResult.stdout || "");
|
|
896
|
+
}
|
|
897
|
+
} catch {
|
|
898
|
+
}
|
|
781
899
|
}
|
|
782
900
|
const packages = [];
|
|
783
901
|
for (const [name, version] of installedVersions.entries()) {
|
|
@@ -1016,14 +1134,14 @@ function getIntelligenceSourceConfig() {
|
|
|
1016
1134
|
}
|
|
1017
1135
|
|
|
1018
1136
|
// src/platform/idempotency.ts
|
|
1019
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as
|
|
1020
|
-
import { join as
|
|
1137
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
1138
|
+
import { join as join7 } from "path";
|
|
1021
1139
|
var DEFAULT_INDEX = {
|
|
1022
1140
|
schemaVersion: "1.0",
|
|
1023
1141
|
entries: {}
|
|
1024
1142
|
};
|
|
1025
1143
|
function indexFilePath(cwd) {
|
|
1026
|
-
return
|
|
1144
|
+
return join7(cwd, ".autoremediator", "state", "idempotency.json");
|
|
1027
1145
|
}
|
|
1028
1146
|
function entryKey(idempotencyKey, cveId) {
|
|
1029
1147
|
return `${idempotencyKey}::${cveId.toUpperCase()}`;
|
|
@@ -1032,7 +1150,7 @@ function loadIndex(cwd) {
|
|
|
1032
1150
|
const filePath = indexFilePath(cwd);
|
|
1033
1151
|
if (!existsSync6(filePath)) return DEFAULT_INDEX;
|
|
1034
1152
|
try {
|
|
1035
|
-
const parsed = JSON.parse(
|
|
1153
|
+
const parsed = JSON.parse(readFileSync5(filePath, "utf8"));
|
|
1036
1154
|
if (parsed && parsed.schemaVersion === "1.0" && parsed.entries) {
|
|
1037
1155
|
return parsed;
|
|
1038
1156
|
}
|
|
@@ -1043,7 +1161,7 @@ function loadIndex(cwd) {
|
|
|
1043
1161
|
}
|
|
1044
1162
|
function saveIndex(cwd, index) {
|
|
1045
1163
|
const filePath = indexFilePath(cwd);
|
|
1046
|
-
mkdirSync2(
|
|
1164
|
+
mkdirSync2(join7(cwd, ".autoremediator", "state"), { recursive: true });
|
|
1047
1165
|
writeFileSync2(filePath, JSON.stringify(index, null, 2) + "\n", "utf8");
|
|
1048
1166
|
}
|
|
1049
1167
|
function readIdempotentReport(cwd, idempotencyKey, cveId) {
|
|
@@ -1331,8 +1449,8 @@ async function enrichWithNvd(details) {
|
|
|
1331
1449
|
|
|
1332
1450
|
// src/remediation/tools/check-reachability.ts
|
|
1333
1451
|
import { z as z2 } from "zod";
|
|
1334
|
-
import { readdirSync, readFileSync as
|
|
1335
|
-
import { join as
|
|
1452
|
+
import { readdirSync, readFileSync as readFileSync6, statSync } from "fs";
|
|
1453
|
+
import { join as join8, extname } from "path";
|
|
1336
1454
|
var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
1337
1455
|
var SKIP_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", "out", ".git", "coverage", ".cache"]);
|
|
1338
1456
|
var MAX_FILES = 500;
|
|
@@ -1346,7 +1464,7 @@ function collectSourceFiles(dir, files = []) {
|
|
|
1346
1464
|
}
|
|
1347
1465
|
for (const entry of entries) {
|
|
1348
1466
|
if (files.length >= MAX_FILES) break;
|
|
1349
|
-
const full =
|
|
1467
|
+
const full = join8(dir, entry);
|
|
1350
1468
|
let stat2;
|
|
1351
1469
|
try {
|
|
1352
1470
|
stat2 = statSync(full);
|
|
@@ -1379,7 +1497,7 @@ function assessPackageReachability(cwd, packageName) {
|
|
|
1379
1497
|
for (const filePath of files) {
|
|
1380
1498
|
let content;
|
|
1381
1499
|
try {
|
|
1382
|
-
content =
|
|
1500
|
+
content = readFileSync6(filePath, "utf8");
|
|
1383
1501
|
} catch {
|
|
1384
1502
|
continue;
|
|
1385
1503
|
}
|
|
@@ -1535,8 +1653,8 @@ function buildSbom(packages, vulnerableNames, results) {
|
|
|
1535
1653
|
}
|
|
1536
1654
|
|
|
1537
1655
|
// src/intelligence/sources/registry.ts
|
|
1538
|
-
import { readFileSync as
|
|
1539
|
-
import { join as
|
|
1656
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
1657
|
+
import { join as join9 } from "path";
|
|
1540
1658
|
import { execa as execa4 } from "execa";
|
|
1541
1659
|
import semver from "semver";
|
|
1542
1660
|
var NPM_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -1705,7 +1823,7 @@ async function queryOutdatedPackages(cwd, options = {}) {
|
|
|
1705
1823
|
}
|
|
1706
1824
|
let directDeps;
|
|
1707
1825
|
try {
|
|
1708
|
-
const pkgRaw = JSON.parse(
|
|
1826
|
+
const pkgRaw = JSON.parse(readFileSync7(join9(cwd, "package.json"), "utf8"));
|
|
1709
1827
|
directDeps = /* @__PURE__ */ new Set([
|
|
1710
1828
|
...Object.keys(pkgRaw.dependencies ?? {}),
|
|
1711
1829
|
...Object.keys(pkgRaw.devDependencies ?? {})
|
|
@@ -1735,22 +1853,22 @@ async function queryOutdatedPackages(cwd, options = {}) {
|
|
|
1735
1853
|
|
|
1736
1854
|
// src/remediation/tools/apply-version-bump.ts
|
|
1737
1855
|
import { z as z4 } from "zod";
|
|
1738
|
-
import { join as
|
|
1739
|
-
import { readFileSync as
|
|
1856
|
+
import { join as join11 } from "path";
|
|
1857
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "fs";
|
|
1740
1858
|
import { execa as execa5 } from "execa";
|
|
1741
1859
|
import semver2 from "semver";
|
|
1742
1860
|
|
|
1743
1861
|
// src/platform/repo-lock.ts
|
|
1744
1862
|
import { mkdir, rm } from "fs/promises";
|
|
1745
|
-
import { join as
|
|
1863
|
+
import { join as join10 } from "path";
|
|
1746
1864
|
async function sleep(ms) {
|
|
1747
1865
|
await new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1748
1866
|
}
|
|
1749
1867
|
async function acquireRepoLock(cwd, options = {}) {
|
|
1750
1868
|
const timeoutMs = options.timeoutMs ?? 15e3;
|
|
1751
1869
|
const retryDelayMs = options.retryDelayMs ?? 125;
|
|
1752
|
-
const lockRoot =
|
|
1753
|
-
const lockPath =
|
|
1870
|
+
const lockRoot = join10(cwd, ".autoremediator", "locks");
|
|
1871
|
+
const lockPath = join10(cwd, ".autoremediator", "locks", "remediation.lock");
|
|
1754
1872
|
const startedAt = Date.now();
|
|
1755
1873
|
await mkdir(lockRoot, { recursive: true });
|
|
1756
1874
|
while (true) {
|
|
@@ -1784,7 +1902,7 @@ var applyVersionBumpTool = defineTool({
|
|
|
1784
1902
|
description: "Update package.json to use the safe version of a vulnerable package and run the project's package manager install. In dry-run mode, only reports what would change.",
|
|
1785
1903
|
parameters: z4.object({
|
|
1786
1904
|
cwd: z4.string().describe("Absolute path to the consumer project root"),
|
|
1787
|
-
packageManager: z4.enum(["npm", "pnpm", "yarn"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
1905
|
+
packageManager: z4.enum(["npm", "pnpm", "yarn", "bun", "deno"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
1788
1906
|
packageName: z4.string().describe("The npm package to upgrade"),
|
|
1789
1907
|
fromVersion: z4.string().describe("The currently installed vulnerable version"),
|
|
1790
1908
|
toVersion: z4.string().describe("The safe target version to upgrade to"),
|
|
@@ -1811,7 +1929,7 @@ var applyVersionBumpTool = defineTool({
|
|
|
1811
1929
|
workspace
|
|
1812
1930
|
}) => {
|
|
1813
1931
|
const pm = packageManager ?? detectPackageManager(cwd);
|
|
1814
|
-
const pkgPath =
|
|
1932
|
+
const pkgPath = join11(cwd, "package.json");
|
|
1815
1933
|
const loadedPolicy = loadPolicy(cwd, policy);
|
|
1816
1934
|
const commandConstraints = {
|
|
1817
1935
|
...loadedPolicy.constraints,
|
|
@@ -1851,7 +1969,7 @@ var applyVersionBumpTool = defineTool({
|
|
|
1851
1969
|
}
|
|
1852
1970
|
let pkgJson;
|
|
1853
1971
|
try {
|
|
1854
|
-
pkgJson = JSON.parse(
|
|
1972
|
+
pkgJson = JSON.parse(readFileSync8(pkgPath, "utf8"));
|
|
1855
1973
|
} catch {
|
|
1856
1974
|
return {
|
|
1857
1975
|
packageName,
|
|
@@ -1975,8 +2093,8 @@ var applyVersionBumpTool = defineTool({
|
|
|
1975
2093
|
|
|
1976
2094
|
// src/remediation/tools/apply-package-override/index.ts
|
|
1977
2095
|
import { z as z5 } from "zod";
|
|
1978
|
-
import { join as
|
|
1979
|
-
import { readFileSync as
|
|
2096
|
+
import { join as join12 } from "path";
|
|
2097
|
+
import { existsSync as existsSync7, readFileSync as readFileSync9, writeFileSync as writeFileSync4 } from "fs";
|
|
1980
2098
|
import { execa as execa7 } from "execa";
|
|
1981
2099
|
import semver3 from "semver";
|
|
1982
2100
|
|
|
@@ -1985,6 +2103,7 @@ import { execa as execa6 } from "execa";
|
|
|
1985
2103
|
async function collectDependencyTrace(cwd, pm, packageName, constraints) {
|
|
1986
2104
|
try {
|
|
1987
2105
|
const whyCommand = resolveWhyCommand(pm, packageName, constraints);
|
|
2106
|
+
if (whyCommand.length === 0) return void 0;
|
|
1988
2107
|
const [whyCmd, ...whyArgs] = whyCommand;
|
|
1989
2108
|
const result = await execa6(whyCmd, whyArgs, {
|
|
1990
2109
|
cwd,
|
|
@@ -1999,17 +2118,20 @@ async function collectDependencyTrace(cwd, pm, packageName, constraints) {
|
|
|
1999
2118
|
}
|
|
2000
2119
|
}
|
|
2001
2120
|
function describeOverrideField(packageManager) {
|
|
2002
|
-
if (packageManager === "npm") return "overrides";
|
|
2121
|
+
if (packageManager === "npm" || packageManager === "bun") return "overrides";
|
|
2003
2122
|
if (packageManager === "pnpm") return "pnpm.overrides";
|
|
2123
|
+
if (packageManager === "deno") return "overrides";
|
|
2004
2124
|
return "resolutions";
|
|
2005
2125
|
}
|
|
2006
2126
|
function getOverrideValue(pkgJson, packageManager, packageName) {
|
|
2007
|
-
if (packageManager === "npm")
|
|
2127
|
+
if (packageManager === "npm" || packageManager === "bun" || packageManager === "deno") {
|
|
2128
|
+
return pkgJson.overrides?.[packageName];
|
|
2129
|
+
}
|
|
2008
2130
|
if (packageManager === "pnpm") return pkgJson.pnpm?.overrides?.[packageName];
|
|
2009
2131
|
return pkgJson.resolutions?.[packageName];
|
|
2010
2132
|
}
|
|
2011
2133
|
function setOverrideValue(pkgJson, packageManager, packageName, version) {
|
|
2012
|
-
if (packageManager === "npm") {
|
|
2134
|
+
if (packageManager === "npm" || packageManager === "bun" || packageManager === "deno") {
|
|
2013
2135
|
pkgJson.overrides = { ...pkgJson.overrides ?? {}, [packageName]: version };
|
|
2014
2136
|
return;
|
|
2015
2137
|
}
|
|
@@ -2026,7 +2148,7 @@ function setOverrideValue(pkgJson, packageManager, packageName, version) {
|
|
|
2026
2148
|
pkgJson.resolutions = { ...pkgJson.resolutions ?? {}, [packageName]: version };
|
|
2027
2149
|
}
|
|
2028
2150
|
function restoreOverrideValue(pkgJson, packageManager, packageName, previousValue) {
|
|
2029
|
-
if (packageManager === "npm") {
|
|
2151
|
+
if (packageManager === "npm" || packageManager === "bun" || packageManager === "deno") {
|
|
2030
2152
|
pkgJson.overrides = restoreRecord(pkgJson.overrides, packageName, previousValue);
|
|
2031
2153
|
return;
|
|
2032
2154
|
}
|
|
@@ -2045,6 +2167,34 @@ function restoreOverrideValue(pkgJson, packageManager, packageName, previousValu
|
|
|
2045
2167
|
}
|
|
2046
2168
|
pkgJson.resolutions = restoreRecord(pkgJson.resolutions, packageName, previousValue);
|
|
2047
2169
|
}
|
|
2170
|
+
function getDenoJsonImportValue(denoJson, packageName) {
|
|
2171
|
+
const imports = denoJson.imports ?? {};
|
|
2172
|
+
if (imports[packageName] !== void 0) {
|
|
2173
|
+
return { key: packageName, value: imports[packageName] };
|
|
2174
|
+
}
|
|
2175
|
+
const npmKey = `npm:${packageName}`;
|
|
2176
|
+
if (imports[npmKey] !== void 0) {
|
|
2177
|
+
return { key: npmKey, value: imports[npmKey] };
|
|
2178
|
+
}
|
|
2179
|
+
return void 0;
|
|
2180
|
+
}
|
|
2181
|
+
function setDenoJsonImportValue(denoJson, packageName, version) {
|
|
2182
|
+
const existing = getDenoJsonImportValue(denoJson, packageName);
|
|
2183
|
+
const key = existing?.key ?? `npm:${packageName}`;
|
|
2184
|
+
denoJson.imports = { ...denoJson.imports ?? {}, [key]: `npm:${packageName}@${version}` };
|
|
2185
|
+
}
|
|
2186
|
+
function restoreDenoJsonImportValue(denoJson, packageName, previousEntry) {
|
|
2187
|
+
const existing = getDenoJsonImportValue(denoJson, packageName);
|
|
2188
|
+
if (!existing) return;
|
|
2189
|
+
const imports = { ...denoJson.imports ?? {} };
|
|
2190
|
+
if (previousEntry === void 0) {
|
|
2191
|
+
delete imports[existing.key];
|
|
2192
|
+
} else {
|
|
2193
|
+
delete imports[existing.key];
|
|
2194
|
+
imports[previousEntry.key] = previousEntry.value;
|
|
2195
|
+
}
|
|
2196
|
+
denoJson.imports = Object.keys(imports).length > 0 ? imports : void 0;
|
|
2197
|
+
}
|
|
2048
2198
|
function restoreRecord(record, key, previousValue) {
|
|
2049
2199
|
const nextRecord = { ...record ?? {} };
|
|
2050
2200
|
if (previousValue === void 0) {
|
|
@@ -2057,10 +2207,10 @@ function restoreRecord(record, key, previousValue) {
|
|
|
2057
2207
|
|
|
2058
2208
|
// src/remediation/tools/apply-package-override/index.ts
|
|
2059
2209
|
var applyPackageOverrideTool = defineTool({
|
|
2060
|
-
description: "Apply a package-manager-native package.json override for a vulnerable transitive dependency and reinstall. Uses npm overrides, pnpm.overrides,
|
|
2210
|
+
description: "Apply a package-manager-native package.json override for a vulnerable transitive dependency and reinstall. Uses npm overrides, pnpm.overrides, yarn resolutions, bun overrides, or deno.json imports.",
|
|
2061
2211
|
parameters: z5.object({
|
|
2062
2212
|
cwd: z5.string().describe("Absolute path to the consumer project root"),
|
|
2063
|
-
packageManager: z5.enum(["npm", "pnpm", "yarn"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
2213
|
+
packageManager: z5.enum(["npm", "pnpm", "yarn", "bun", "deno"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
2064
2214
|
packageName: z5.string().describe("The npm package to override"),
|
|
2065
2215
|
selector: z5.string().optional().describe("Optional manager-native override selector key (for nested or scoped overrides)"),
|
|
2066
2216
|
fromVersion: z5.string().describe("The currently installed vulnerable version"),
|
|
@@ -2089,7 +2239,9 @@ var applyPackageOverrideTool = defineTool({
|
|
|
2089
2239
|
workspace
|
|
2090
2240
|
}) => {
|
|
2091
2241
|
const pm = packageManager ?? detectPackageManager(cwd);
|
|
2092
|
-
const pkgPath =
|
|
2242
|
+
const pkgPath = join12(cwd, "package.json");
|
|
2243
|
+
const denoJsonPath = join12(cwd, "deno.json");
|
|
2244
|
+
const isDenoNative = pm === "deno" && !existsSync7(pkgPath);
|
|
2093
2245
|
const loadedPolicy = loadPolicy(cwd, policy);
|
|
2094
2246
|
const commandConstraints = {
|
|
2095
2247
|
...loadedPolicy.constraints,
|
|
@@ -2128,9 +2280,108 @@ var applyPackageOverrideTool = defineTool({
|
|
|
2128
2280
|
message: `Policy blocked major override for "${packageName}" (${fromVersion} -> ${toVersion}).`
|
|
2129
2281
|
};
|
|
2130
2282
|
}
|
|
2283
|
+
if (isDenoNative) {
|
|
2284
|
+
let denoJson;
|
|
2285
|
+
try {
|
|
2286
|
+
denoJson = JSON.parse(readFileSync9(denoJsonPath, "utf8"));
|
|
2287
|
+
} catch {
|
|
2288
|
+
return {
|
|
2289
|
+
packageName,
|
|
2290
|
+
strategy: "none",
|
|
2291
|
+
fromVersion,
|
|
2292
|
+
toVersion,
|
|
2293
|
+
applied: false,
|
|
2294
|
+
dryRun,
|
|
2295
|
+
unresolvedReason: "package-json-not-found",
|
|
2296
|
+
message: `Could not read deno.json at "${denoJsonPath}".`
|
|
2297
|
+
};
|
|
2298
|
+
}
|
|
2299
|
+
const existingEntry = getDenoJsonImportValue(denoJson, overrideSelector);
|
|
2300
|
+
if (!existingEntry) {
|
|
2301
|
+
return {
|
|
2302
|
+
packageName,
|
|
2303
|
+
strategy: "none",
|
|
2304
|
+
fromVersion,
|
|
2305
|
+
toVersion,
|
|
2306
|
+
applied: false,
|
|
2307
|
+
dryRun,
|
|
2308
|
+
unresolvedReason: "transitive-override-unsupported-deno-native",
|
|
2309
|
+
message: `Cannot apply transitive override for "${overrideSelector}" in a native Deno project (no package.json). Only direct dependencies declared in deno.json imports can be overridden.`
|
|
2310
|
+
};
|
|
2311
|
+
}
|
|
2312
|
+
const dependencyTrace2 = await collectDependencyTrace(cwd, pm, packageName, commandConstraints);
|
|
2313
|
+
const dependencyTraceSuffix2 = dependencyTrace2 ? ` Dependency trace: ${dependencyTrace2}` : "";
|
|
2314
|
+
if (dryRun) {
|
|
2315
|
+
return {
|
|
2316
|
+
packageName,
|
|
2317
|
+
strategy: "override",
|
|
2318
|
+
fromVersion,
|
|
2319
|
+
toVersion,
|
|
2320
|
+
applied: false,
|
|
2321
|
+
dryRun: true,
|
|
2322
|
+
message: `[DRY RUN] Would update deno.json imports["${existingEntry.key}"] to "npm:${overrideSelector}@${toVersion}", then run ${installCommand.join(" ")}.${dependencyTraceSuffix2}`
|
|
2323
|
+
};
|
|
2324
|
+
}
|
|
2325
|
+
return withRepoLock(cwd, async () => {
|
|
2326
|
+
setDenoJsonImportValue(denoJson, overrideSelector, toVersion);
|
|
2327
|
+
writeFileSync4(denoJsonPath, JSON.stringify(denoJson, null, 2) + "\n", "utf8");
|
|
2328
|
+
try {
|
|
2329
|
+
const [installCmd, ...installArgs] = installCommand;
|
|
2330
|
+
await execa7(installCmd, installArgs, { cwd, stdio: "pipe" });
|
|
2331
|
+
} catch (err) {
|
|
2332
|
+
restoreDenoJsonImportValue(denoJson, overrideSelector, existingEntry);
|
|
2333
|
+
writeFileSync4(denoJsonPath, JSON.stringify(denoJson, null, 2) + "\n", "utf8");
|
|
2334
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2335
|
+
return {
|
|
2336
|
+
packageName,
|
|
2337
|
+
strategy: "override",
|
|
2338
|
+
fromVersion,
|
|
2339
|
+
toVersion,
|
|
2340
|
+
applied: false,
|
|
2341
|
+
dryRun: false,
|
|
2342
|
+
unresolvedReason: "override-apply-failed",
|
|
2343
|
+
message: `${installCommand.join(" ")} failed after updating deno.json imports for "${overrideSelector}" to ${toVersion}. Reverted. Error: ${message}${dependencyTraceSuffix2}`
|
|
2344
|
+
};
|
|
2345
|
+
}
|
|
2346
|
+
if (runTests) {
|
|
2347
|
+
try {
|
|
2348
|
+
const [testCmd, ...testArgs] = testCommand;
|
|
2349
|
+
await execa7(testCmd, testArgs, { cwd, stdio: "pipe" });
|
|
2350
|
+
} catch (err) {
|
|
2351
|
+
restoreDenoJsonImportValue(denoJson, overrideSelector, existingEntry);
|
|
2352
|
+
writeFileSync4(denoJsonPath, JSON.stringify(denoJson, null, 2) + "\n", "utf8");
|
|
2353
|
+
try {
|
|
2354
|
+
const [rollbackCmd, ...rollbackArgs] = installCommand;
|
|
2355
|
+
await execa7(rollbackCmd, rollbackArgs, { cwd, stdio: "pipe" });
|
|
2356
|
+
} catch {
|
|
2357
|
+
}
|
|
2358
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2359
|
+
return {
|
|
2360
|
+
packageName,
|
|
2361
|
+
strategy: "override",
|
|
2362
|
+
fromVersion,
|
|
2363
|
+
toVersion,
|
|
2364
|
+
applied: false,
|
|
2365
|
+
dryRun: false,
|
|
2366
|
+
unresolvedReason: "validation-failed",
|
|
2367
|
+
message: `${testCommand.join(" ")} failed after updating deno.json imports for "${overrideSelector}" to ${toVersion}. Reverted. Error: ${message}${dependencyTraceSuffix2}`
|
|
2368
|
+
};
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
return {
|
|
2372
|
+
packageName,
|
|
2373
|
+
strategy: "override",
|
|
2374
|
+
fromVersion,
|
|
2375
|
+
toVersion,
|
|
2376
|
+
applied: true,
|
|
2377
|
+
dryRun: false,
|
|
2378
|
+
message: `Successfully updated deno.json imports["${existingEntry.key}"] for "${overrideSelector}" from ${fromVersion} to ${toVersion}, then ran ${installCommand.join(" ")}${runTests ? ` and passed ${testCommand.join(" ")}` : ""}.${dependencyTraceSuffix2}`
|
|
2379
|
+
};
|
|
2380
|
+
});
|
|
2381
|
+
}
|
|
2131
2382
|
let pkgJson;
|
|
2132
2383
|
try {
|
|
2133
|
-
pkgJson = JSON.parse(
|
|
2384
|
+
pkgJson = JSON.parse(readFileSync9(pkgPath, "utf8"));
|
|
2134
2385
|
} catch {
|
|
2135
2386
|
return {
|
|
2136
2387
|
packageName,
|
|
@@ -2205,12 +2456,14 @@ var applyPackageOverrideTool = defineTool({
|
|
|
2205
2456
|
}
|
|
2206
2457
|
}
|
|
2207
2458
|
let dedupeNote = "";
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2459
|
+
if (dedupeCommand.length > 0) {
|
|
2460
|
+
try {
|
|
2461
|
+
const [dedupeCmd, ...dedupeArgs] = dedupeCommand;
|
|
2462
|
+
await execa7(dedupeCmd, dedupeArgs, { cwd, stdio: "pipe" });
|
|
2463
|
+
} catch (err) {
|
|
2464
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2465
|
+
dedupeNote = ` Dedupe warning: ${dedupeCommand.join(" ")} failed (${message}).`;
|
|
2466
|
+
}
|
|
2214
2467
|
}
|
|
2215
2468
|
return {
|
|
2216
2469
|
packageName,
|
|
@@ -2369,7 +2622,7 @@ async function resolvePrimaryResult(params) {
|
|
|
2369
2622
|
// src/remediation/tools/fetch-package-source.ts
|
|
2370
2623
|
import { z as z6 } from "zod";
|
|
2371
2624
|
import { mkdir as mkdir2, readdir as readdir2, readFile as readFile3, rm as rm2 } from "fs/promises";
|
|
2372
|
-
import { join as
|
|
2625
|
+
import { join as join13 } from "path";
|
|
2373
2626
|
import { execa as execa8 } from "execa";
|
|
2374
2627
|
var fetchPackageSourceTool = defineTool({
|
|
2375
2628
|
description: "Download package tarball from npm and extract source files for CVE analysis. Supports custom file patterns (default: *.js, *.ts).",
|
|
@@ -2386,23 +2639,23 @@ var fetchPackageSourceTool = defineTool({
|
|
|
2386
2639
|
filePatterns
|
|
2387
2640
|
}) => {
|
|
2388
2641
|
const tempBaseDir = `/tmp/autoremediator-pkg-${Date.now()}`;
|
|
2389
|
-
const extractDir =
|
|
2642
|
+
const extractDir = join13(tempBaseDir, "out");
|
|
2390
2643
|
try {
|
|
2391
2644
|
const npmUrl = `https://registry.npmjs.org/${packageName}/-/${packageName.split("/").pop()}-${version}.tgz`;
|
|
2392
2645
|
await mkdir2(tempBaseDir, { recursive: true });
|
|
2393
|
-
const tarballPath =
|
|
2646
|
+
const tarballPath = join13(tempBaseDir, "package.tgz");
|
|
2394
2647
|
await execa8("curl", ["-L", "-o", tarballPath, npmUrl]);
|
|
2395
2648
|
await mkdir2(extractDir, { recursive: true });
|
|
2396
2649
|
await execa8("tar", ["-xzf", tarballPath, "-C", extractDir]);
|
|
2397
2650
|
const extractedContents = await readdir2(extractDir);
|
|
2398
|
-
const packageRootDir = extractedContents.includes("package") ?
|
|
2651
|
+
const packageRootDir = extractedContents.includes("package") ? join13(extractDir, "package") : extractDir;
|
|
2399
2652
|
const sourceCode = {};
|
|
2400
2653
|
async function walkDir(dir, relativeBase) {
|
|
2401
2654
|
try {
|
|
2402
2655
|
const files = await readdir2(dir, { withFileTypes: true });
|
|
2403
2656
|
for (const file of files) {
|
|
2404
|
-
const fullPath =
|
|
2405
|
-
const relPath =
|
|
2657
|
+
const fullPath = join13(dir, file.name);
|
|
2658
|
+
const relPath = join13(relativeBase, file.name);
|
|
2406
2659
|
if (file.isDirectory()) {
|
|
2407
2660
|
if (![
|
|
2408
2661
|
"node_modules",
|
|
@@ -2774,24 +3027,23 @@ var generatePatchTool = defineTool({
|
|
|
2774
3027
|
// src/remediation/tools/apply-patch-file/index.ts
|
|
2775
3028
|
import { z as z8 } from "zod";
|
|
2776
3029
|
import { mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
|
|
2777
|
-
import { join as
|
|
3030
|
+
import { join as join15 } from "path";
|
|
2778
3031
|
import { execa as execa10 } from "execa";
|
|
2779
3032
|
|
|
2780
3033
|
// src/remediation/tools/apply-patch-file/helpers.ts
|
|
2781
|
-
import { existsSync as
|
|
3034
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2782
3035
|
import { mkdtemp, readFile as readFile4, rm as rm3, writeFile } from "fs/promises";
|
|
2783
3036
|
import { createHash } from "crypto";
|
|
2784
3037
|
import { tmpdir } from "os";
|
|
2785
|
-
import { join as
|
|
3038
|
+
import { join as join14 } from "path";
|
|
2786
3039
|
import { execa as execa9 } from "execa";
|
|
2787
3040
|
async function resolvePatchMode(packageManager, cwd) {
|
|
2788
|
-
if (packageManager === "npm") return "patch-package";
|
|
3041
|
+
if (packageManager === "npm" || packageManager === "bun" || packageManager === "deno") return "patch-package";
|
|
2789
3042
|
if (packageManager === "pnpm") return "native-pnpm";
|
|
2790
3043
|
const major = await getYarnMajorVersion(cwd);
|
|
2791
3044
|
return major >= 2 ? "native-yarn" : "patch-package";
|
|
2792
3045
|
}
|
|
2793
3046
|
function patchModeRequiresPackageJsonSnapshot(packageManager) {
|
|
2794
|
-
if (packageManager === "npm") return true;
|
|
2795
3047
|
if (packageManager === "pnpm") return false;
|
|
2796
3048
|
return true;
|
|
2797
3049
|
}
|
|
@@ -2817,7 +3069,7 @@ async function writePatchManifest(manifestFilePath, artifact) {
|
|
|
2817
3069
|
await writeFile(manifestFilePath, JSON.stringify(artifact, null, 2) + "\n", "utf8");
|
|
2818
3070
|
}
|
|
2819
3071
|
async function configurePatchPackagePostinstall(cwd, packageManager) {
|
|
2820
|
-
const pkgJsonPath =
|
|
3072
|
+
const pkgJsonPath = join14(cwd, "package.json");
|
|
2821
3073
|
let pkgJson;
|
|
2822
3074
|
try {
|
|
2823
3075
|
pkgJson = JSON.parse(await readFile4(pkgJsonPath, "utf8"));
|
|
@@ -2857,7 +3109,7 @@ async function configurePatchPackagePostinstall(cwd, packageManager) {
|
|
|
2857
3109
|
return { success: true };
|
|
2858
3110
|
}
|
|
2859
3111
|
async function capturePackageJsonSnapshot(cwd) {
|
|
2860
|
-
const path =
|
|
3112
|
+
const path = join14(cwd, "package.json");
|
|
2861
3113
|
try {
|
|
2862
3114
|
const content = await readFile4(path, "utf8");
|
|
2863
3115
|
return { path, content };
|
|
@@ -2927,8 +3179,8 @@ ${createResult.stderr}`);
|
|
|
2927
3179
|
error: `Could not determine native patch directory for ${packageSpec}.`
|
|
2928
3180
|
};
|
|
2929
3181
|
}
|
|
2930
|
-
const tempPatchDir = await mkdtemp(
|
|
2931
|
-
const tempPatchFile =
|
|
3182
|
+
const tempPatchDir = await mkdtemp(join14(tmpdir(), "autoremediator-native-patch-"));
|
|
3183
|
+
const tempPatchFile = join14(tempPatchDir, "change.patch");
|
|
2932
3184
|
try {
|
|
2933
3185
|
await writeFile(tempPatchFile, patchContent, "utf8");
|
|
2934
3186
|
await execa9("patch", ["-p1", "-i", tempPatchFile], {
|
|
@@ -2959,12 +3211,12 @@ ${createResult.stderr}`);
|
|
|
2959
3211
|
function extractPatchDirectory(output) {
|
|
2960
3212
|
const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
2961
3213
|
for (const line of lines) {
|
|
2962
|
-
if (
|
|
3214
|
+
if (existsSync8(line)) {
|
|
2963
3215
|
return line;
|
|
2964
3216
|
}
|
|
2965
3217
|
const tokens = line.split(/\s+/).map((token) => token.replace(/^['"]|['"]$/g, ""));
|
|
2966
3218
|
for (const token of tokens) {
|
|
2967
|
-
if (token.startsWith("/") &&
|
|
3219
|
+
if (token.startsWith("/") && existsSync8(token)) {
|
|
2968
3220
|
return token;
|
|
2969
3221
|
}
|
|
2970
3222
|
}
|
|
@@ -3030,7 +3282,7 @@ var applyPatchFileTool = defineTool({
|
|
|
3030
3282
|
).optional().describe("Patch list from generate-patch; first patch is applied"),
|
|
3031
3283
|
patchesDir: z8.string().optional().default("./patches").describe("Directory to store patch files"),
|
|
3032
3284
|
cwd: z8.string().describe("Project root directory (for package.json)"),
|
|
3033
|
-
packageManager: z8.enum(["npm", "pnpm", "yarn"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
3285
|
+
packageManager: z8.enum(["npm", "pnpm", "yarn", "bun", "deno"]).optional().describe("Package manager used by the target project (auto-detected if omitted)"),
|
|
3034
3286
|
policy: z8.string().optional().describe("Optional path to .autoremediator policy file"),
|
|
3035
3287
|
installMode: z8.enum(["standard", "prefer-offline", "deterministic"]).optional(),
|
|
3036
3288
|
installPreferOffline: z8.boolean().optional(),
|
|
@@ -3108,7 +3360,7 @@ var applyPatchFileTool = defineTool({
|
|
|
3108
3360
|
};
|
|
3109
3361
|
}
|
|
3110
3362
|
const patchFileName = buildPatchFileName(packageName, vulnerableVersion);
|
|
3111
|
-
const patchFilePath =
|
|
3363
|
+
const patchFilePath = join15(cwd, patchesDir, patchFileName);
|
|
3112
3364
|
const manifestFilePath = `${patchFilePath}.json`;
|
|
3113
3365
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3114
3366
|
const baseArtifact = {
|
|
@@ -3147,7 +3399,7 @@ var applyPatchFileTool = defineTool({
|
|
|
3147
3399
|
}
|
|
3148
3400
|
return withRepoLock(cwd, async () => {
|
|
3149
3401
|
const packageJsonSnapshot = patchModeRequiresPackageJsonSnapshot(pm) ? await capturePackageJsonSnapshot(cwd) : void 0;
|
|
3150
|
-
const patchesDirPath =
|
|
3402
|
+
const patchesDirPath = join15(cwd, patchesDir);
|
|
3151
3403
|
await mkdir3(patchesDirPath, { recursive: true });
|
|
3152
3404
|
await writeFile2(patchFilePath, selectedPatch, "utf8");
|
|
3153
3405
|
validationPhases.push({
|
|
@@ -4107,8 +4359,8 @@ function accumulateStepResults(params) {
|
|
|
4107
4359
|
}
|
|
4108
4360
|
|
|
4109
4361
|
// src/remediation/orchestration-prompt.ts
|
|
4110
|
-
import { existsSync as
|
|
4111
|
-
import { join as
|
|
4362
|
+
import { existsSync as existsSync9, readFileSync as readFileSync10 } from "fs";
|
|
4363
|
+
import { join as join16 } from "path";
|
|
4112
4364
|
function buildProviderAddendum(provider, personality = "balanced") {
|
|
4113
4365
|
const personalityDirective = personality === "analytical" ? "Use concise, explicit rationale for tool decisions and unresolved outcomes." : personality === "pragmatic" ? "Prefer the smallest safe remediation path while preserving policy and validation gates." : "Balance concise execution with brief rationale for risky or unresolved outcomes.";
|
|
4114
4366
|
const providerDirective = provider === "remote" ? "Use strict structured output and deterministic reporting fields." : "Use deterministic-first behavior and only rely on remote model fallback when required by patch generation.";
|
|
@@ -4119,8 +4371,8 @@ Provider profile:
|
|
|
4119
4371
|
- ${personalityDirective}`;
|
|
4120
4372
|
}
|
|
4121
4373
|
function loadOrchestrationPrompt(ctx) {
|
|
4122
|
-
const promptPath =
|
|
4123
|
-
if (!
|
|
4374
|
+
const promptPath = join16(process.cwd(), ".github", "instructions", "orchestration.instructions.md");
|
|
4375
|
+
if (!existsSync9(promptPath)) {
|
|
4124
4376
|
return `You are autoremediator, an agentic security remediation system for Node.js package dependencies.
|
|
4125
4377
|
Working directory: ${ctx.cwd}
|
|
4126
4378
|
Package manager: ${ctx.packageManager}
|
|
@@ -4146,7 +4398,7 @@ Fallback sequence (when neither version bump nor override can be applied):
|
|
|
4146
4398
|
|
|
4147
4399
|
Always respect dryRun and policy constraints.`;
|
|
4148
4400
|
}
|
|
4149
|
-
const template =
|
|
4401
|
+
const template = readFileSync10(promptPath, "utf8");
|
|
4150
4402
|
return template.replaceAll("{{cveId}}", ctx.cveId).replaceAll("{{cwd}}", ctx.cwd).replaceAll("{{packageManager}}", ctx.packageManager).replaceAll("{{dryRun}}", String(ctx.dryRun)).replaceAll("{{runTests}}", String(ctx.runTests)).replaceAll("{{policy}}", ctx.policy || "undefined").replaceAll("{{patchesDir}}", ctx.patchesDir).replaceAll("{{directDependenciesOnly}}", String(ctx.constraints.directDependenciesOnly ?? false)).replaceAll("{{preferVersionBump}}", String(ctx.constraints.preferVersionBump ?? false)) + buildProviderAddendum(ctx.llmProvider, ctx.modelPersonality);
|
|
4151
4403
|
}
|
|
4152
4404
|
|
|
@@ -5050,7 +5302,7 @@ function resolveConstraints(options, cwd) {
|
|
|
5050
5302
|
|
|
5051
5303
|
// src/platform/evidence.ts
|
|
5052
5304
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
5053
|
-
import { join as
|
|
5305
|
+
import { join as join17 } from "path";
|
|
5054
5306
|
function createEvidenceLog(cwd, cveIds, context = {}) {
|
|
5055
5307
|
return {
|
|
5056
5308
|
runId: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
@@ -5081,9 +5333,9 @@ function finalizeEvidence(log) {
|
|
|
5081
5333
|
return log;
|
|
5082
5334
|
}
|
|
5083
5335
|
function writeEvidenceLog(cwd, log) {
|
|
5084
|
-
const dir =
|
|
5336
|
+
const dir = join17(cwd, ".autoremediator", "evidence");
|
|
5085
5337
|
mkdirSync3(dir, { recursive: true });
|
|
5086
|
-
const filePath =
|
|
5338
|
+
const filePath = join17(dir, `${log.runId}.json`);
|
|
5087
5339
|
writeFileSync5(filePath, JSON.stringify(log, null, 2) + "\n", "utf8");
|
|
5088
5340
|
return filePath;
|
|
5089
5341
|
}
|
|
@@ -5652,11 +5904,11 @@ async function planRemediation(cveId, options = {}) {
|
|
|
5652
5904
|
|
|
5653
5905
|
// src/scanner/parse-input.ts
|
|
5654
5906
|
import { extname as extname2 } from "path";
|
|
5655
|
-
import { readFileSync as
|
|
5907
|
+
import { readFileSync as readFileSync14 } from "fs";
|
|
5656
5908
|
import { execa as execa12 } from "execa";
|
|
5657
5909
|
|
|
5658
5910
|
// src/scanner/adapters/npm-audit.ts
|
|
5659
|
-
import { readFileSync as
|
|
5911
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
5660
5912
|
var CVE_REGEX = /CVE-\d{4}-\d+/gi;
|
|
5661
5913
|
function normalizeSeverity(raw) {
|
|
5662
5914
|
if (!raw) return "UNKNOWN";
|
|
@@ -5690,12 +5942,12 @@ function parseNpmAuditJsonFromString(content) {
|
|
|
5690
5942
|
return findings;
|
|
5691
5943
|
}
|
|
5692
5944
|
function parseNpmAuditJsonFile(filePath) {
|
|
5693
|
-
const content =
|
|
5945
|
+
const content = readFileSync11(filePath, "utf8");
|
|
5694
5946
|
return parseNpmAuditJsonFromString(content);
|
|
5695
5947
|
}
|
|
5696
5948
|
|
|
5697
5949
|
// src/scanner/adapters/yarn-audit.ts
|
|
5698
|
-
import { readFileSync as
|
|
5950
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
5699
5951
|
var CVE_REGEX2 = /CVE-\d{4}-\d+/gi;
|
|
5700
5952
|
function normalizeSeverity2(raw) {
|
|
5701
5953
|
if (!raw) return "UNKNOWN";
|
|
@@ -5738,12 +5990,12 @@ function parseYarnAuditJsonFromString(content) {
|
|
|
5738
5990
|
return findings;
|
|
5739
5991
|
}
|
|
5740
5992
|
function parseYarnAuditJsonFile(filePath) {
|
|
5741
|
-
const content =
|
|
5993
|
+
const content = readFileSync12(filePath, "utf8");
|
|
5742
5994
|
return parseYarnAuditJsonFromString(content);
|
|
5743
5995
|
}
|
|
5744
5996
|
|
|
5745
5997
|
// src/scanner/adapters/sarif.ts
|
|
5746
|
-
import { readFileSync as
|
|
5998
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
5747
5999
|
var CVE_REGEX3 = /CVE-\d{4}-\d+/gi;
|
|
5748
6000
|
function extractPackageName(result) {
|
|
5749
6001
|
const pkg = result.properties?.["packageName"];
|
|
@@ -5775,7 +6027,7 @@ function parseSarifFromString(content) {
|
|
|
5775
6027
|
return findings;
|
|
5776
6028
|
}
|
|
5777
6029
|
function parseSarifFile(filePath) {
|
|
5778
|
-
const content =
|
|
6030
|
+
const content = readFileSync13(filePath, "utf8");
|
|
5779
6031
|
return parseSarifFromString(content);
|
|
5780
6032
|
}
|
|
5781
6033
|
|
|
@@ -5826,10 +6078,21 @@ async function parseScanInputFromAudit(params) {
|
|
|
5826
6078
|
}
|
|
5827
6079
|
}
|
|
5828
6080
|
function defaultAuditFormat(pm) {
|
|
5829
|
-
|
|
6081
|
+
if (pm === "yarn") return "yarn-audit";
|
|
6082
|
+
if (pm === "deno") {
|
|
6083
|
+
throw new Error(
|
|
6084
|
+
"Deno does not support a native audit command. Use --input with a SARIF or npm-audit scan file instead."
|
|
6085
|
+
);
|
|
6086
|
+
}
|
|
6087
|
+
return "npm-audit";
|
|
5830
6088
|
}
|
|
5831
6089
|
function ensureAuditFormatCompatibility(pm, resolved) {
|
|
5832
6090
|
if (resolved === "sarif") return;
|
|
6091
|
+
if (pm === "deno") {
|
|
6092
|
+
throw new Error(
|
|
6093
|
+
"Deno does not support a native audit command. Use --input with a SARIF or npm-audit scan file instead."
|
|
6094
|
+
);
|
|
6095
|
+
}
|
|
5833
6096
|
if (pm === "yarn" && resolved !== "yarn-audit") {
|
|
5834
6097
|
throw new Error('Format "npm-audit" is not supported with package manager "yarn" in --audit mode. Use --format yarn-audit or --format auto.');
|
|
5835
6098
|
}
|
|
@@ -5841,7 +6104,7 @@ function inferFormat(filePath) {
|
|
|
5841
6104
|
const ext = extname2(filePath).toLowerCase();
|
|
5842
6105
|
if (ext === ".sarif") return "sarif";
|
|
5843
6106
|
try {
|
|
5844
|
-
const content =
|
|
6107
|
+
const content = readFileSync14(filePath, "utf8");
|
|
5845
6108
|
const firstLine = content.split("\n").find((line) => line.trim().startsWith("{"));
|
|
5846
6109
|
if (firstLine) {
|
|
5847
6110
|
const parsed = JSON.parse(firstLine);
|
|
@@ -6239,14 +6502,14 @@ async function remediatePortfolio(targets, options = {}) {
|
|
|
6239
6502
|
}
|
|
6240
6503
|
|
|
6241
6504
|
// src/api/update-outdated/index.ts
|
|
6242
|
-
import { join as
|
|
6243
|
-
import { readFileSync as
|
|
6505
|
+
import { join as join18 } from "path";
|
|
6506
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync6 } from "fs";
|
|
6244
6507
|
import { execa as execa13 } from "execa";
|
|
6245
6508
|
async function applyBump(params) {
|
|
6246
|
-
const pkgPath =
|
|
6509
|
+
const pkgPath = join18(params.cwd, "package.json");
|
|
6247
6510
|
let pkgJson;
|
|
6248
6511
|
try {
|
|
6249
|
-
pkgJson = JSON.parse(
|
|
6512
|
+
pkgJson = JSON.parse(readFileSync15(pkgPath, "utf8"));
|
|
6250
6513
|
} catch {
|
|
6251
6514
|
return {
|
|
6252
6515
|
applied: false,
|
|
@@ -6547,9 +6810,9 @@ function toSarifOutput(report) {
|
|
|
6547
6810
|
}
|
|
6548
6811
|
|
|
6549
6812
|
// src/version.ts
|
|
6550
|
-
import { readFileSync as
|
|
6813
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
6551
6814
|
function readPackageVersion() {
|
|
6552
|
-
const raw =
|
|
6815
|
+
const raw = readFileSync16(new URL("../package.json", import.meta.url), "utf8");
|
|
6553
6816
|
const metadata = JSON.parse(raw);
|
|
6554
6817
|
if (!metadata.version) {
|
|
6555
6818
|
throw new Error("packages/core/package.json is missing a version field.");
|
|
@@ -6577,4 +6840,4 @@ export {
|
|
|
6577
6840
|
updateOutdated,
|
|
6578
6841
|
PACKAGE_VERSION
|
|
6579
6842
|
};
|
|
6580
|
-
//# sourceMappingURL=chunk-
|
|
6843
|
+
//# sourceMappingURL=chunk-3NNNFJLV.js.map
|