autoremediator 0.3.0 → 0.4.1

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 CHANGED
@@ -56,6 +56,17 @@ Primary sources:
56
56
  - [GitHub Advisory Database](https://github.com/advisories)
57
57
  - [NVD](https://nvd.nist.gov)
58
58
 
59
+ Supplemental enrichment and prioritization sources:
60
+
61
+ - [CISA KEV](https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
62
+ - [FIRST EPSS](https://www.first.org/epss/)
63
+ - [CVE Services](https://www.cve.org/)
64
+ - [GitLab Advisory Database](https://advisories.gitlab.com)
65
+ - [CERT/CC Vulnerability Notes](https://www.kb.cert.org/vuls/)
66
+ - [deps.dev](https://deps.dev)
67
+ - [OpenSSF Scorecard](https://securityscorecards.dev)
68
+ - Optional vendor and commercial feeds via environment-configured connectors
69
+
59
70
  Trust controls:
60
71
 
61
72
  - correlate advisory data with local dependency inventory before action
@@ -70,6 +81,8 @@ Trust controls:
70
81
  - MCP: AI host integrations
71
82
  - OpenAPI: service-based automation
72
83
 
84
+ Public API naming canon: `runTests`, `policy`, `evidence`, `patchCount`, and `patchesDir`.
85
+
73
86
  ## Documentation
74
87
 
75
88
  - [Docs Home](https://rawlings.github.io/autoremediator/)
@@ -64,6 +64,19 @@ function getNvdConfig() {
64
64
  function getGitHubToken() {
65
65
  return process.env.GITHUB_TOKEN;
66
66
  }
67
+ function getIntelligenceSourceConfig() {
68
+ return {
69
+ gitLabAdvisoryApi: process.env.AUTOREMEDIATOR_GITLAB_ADVISORY_API ?? "https://advisories.gitlab.com/api/v1/advisories",
70
+ certCcSearchUrl: process.env.AUTOREMEDIATOR_CERTCC_SEARCH_URL ?? "https://www.kb.cert.org/vuls/search",
71
+ epssApi: process.env.AUTOREMEDIATOR_EPSS_API ?? "https://api.first.org/data/v1/epss",
72
+ cveServicesApi: process.env.AUTOREMEDIATOR_CVE_SERVICES_API ?? "https://cveawg.mitre.org/api/cve",
73
+ depsDevApi: process.env.AUTOREMEDIATOR_DEPSDEV_API ?? "https://api.deps.dev/v3",
74
+ scorecardApi: process.env.AUTOREMEDIATOR_SCORECARD_API ?? "https://api.securityscorecards.dev",
75
+ vendorAdvisoryFeeds: (process.env.AUTOREMEDIATOR_VENDOR_ADVISORY_FEEDS ?? "").split(",").map((v) => v.trim()).filter(Boolean),
76
+ commercialFeeds: (process.env.AUTOREMEDIATOR_COMMERCIAL_FEEDS ?? "").split(",").map((v) => v.trim()).filter(Boolean),
77
+ commercialFeedToken: process.env.AUTOREMEDIATOR_COMMERCIAL_FEED_TOKEN
78
+ };
79
+ }
67
80
 
68
81
  // src/platform/package-manager.ts
69
82
  import { existsSync } from "fs";
@@ -343,6 +356,288 @@ async function enrichWithNvd(details) {
343
356
  return details;
344
357
  }
345
358
 
359
+ // src/intelligence/sources/cisa-kev.ts
360
+ var CISA_KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json";
361
+ async function fetchCisaKevFeed() {
362
+ try {
363
+ const res = await fetch(CISA_KEV_URL, {
364
+ headers: { Accept: "application/json" }
365
+ });
366
+ if (!res.ok) return void 0;
367
+ return await res.json();
368
+ } catch {
369
+ return void 0;
370
+ }
371
+ }
372
+ function findKevEntry(feed, cveId) {
373
+ if (!feed?.vulnerabilities?.length) return void 0;
374
+ const normalized = cveId.toUpperCase();
375
+ return feed.vulnerabilities.find((v) => v.cveID.toUpperCase() === normalized);
376
+ }
377
+ async function enrichWithCisaKev(details) {
378
+ const feed = await fetchCisaKevFeed();
379
+ const entry = findKevEntry(feed, details.id);
380
+ if (!entry) return details;
381
+ details.kev = {
382
+ knownExploited: true,
383
+ dateAdded: entry.dateAdded,
384
+ dueDate: entry.dueDate,
385
+ requiredAction: entry.requiredAction,
386
+ knownRansomwareCampaignUse: entry.knownRansomwareCampaignUse
387
+ };
388
+ if (!details.references.includes(CISA_KEV_URL)) {
389
+ details.references.push(CISA_KEV_URL);
390
+ }
391
+ return details;
392
+ }
393
+
394
+ // src/intelligence/sources/epss.ts
395
+ async function fetchEpss(cveId) {
396
+ const { epssApi } = getIntelligenceSourceConfig();
397
+ if (!epssApi) return void 0;
398
+ try {
399
+ const url = new URL(epssApi);
400
+ url.searchParams.set("cve", cveId);
401
+ const res = await fetch(url.toString(), {
402
+ headers: { Accept: "application/json" }
403
+ });
404
+ if (!res.ok) return void 0;
405
+ const body = await res.json();
406
+ return body.data?.[0];
407
+ } catch {
408
+ return void 0;
409
+ }
410
+ }
411
+ async function enrichWithEpss(details) {
412
+ const row = await fetchEpss(details.id);
413
+ if (!row) return details;
414
+ const score = Number.parseFloat(row.epss);
415
+ const percentile = Number.parseFloat(row.percentile);
416
+ if (!Number.isFinite(score) || !Number.isFinite(percentile)) {
417
+ return details;
418
+ }
419
+ details.epss = {
420
+ score,
421
+ percentile,
422
+ date: row.date
423
+ };
424
+ return details;
425
+ }
426
+
427
+ // src/intelligence/sources/cve-services.ts
428
+ function pickEnglishDescription(container) {
429
+ if (!container?.descriptions?.length) return void 0;
430
+ const en = container.descriptions.find((d) => d.lang === "en" && d.value);
431
+ return (en?.value ?? container.descriptions[0]?.value)?.trim() || void 0;
432
+ }
433
+ function collectReferences(record) {
434
+ const refs = /* @__PURE__ */ new Set();
435
+ const cnaRefs = record.containers?.cna?.references ?? [];
436
+ const adpRefs = (record.containers?.adp ?? []).flatMap((c) => c.references ?? []);
437
+ for (const ref of [...cnaRefs, ...adpRefs]) {
438
+ if (ref.url) refs.add(ref.url);
439
+ }
440
+ return Array.from(refs);
441
+ }
442
+ async function fetchCveServicesRecord(cveId) {
443
+ const { cveServicesApi } = getIntelligenceSourceConfig();
444
+ if (!cveServicesApi) return void 0;
445
+ try {
446
+ const res = await fetch(`${cveServicesApi}/${encodeURIComponent(cveId)}`, {
447
+ headers: { Accept: "application/json" }
448
+ });
449
+ if (!res.ok) return void 0;
450
+ return await res.json();
451
+ } catch {
452
+ return void 0;
453
+ }
454
+ }
455
+ async function enrichWithCveServices(details) {
456
+ const record = await fetchCveServicesRecord(details.id);
457
+ if (!record) return details;
458
+ const summary = pickEnglishDescription(record.containers?.cna);
459
+ if (summary && (!details.summary || details.summary.includes("No summary available"))) {
460
+ details.summary = summary;
461
+ }
462
+ const refs = collectReferences(record);
463
+ if (refs.length > 0) {
464
+ const merged = /* @__PURE__ */ new Set([...details.references, ...refs]);
465
+ details.references = Array.from(merged);
466
+ }
467
+ details.intelligence = {
468
+ ...details.intelligence ?? {},
469
+ cveServicesEnriched: true
470
+ };
471
+ return details;
472
+ }
473
+
474
+ // src/intelligence/sources/gitlab-advisory.ts
475
+ function advisoryMatchesCve(advisory, cveId) {
476
+ const normalized = cveId.toUpperCase();
477
+ return (advisory.identifiers ?? []).some(
478
+ (id) => id.type?.toUpperCase() === "CVE" && id.value?.toUpperCase() === normalized
479
+ );
480
+ }
481
+ async function fetchGitLabAdvisories(cveId) {
482
+ const { gitLabAdvisoryApi } = getIntelligenceSourceConfig();
483
+ if (!gitLabAdvisoryApi) return [];
484
+ try {
485
+ const url = new URL(gitLabAdvisoryApi);
486
+ url.searchParams.set("identifier", cveId);
487
+ url.searchParams.set("ecosystem", "npm");
488
+ const res = await fetch(url.toString(), {
489
+ headers: { Accept: "application/json" }
490
+ });
491
+ if (!res.ok) return [];
492
+ const body = await res.json();
493
+ return Array.isArray(body) ? body : [];
494
+ } catch {
495
+ return [];
496
+ }
497
+ }
498
+ async function enrichWithGitLabAdvisory(details) {
499
+ const advisories = await fetchGitLabAdvisories(details.id);
500
+ const matched = advisories.filter((a) => advisoryMatchesCve(a, details.id));
501
+ if (matched.length === 0) return details;
502
+ const refs = matched.flatMap((m) => m.references ?? []);
503
+ if (refs.length > 0) {
504
+ const merged = /* @__PURE__ */ new Set([...details.references, ...refs]);
505
+ details.references = Array.from(merged);
506
+ }
507
+ details.intelligence = {
508
+ ...details.intelligence ?? {},
509
+ gitlabAdvisoryMatched: true
510
+ };
511
+ return details;
512
+ }
513
+
514
+ // src/intelligence/sources/certcc.ts
515
+ var CERTCC_HOME = "https://www.kb.cert.org/vuls/";
516
+ async function findCertCcReference(cveId) {
517
+ const { certCcSearchUrl } = getIntelligenceSourceConfig();
518
+ if (!certCcSearchUrl) return void 0;
519
+ try {
520
+ const url = new URL(certCcSearchUrl);
521
+ url.searchParams.set("query", cveId);
522
+ const res = await fetch(url.toString(), {
523
+ headers: { Accept: "text/html" }
524
+ });
525
+ if (!res.ok) return void 0;
526
+ const html = await res.text();
527
+ const match = html.match(/https:\/\/www\.kb\.cert\.org\/vuls\/id\/\d+/i);
528
+ return match?.[0] ?? void 0;
529
+ } catch {
530
+ return void 0;
531
+ }
532
+ }
533
+ async function enrichWithCertCc(details) {
534
+ const ref = await findCertCcReference(details.id);
535
+ if (!ref) return details;
536
+ if (!details.references.includes(ref)) {
537
+ details.references.push(ref);
538
+ }
539
+ details.intelligence = {
540
+ ...details.intelligence ?? {},
541
+ certCcMatched: true
542
+ };
543
+ if (!details.references.includes(CERTCC_HOME)) {
544
+ details.references.push(CERTCC_HOME);
545
+ }
546
+ return details;
547
+ }
548
+
549
+ // src/intelligence/sources/deps-dev.ts
550
+ async function fetchDepsDevPackage(name) {
551
+ const { depsDevApi } = getIntelligenceSourceConfig();
552
+ if (!depsDevApi) return false;
553
+ try {
554
+ const url = `${depsDevApi}/systems/npm/packages/${encodeURIComponent(name)}`;
555
+ const res = await fetch(url, { headers: { Accept: "application/json" } });
556
+ return res.ok;
557
+ } catch {
558
+ return false;
559
+ }
560
+ }
561
+ async function enrichWithDepsDev(details) {
562
+ const names = Array.from(new Set(details.affectedPackages.map((p) => p.name))).slice(0, 20);
563
+ if (names.length === 0) return details;
564
+ const checks = await Promise.all(names.map((name) => fetchDepsDevPackage(name)));
565
+ const matched = checks.filter(Boolean).length;
566
+ if (matched === 0) return details;
567
+ details.intelligence = {
568
+ ...details.intelligence ?? {},
569
+ depsDevEnrichedPackages: matched
570
+ };
571
+ return details;
572
+ }
573
+
574
+ // src/intelligence/sources/ossf-scorecard.ts
575
+ async function checkProject(project) {
576
+ const { scorecardApi } = getIntelligenceSourceConfig();
577
+ if (!scorecardApi) return false;
578
+ try {
579
+ const url = new URL(`${scorecardApi}/projects`);
580
+ url.searchParams.set("project", project);
581
+ const res = await fetch(url.toString(), {
582
+ headers: { Accept: "application/json" }
583
+ });
584
+ return res.ok;
585
+ } catch {
586
+ return false;
587
+ }
588
+ }
589
+ async function enrichWithOssfScorecard(details) {
590
+ const projects = Array.from(
591
+ new Set(details.affectedPackages.map((p) => `github.com/${p.name}/${p.name}`))
592
+ ).slice(0, 10);
593
+ if (projects.length === 0) return details;
594
+ const checks = await Promise.all(projects.map((project) => checkProject(project)));
595
+ const matched = checks.filter(Boolean).length;
596
+ if (matched === 0) return details;
597
+ details.intelligence = {
598
+ ...details.intelligence ?? {},
599
+ scorecardProjects: matched
600
+ };
601
+ return details;
602
+ }
603
+
604
+ // src/intelligence/sources/external-feeds.ts
605
+ async function probeFeed(url, cveId, token) {
606
+ try {
607
+ const feedUrl = new URL(url);
608
+ feedUrl.searchParams.set("cve", cveId);
609
+ const headers = { Accept: "application/json" };
610
+ if (token) headers.Authorization = `Bearer ${token}`;
611
+ const res = await fetch(feedUrl.toString(), { headers });
612
+ if (!res.ok) return void 0;
613
+ return feedUrl.toString();
614
+ } catch {
615
+ return void 0;
616
+ }
617
+ }
618
+ async function enrichWithExternalFeeds(details) {
619
+ const {
620
+ vendorAdvisoryFeeds,
621
+ commercialFeeds,
622
+ commercialFeedToken
623
+ } = getIntelligenceSourceConfig();
624
+ const vendorHits = (await Promise.all(vendorAdvisoryFeeds.map((url) => probeFeed(url, details.id)))).filter((v) => Boolean(v));
625
+ const commercialHits = (await Promise.all(
626
+ commercialFeeds.map((url) => probeFeed(url, details.id, commercialFeedToken))
627
+ )).filter((v) => Boolean(v));
628
+ if (vendorHits.length === 0 && commercialHits.length === 0) {
629
+ return details;
630
+ }
631
+ details.intelligence = {
632
+ ...details.intelligence ?? {},
633
+ vendorAdvisories: vendorHits.length > 0 ? vendorHits : details.intelligence?.vendorAdvisories,
634
+ commercialFeeds: commercialHits.length > 0 ? commercialHits : details.intelligence?.commercialFeeds
635
+ };
636
+ const mergedRefs = /* @__PURE__ */ new Set([...details.references, ...vendorHits, ...commercialHits]);
637
+ details.references = Array.from(mergedRefs);
638
+ return details;
639
+ }
640
+
346
641
  // src/remediation/tools/lookup-cve.ts
347
642
  var lookupCveTool = tool({
348
643
  description: "Look up a CVE ID and return the list of affected npm packages, their vulnerable version ranges, and the first patched version. Always call this first.",
@@ -371,7 +666,37 @@ var lookupCveTool = tool({
371
666
  if (ghPackages.length > 0) {
372
667
  details = mergeGhDataIntoCveDetails(details, ghPackages);
373
668
  }
374
- details = await enrichWithNvd(details);
669
+ const sourceHealth = {};
670
+ const applyEnricher = async (sourceName, enricher) => {
671
+ const before = JSON.stringify(details);
672
+ try {
673
+ details = await enricher(details);
674
+ const after = JSON.stringify(details);
675
+ sourceHealth[sourceName] = {
676
+ attempted: true,
677
+ changed: before !== after
678
+ };
679
+ } catch (error) {
680
+ sourceHealth[sourceName] = {
681
+ attempted: true,
682
+ changed: false,
683
+ error: error instanceof Error ? error.message : String(error)
684
+ };
685
+ }
686
+ };
687
+ await applyEnricher("nvd", enrichWithNvd);
688
+ await applyEnricher("cisa-kev", enrichWithCisaKev);
689
+ await applyEnricher("epss", enrichWithEpss);
690
+ await applyEnricher("cve-services", enrichWithCveServices);
691
+ await applyEnricher("gitlab-advisory", enrichWithGitLabAdvisory);
692
+ await applyEnricher("certcc", enrichWithCertCc);
693
+ await applyEnricher("deps-dev", enrichWithDepsDev);
694
+ await applyEnricher("ossf-scorecard", enrichWithOssfScorecard);
695
+ await applyEnricher("external-feeds", enrichWithExternalFeeds);
696
+ details.intelligence = {
697
+ ...details.intelligence ?? {},
698
+ sourceHealth
699
+ };
375
700
  if (details.affectedPackages.length === 0) {
376
701
  return {
377
702
  success: false,
@@ -666,8 +991,8 @@ var applyVersionBumpTool = tool5({
666
991
  fromVersion: z5.string().describe("The currently installed vulnerable version"),
667
992
  toVersion: z5.string().describe("The safe target version to upgrade to"),
668
993
  dryRun: z5.boolean().default(false).describe("If true, report changes but do not write"),
669
- policyPath: z5.string().optional().describe("Optional path to .autoremediator policy file"),
670
- skipTests: z5.boolean().default(true).describe("If true, skip test validation after applying the fix")
994
+ policy: z5.string().optional().describe("Optional path to .autoremediator policy file"),
995
+ runTests: z5.boolean().default(false).describe("If true, run test validation after applying the fix")
671
996
  }),
672
997
  execute: async ({
673
998
  cwd,
@@ -676,14 +1001,14 @@ var applyVersionBumpTool = tool5({
676
1001
  fromVersion,
677
1002
  toVersion,
678
1003
  dryRun,
679
- policyPath,
680
- skipTests
1004
+ policy,
1005
+ runTests
681
1006
  }) => {
682
1007
  const pm = packageManager ?? detectPackageManager(cwd);
683
1008
  const commands = getPackageManagerCommands(pm);
684
1009
  const pkgPath = join5(cwd, "package.json");
685
- const policy = loadPolicy(cwd, policyPath);
686
- if (!isPackageAllowed(policy, packageName)) {
1010
+ const loadedPolicy = loadPolicy(cwd, policy);
1011
+ if (!isPackageAllowed(loadedPolicy, packageName)) {
687
1012
  return {
688
1013
  packageName,
689
1014
  strategy: "none",
@@ -695,7 +1020,7 @@ var applyVersionBumpTool = tool5({
695
1020
  };
696
1021
  }
697
1022
  const isMajorBump = semver3.valid(fromVersion) && semver3.valid(toVersion) && semver3.major(toVersion) > semver3.major(fromVersion);
698
- if (isMajorBump && !policy.allowMajorBumps) {
1023
+ if (isMajorBump && !loadedPolicy.allowMajorBumps) {
699
1024
  return {
700
1025
  packageName,
701
1026
  strategy: "none",
@@ -746,7 +1071,7 @@ var applyVersionBumpTool = tool5({
746
1071
  toVersion,
747
1072
  applied: false,
748
1073
  dryRun: true,
749
- message: `[DRY RUN] Would update ${depField}.${packageName}: "${currentRange}" \u2192 "${newRange}", then run ${installCmd}${skipTests ? "" : ` and ${testCmd}`}.`
1074
+ message: `[DRY RUN] Would update ${depField}.${packageName}: "${currentRange}" -> "${newRange}", then run ${installCmd}${runTests ? ` and ${testCmd}` : ""}.`
750
1075
  };
751
1076
  }
752
1077
  return withRepoLock(cwd, async () => {
@@ -772,7 +1097,7 @@ var applyVersionBumpTool = tool5({
772
1097
  message: `${commands.installPreferOffline.join(" ")} failed after updating "${packageName}" to ${toVersion}. Reverted. Error: ${message}`
773
1098
  };
774
1099
  }
775
- if (!skipTests) {
1100
+ if (runTests) {
776
1101
  try {
777
1102
  const [testCmd, ...testArgs] = commands.test;
778
1103
  await execa2(testCmd, testArgs, {
@@ -809,7 +1134,7 @@ var applyVersionBumpTool = tool5({
809
1134
  toVersion,
810
1135
  applied: true,
811
1136
  dryRun: false,
812
- message: `Successfully upgraded "${packageName}" from ${fromVersion} to ${toVersion}, ran ${commands.installPreferOffline.join(" ")}${skipTests ? "" : `, and passed ${commands.test.join(" ")}`}.`
1137
+ message: `Successfully upgraded "${packageName}" from ${fromVersion} to ${toVersion}, ran ${commands.installPreferOffline.join(" ")}${runTests ? `, and passed ${commands.test.join(" ")}` : ""}.`
813
1138
  };
814
1139
  });
815
1140
  }
@@ -1442,16 +1767,16 @@ async function runRemediationPipeline(cveId, options = {}) {
1442
1767
  const packageManager = options.packageManager ?? detectPackageManager(cwd);
1443
1768
  const preview = options.preview ?? false;
1444
1769
  const dryRun = (options.dryRun ?? false) || preview;
1445
- const skipTests = options.skipTests ?? true;
1446
- const policyPath = options.policyPath ?? "";
1770
+ const runTests = options.runTests ?? false;
1771
+ const policy = options.policy ?? "";
1447
1772
  const patchesDir = options.patchesDir || "./patches";
1448
1773
  const model = await createModel(options);
1449
1774
  const systemPrompt = loadOrchestrationPrompt({
1450
1775
  cveId,
1451
1776
  cwd,
1452
1777
  dryRun,
1453
- skipTests,
1454
- policyPath,
1778
+ runTests,
1779
+ policy,
1455
1780
  patchesDir,
1456
1781
  packageManager
1457
1782
  });
@@ -1536,8 +1861,8 @@ async function runLocalRemediationPipeline(cveId, options = {}) {
1536
1861
  const packageManager = options.packageManager ?? detectPackageManager(cwd);
1537
1862
  const preview = options.preview ?? false;
1538
1863
  const dryRun = (options.dryRun ?? false) || preview;
1539
- const skipTests = options.skipTests ?? true;
1540
- const policyPath = options.policyPath ?? "";
1864
+ const runTests = options.runTests ?? false;
1865
+ const policy = options.policy ?? "";
1541
1866
  const collectedResults = [];
1542
1867
  const vulnerablePackages = [];
1543
1868
  let cveDetails = null;
@@ -1678,8 +2003,8 @@ async function runLocalRemediationPipeline(cveId, options = {}) {
1678
2003
  fromVersion: pkg.version,
1679
2004
  toVersion: safeVersion,
1680
2005
  dryRun,
1681
- policyPath,
1682
- skipTests
2006
+ policy,
2007
+ runTests
1683
2008
  });
1684
2009
  agentSteps += 1;
1685
2010
  collectedResults.push(applyResult);
@@ -1708,8 +2033,8 @@ function loadOrchestrationPrompt(ctx) {
1708
2033
  Working directory: ${ctx.cwd}
1709
2034
  Package manager: ${ctx.packageManager}
1710
2035
  Dry run: ${ctx.dryRun}
1711
- Skip tests: ${ctx.skipTests}
1712
- Policy path: ${ctx.policyPath || "undefined"}
2036
+ Run tests: ${ctx.runTests}
2037
+ Policy: ${ctx.policy || "undefined"}
1713
2038
  Patches dir: ${ctx.patchesDir}
1714
2039
 
1715
2040
  Required sequence:
@@ -1727,7 +2052,7 @@ Fallback sequence (when strategy="none"):
1727
2052
  Always respect dryRun and policy constraints.`;
1728
2053
  }
1729
2054
  const template = readFileSync4(promptPath, "utf8");
1730
- return template.replaceAll("{{cveId}}", ctx.cveId).replaceAll("{{cwd}}", ctx.cwd).replaceAll("{{packageManager}}", ctx.packageManager).replaceAll("{{dryRun}}", String(ctx.dryRun)).replaceAll("{{skipTests}}", String(ctx.skipTests)).replaceAll("{{policyPath}}", ctx.policyPath || "undefined").replaceAll("{{patchesDir}}", ctx.patchesDir);
2055
+ 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);
1731
2056
  }
1732
2057
 
1733
2058
  // src/scanner/index.ts
@@ -1999,7 +2324,7 @@ function resolveProvenanceContext(options) {
1999
2324
  };
2000
2325
  }
2001
2326
  function resolveConstraints(options, cwd) {
2002
- const policy = loadPolicy(cwd, options.policyPath);
2327
+ const policy = loadPolicy(cwd, options.policy);
2003
2328
  return {
2004
2329
  directDependenciesOnly: options.constraints?.directDependenciesOnly ?? policy.constraints?.directDependenciesOnly ?? false,
2005
2330
  preferVersionBump: options.constraints?.preferVersionBump ?? policy.constraints?.preferVersionBump ?? false
@@ -2090,7 +2415,7 @@ async function remediateFromScan(inputPath, options = {}) {
2090
2415
  const patchesDir = options.patchesDir ?? "./patches";
2091
2416
  const findings = parseScanInput(inputPath, format);
2092
2417
  const cveIds = uniqueCveIds(findings);
2093
- const policy = loadPolicy(cwd, options.policyPath);
2418
+ const policy = loadPolicy(cwd, options.policy);
2094
2419
  const correlation = resolveCorrelationContext(options);
2095
2420
  const provenance = resolveProvenanceContext(options);
2096
2421
  const constraints = resolveConstraints(options, cwd);
@@ -2104,7 +2429,7 @@ async function remediateFromScan(inputPath, options = {}) {
2104
2429
  const reports = [];
2105
2430
  const errors = [];
2106
2431
  const patchValidationFailures = [];
2107
- let patchFileCount = 0;
2432
+ let patchCount = 0;
2108
2433
  for (const cveId of cveIds) {
2109
2434
  try {
2110
2435
  addEvidenceStep(evidence, "remediate.start", { cveId });
@@ -2119,7 +2444,7 @@ async function remediateFromScan(inputPath, options = {}) {
2119
2444
  report.results = report.results.filter((r) => isPackageAllowed(policy, r.packageName));
2120
2445
  for (const result of report.results) {
2121
2446
  if (result.strategy === "patch-file") {
2122
- patchFileCount += 1;
2447
+ patchCount += 1;
2123
2448
  }
2124
2449
  if (result.validation?.passed === false && result.validation?.error) {
2125
2450
  patchValidationFailures.push({
@@ -2156,7 +2481,7 @@ async function remediateFromScan(inputPath, options = {}) {
2156
2481
  status = "failed";
2157
2482
  }
2158
2483
  finalizeEvidence(evidence);
2159
- const evidenceFile = options.writeEvidence === false ? void 0 : writeEvidenceLog(cwd, evidence);
2484
+ const evidenceFile = options.evidence === false ? void 0 : writeEvidenceLog(cwd, evidence);
2160
2485
  return {
2161
2486
  schemaVersion: "1.0",
2162
2487
  status,
@@ -2167,9 +2492,9 @@ async function remediateFromScan(inputPath, options = {}) {
2167
2492
  failedCount,
2168
2493
  errors,
2169
2494
  evidenceFile,
2170
- patchFileCount,
2495
+ patchCount,
2171
2496
  patchValidationFailures: patchValidationFailures.length > 0 ? patchValidationFailures : void 0,
2172
- patchStorageDir: patchFileCount > 0 ? patchesDir : void 0,
2497
+ patchesDir: patchCount > 0 ? patchesDir : void 0,
2173
2498
  correlation,
2174
2499
  provenance,
2175
2500
  constraints,
@@ -2191,9 +2516,9 @@ function toCiSummary(report) {
2191
2516
  failedCount: report.failedCount,
2192
2517
  errors: report.errors,
2193
2518
  evidenceFile: report.evidenceFile,
2194
- patchFileCount: report.patchFileCount || 0,
2519
+ patchCount: report.patchCount || 0,
2195
2520
  patchValidationFailures: report.patchValidationFailures,
2196
- patchStorageDir: report.patchStorageDir,
2521
+ patchesDir: report.patchesDir,
2197
2522
  correlation: report.correlation,
2198
2523
  provenance: report.provenance,
2199
2524
  constraints: report.constraints,
@@ -2212,4 +2537,4 @@ export {
2212
2537
  toCiSummary,
2213
2538
  ciExitCode
2214
2539
  };
2215
- //# sourceMappingURL=chunk-URM53GSJ.js.map
2540
+ //# sourceMappingURL=chunk-GBOD3DV6.js.map