sentinello 3.0.1 → 3.1.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.
Files changed (2) hide show
  1. package/dist/cli.cjs +85 -27
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -27,7 +27,11 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
27
27
  throw Error('Dynamic require of "' + x + '" is not supported');
28
28
  });
29
29
  var __commonJS = (cb, mod) => function __require2() {
30
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
30
+ try {
31
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
32
+ } catch (e) {
33
+ throw mod = 0, e;
34
+ }
31
35
  };
32
36
  var __export = (target, all) => {
33
37
  for (var name in all)
@@ -13130,8 +13134,8 @@ function isSourceUnavailableReason(code) {
13130
13134
  }
13131
13135
 
13132
13136
  // ../../packages/core/src/advisory-rows.ts
13133
- var OSV_NORMALIZER_VERSION = 3;
13134
- var GEMNASIUM_NORMALIZER_VERSION = 2;
13137
+ var OSV_NORMALIZER_VERSION = 4;
13138
+ var GEMNASIUM_NORMALIZER_VERSION = 3;
13135
13139
 
13136
13140
  // ../../packages/core/src/advisory-export.ts
13137
13141
  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.
@@ -28604,6 +28608,10 @@ async function detectYarnMajor(projectPath, lockfile) {
28604
28608
  }
28605
28609
  return null;
28606
28610
  }
28611
+ function auditSummary(ctx, findingCount) {
28612
+ const packageCount = ctx.resolvedGraph?.packages?.length ?? null;
28613
+ return JSON.stringify({ source: SCANNER_NAME, packageCount, findingCount });
28614
+ }
28607
28615
  function logCrossCheckDrops(result, packageManager) {
28608
28616
  if (result.droppedCount === 0) return;
28609
28617
  const MAX_LIST = 10;
@@ -28712,7 +28720,7 @@ async function runNpmAudit(projectPath, ctx, deps = REAL_DEPS) {
28712
28720
  status: "ok",
28713
28721
  reasonCode: "ok",
28714
28722
  findings: crossChecked2.kept,
28715
- rawJson: rawText,
28723
+ rawJson: auditSummary(ctx, crossChecked2.kept.length),
28716
28724
  errorText: null,
28717
28725
  durationMs: Date.now() - startedAt
28718
28726
  };
@@ -28736,7 +28744,7 @@ async function runNpmAudit(projectPath, ctx, deps = REAL_DEPS) {
28736
28744
  status: "ok",
28737
28745
  reasonCode: "ok",
28738
28746
  findings: crossChecked.kept,
28739
- rawJson: rawText,
28747
+ rawJson: auditSummary(ctx, crossChecked.kept.length),
28740
28748
  errorText: null,
28741
28749
  durationMs: Date.now() - startedAt
28742
28750
  };
@@ -28997,7 +29005,7 @@ function nameFromNodePath(nodePath) {
28997
29005
  return slash < 0 ? tail : tail.slice(0, slash);
28998
29006
  }
28999
29007
 
29000
- // ../../node_modules/.pnpm/js-yaml@4.3.0/node_modules/js-yaml/dist/js-yaml.mjs
29008
+ // ../../node_modules/.pnpm/js-yaml@4.3.1/node_modules/js-yaml/dist/js-yaml.mjs
29001
29009
  function getDefaultExportFromCjs(x) {
29002
29010
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
29003
29011
  }
@@ -29858,7 +29866,7 @@ function requireOmap() {
29858
29866
  const _toString = Object.prototype.toString;
29859
29867
  function resolveYamlOmap(data) {
29860
29868
  if (data === null) return true;
29861
- const objectKeys = [];
29869
+ const objectKeys = {};
29862
29870
  const object2 = data;
29863
29871
  for (let index = 0, length = object2.length; index < length; index += 1) {
29864
29872
  const pair = object2[index];
@@ -29872,8 +29880,8 @@ function requireOmap() {
29872
29880
  }
29873
29881
  }
29874
29882
  if (!pairHasKey) return false;
29875
- if (objectKeys.indexOf(pairKey) === -1) objectKeys.push(pairKey);
29876
- else return false;
29883
+ if (_hasOwnProperty.call(objectKeys, pairKey)) return false;
29884
+ Object.defineProperty(objectKeys, pairKey, { value: true });
29877
29885
  }
29878
29886
  return true;
29879
29887
  }
@@ -33420,18 +33428,21 @@ function normalizeOsvRecord(record2, ecosystem) {
33420
33428
  const url2 = pickUrl(r, advisoryId);
33421
33429
  const withdrawn = typeof r.withdrawn === "string" ? Date.parse(r.withdrawn) || null : null;
33422
33430
  const rows = [];
33423
- const seenPackages = /* @__PURE__ */ new Set();
33431
+ const byPackage = /* @__PURE__ */ new Map();
33424
33432
  for (const affected of r.affected) {
33425
33433
  const pkg2 = affected.package;
33426
33434
  if (!pkg2 || pkg2.ecosystem !== ecosystem) continue;
33427
33435
  const packageName = typeof pkg2.name === "string" ? pkg2.name : null;
33428
33436
  if (!packageName) continue;
33429
- if (seenPackages.has(packageName)) continue;
33430
- seenPackages.add(packageName);
33431
33437
  const ranges = extractRanges(affected.ranges);
33432
33438
  const versions = extractVersions(affected.versions);
33433
- if (ranges.length === 0 && versions.length === 0 && !malicious) continue;
33434
- rows.push({
33439
+ const existing = byPackage.get(packageName);
33440
+ if (existing) {
33441
+ for (const range of ranges) existing.ranges.push(range);
33442
+ for (const version2 of versions) existing.versions.push(version2);
33443
+ continue;
33444
+ }
33445
+ byPackage.set(packageName, {
33435
33446
  advisoryId,
33436
33447
  ecosystem,
33437
33448
  packageName,
@@ -33445,6 +33456,10 @@ function normalizeOsvRecord(record2, ecosystem) {
33445
33456
  withdrawn
33446
33457
  });
33447
33458
  }
33459
+ for (const row of byPackage.values()) {
33460
+ if (row.ranges.length === 0 && row.versions.length === 0 && !malicious) continue;
33461
+ rows.push(row);
33462
+ }
33448
33463
  return rows;
33449
33464
  }
33450
33465
  function extractVersions(versions) {
@@ -33729,8 +33744,11 @@ function normalizeGemnasiumRecord(record2, ecosystem, slugPrefix) {
33729
33744
  const advisoryId = typeof r.identifier === "string" && r.identifier.length > 0 ? r.identifier : identifiers[0] ?? null;
33730
33745
  if (!advisoryId) return [];
33731
33746
  const fixedVersions = stringArray(r.fixed_versions);
33732
- const parsed = parseAffectedRange(typeof r.affected_range === "string" ? r.affected_range : "", fixedVersions);
33733
- if (parsed.ranges.length === 0 && parsed.versions.length === 0) return [];
33747
+ const parsed = parseAffectedRange(
33748
+ typeof r.affected_range === "string" ? r.affected_range : "",
33749
+ fixedVersions,
33750
+ typeof r.affected_versions === "string" ? r.affected_versions : ""
33751
+ );
33734
33752
  const severity = severityFromCvss(
33735
33753
  typeof r.cvss_v3 === "string" ? r.cvss_v3 : null,
33736
33754
  typeof r.cvss_v2 === "string" ? r.cvss_v2 : null
@@ -33752,19 +33770,15 @@ function normalizeGemnasiumRecord(record2, ecosystem, slugPrefix) {
33752
33770
  summary,
33753
33771
  url: url2,
33754
33772
  malicious: false,
33755
- withdrawn: null
33773
+ withdrawn: null,
33774
+ rangeSource: parsed.source
33756
33775
  }];
33757
33776
  }
33758
- function parseAffectedRange(affectedRange, fixedVersions) {
33777
+ function parseAffectedRange(affectedRange, fixedVersions, affectedVersions = "") {
33759
33778
  const ranges = [];
33760
33779
  const versions = [];
33761
33780
  const trimmed = affectedRange.trim();
33762
33781
  const disjuncts = trimmed.length > 0 ? trimmed.split("||").map(trimToken).filter(nonEmpty) : [];
33763
- if (disjuncts.length === 0) {
33764
- const fixed = fixedVersions[0];
33765
- if (fixed !== void 0) return { ranges: [{ introduced: "0", fixed }], versions };
33766
- return { ranges, versions };
33767
- }
33768
33782
  for (const disjunct of disjuncts) {
33769
33783
  const interval = parseDisjunct(disjunct);
33770
33784
  if (!interval) continue;
@@ -33774,12 +33788,56 @@ function parseAffectedRange(affectedRange, fixedVersions) {
33774
33788
  ranges.push({ introduced: interval.introduced, fixed: interval.fixed });
33775
33789
  }
33776
33790
  }
33791
+ if (versions.length === 0 && ranges.every(isEmptyInterval)) {
33792
+ const prose = parseAffectedVersionsProse(affectedVersions);
33793
+ if (prose) return { ranges: prose, versions, source: "prose" };
33794
+ return { ranges: [], versions: [], source: "unresolved" };
33795
+ }
33777
33796
  const only = ranges[0];
33778
33797
  const authoritativeFixed = fixedVersions[0];
33779
- if (ranges.length === 1 && versions.length === 0 && only && authoritativeFixed !== void 0) {
33798
+ if (ranges.length === 1 && versions.length === 0 && only && fixedVersions.length === 1 && authoritativeFixed !== void 0) {
33780
33799
  ranges[0] = { introduced: only.introduced, fixed: authoritativeFixed };
33781
33800
  }
33782
- return { ranges, versions };
33801
+ return { ranges, versions, source: "range" };
33802
+ }
33803
+ function isEmptyInterval(range) {
33804
+ if (range.fixed === null) return false;
33805
+ if (range.fixed === range.introduced) return true;
33806
+ return isZeroVersion(range.introduced) && isZeroVersion(range.fixed);
33807
+ }
33808
+ function isZeroVersion(version2) {
33809
+ return /^0(\.0)*$/.test(version2);
33810
+ }
33811
+ function parseAffectedVersionsProse(text) {
33812
+ const sentence = text.replace(/\s+/g, " ").trim();
33813
+ if (sentence.length === 0) return null;
33814
+ const lower = sentence.toLowerCase();
33815
+ if (lower === "none" || lower.startsWith("no version") || lower.startsWith("this advisory has been withdrawn")) return null;
33816
+ const out = [];
33817
+ for (const clause of sentence.split(",")) {
33818
+ const c = clause.trim();
33819
+ const fromBefore = /^all versions starting from (\S+) before (\S+)$/i.exec(c);
33820
+ if (fromBefore && fromBefore[1] && fromBefore[2]) {
33821
+ out.push({ introduced: stripV(fromBefore[1]), fixed: stripV(fromBefore[2]) });
33822
+ continue;
33823
+ }
33824
+ const before = /^all versions before (\S+)$/i.exec(c);
33825
+ if (before && before[1]) {
33826
+ out.push({ introduced: "0", fixed: stripV(before[1]) });
33827
+ continue;
33828
+ }
33829
+ const from = /^all versions starting from (\S+)$/i.exec(c);
33830
+ if (from && from[1]) {
33831
+ out.push({ introduced: stripV(from[1]), fixed: null });
33832
+ continue;
33833
+ }
33834
+ if (/^all versions$/i.test(c)) {
33835
+ out.push({ introduced: "0", fixed: null });
33836
+ continue;
33837
+ }
33838
+ return null;
33839
+ }
33840
+ return out;
33783
33841
  }
33784
33842
  function parseDisjunct(disjunct) {
33785
33843
  const first = disjunct[0];
@@ -35368,8 +35426,8 @@ function createUi(options) {
35368
35426
 
35369
35427
  // src/help.ts
35370
35428
  var CLI_VERSION = (function resolveVersion() {
35371
- if ("3.0.1".length > 0) {
35372
- return "3.0.1";
35429
+ if ("3.1.1".length > 0) {
35430
+ return "3.1.1";
35373
35431
  }
35374
35432
  const fromEnv = process.env.SENTINELLO_VERSION;
35375
35433
  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.0.1",
3
+ "version": "3.1.1",
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": [