sentinello 3.1.0 → 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 +70 -20
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -13134,8 +13134,8 @@ function isSourceUnavailableReason(code) {
13134
13134
  }
13135
13135
 
13136
13136
  // ../../packages/core/src/advisory-rows.ts
13137
- var OSV_NORMALIZER_VERSION = 3;
13138
- var GEMNASIUM_NORMALIZER_VERSION = 2;
13137
+ var OSV_NORMALIZER_VERSION = 4;
13138
+ var GEMNASIUM_NORMALIZER_VERSION = 3;
13139
13139
 
13140
13140
  // ../../packages/core/src/advisory-export.ts
13141
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.
@@ -33428,18 +33428,21 @@ function normalizeOsvRecord(record2, ecosystem) {
33428
33428
  const url2 = pickUrl(r, advisoryId);
33429
33429
  const withdrawn = typeof r.withdrawn === "string" ? Date.parse(r.withdrawn) || null : null;
33430
33430
  const rows = [];
33431
- const seenPackages = /* @__PURE__ */ new Set();
33431
+ const byPackage = /* @__PURE__ */ new Map();
33432
33432
  for (const affected of r.affected) {
33433
33433
  const pkg2 = affected.package;
33434
33434
  if (!pkg2 || pkg2.ecosystem !== ecosystem) continue;
33435
33435
  const packageName = typeof pkg2.name === "string" ? pkg2.name : null;
33436
33436
  if (!packageName) continue;
33437
- if (seenPackages.has(packageName)) continue;
33438
- seenPackages.add(packageName);
33439
33437
  const ranges = extractRanges(affected.ranges);
33440
33438
  const versions = extractVersions(affected.versions);
33441
- if (ranges.length === 0 && versions.length === 0 && !malicious) continue;
33442
- 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, {
33443
33446
  advisoryId,
33444
33447
  ecosystem,
33445
33448
  packageName,
@@ -33453,6 +33456,10 @@ function normalizeOsvRecord(record2, ecosystem) {
33453
33456
  withdrawn
33454
33457
  });
33455
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
+ }
33456
33463
  return rows;
33457
33464
  }
33458
33465
  function extractVersions(versions) {
@@ -33737,8 +33744,11 @@ function normalizeGemnasiumRecord(record2, ecosystem, slugPrefix) {
33737
33744
  const advisoryId = typeof r.identifier === "string" && r.identifier.length > 0 ? r.identifier : identifiers[0] ?? null;
33738
33745
  if (!advisoryId) return [];
33739
33746
  const fixedVersions = stringArray(r.fixed_versions);
33740
- const parsed = parseAffectedRange(typeof r.affected_range === "string" ? r.affected_range : "", fixedVersions);
33741
- 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
+ );
33742
33752
  const severity = severityFromCvss(
33743
33753
  typeof r.cvss_v3 === "string" ? r.cvss_v3 : null,
33744
33754
  typeof r.cvss_v2 === "string" ? r.cvss_v2 : null
@@ -33760,19 +33770,15 @@ function normalizeGemnasiumRecord(record2, ecosystem, slugPrefix) {
33760
33770
  summary,
33761
33771
  url: url2,
33762
33772
  malicious: false,
33763
- withdrawn: null
33773
+ withdrawn: null,
33774
+ rangeSource: parsed.source
33764
33775
  }];
33765
33776
  }
33766
- function parseAffectedRange(affectedRange, fixedVersions) {
33777
+ function parseAffectedRange(affectedRange, fixedVersions, affectedVersions = "") {
33767
33778
  const ranges = [];
33768
33779
  const versions = [];
33769
33780
  const trimmed = affectedRange.trim();
33770
33781
  const disjuncts = trimmed.length > 0 ? trimmed.split("||").map(trimToken).filter(nonEmpty) : [];
33771
- if (disjuncts.length === 0) {
33772
- const fixed = fixedVersions[0];
33773
- if (fixed !== void 0) return { ranges: [{ introduced: "0", fixed }], versions };
33774
- return { ranges, versions };
33775
- }
33776
33782
  for (const disjunct of disjuncts) {
33777
33783
  const interval = parseDisjunct(disjunct);
33778
33784
  if (!interval) continue;
@@ -33782,12 +33788,56 @@ function parseAffectedRange(affectedRange, fixedVersions) {
33782
33788
  ranges.push({ introduced: interval.introduced, fixed: interval.fixed });
33783
33789
  }
33784
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
+ }
33785
33796
  const only = ranges[0];
33786
33797
  const authoritativeFixed = fixedVersions[0];
33787
- 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) {
33788
33799
  ranges[0] = { introduced: only.introduced, fixed: authoritativeFixed };
33789
33800
  }
33790
- 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;
33791
33841
  }
33792
33842
  function parseDisjunct(disjunct) {
33793
33843
  const first = disjunct[0];
@@ -35376,8 +35426,8 @@ function createUi(options) {
35376
35426
 
35377
35427
  // src/help.ts
35378
35428
  var CLI_VERSION = (function resolveVersion() {
35379
- if ("3.1.0".length > 0) {
35380
- return "3.1.0";
35429
+ if ("3.1.1".length > 0) {
35430
+ return "3.1.1";
35381
35431
  }
35382
35432
  const fromEnv = process.env.SENTINELLO_VERSION;
35383
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.1.0",
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": [