fad-checker 2.4.0 → 2.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/lib/cve-report.js CHANGED
@@ -403,11 +403,20 @@ function renderDefinedIn(dep, srcRoot) {
403
403
  const paths = (dep.manifestPaths && dep.manifestPaths.length) ? dep.manifestPaths
404
404
  : (dep.pomPaths && dep.pomPaths.length) ? dep.pomPaths
405
405
  : [];
406
- if (!paths.length) return "";
407
- const rel = paths.map(p => makeRelative(p, srcRoot));
408
- const shown = rel.slice(0, 3).map(p => `<code>${esc(p)}</code>`).join(", ");
409
- const more = rel.length > 3 ? ` <span class="defined-more">+${rel.length - 3} more</span>` : "";
410
- return `<div class="defined-in"><span class="defined-label">defined in:</span> ${shown}${more}</div>`;
406
+ let definedLine = "";
407
+ if (paths.length) {
408
+ const rel = paths.map(p => makeRelative(p, srcRoot));
409
+ const shown = rel.slice(0, 3).map(p => `<code>${esc(p)}</code>`).join(", ");
410
+ const more = rel.length > 3 ? ` <span class="defined-more">+${rel.length - 3} more</span>` : "";
411
+ definedLine = `<div class="defined-in"><span class="defined-label">defined in:</span> ${shown}${more}</div>`;
412
+ }
413
+ // A versionless declared dep (typical Spring Boot / Gradle) gets its version from an import
414
+ // BOM, not the manifest it's declared in. Disclose that so 6.0.3 doesn't read as fabricated.
415
+ const vs = dep.versionSource;
416
+ const versionLine = (vs && vs.via === "bom" && vs.bom)
417
+ ? `<div class="defined-in"><span class="defined-label">version managed by:</span> <code>${esc(vs.bom)}</code> (BOM)</div>`
418
+ : "";
419
+ return definedLine + versionLine;
411
420
  }
412
421
 
413
422
  function makeRelative(absPath, srcRoot) {
@@ -30,6 +30,9 @@ function depBrief(dep) {
30
30
  provenance: dep.provenance || "manifest",
31
31
  purl: purlFor(dep),
32
32
  manifestPaths: dep.manifestPaths || dep.pomPaths || [],
33
+ // When the version was backfilled from an import/platform BOM, record which BOM
34
+ // supplied it — { via: "bom", bom: "g:a:v" } — so the finding is traceable.
35
+ versionSource: dep.versionSource || null,
33
36
  };
34
37
  }
35
38
 
package/lib/maven-bom.js CHANGED
@@ -48,6 +48,12 @@ function collectImportBoms(propsByPom) {
48
48
  /**
49
49
  * Resolve each import BOM to its managed-version table and merge them into one map.
50
50
  * First BOM to manage a given g:a wins (mirrors Maven's declaration-order precedence).
51
+ *
52
+ * Each value is `{ version, bom }` where `bom` is the `groupId:artifactId:version` of the
53
+ * TOP-LEVEL platform/import BOM that supplied the version (e.g. spring-boot-dependencies),
54
+ * not the nested BOM it may import (spring-batch-bom) — that's the coordinate the user wrote
55
+ * in `platform(...)`/`<scope>import</scope>` and recognizes. Carried so backfillVersions can
56
+ * record per-dep provenance ("version managed by <bom>").
51
57
  */
52
58
  async function resolveBomManagedVersions(boms, opts = {}) {
53
59
  const effectivePom = opts.effectivePom || transitive.effectivePom;
@@ -57,11 +63,12 @@ async function resolveBomManagedVersions(boms, opts = {}) {
57
63
  try { eff = await effectivePom(bom.groupId, bom.artifactId, bom.version, opts); }
58
64
  catch { eff = null; }
59
65
  if (!eff || !eff.depMgmt) continue;
66
+ const bomCoord = `${bom.groupId}:${bom.artifactId}:${bom.version}`;
60
67
  for (const d of eff.depMgmt) {
61
68
  if (!d.groupId || !d.artifactId) continue;
62
69
  const k = `${d.groupId}:${d.artifactId}`;
63
70
  if (map.has(k)) continue;
64
- if (d.version && !/\$\{/.test(String(d.version))) map.set(k, String(d.version));
71
+ if (d.version && !/\$\{/.test(String(d.version))) map.set(k, { version: String(d.version), bom: bomCoord });
65
72
  }
66
73
  }
67
74
  return map;
@@ -69,7 +76,10 @@ async function resolveBomManagedVersions(boms, opts = {}) {
69
76
 
70
77
  /**
71
78
  * Fill the version of every Maven dep that has no concrete version (null or `${…}`)
72
- * from the BOM-managed map. Mutates the resolvedDeps Map entries in place.
79
+ * from the BOM-managed map. Mutates the resolvedDeps Map entries in place. Each filled
80
+ * dep is stamped with `versionSource = { via: "bom", bom: "<coord>" }` so the report can
81
+ * disclose that the version came from a BOM (e.g. "version managed by spring-boot-dependencies")
82
+ * rather than the manifest it's declared in — the usual versionless Spring Boot / Gradle case.
73
83
  * @returns number of deps filled
74
84
  */
75
85
  function backfillVersions(resolvedDeps, mgmtMap) {
@@ -78,11 +88,13 @@ function backfillVersions(resolvedDeps, mgmtMap) {
78
88
  if (dep.ecosystem !== "maven") continue;
79
89
  if (dep.provenance === "embedded" || dep.provenance === "binary") continue;
80
90
  if (dep.version && !/\$\{/.test(String(dep.version))) continue; // already concrete
81
- const v = mgmtMap.get(`${dep.groupId}:${dep.artifactId}`);
82
- if (!v) continue;
91
+ const entry = mgmtMap.get(`${dep.groupId}:${dep.artifactId}`);
92
+ if (!entry) continue;
93
+ const v = entry.version;
83
94
  dep.version = v;
84
95
  if (!Array.isArray(dep.versions)) dep.versions = [];
85
96
  if (!dep.versions.includes(v)) dep.versions.push(v);
97
+ dep.versionSource = { via: "bom", bom: entry.bom };
86
98
  filled++;
87
99
  }
88
100
  return filled;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fad-checker",
3
- "version": "2.4.0",
3
+ "version": "2.4.1",
4
4
  "description": "Scan ALL Maven, Gradle, npm, Yarn, Composer, Python, C#/.NET, Go & Ruby dependencies — plus embedded JARs (fat-jars/war/ear) — in a source tree ONE SHOT without mvn/python/etc — CVE (EPSS/KEV-prioritised), EOL, obsolete, outdated & licenses, with SBOM/CSAF/SARIF/JSON exports, CI gating and fix recos",
5
5
  "keywords": [
6
6
  "sca",