sentinello 3.2.0 → 3.3.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.
Files changed (2) hide show
  1. package/dist/cli.cjs +368 -282
  2. package/package.json +1 -2
package/dist/cli.cjs CHANGED
@@ -526,11 +526,11 @@ var require_parse = __commonJS({
526
526
  var require_valid = __commonJS({
527
527
  "../../node_modules/.pnpm/semver@7.7.4/node_modules/semver/functions/valid.js"(exports2, module2) {
528
528
  var parse3 = require_parse();
529
- var valid4 = (version2, options) => {
529
+ var valid3 = (version2, options) => {
530
530
  const v = parse3(version2, options);
531
531
  return v ? v.version : null;
532
532
  };
533
- module2.exports = valid4;
533
+ module2.exports = valid3;
534
534
  }
535
535
  });
536
536
 
@@ -772,7 +772,7 @@ var require_cmp = __commonJS({
772
772
  var gte2 = require_gte();
773
773
  var lt = require_lt();
774
774
  var lte = require_lte();
775
- var cmp = (a, op, b, loose) => {
775
+ var cmp2 = (a, op, b, loose) => {
776
776
  switch (op) {
777
777
  case "===":
778
778
  if (typeof a === "object") {
@@ -808,7 +808,7 @@ var require_cmp = __commonJS({
808
808
  throw new TypeError(`Invalid operator: ${op}`);
809
809
  }
810
810
  };
811
- module2.exports = cmp;
811
+ module2.exports = cmp2;
812
812
  }
813
813
  });
814
814
 
@@ -818,7 +818,7 @@ var require_coerce = __commonJS({
818
818
  var SemVer = require_semver();
819
819
  var parse3 = require_parse();
820
820
  var { safeRe: re, t } = require_re();
821
- var coerce4 = (version2, options) => {
821
+ var coerce3 = (version2, options) => {
822
822
  if (version2 instanceof SemVer) {
823
823
  return version2;
824
824
  }
@@ -853,7 +853,7 @@ var require_coerce = __commonJS({
853
853
  const build = options.includePrerelease && match[6] ? `+${match[6]}` : "";
854
854
  return parse3(`${major}.${minor}.${patch}${prerelease}${build}`, options);
855
855
  };
856
- module2.exports = coerce4;
856
+ module2.exports = coerce3;
857
857
  }
858
858
  });
859
859
 
@@ -1330,7 +1330,7 @@ var require_comparator = __commonJS({
1330
1330
  return false;
1331
1331
  }
1332
1332
  }
1333
- return cmp(version2, this.operator, this.semver, this.options);
1333
+ return cmp2(version2, this.operator, this.semver, this.options);
1334
1334
  }
1335
1335
  intersects(comp, options) {
1336
1336
  if (!(comp instanceof _Comparator)) {
@@ -1363,10 +1363,10 @@ var require_comparator = __commonJS({
1363
1363
  if (this.semver.version === comp.semver.version && this.operator.includes("=") && comp.operator.includes("=")) {
1364
1364
  return true;
1365
1365
  }
1366
- if (cmp(this.semver, "<", comp.semver, options) && this.operator.startsWith(">") && comp.operator.startsWith("<")) {
1366
+ if (cmp2(this.semver, "<", comp.semver, options) && this.operator.startsWith(">") && comp.operator.startsWith("<")) {
1367
1367
  return true;
1368
1368
  }
1369
- if (cmp(this.semver, ">", comp.semver, options) && this.operator.startsWith("<") && comp.operator.startsWith(">")) {
1369
+ if (cmp2(this.semver, ">", comp.semver, options) && this.operator.startsWith("<") && comp.operator.startsWith(">")) {
1370
1370
  return true;
1371
1371
  }
1372
1372
  return false;
@@ -1375,7 +1375,7 @@ var require_comparator = __commonJS({
1375
1375
  module2.exports = Comparator;
1376
1376
  var parseOptions = require_parse_options();
1377
1377
  var { safeRe: re, t } = require_re();
1378
- var cmp = require_cmp();
1378
+ var cmp2 = require_cmp();
1379
1379
  var debug = require_debug();
1380
1380
  var SemVer = require_semver();
1381
1381
  var Range2 = require_range();
@@ -1853,7 +1853,7 @@ var require_semver2 = __commonJS({
1853
1853
  var SemVer = require_semver();
1854
1854
  var identifiers = require_identifiers();
1855
1855
  var parse3 = require_parse();
1856
- var valid4 = require_valid();
1856
+ var valid3 = require_valid();
1857
1857
  var clean = require_clean();
1858
1858
  var inc = require_inc();
1859
1859
  var diff = require_diff();
@@ -1873,8 +1873,8 @@ var require_semver2 = __commonJS({
1873
1873
  var neq = require_neq();
1874
1874
  var gte2 = require_gte();
1875
1875
  var lte = require_lte();
1876
- var cmp = require_cmp();
1877
- var coerce4 = require_coerce();
1876
+ var cmp2 = require_cmp();
1877
+ var coerce3 = require_coerce();
1878
1878
  var Comparator = require_comparator();
1879
1879
  var Range2 = require_range();
1880
1880
  var satisfies3 = require_satisfies();
@@ -1891,7 +1891,7 @@ var require_semver2 = __commonJS({
1891
1891
  var subset = require_subset();
1892
1892
  module2.exports = {
1893
1893
  parse: parse3,
1894
- valid: valid4,
1894
+ valid: valid3,
1895
1895
  clean,
1896
1896
  inc,
1897
1897
  diff,
@@ -1911,8 +1911,8 @@ var require_semver2 = __commonJS({
1911
1911
  neq,
1912
1912
  gte: gte2,
1913
1913
  lte,
1914
- cmp,
1915
- coerce: coerce4,
1914
+ cmp: cmp2,
1915
+ coerce: coerce3,
1916
1916
  Comparator,
1917
1917
  Range: Range2,
1918
1918
  satisfies: satisfies3,
@@ -3411,7 +3411,7 @@ var require_stream_writable = __commonJS({
3411
3411
  pna.nextTick(cb, er);
3412
3412
  }
3413
3413
  function validChunk(stream, state, chunk, cb) {
3414
- var valid4 = true;
3414
+ var valid3 = true;
3415
3415
  var er = false;
3416
3416
  if (chunk === null) {
3417
3417
  er = new TypeError("May not write null values to stream");
@@ -3421,9 +3421,9 @@ var require_stream_writable = __commonJS({
3421
3421
  if (er) {
3422
3422
  stream.emit("error", er);
3423
3423
  pna.nextTick(cb, er);
3424
- valid4 = false;
3424
+ valid3 = false;
3425
3425
  }
3426
- return valid4;
3426
+ return valid3;
3427
3427
  }
3428
3428
  Writable.prototype.write = function(chunk, encoding, cb) {
3429
3429
  var state = this._writableState;
@@ -13136,6 +13136,12 @@ function maxSeverity(severities) {
13136
13136
  }
13137
13137
  return best;
13138
13138
  }
13139
+ function escalatedSeverity(own, corroborations) {
13140
+ if (corroborations.length === 0) return own;
13141
+ return maxSeverity([own, ...corroborations.map(function grade(c) {
13142
+ return c.severity;
13143
+ })]);
13144
+ }
13139
13145
  var SOURCE_UNAVAILABLE_REASON_CODES = [
13140
13146
  "osv_db_not_seeded",
13141
13147
  "osv_db_unavailable",
@@ -13148,7 +13154,7 @@ function isSourceUnavailableReason(code) {
13148
13154
 
13149
13155
  // ../../packages/core/src/advisory-rows.ts
13150
13156
  var OSV_NORMALIZER_VERSION = 4;
13151
- var GEMNASIUM_NORMALIZER_VERSION = 4;
13157
+ var GEMNASIUM_NORMALIZER_VERSION = 5;
13152
13158
 
13153
13159
  // ../../packages/core/src/advisory-export.ts
13154
13160
  var DEFAULT_EXPORT_PROMPT = `You are helping a development team triage and fix the vulnerabilities listed at the bottom of this document. Treat this as a remediation work list, not a checklist to rubber-stamp. Work in a planning posture from the start: if your tooling has a read-only planning mode (Claude Code's plan mode, for example), enter it now and stay in it until the human has approved the triage below. Nothing in this document authorises you to edit a file before then.
@@ -13365,7 +13371,10 @@ var ECOSYSTEMS = [
13365
13371
  {
13366
13372
  id: "npm",
13367
13373
  language: "javascript",
13368
- displayName: "JavaScript",
13374
+ // The registry ecosystem is npm and the toolchain is Node — 'JavaScript' overclaimed, naming a
13375
+ // language rather than the package ecosystem actually scanned.
13376
+ displayName: "Node.js",
13377
+ status: "stable",
13369
13378
  osvEcosystem: "npm",
13370
13379
  gemnasiumPackageType: "npm",
13371
13380
  resolverKinds: ["package-lock.json", "pnpm-lock.yaml", "yarn.lock"],
@@ -13375,6 +13384,7 @@ var ECOSYSTEMS = [
13375
13384
  id: "PyPI",
13376
13385
  language: "python",
13377
13386
  displayName: "Python",
13387
+ status: "preview",
13378
13388
  osvEcosystem: "PyPI",
13379
13389
  gemnasiumPackageType: "pypi",
13380
13390
  resolverKinds: ["poetry.lock", "Pipfile.lock", "requirements.txt", "uv.lock"],
@@ -13384,6 +13394,7 @@ var ECOSYSTEMS = [
13384
13394
  id: "Go",
13385
13395
  language: "go",
13386
13396
  displayName: "Go",
13397
+ status: "preview",
13387
13398
  osvEcosystem: "Go",
13388
13399
  gemnasiumPackageType: "go",
13389
13400
  resolverKinds: ["go.mod", "go.sum"],
@@ -13393,6 +13404,7 @@ var ECOSYSTEMS = [
13393
13404
  id: "crates.io",
13394
13405
  language: "rust",
13395
13406
  displayName: "Rust",
13407
+ status: "preview",
13396
13408
  osvEcosystem: "crates.io",
13397
13409
  gemnasiumPackageType: "cargo",
13398
13410
  resolverKinds: ["Cargo.lock"],
@@ -13400,6 +13412,9 @@ var ECOSYSTEMS = [
13400
13412
  }
13401
13413
  ];
13402
13414
  var DEFAULT_ECOSYSTEM = "npm";
13415
+ var STABLE_ECOSYSTEMS = ECOSYSTEMS.filter(function stable(eco) {
13416
+ return eco.status === "stable";
13417
+ });
13403
13418
  function getEcosystem(id) {
13404
13419
  for (const eco of ECOSYSTEMS) {
13405
13420
  if (eco.id === id) return eco;
@@ -13409,7 +13424,241 @@ function getEcosystem(id) {
13409
13424
  var GEMNASIUM_SEED_DOWNLOAD_BYTES = 52 * 1024 * 1024;
13410
13425
 
13411
13426
  // ../../packages/scanners/src/lockfile-cross-check.ts
13427
+ var import_semver5 = __toESM(require_semver2());
13428
+
13429
+ // ../../packages/versions/src/range.ts
13430
+ function isZeroVersion(version2) {
13431
+ return /^0(\.0)*$/.test(version2.trim());
13432
+ }
13433
+ function formatRange(range, options) {
13434
+ const lo = range.introduced === "0" ? options.zero : range.introduced;
13435
+ const lower = (range.introducedExclusive === true ? ">" : ">=") + lo;
13436
+ if (range.fixed !== null && range.fixed !== void 0) return lower + " <" + range.fixed;
13437
+ const lastAffected = range.lastAffected;
13438
+ if (lastAffected !== null && lastAffected !== void 0) return lower + " <=" + lastAffected;
13439
+ return lower;
13440
+ }
13441
+ function formatRanges(ranges, options) {
13442
+ return ranges.map(function one(range) {
13443
+ return formatRange(range, options);
13444
+ }).join(" || ");
13445
+ }
13446
+
13447
+ // ../../packages/versions/src/match.ts
13448
+ function versionInRange(version2, range, comparator) {
13449
+ const installed = comparator.normalize(version2);
13450
+ if (installed === null) return false;
13451
+ if (!aboveLowerBound(installed, range, comparator)) return false;
13452
+ if (range.fixed !== null && range.fixed !== void 0) {
13453
+ const fixed = comparator.normalize(range.fixed);
13454
+ return fixed !== null && comparator.lt(installed, fixed);
13455
+ }
13456
+ const lastAffectedRaw = range.lastAffected;
13457
+ if (lastAffectedRaw !== null && lastAffectedRaw !== void 0) {
13458
+ const lastAffected = comparator.normalize(lastAffectedRaw);
13459
+ return lastAffected !== null && comparator.lte(installed, lastAffected);
13460
+ }
13461
+ return true;
13462
+ }
13463
+ function aboveLowerBound(installed, range, comparator) {
13464
+ if (range.introducedExclusive !== true && isZeroVersion(range.introduced)) return true;
13465
+ const introduced = comparator.normalize(range.introduced);
13466
+ if (introduced === null) return false;
13467
+ return range.introducedExclusive === true ? comparator.gt(installed, introduced) : comparator.gte(installed, introduced);
13468
+ }
13469
+
13470
+ // ../../packages/versions/src/compare.ts
13471
+ __toESM(require_semver2());
13472
+
13473
+ // ../../packages/versions/src/comparators/semver.ts
13412
13474
  var import_semver = __toESM(require_semver2());
13475
+ var MEANING_CHANGING_RANGE_SYNTAX = /[<>^~|*]|\s-\s|(^|\.)[xX](\.|$)/;
13476
+ function normalizeSemver(raw) {
13477
+ const strict = (0, import_semver.valid)(raw);
13478
+ if (strict !== null) return strict;
13479
+ if (MEANING_CHANGING_RANGE_SYNTAX.test(raw)) return null;
13480
+ const coerced = (0, import_semver.coerce)(raw);
13481
+ return coerced === null ? null : coerced.version;
13482
+ }
13483
+ var semverComparator = {
13484
+ normalize(raw) {
13485
+ return normalizeSemver(raw);
13486
+ },
13487
+ gt(a, b) {
13488
+ return (0, import_semver.gt)(a, b);
13489
+ },
13490
+ gte(a, b) {
13491
+ return (0, import_semver.gte)(a, b);
13492
+ },
13493
+ lt(a, b) {
13494
+ return (0, import_semver.lt)(a, b);
13495
+ },
13496
+ lte(a, b) {
13497
+ return (0, import_semver.lte)(a, b);
13498
+ }
13499
+ };
13500
+
13501
+ // ../../packages/versions/src/comparators/pep440.ts
13502
+ var PRE_RANK = { a: 0, b: 1, rc: 2 };
13503
+ var PEP440_RE = new RegExp(
13504
+ "^\\s*v?(?:(?<epoch>[0-9]+)!)?(?<release>[0-9]+(?:\\.[0-9]+)*)(?:[-_.]?(?<preL>a|b|c|rc|alpha|beta|pre|preview)[-_.]?(?<preN>[0-9]+)?)?(?:(?:-(?<postN1>[0-9]+))|(?:[-_.]?(?<postL>post|rev|r)[-_.]?(?<postN2>[0-9]+)?))?(?:[-_.]?(?<devL>dev)[-_.]?(?<devN>[0-9]+)?)?(?:\\+(?<local>[a-z0-9]+(?:[-_.][a-z0-9]+)*))?\\s*$",
13505
+ "i"
13506
+ );
13507
+ function foldPreLetter(raw) {
13508
+ const l = raw.toLowerCase();
13509
+ if (l === "alpha") return "a";
13510
+ if (l === "beta") return "b";
13511
+ if (l === "c" || l === "pre" || l === "preview" || l === "rc") return "rc";
13512
+ return l;
13513
+ }
13514
+ function parsePep440(raw) {
13515
+ const m = PEP440_RE.exec(raw.trim());
13516
+ if (!m || !m.groups) return null;
13517
+ const g = m.groups;
13518
+ if (!g.release) return null;
13519
+ const release = g.release.split(".").map(function toInt(s) {
13520
+ return parseInt(s, 10);
13521
+ });
13522
+ if (release.some(function bad(n) {
13523
+ return Number.isNaN(n);
13524
+ })) return null;
13525
+ let pre = null;
13526
+ if (g.preL) {
13527
+ pre = { letter: foldPreLetter(g.preL), n: g.preN ? parseInt(g.preN, 10) : 0 };
13528
+ }
13529
+ let post = null;
13530
+ if (g.postN1 !== void 0) {
13531
+ post = parseInt(g.postN1, 10);
13532
+ } else if (g.postL) {
13533
+ post = g.postN2 ? parseInt(g.postN2, 10) : 0;
13534
+ }
13535
+ const dev = g.devL ? g.devN ? parseInt(g.devN, 10) : 0 : null;
13536
+ let local = null;
13537
+ if (g.local) {
13538
+ local = g.local.toLowerCase().split(/[-_.]/).map(function part(seg) {
13539
+ return /^[0-9]+$/.test(seg) ? parseInt(seg, 10) : seg;
13540
+ });
13541
+ }
13542
+ return { epoch: g.epoch ? parseInt(g.epoch, 10) : 0, release, pre, post, dev, local };
13543
+ }
13544
+ function stripTrailingZeros(release) {
13545
+ let end = release.length;
13546
+ while (end > 1 && release[end - 1] === 0) end--;
13547
+ return release.slice(0, end);
13548
+ }
13549
+ function canonicalPep440(v) {
13550
+ const parts = [];
13551
+ if (v.epoch > 0) parts.push(v.epoch.toString() + "!");
13552
+ parts.push(stripTrailingZeros(v.release).join("."));
13553
+ if (v.pre) parts.push(v.pre.letter + v.pre.n.toString());
13554
+ if (v.post !== null) parts.push(".post" + v.post.toString());
13555
+ if (v.dev !== null) parts.push(".dev" + v.dev.toString());
13556
+ if (v.local) parts.push("+" + v.local.join("."));
13557
+ return parts.join("");
13558
+ }
13559
+ function cmpRelease(a, b) {
13560
+ const ra = stripTrailingZeros(a);
13561
+ const rb = stripTrailingZeros(b);
13562
+ const len = Math.max(ra.length, rb.length);
13563
+ for (let i = 0; i < len; i++) {
13564
+ const x = ra[i] ?? 0;
13565
+ const y = rb[i] ?? 0;
13566
+ if (x !== y) return x < y ? -1 : 1;
13567
+ }
13568
+ return 0;
13569
+ }
13570
+ function preKind(v) {
13571
+ if (v.pre !== null) return 0;
13572
+ if (v.post === null && v.dev !== null) return -1;
13573
+ return 1;
13574
+ }
13575
+ function cmpPre(a, b) {
13576
+ const ka = preKind(a);
13577
+ const kb = preKind(b);
13578
+ if (ka !== kb) return ka < kb ? -1 : 1;
13579
+ if (ka !== 0 || !a.pre || !b.pre) return 0;
13580
+ const la = PRE_RANK[a.pre.letter] ?? 0;
13581
+ const lb = PRE_RANK[b.pre.letter] ?? 0;
13582
+ if (la !== lb) return la < lb ? -1 : 1;
13583
+ if (a.pre.n !== b.pre.n) return a.pre.n < b.pre.n ? -1 : 1;
13584
+ return 0;
13585
+ }
13586
+ function cmpPost(a, b) {
13587
+ if (a === null && b === null) return 0;
13588
+ if (a === null) return -1;
13589
+ if (b === null) return 1;
13590
+ return a < b ? -1 : a > b ? 1 : 0;
13591
+ }
13592
+ function cmpDev(a, b) {
13593
+ if (a === null && b === null) return 0;
13594
+ if (a === null) return 1;
13595
+ if (b === null) return -1;
13596
+ return a < b ? -1 : a > b ? 1 : 0;
13597
+ }
13598
+ function cmpLocal(a, b) {
13599
+ if (a === null && b === null) return 0;
13600
+ if (a === null) return -1;
13601
+ if (b === null) return 1;
13602
+ const len = Math.max(a.length, b.length);
13603
+ for (let i = 0; i < len; i++) {
13604
+ if (i >= a.length) return -1;
13605
+ if (i >= b.length) return 1;
13606
+ const x = a[i];
13607
+ const y = b[i];
13608
+ const xNum = typeof x === "number";
13609
+ const yNum = typeof y === "number";
13610
+ if (xNum && yNum) {
13611
+ if (x !== y) return x < y ? -1 : 1;
13612
+ } else if (xNum !== yNum) {
13613
+ return xNum ? 1 : -1;
13614
+ } else if (x !== y) {
13615
+ return x < y ? -1 : 1;
13616
+ }
13617
+ }
13618
+ return 0;
13619
+ }
13620
+ function comparePep440(a, b) {
13621
+ if (a.epoch !== b.epoch) return a.epoch < b.epoch ? -1 : 1;
13622
+ const r = cmpRelease(a.release, b.release);
13623
+ if (r !== 0) return r;
13624
+ const p = cmpPre(a, b);
13625
+ if (p !== 0) return p;
13626
+ const po = cmpPost(a.post, b.post);
13627
+ if (po !== 0) return po;
13628
+ const d = cmpDev(a.dev, b.dev);
13629
+ if (d !== 0) return d;
13630
+ return cmpLocal(a.local, b.local);
13631
+ }
13632
+ function cmp(a, b) {
13633
+ const pa = parsePep440(a);
13634
+ const pb = parsePep440(b);
13635
+ if (!pa || !pb) return null;
13636
+ return comparePep440(pa, pb);
13637
+ }
13638
+ var pep440Comparator = {
13639
+ normalize(raw) {
13640
+ const parsed = parsePep440(raw);
13641
+ return parsed === null ? null : canonicalPep440(parsed);
13642
+ },
13643
+ gt(a, b) {
13644
+ const r = cmp(a, b);
13645
+ return r !== null && r > 0;
13646
+ },
13647
+ gte(a, b) {
13648
+ const r = cmp(a, b);
13649
+ return r !== null && r >= 0;
13650
+ },
13651
+ lt(a, b) {
13652
+ const r = cmp(a, b);
13653
+ return r !== null && r < 0;
13654
+ },
13655
+ lte(a, b) {
13656
+ const r = cmp(a, b);
13657
+ return r !== null && r <= 0;
13658
+ }
13659
+ };
13660
+
13661
+ // ../../packages/scanners/src/lockfile-cross-check.ts
13413
13662
  function filterFindingsByLockfileResolution(findings) {
13414
13663
  const kept = [];
13415
13664
  const droppedAdvisoryIds = [];
@@ -13426,7 +13675,7 @@ function shouldKeep(finding) {
13426
13675
  const installed = finding.installedVersion.trim();
13427
13676
  const range = finding.vulnerableRange.trim();
13428
13677
  if (!installed || !range) return true;
13429
- if ((0, import_semver.validRange)(range) === null) return true;
13678
+ if ((0, import_semver5.validRange)(range) === null) return true;
13430
13679
  const candidates = installed.split(/,\s*/).map(function trim(s) {
13431
13680
  return s.trim();
13432
13681
  }).filter(Boolean);
@@ -13434,19 +13683,11 @@ function shouldKeep(finding) {
13434
13683
  for (const candidate of candidates) {
13435
13684
  const cleaned = normalizeVersion(candidate);
13436
13685
  if (cleaned === null) return true;
13437
- if ((0, import_semver.satisfies)(cleaned, range, { includePrerelease: true })) return true;
13686
+ if ((0, import_semver5.satisfies)(cleaned, range, { includePrerelease: true })) return true;
13438
13687
  }
13439
13688
  return false;
13440
13689
  }
13441
- var RANGE_SYNTAX = /[<>=^~|*]|\s-\s|(^|\.)[xX](\.|$)/;
13442
- function normalizeVersion(raw) {
13443
- const strict = (0, import_semver.valid)(raw);
13444
- if (strict !== null) return strict;
13445
- if (RANGE_SYNTAX.test(raw)) return null;
13446
- const coerced = (0, import_semver.coerce)(raw);
13447
- if (coerced === null) return null;
13448
- return coerced.version;
13449
- }
13690
+ var normalizeVersion = normalizeSemver;
13450
13691
 
13451
13692
  // ../../node_modules/.pnpm/zod@4.4.1/node_modules/zod/v4/classic/external.js
13452
13693
  var external_exports = {};
@@ -27931,7 +28172,7 @@ function date4(params) {
27931
28172
  config(en_default());
27932
28173
 
27933
28174
  // ../../packages/scanners/src/version-fix.ts
27934
- var import_semver2 = __toESM(require_semver2());
28175
+ var import_semver6 = __toESM(require_semver2());
27935
28176
  var VERSION_LITERAL_RE = /\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?/g;
27936
28177
  function parseRangeSafely(input) {
27937
28178
  if (!input) return null;
@@ -27939,7 +28180,7 @@ function parseRangeSafely(input) {
27939
28180
  if (!trimmed) return null;
27940
28181
  if (trimmed === "<0.0.0") return null;
27941
28182
  try {
27942
- return new import_semver2.Range(trimmed, { includePrerelease: false });
28183
+ return new import_semver6.Range(trimmed, { includePrerelease: false });
27943
28184
  } catch {
27944
28185
  return null;
27945
28186
  }
@@ -27950,12 +28191,12 @@ function extractLiteralCandidates(input) {
27950
28191
  if (!matches) return [];
27951
28192
  const out = [];
27952
28193
  for (const m of matches) {
27953
- if ((0, import_semver2.valid)(m)) out.push(m);
28194
+ if ((0, import_semver6.valid)(m)) out.push(m);
27954
28195
  }
27955
28196
  return out;
27956
28197
  }
27957
28198
  function bumpPatch(v) {
27958
- const sv = (0, import_semver2.coerce)(v);
28199
+ const sv = (0, import_semver6.coerce)(v);
27959
28200
  if (!sv) return null;
27960
28201
  return sv.major + "." + sv.minor + "." + (sv.patch + 1);
27961
28202
  }
@@ -27966,13 +28207,13 @@ function extractRangeLowerBounds(range) {
27966
28207
  for (const c of conjuncts) {
27967
28208
  if (!c.semver || !c.semver.version) continue;
27968
28209
  const v = c.semver.version;
27969
- if (!(0, import_semver2.valid)(v)) continue;
28210
+ if (!(0, import_semver6.valid)(v)) continue;
27970
28211
  const op = c.operator;
27971
28212
  if (op === ">=" || op === "=" || op === "") {
27972
- if (!candidate || (0, import_semver2.gt)(v, candidate)) candidate = v;
28213
+ if (!candidate || (0, import_semver6.gt)(v, candidate)) candidate = v;
27973
28214
  } else if (op === ">") {
27974
28215
  const inc = bumpPatch(v);
27975
- if (inc && (!candidate || (0, import_semver2.gt)(inc, candidate))) candidate = inc;
28216
+ if (inc && (!candidate || (0, import_semver6.gt)(inc, candidate))) candidate = inc;
27976
28217
  }
27977
28218
  }
27978
28219
  if (candidate) out.push(candidate);
@@ -27985,7 +28226,7 @@ function extractRangeUpperBoundsBeyond(range) {
27985
28226
  for (const c of conjuncts) {
27986
28227
  if (!c.semver || !c.semver.version) continue;
27987
28228
  const v = c.semver.version;
27988
- if (!(0, import_semver2.valid)(v)) continue;
28229
+ if (!(0, import_semver6.valid)(v)) continue;
27989
28230
  const op = c.operator;
27990
28231
  if (op === "<") {
27991
28232
  out.push(v);
@@ -28004,8 +28245,8 @@ function pickHighestInstalled(installed) {
28004
28245
  for (const raw of parts) {
28005
28246
  const part = raw.trim();
28006
28247
  if (!part) continue;
28007
- if (!(0, import_semver2.valid)(part)) continue;
28008
- if (!highest || (0, import_semver2.gt)(part, highest)) highest = part;
28248
+ if (!(0, import_semver6.valid)(part)) continue;
28249
+ if (!highest || (0, import_semver6.gt)(part, highest)) highest = part;
28009
28250
  }
28010
28251
  return highest;
28011
28252
  }
@@ -28027,17 +28268,17 @@ function pickSafeFixVersion(args) {
28027
28268
  if (candidates.size === 0) return null;
28028
28269
  let best = null;
28029
28270
  for (const v of candidates) {
28030
- if (patchedRange && !(0, import_semver2.satisfies)(v, patchedRange)) continue;
28031
- if (vulnRange && (0, import_semver2.satisfies)(v, vulnRange)) continue;
28032
- if (installedFloor && !(0, import_semver2.gte)(v, installedFloor)) continue;
28033
- if (!best || (0, import_semver2.gt)(best, v)) best = v;
28271
+ if (patchedRange && !(0, import_semver6.satisfies)(v, patchedRange)) continue;
28272
+ if (vulnRange && (0, import_semver6.satisfies)(v, vulnRange)) continue;
28273
+ if (installedFloor && !(0, import_semver6.gte)(v, installedFloor)) continue;
28274
+ if (!best || (0, import_semver6.gt)(best, v)) best = v;
28034
28275
  }
28035
28276
  return best;
28036
28277
  }
28037
28278
 
28038
28279
  // ../../packages/scanners/src/npm-audit-parse.ts
28039
28280
  var SEVERITY_VALUES = ["critical", "high", "moderate", "low", "info"];
28040
- var severitySchema = external_exports.enum(SEVERITY_VALUES);
28281
+ var severitySchema = external_exports.enum(SEVERITY_VALUES).catch("moderate");
28041
28282
  var viaObjectSchema = external_exports.object({
28042
28283
  source: external_exports.number().int().optional(),
28043
28284
  name: external_exports.string().optional(),
@@ -28214,10 +28455,17 @@ function pickAdvisoryId(via) {
28214
28455
  if (via.source == null && !via.url && !via.title) return null;
28215
28456
  return fallbackAdvisoryHash(via);
28216
28457
  }
28458
+ function pickAdvisoryAliases(advisoryId, url2, githubAdvisoryId) {
28459
+ const explicit = typeof githubAdvisoryId === "string" && githubAdvisoryId.length > 0 && githubAdvisoryId;
28460
+ const ghsa = explicit || pickGhsaIdFromUrl(url2);
28461
+ if (!ghsa) return [];
28462
+ if (ghsa.toLowerCase() === advisoryId.toLowerCase()) return [];
28463
+ return [ghsa];
28464
+ }
28217
28465
  function pickSeverity(via, vuln) {
28218
28466
  if (via.severity) return via.severity;
28219
28467
  if (vuln.severity) return vuln.severity;
28220
- return "info";
28468
+ return "moderate";
28221
28469
  }
28222
28470
  function pickFixAvailability(fix) {
28223
28471
  if (fix === void 0) return { fixAvailable: false, fixVersion: null };
@@ -28275,6 +28523,7 @@ function normalizeOneVulnerability(vuln, packageName, installedVersions, classif
28275
28523
  const cls = classifier.classify(packageName, installedVersion);
28276
28524
  const finding = {
28277
28525
  advisoryId,
28526
+ aliases: pickAdvisoryAliases(advisoryId, via.url),
28278
28527
  advisoryTitle: via.title || null,
28279
28528
  advisoryUrl: via.url || null,
28280
28529
  packageName,
@@ -28331,12 +28580,13 @@ function normalizePnpmAuditOutput(parsed, classifier) {
28331
28580
  const adv = advisories[idKey];
28332
28581
  if (!adv) continue;
28333
28582
  const advisoryId = pickPnpmAdvisoryId(adv, idKey);
28334
- const severity = adv.severity || "info";
28583
+ const severity = adv.severity || "moderate";
28335
28584
  const patched = adv.patched_versions || null;
28336
28585
  const recommendation = adv.recommendation || null;
28337
28586
  const vulnRange = adv.vulnerable_versions || "";
28338
28587
  const advisoryTitle = adv.title || null;
28339
28588
  const advisoryUrl = adv.url || null;
28589
+ const aliases = pickAdvisoryAliases(advisoryId, adv.url ?? void 0, adv.github_advisory_id);
28340
28590
  const packageName = adv.module_name;
28341
28591
  const findings = adv.findings || [];
28342
28592
  if (findings.length === 0) {
@@ -28344,6 +28594,7 @@ function normalizePnpmAuditOutput(parsed, classifier) {
28344
28594
  const cls = classifier.classify(packageName, null);
28345
28595
  out.push({
28346
28596
  advisoryId,
28597
+ aliases,
28347
28598
  advisoryTitle,
28348
28599
  advisoryUrl,
28349
28600
  packageName,
@@ -28367,6 +28618,7 @@ function normalizePnpmAuditOutput(parsed, classifier) {
28367
28618
  const cls = classifier.classify(packageName, f.version || null);
28368
28619
  out.push({
28369
28620
  advisoryId,
28621
+ aliases,
28370
28622
  advisoryTitle,
28371
28623
  advisoryUrl,
28372
28624
  packageName,
@@ -28386,6 +28638,7 @@ function normalizePnpmAuditOutput(parsed, classifier) {
28386
28638
  const cls = classifier.classify(packageName, f.version || null);
28387
28639
  out.push({
28388
28640
  advisoryId,
28641
+ aliases,
28389
28642
  advisoryTitle,
28390
28643
  advisoryUrl,
28391
28644
  packageName,
@@ -28969,15 +29222,11 @@ async function parseNpmLock(projectPath, absolutePath) {
28969
29222
  if (!entry || !entry.version) continue;
28970
29223
  const name = entry.name || nameFromNodePath(nodePath);
28971
29224
  if (!name) continue;
28972
- let isDev = entry.dev === true || entry.devOptional === true;
28973
- let isProd = !isDev;
28974
- if (direct.prod.has(name)) {
28975
- isProd = true;
28976
- }
28977
- if (direct.dev.has(name) && !direct.prod.has(name)) {
28978
- isDev = true;
28979
- isProd = false;
28980
- }
29225
+ const lockSaysDevOnly = entry.dev === true || entry.devOptional === true;
29226
+ let isProd = !lockSaysDevOnly;
29227
+ let isDev = lockSaysDevOnly;
29228
+ if (direct.prod.has(name)) isProd = true;
29229
+ if (direct.dev.has(name)) isDev = true;
28981
29230
  out.push({
28982
29231
  ecosystem: NPM_ECOSYSTEM,
28983
29232
  name,
@@ -32435,7 +32684,7 @@ function stripComment3(line) {
32435
32684
  // ../../packages/scanners/src/resolver/index.ts
32436
32685
  async function detectManifests(projectPath) {
32437
32686
  const out = [];
32438
- for (const eco of ECOSYSTEMS) {
32687
+ for (const eco of STABLE_ECOSYSTEMS) {
32439
32688
  for (const kind of eco.resolverKinds) {
32440
32689
  const absolutePath = path.join(projectPath, kind);
32441
32690
  if (await fileExists2(absolutePath)) {
@@ -32613,7 +32862,7 @@ function detectProject(rootPath, dir) {
32613
32862
  }
32614
32863
  function detectEcosystems(dir) {
32615
32864
  const out = [];
32616
- for (const eco of ECOSYSTEMS) {
32865
+ for (const eco of STABLE_ECOSYSTEMS) {
32617
32866
  if (eco.id === "npm") {
32618
32867
  if (existsFile(path.join(dir, "package.json"))) out.push(eco.id);
32619
32868
  continue;
@@ -32699,162 +32948,6 @@ function isFile(path) {
32699
32948
  }
32700
32949
  }
32701
32950
 
32702
- // ../../packages/scanners/src/engine/comparators/pep440.ts
32703
- var PRE_RANK = { a: 0, b: 1, rc: 2 };
32704
- var PEP440_RE = new RegExp(
32705
- "^\\s*v?(?:(?<epoch>[0-9]+)!)?(?<release>[0-9]+(?:\\.[0-9]+)*)(?:[-_.]?(?<preL>a|b|c|rc|alpha|beta|pre|preview)[-_.]?(?<preN>[0-9]+)?)?(?:(?:-(?<postN1>[0-9]+))|(?:[-_.]?(?<postL>post|rev|r)[-_.]?(?<postN2>[0-9]+)?))?(?:[-_.]?(?<devL>dev)[-_.]?(?<devN>[0-9]+)?)?(?:\\+(?<local>[a-z0-9]+(?:[-_.][a-z0-9]+)*))?\\s*$",
32706
- "i"
32707
- );
32708
- function foldPreLetter(raw) {
32709
- const l = raw.toLowerCase();
32710
- if (l === "alpha") return "a";
32711
- if (l === "beta") return "b";
32712
- if (l === "c" || l === "pre" || l === "preview" || l === "rc") return "rc";
32713
- return l;
32714
- }
32715
- function parsePep440(raw) {
32716
- const m = PEP440_RE.exec(raw.trim());
32717
- if (!m || !m.groups) return null;
32718
- const g = m.groups;
32719
- if (!g.release) return null;
32720
- const release = g.release.split(".").map(function toInt(s) {
32721
- return parseInt(s, 10);
32722
- });
32723
- if (release.some(function bad(n) {
32724
- return Number.isNaN(n);
32725
- })) return null;
32726
- let pre = null;
32727
- if (g.preL) {
32728
- pre = { letter: foldPreLetter(g.preL), n: g.preN ? parseInt(g.preN, 10) : 0 };
32729
- }
32730
- let post = null;
32731
- if (g.postN1 !== void 0) {
32732
- post = parseInt(g.postN1, 10);
32733
- } else if (g.postL) {
32734
- post = g.postN2 ? parseInt(g.postN2, 10) : 0;
32735
- }
32736
- const dev = g.devL ? g.devN ? parseInt(g.devN, 10) : 0 : null;
32737
- let local = null;
32738
- if (g.local) {
32739
- local = g.local.toLowerCase().split(/[-_.]/).map(function part(seg) {
32740
- return /^[0-9]+$/.test(seg) ? parseInt(seg, 10) : seg;
32741
- });
32742
- }
32743
- return { epoch: g.epoch ? parseInt(g.epoch, 10) : 0, release, pre, post, dev, local };
32744
- }
32745
- function stripTrailingZeros(release) {
32746
- let end = release.length;
32747
- while (end > 1 && release[end - 1] === 0) end--;
32748
- return release.slice(0, end);
32749
- }
32750
- function cmpRelease(a, b) {
32751
- const ra = stripTrailingZeros(a);
32752
- const rb = stripTrailingZeros(b);
32753
- const len = Math.max(ra.length, rb.length);
32754
- for (let i = 0; i < len; i++) {
32755
- const x = ra[i] ?? 0;
32756
- const y = rb[i] ?? 0;
32757
- if (x !== y) return x < y ? -1 : 1;
32758
- }
32759
- return 0;
32760
- }
32761
- function preKind(v) {
32762
- if (v.pre !== null) return 0;
32763
- if (v.post === null && v.dev !== null) return -1;
32764
- return 1;
32765
- }
32766
- function cmpPre(a, b) {
32767
- const ka = preKind(a);
32768
- const kb = preKind(b);
32769
- if (ka !== kb) return ka < kb ? -1 : 1;
32770
- if (ka !== 0 || !a.pre || !b.pre) return 0;
32771
- const la = PRE_RANK[a.pre.letter] ?? 0;
32772
- const lb = PRE_RANK[b.pre.letter] ?? 0;
32773
- if (la !== lb) return la < lb ? -1 : 1;
32774
- if (a.pre.n !== b.pre.n) return a.pre.n < b.pre.n ? -1 : 1;
32775
- return 0;
32776
- }
32777
- function cmpPost(a, b) {
32778
- if (a === null && b === null) return 0;
32779
- if (a === null) return -1;
32780
- if (b === null) return 1;
32781
- return a < b ? -1 : a > b ? 1 : 0;
32782
- }
32783
- function cmpDev(a, b) {
32784
- if (a === null && b === null) return 0;
32785
- if (a === null) return 1;
32786
- if (b === null) return -1;
32787
- return a < b ? -1 : a > b ? 1 : 0;
32788
- }
32789
- function cmpLocal(a, b) {
32790
- if (a === null && b === null) return 0;
32791
- if (a === null) return -1;
32792
- if (b === null) return 1;
32793
- const len = Math.max(a.length, b.length);
32794
- for (let i = 0; i < len; i++) {
32795
- if (i >= a.length) return -1;
32796
- if (i >= b.length) return 1;
32797
- const x = a[i];
32798
- const y = b[i];
32799
- const xNum = typeof x === "number";
32800
- const yNum = typeof y === "number";
32801
- if (xNum && yNum) {
32802
- if (x !== y) return x < y ? -1 : 1;
32803
- } else if (xNum !== yNum) {
32804
- return xNum ? 1 : -1;
32805
- } else if (x !== y) {
32806
- return x < y ? -1 : 1;
32807
- }
32808
- }
32809
- return 0;
32810
- }
32811
- function comparePep440(a, b) {
32812
- if (a.epoch !== b.epoch) return a.epoch < b.epoch ? -1 : 1;
32813
- const r = cmpRelease(a.release, b.release);
32814
- if (r !== 0) return r;
32815
- const p = cmpPre(a, b);
32816
- if (p !== 0) return p;
32817
- const po = cmpPost(a.post, b.post);
32818
- if (po !== 0) return po;
32819
- const d = cmpDev(a.dev, b.dev);
32820
- if (d !== 0) return d;
32821
- return cmpLocal(a.local, b.local);
32822
- }
32823
- var pep440Comparator = {
32824
- normalize(raw) {
32825
- return parsePep440(raw) === null ? null : raw.trim();
32826
- },
32827
- gte(a, b) {
32828
- const pa = parsePep440(a);
32829
- const pb = parsePep440(b);
32830
- if (!pa || !pb) return false;
32831
- return comparePep440(pa, pb) >= 0;
32832
- },
32833
- lt(a, b) {
32834
- const pa = parsePep440(a);
32835
- const pb = parsePep440(b);
32836
- if (!pa || !pb) return false;
32837
- return comparePep440(pa, pb) < 0;
32838
- }
32839
- };
32840
-
32841
- // ../../packages/scanners/src/engine/comparators/semver.ts
32842
- var import_semver3 = __toESM(require_semver2());
32843
- var semverComparator = {
32844
- normalize(raw) {
32845
- const strict = (0, import_semver3.valid)(raw);
32846
- if (strict !== null) return strict;
32847
- const coerced = (0, import_semver3.coerce)(raw);
32848
- return coerced === null ? null : coerced.version;
32849
- },
32850
- gte(a, b) {
32851
- return (0, import_semver3.gte)(a, b);
32852
- },
32853
- lt(a, b) {
32854
- return (0, import_semver3.lt)(a, b);
32855
- }
32856
- };
32857
-
32858
32951
  // ../../packages/scanners/src/engine/comparators/index.ts
32859
32952
  var COMPARATORS = {
32860
32953
  semver: semverComparator,
@@ -32876,6 +32969,8 @@ function acceptedRangeTypesForEcosystem(ecosystem) {
32876
32969
  }
32877
32970
 
32878
32971
  // ../../packages/scanners/src/engine/matcher.ts
32972
+ var DISPLAY_FORMAT = { zero: "0" };
32973
+ var SEMVER_FORMAT = { zero: "0.0.0" };
32879
32974
  function matchAdvisories(packages, byPackage, comparator, acceptedRangeTypes) {
32880
32975
  const findings = [];
32881
32976
  for (const pkg2 of packages) {
@@ -32900,6 +32995,7 @@ function applicableRanges(ranges, acceptedRangeTypes) {
32900
32995
  });
32901
32996
  }
32902
32997
  function matchOne(pkg2, advisory, comparator, acceptedRangeTypes) {
32998
+ if (advisory.withdrawn !== null) return null;
32903
32999
  const ranges = applicableRanges(advisory.affected.ranges, acceptedRangeTypes);
32904
33000
  const exactVersions = advisory.affected.exactVersions;
32905
33001
  const hasVersionData = ranges.length > 0 || exactVersions.length > 0;
@@ -32929,25 +33025,12 @@ function isAffected(installedRaw, ranges, exactVersions, comparator) {
32929
33025
  let affected = false;
32930
33026
  let firstFixed = null;
32931
33027
  for (const range of ranges) {
32932
- const introduced = range.introduced === "0" ? "0.0.0" : comparator.normalize(range.introduced);
32933
- if (introduced === null) continue;
32934
- if (!comparator.gte(installed, introduced)) continue;
33028
+ if (!versionInRange(installedRaw, range, comparator)) continue;
33029
+ affected = true;
32935
33030
  const fixed = range.fixed ? comparator.normalize(range.fixed) : null;
32936
- if (fixed !== null) {
32937
- if (comparator.lt(installed, fixed)) {
32938
- affected = true;
32939
- if (firstFixed === null || comparator.lt(fixed, firstFixed)) {
32940
- firstFixed = fixed;
32941
- }
32942
- }
32943
- continue;
32944
- }
32945
- const lastAffected = range.lastAffected ? comparator.normalize(range.lastAffected) : null;
32946
- if (lastAffected !== null) {
32947
- if (comparator.gte(lastAffected, installed)) affected = true;
32948
- continue;
33031
+ if (fixed !== null && (firstFixed === null || comparator.lt(fixed, firstFixed))) {
33032
+ firstFixed = fixed;
32949
33033
  }
32950
- affected = true;
32951
33034
  }
32952
33035
  return { affected, firstFixed };
32953
33036
  }
@@ -32973,29 +33056,11 @@ function buildFinding(pkg2, advisory, severity, fixVersion, vulnerableRange) {
32973
33056
  function rangesToDisplay(ranges, exactVersions) {
32974
33057
  const parts = [];
32975
33058
  for (const v of exactVersions) parts.push("=" + v);
32976
- for (const range of ranges) {
32977
- const lo = range.introduced === "0" ? "0" : range.introduced;
32978
- if (range.fixed) {
32979
- parts.push(">=" + lo + " <" + range.fixed);
32980
- } else if (range.lastAffected) {
32981
- parts.push(">=" + lo + " <=" + range.lastAffected);
32982
- } else {
32983
- parts.push(">=" + lo);
32984
- }
32985
- }
33059
+ for (const range of ranges) parts.push(formatRange(range, DISPLAY_FORMAT));
32986
33060
  return parts.length > 0 ? parts.join(" || ") : "*";
32987
33061
  }
32988
33062
  function vulnerableRangeForFix(ranges) {
32989
- const parts = [];
32990
- for (const range of ranges) {
32991
- const lo = range.introduced === "0" ? "0.0.0" : range.introduced;
32992
- if (range.fixed) {
32993
- parts.push(">=" + lo + " <" + range.fixed);
32994
- } else {
32995
- parts.push(">=" + lo);
32996
- }
32997
- }
32998
- return parts.join(" || ");
33063
+ return formatRanges(ranges, SEMVER_FORMAT);
32999
33064
  }
33000
33065
  function mapSeverity(severity) {
33001
33066
  if (!severity) return "moderate";
@@ -33071,7 +33136,7 @@ function toCanonicalAdvisory(packageName, ecosystem, advisory) {
33071
33136
  severity: advisory.severity,
33072
33137
  summary: advisory.summary,
33073
33138
  url: advisory.url,
33074
- withdrawn: null
33139
+ withdrawn: advisory.withdrawn
33075
33140
  };
33076
33141
  }
33077
33142
  function groupByEcosystem(packages) {
@@ -33257,12 +33322,6 @@ function firstReported(existing, keys) {
33257
33322
  }
33258
33323
  return null;
33259
33324
  }
33260
- function escalatedSeverity(own, corroborations) {
33261
- if (corroborations.length === 0) return own;
33262
- return maxSeverity([own, ...corroborations.map(function grade(c) {
33263
- return c.severity;
33264
- })]);
33265
- }
33266
33325
 
33267
33326
  // ../../packages/scanners/src/index.ts
33268
33327
  var registry2 = /* @__PURE__ */ new Map();
@@ -33746,7 +33805,7 @@ function roundUpV3(value) {
33746
33805
  return (Math.floor(intInput / 1e4) + 1) / 10;
33747
33806
  }
33748
33807
  function bucketV3(score) {
33749
- if (score === 0) return "none";
33808
+ if (score === 0) return "info";
33750
33809
  if (score < 4) return "low";
33751
33810
  if (score < 7) return "moderate";
33752
33811
  if (score < 9) return "high";
@@ -33843,44 +33902,55 @@ function parseAffectedRange(affectedRange, fixedVersions) {
33843
33902
  if (interval.exact !== null) {
33844
33903
  versions.push(interval.exact);
33845
33904
  } else {
33846
- ranges.push({ introduced: interval.introduced, fixed: interval.fixed });
33905
+ ranges.push(toRange(interval.introduced, interval.introducedExclusive, interval.fixed, interval.lastAffected));
33847
33906
  }
33848
33907
  }
33849
33908
  if (versions.length === 0 && ranges.every(isEmptyInterval)) return { ranges: [], versions: [] };
33850
33909
  const only = ranges[0];
33851
33910
  const authoritativeFixed = fixedVersions[0];
33852
33911
  if (ranges.length === 1 && versions.length === 0 && only && fixedVersions.length === 1 && authoritativeFixed !== void 0) {
33853
- ranges[0] = { introduced: only.introduced, fixed: authoritativeFixed };
33912
+ ranges[0] = toRange(only.introduced, only.introducedExclusive === true, authoritativeFixed, null);
33854
33913
  }
33855
33914
  return { ranges, versions };
33856
33915
  }
33916
+ function toRange(introduced, introducedExclusive, fixed, lastAffected) {
33917
+ const range = { introduced, fixed, lastAffected };
33918
+ if (introducedExclusive) range.introducedExclusive = true;
33919
+ return range;
33920
+ }
33857
33921
  function isEmptyInterval(range) {
33922
+ if (range.lastAffected !== null) {
33923
+ return range.introducedExclusive === true && range.lastAffected === range.introduced;
33924
+ }
33858
33925
  if (range.fixed === null) return false;
33859
33926
  if (range.fixed === range.introduced) return true;
33860
33927
  return isZeroVersion(range.introduced) && isZeroVersion(range.fixed);
33861
33928
  }
33862
- function isZeroVersion(version2) {
33863
- return /^0(\.0)*$/.test(version2);
33864
- }
33865
33929
  function parseDisjunct(disjunct) {
33866
33930
  const first = disjunct[0];
33867
33931
  if (first === "(" || first === "[") return parseIntervalNotation(disjunct);
33868
33932
  return parseComparatorForm(disjunct);
33869
33933
  }
33870
33934
  function parseIntervalNotation(disjunct) {
33935
+ const open = disjunct[0];
33871
33936
  const close = disjunct[disjunct.length - 1];
33872
33937
  if (close !== ")" && close !== "]") return null;
33873
33938
  const inner = disjunct.slice(1, -1);
33874
33939
  const comma = inner.indexOf(",");
33875
33940
  if (comma < 0) {
33876
33941
  const exact = inner.trim();
33877
- return exact.length > 0 ? { introduced: "0", fixed: null, exact } : null;
33942
+ return exact.length > 0 ? { introduced: "0", introducedExclusive: false, fixed: null, lastAffected: null, exact } : null;
33878
33943
  }
33879
33944
  const lo = inner.slice(0, comma).trim();
33880
33945
  const hi = inner.slice(comma + 1).trim();
33946
+ const hasUpper = hi.length > 0;
33881
33947
  return {
33882
33948
  introduced: lo.length > 0 ? lo : "0",
33883
- fixed: hi.length > 0 ? hi : null,
33949
+ // An open "(" excludes the lower bound — but only when one was actually given; "(,2.0.0)" has no
33950
+ // lower bound at all and starts from the bottom of the version space inclusively.
33951
+ introducedExclusive: open === "(" && lo.length > 0,
33952
+ fixed: hasUpper && close === ")" ? hi : null,
33953
+ lastAffected: hasUpper && close === "]" ? hi : null,
33884
33954
  exact: null
33885
33955
  };
33886
33956
  }
@@ -33888,23 +33958,29 @@ function parseComparatorForm(disjunct) {
33888
33958
  const tokens = disjunct.split(/\s+/).filter(nonEmpty);
33889
33959
  if (tokens.length === 0) return null;
33890
33960
  let introduced = "0";
33961
+ let introducedExclusive = false;
33891
33962
  let fixed = null;
33963
+ let lastAffected = null;
33892
33964
  for (const token of tokens) {
33893
33965
  const op = readOperator(token);
33894
- if (!op) continue;
33966
+ if (!op) return null;
33895
33967
  if (op.operator === "=") {
33896
- return { introduced: "0", fixed: null, exact: op.version };
33968
+ return { introduced: "0", introducedExclusive: false, fixed: null, lastAffected: null, exact: op.version };
33897
33969
  }
33898
33970
  if (op.operator === ">=" || op.operator === ">") {
33899
33971
  introduced = op.version;
33972
+ introducedExclusive = op.operator === ">";
33900
33973
  } else if (op.operator === "<") {
33901
33974
  fixed = op.version;
33902
- } else if (op.operator === "<=") {
33903
- fixed = op.version;
33975
+ lastAffected = null;
33976
+ } else {
33977
+ lastAffected = op.version;
33978
+ fixed = null;
33904
33979
  }
33905
33980
  }
33906
- return { introduced, fixed, exact: null };
33981
+ return { introduced, introducedExclusive, fixed, lastAffected, exact: null };
33907
33982
  }
33983
+ var BARE_VERSION = /^[0-9]+(\.[0-9]+)*([-+][0-9A-Za-z.-]*)?$/;
33908
33984
  function readOperator(token) {
33909
33985
  if (token.startsWith(">=")) return { operator: ">=", version: stripV(token.slice(2)) };
33910
33986
  if (token.startsWith("<=")) return { operator: "<=", version: stripV(token.slice(2)) };
@@ -33912,7 +33988,7 @@ function readOperator(token) {
33912
33988
  if (token.startsWith("<")) return { operator: "<", version: stripV(token.slice(1)) };
33913
33989
  if (token.startsWith("=")) return { operator: "=", version: stripV(token.slice(1)) };
33914
33990
  const bare = stripV(token);
33915
- return bare.length > 0 ? { operator: "=", version: bare } : null;
33991
+ return BARE_VERSION.test(bare) ? { operator: "=", version: bare } : null;
33916
33992
  }
33917
33993
  function stripV(raw) {
33918
33994
  const t = raw.trim();
@@ -34340,7 +34416,8 @@ function toOsvAdvisory(row) {
34340
34416
  severity: row.severity,
34341
34417
  summary: row.summary,
34342
34418
  url: row.url,
34343
- malicious: row.malicious
34419
+ malicious: row.malicious,
34420
+ withdrawn: row.withdrawn
34344
34421
  };
34345
34422
  }
34346
34423
  function toGemnasiumAdvisory(row) {
@@ -34512,23 +34589,32 @@ async function refreshOsv(options, meta3, item) {
34512
34589
  return { source: "osv", ecosystem: item.ecosystem, status: "unchanged", rowCount: state?.recordCount ?? 0, message: null };
34513
34590
  }
34514
34591
  const append = [];
34592
+ const replaced = /* @__PURE__ */ new Set();
34593
+ let skipped = 0;
34515
34594
  for (const id of changed.ids) {
34516
- if (options.abortSignal && options.abortSignal.aborted) break;
34595
+ if (options.abortSignal && options.abortSignal.aborted) {
34596
+ skipped += 1;
34597
+ break;
34598
+ }
34517
34599
  try {
34518
34600
  const rows = await fetchOsvAdvisoryRows(id, item.ecosystem, fetchOptionsFor(options, item));
34519
34601
  for (const row of rows) append.push(row);
34602
+ replaced.add(id);
34520
34603
  } catch {
34604
+ skipped += 1;
34521
34605
  continue;
34522
34606
  }
34523
34607
  }
34524
34608
  const path = advisoryFilePath(options.cacheDir, "osv", item.ecosystem);
34525
- const rowCount = await rewriteRows(path, { dropAdvisoryIds: new Set(changed.ids), append });
34609
+ const rowCount = await rewriteRows(path, { dropAdvisoryIds: replaced, append });
34610
+ const complete = skipped === 0;
34611
+ const previousCursor = state?.cursorIso ?? null;
34526
34612
  setSourceState(meta3, "osv", item.ecosystem, {
34527
34613
  normalizerVersion: OSV_NORMALIZER_VERSION,
34528
34614
  recordCount: rowCount,
34529
34615
  refreshedAt: Date.now(),
34530
- cursorIso: changed.newestIso ?? state?.cursorIso ?? null,
34531
- etag: changed.etag
34616
+ cursorIso: complete ? changed.newestIso ?? previousCursor : previousCursor,
34617
+ etag: complete ? changed.etag : null
34532
34618
  });
34533
34619
  return {
34534
34620
  source: "osv",
@@ -34910,7 +34996,7 @@ function emptyCounts() {
34910
34996
  function matchesDepType(finding, depType) {
34911
34997
  if (depType === "all") return true;
34912
34998
  if (depType === "prod") return finding.isProd;
34913
- return finding.isDev;
34999
+ return finding.isDev && !finding.isProd;
34914
35000
  }
34915
35001
  function summarize(results, options) {
34916
35002
  const projects = [];
@@ -35449,8 +35535,8 @@ function createUi(options) {
35449
35535
 
35450
35536
  // src/help.ts
35451
35537
  var CLI_VERSION = (function resolveVersion() {
35452
- if ("3.2.0".length > 0) {
35453
- return "3.2.0";
35538
+ if ("3.3.0".length > 0) {
35539
+ return "3.3.0";
35454
35540
  }
35455
35541
  const fromEnv = process.env.SENTINELLO_VERSION;
35456
35542
  if (fromEnv && fromEnv.trim().length > 0) return fromEnv.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sentinello",
3
- "version": "3.2.0",
3
+ "version": "3.3.0",
4
4
  "license": "MIT",
5
5
  "description": "Scan the projects in a folder for vulnerable dependencies and write an advisory an agent can act on.",
6
6
  "keywords": [
@@ -41,7 +41,6 @@
41
41
  },
42
42
  "scripts": {
43
43
  "build": "tsup",
44
- "dev": "tsx src/cli.ts",
45
44
  "lint": "eslint . --max-warnings 0",
46
45
  "typecheck": "tsc -p tsconfig.json --noEmit"
47
46
  },