fad-checker 1.0.3 → 1.0.5

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/CLAUDE.md CHANGED
@@ -15,7 +15,7 @@ Code-level orientation for contributors and Claude Code sessions on this repo.
15
15
  - retire.js (vendored JS signatures),
16
16
  - optionally Snyk (`--snyk`).
17
17
  4. Cross-checks every match's NVD CPE configurations against the dep version (`lib/cpe.js`) to filter false positives.
18
- 5. Reports EOL frameworks (endoflife.date), obsolete libs (curated), outdated libs (Maven Central).
18
+ 5. Reports EOL frameworks (endoflife.date — Maven & npm), obsolete libs (curated Maven + npm-registry per-version `deprecated` field — authoritative, skips nothing), outdated libs (Maven Central + npm registry `dist-tags.latest`). **WebJars** (`org.webjars*`) are reduced to their npm coordinate by `webjarToNpm()` and run through the npm EOL/deprecation/outdated paths — so e.g. `org.webjars:angularjs:1.8.3` is flagged EOL.
19
19
  6. Produces a self-contained HTML report + Word-compatible `.doc`, organised by ecosystem and by defining manifest, with per-tool fix recipes and an executive summary.
20
20
 
21
21
  No build tool (`mvn`, `npm install`, `yarn`) is required on PATH — `pom.xml` / `package-lock.json` / `yarn.lock` are parsed directly.
@@ -67,6 +67,7 @@ lib/retire.js retire.js (vendored-JS scanner) wrapper + cache + n
67
67
  lib/scan-completeness.js Warnings for deps fad-checker couldn't fully resolve.
68
68
  lib/npm/parse.js package.json, package-lock.json (v1/2/3), yarn.lock v1 parsers.
69
69
  lib/npm/collect.js Merge across JS manifests → unified resolvedDeps Map.
70
+ lib/npm/registry.js npm registry packument query → per-version deprecation + dist-tags.latest (npm EOL feeds via lib/outdated.js).
70
71
  lib/cache-archive.js tar.gz / zip export & import of ~/.fad-checker/.
71
72
  lib/config.js Persistent user config in ~/.fad-checker/config.json (mode 0600).
72
73
  data/ known-obsolete.json, eol-mapping.json, cpe-coord-map.json, known-public-namespaces.json
@@ -106,7 +107,7 @@ Test fixtures live in `test/fixtures/`:
106
107
  - CVE bundle from CVEProject is ~500 MB unpacked. Shells out to `curl + unzip` (fallback to `fetch()` + `unzip` / `Expand-Archive`). Extracted JSON deleted after index build. Ships as `cves.zip.zip` (nested zip) — `extractZip()` recurses up to 3 levels.
107
108
  - `endoflife.date` API responses cached 7 days; Maven Central version lookups cached 24 hours. Cache lives in `~/.fad-checker/`.
108
109
  - **Persistent config**: `~/.fad-checker/config.json` (mode 0600). Set NVD key via `fad-checker --set-nvd-key <KEY>` (free, instant from <https://nvd.nist.gov/developers/request-an-api-key> — bumps rate limit from 5/30s to 50/30s).
109
- - **`--offline` umbrella flag**: skips every network call (CVE/OSV/NVD/Maven Central/endoflife/retire). Falls back to whatever is already cached. Per-source variants (`--cve-offline`, `--no-osv`, `--no-nvd`, `--no-retire`, `--no-transitive`) still work independently.
110
+ - **`--offline` umbrella flag**: skips every network call (CVE/OSV/NVD/Maven Central/endoflife/npm-registry/retire). Falls back to whatever is already cached. Per-source variants (`--cve-offline`, `--no-osv`, `--no-nvd`, `--no-retire`, `--no-transitive`, `--no-js`) still work independently. npm registry deprecation always runs when online; npm (and Maven) outdated is gated by `--no-all-libs`.
110
111
  - `snyk` is not a hard dep — shells out via `execFile`. `snyk` exits 1 on findings; the JSON is still on stdout.
111
112
  - The cleaned POM is the union of every profile's deps. Counts will be larger than the source POM. Intentional — don't "fix" that.
112
113
  - Unresolved `${…}` Maven variables stay verbatim in the rewritten POM. `lib/cve-match.js` resolves them lazily via `resolveDepVersion()` when scanning. Deps that *still* can't be resolved (external BOM not in source tree) surface in chapter 0 as `unresolved-versions` warnings.
@@ -122,5 +123,6 @@ Test fixtures live in `test/fixtures/`:
122
123
  | NVD CVE record | `~/.fad-checker/nvd-cache/<cveId>.json` | 7 d |
123
124
  | endoflife.date cycles | `~/.fad-checker/eol-cache.json` | 7 d |
124
125
  | Maven Central latest | `~/.fad-checker/version-cache.json` | 24 h |
126
+ | npm registry (deprecation + latest) | `~/.fad-checker/npm-registry-cache.json` | 24 h |
125
127
  | Transitive POM | `~/.fad-checker/poms-cache/<g>__<a>__<v>.pom` | ∞ (immutable on Maven Central) |
126
128
  | retire.js findings | `~/.fad-checker/retire-cache/<md5(src)>.json` | 24 h |
@@ -0,0 +1,192 @@
1
+ {
2
+ "_comment": "Common CWE identifiers → short human name. Covers the bulk of CVEs in practice. Source: cwe.mitre.org. Names are abbreviated for compact UI display.",
3
+ "CWE-20": "Improper Input Validation",
4
+ "CWE-22": "Path Traversal",
5
+ "CWE-59": "Link Following",
6
+ "CWE-74": "Improper Neutralization of Special Elements (Injection)",
7
+ "CWE-77": "Command Injection",
8
+ "CWE-78": "OS Command Injection",
9
+ "CWE-79": "Cross-site Scripting (XSS)",
10
+ "CWE-88": "Argument Injection",
11
+ "CWE-89": "SQL Injection",
12
+ "CWE-90": "LDAP Injection",
13
+ "CWE-91": "XML Injection",
14
+ "CWE-93": "CRLF Injection",
15
+ "CWE-94": "Code Injection",
16
+ "CWE-95": "Eval Injection",
17
+ "CWE-113": "HTTP Response Splitting",
18
+ "CWE-115": "Misinterpretation of Input",
19
+ "CWE-116": "Improper Encoding or Escaping of Output",
20
+ "CWE-117": "Improper Output Neutralization for Logs",
21
+ "CWE-118": "Incorrect Access of Indexable Resource",
22
+ "CWE-119": "Improper Restriction of Operations within the Bounds of a Memory Buffer",
23
+ "CWE-120": "Buffer Copy without Checking Size (Classic Buffer Overflow)",
24
+ "CWE-121": "Stack-based Buffer Overflow",
25
+ "CWE-122": "Heap-based Buffer Overflow",
26
+ "CWE-125": "Out-of-bounds Read",
27
+ "CWE-129": "Improper Validation of Array Index",
28
+ "CWE-131": "Incorrect Calculation of Buffer Size",
29
+ "CWE-134": "Use of Externally-Controlled Format String",
30
+ "CWE-178": "Improper Handling of Case Sensitivity",
31
+ "CWE-184": "Incomplete List of Disallowed Inputs",
32
+ "CWE-185": "Incorrect Regular Expression",
33
+ "CWE-190": "Integer Overflow or Wraparound",
34
+ "CWE-191": "Integer Underflow",
35
+ "CWE-193": "Off-by-one Error",
36
+ "CWE-200": "Exposure of Sensitive Information to an Unauthorized Actor",
37
+ "CWE-203": "Observable Discrepancy",
38
+ "CWE-204": "Observable Response Discrepancy",
39
+ "CWE-208": "Observable Timing Discrepancy",
40
+ "CWE-209": "Generation of Error Message Containing Sensitive Information",
41
+ "CWE-212": "Improper Removal of Sensitive Information Before Storage or Transfer",
42
+ "CWE-215": "Insertion of Sensitive Information Into Debugging Code",
43
+ "CWE-226": "Sensitive Information in Resource Not Removed Before Reuse",
44
+ "CWE-241": "Improper Handling of Unexpected Data Type",
45
+ "CWE-248": "Uncaught Exception",
46
+ "CWE-252": "Unchecked Return Value",
47
+ "CWE-256": "Plaintext Storage of a Password",
48
+ "CWE-257": "Storing Passwords in a Recoverable Format",
49
+ "CWE-259": "Use of Hard-coded Password",
50
+ "CWE-260": "Password in Configuration File",
51
+ "CWE-261": "Weak Encoding for Password",
52
+ "CWE-262": "Not Using Password Aging",
53
+ "CWE-269": "Improper Privilege Management",
54
+ "CWE-272": "Least Privilege Violation",
55
+ "CWE-273": "Improper Check for Dropped Privileges",
56
+ "CWE-275": "Permission Issues",
57
+ "CWE-276": "Incorrect Default Permissions",
58
+ "CWE-281": "Improper Preservation of Permissions",
59
+ "CWE-284": "Improper Access Control",
60
+ "CWE-285": "Improper Authorization",
61
+ "CWE-287": "Improper Authentication",
62
+ "CWE-288": "Authentication Bypass Using an Alternate Path or Channel",
63
+ "CWE-290": "Authentication Bypass by Spoofing",
64
+ "CWE-294": "Authentication Bypass by Capture-replay",
65
+ "CWE-295": "Improper Certificate Validation",
66
+ "CWE-296": "Improper Following of a Certificate's Chain of Trust",
67
+ "CWE-297": "Improper Validation of Certificate with Host Mismatch",
68
+ "CWE-298": "Improper Validation of Certificate Expiration",
69
+ "CWE-299": "Improper Check for Certificate Revocation",
70
+ "CWE-300": "Channel Accessible by Non-Endpoint (MITM)",
71
+ "CWE-303": "Incorrect Implementation of Authentication Algorithm",
72
+ "CWE-305": "Authentication Bypass by Primary Weakness",
73
+ "CWE-306": "Missing Authentication for Critical Function",
74
+ "CWE-307": "Improper Restriction of Excessive Authentication Attempts",
75
+ "CWE-311": "Missing Encryption of Sensitive Data",
76
+ "CWE-312": "Cleartext Storage of Sensitive Information",
77
+ "CWE-319": "Cleartext Transmission of Sensitive Information",
78
+ "CWE-320": "Key Management Errors",
79
+ "CWE-321": "Use of Hard-coded Cryptographic Key",
80
+ "CWE-326": "Inadequate Encryption Strength",
81
+ "CWE-327": "Use of a Broken or Risky Cryptographic Algorithm",
82
+ "CWE-328": "Use of Weak Hash",
83
+ "CWE-329": "Generation of Predictable IV with CBC Mode",
84
+ "CWE-330": "Use of Insufficiently Random Values",
85
+ "CWE-331": "Insufficient Entropy",
86
+ "CWE-335": "Incorrect Usage of Seeds in PRNG",
87
+ "CWE-338": "Use of Cryptographically Weak PRNG",
88
+ "CWE-345": "Insufficient Verification of Data Authenticity",
89
+ "CWE-346": "Origin Validation Error",
90
+ "CWE-347": "Improper Verification of Cryptographic Signature",
91
+ "CWE-352": "Cross-Site Request Forgery (CSRF)",
92
+ "CWE-354": "Improper Validation of Integrity Check Value",
93
+ "CWE-358": "Improperly Implemented Security Check for Standard",
94
+ "CWE-362": "Race Condition",
95
+ "CWE-367": "TOCTOU Race Condition",
96
+ "CWE-369": "Divide By Zero",
97
+ "CWE-377": "Insecure Temporary File",
98
+ "CWE-378": "Creation of Temporary File With Insecure Permissions",
99
+ "CWE-384": "Session Fixation",
100
+ "CWE-390": "Detection of Error Condition Without Action",
101
+ "CWE-400": "Uncontrolled Resource Consumption (DoS)",
102
+ "CWE-401": "Missing Release of Memory after Effective Lifetime",
103
+ "CWE-402": "Transmission of Private Resources into a New Sphere",
104
+ "CWE-404": "Improper Resource Shutdown or Release",
105
+ "CWE-405": "Asymmetric Resource Consumption (Amplification)",
106
+ "CWE-407": "Inefficient Algorithmic Complexity",
107
+ "CWE-409": "Improper Handling of Highly Compressed Data (Zip Bomb)",
108
+ "CWE-415": "Double Free",
109
+ "CWE-416": "Use After Free",
110
+ "CWE-419": "Unprotected Primary Channel",
111
+ "CWE-425": "Direct Request (Forced Browsing)",
112
+ "CWE-426": "Untrusted Search Path",
113
+ "CWE-427": "Uncontrolled Search Path Element",
114
+ "CWE-428": "Unquoted Search Path or Element",
115
+ "CWE-434": "Unrestricted Upload of File with Dangerous Type",
116
+ "CWE-436": "Interpretation Conflict",
117
+ "CWE-441": "Unintended Proxy or Intermediary (Confused Deputy)",
118
+ "CWE-444": "HTTP Request/Response Smuggling",
119
+ "CWE-451": "UI Misrepresentation of Critical Information",
120
+ "CWE-459": "Incomplete Cleanup",
121
+ "CWE-470": "Unsafe Reflection",
122
+ "CWE-471": "Modification of Assumed-Immutable Data",
123
+ "CWE-476": "NULL Pointer Dereference",
124
+ "CWE-477": "Use of Obsolete Function",
125
+ "CWE-489": "Active Debug Code",
126
+ "CWE-494": "Download of Code Without Integrity Check",
127
+ "CWE-497": "Exposure of Sensitive System Information to an Unauthorized Control Sphere",
128
+ "CWE-502": "Deserialization of Untrusted Data",
129
+ "CWE-521": "Weak Password Requirements",
130
+ "CWE-522": "Insufficiently Protected Credentials",
131
+ "CWE-523": "Unprotected Transport of Credentials",
132
+ "CWE-532": "Insertion of Sensitive Information into Log File",
133
+ "CWE-540": "Inclusion of Sensitive Information in Source Code",
134
+ "CWE-548": "Exposure of Information Through Directory Listing",
135
+ "CWE-552": "Files or Directories Accessible to External Parties",
136
+ "CWE-565": "Reliance on Cookies without Validation and Integrity Checking",
137
+ "CWE-601": "URL Redirection to Untrusted Site (Open Redirect)",
138
+ "CWE-610": "Externally Controlled Reference to a Resource in Another Sphere",
139
+ "CWE-611": "XML External Entity (XXE)",
140
+ "CWE-613": "Insufficient Session Expiration",
141
+ "CWE-617": "Reachable Assertion",
142
+ "CWE-639": "Authorization Bypass Through User-Controlled Key (IDOR)",
143
+ "CWE-640": "Weak Password Recovery Mechanism for Forgotten Password",
144
+ "CWE-641": "Improper Restriction of Names for Files and Other Resources",
145
+ "CWE-643": "XPath Injection",
146
+ "CWE-645": "Overly Restrictive Account Lockout Mechanism",
147
+ "CWE-652": "XQuery Injection",
148
+ "CWE-665": "Improper Initialization",
149
+ "CWE-668": "Exposure of Resource to Wrong Sphere",
150
+ "CWE-670": "Always-Incorrect Control Flow Implementation",
151
+ "CWE-672": "Operation on a Resource after Expiration or Release",
152
+ "CWE-674": "Uncontrolled Recursion",
153
+ "CWE-682": "Incorrect Calculation",
154
+ "CWE-693": "Protection Mechanism Failure",
155
+ "CWE-697": "Incorrect Comparison",
156
+ "CWE-704": "Incorrect Type Conversion or Cast",
157
+ "CWE-732": "Incorrect Permission Assignment for Critical Resource",
158
+ "CWE-749": "Exposed Dangerous Method or Function",
159
+ "CWE-754": "Improper Check for Unusual or Exceptional Conditions",
160
+ "CWE-755": "Improper Handling of Exceptional Conditions",
161
+ "CWE-763": "Release of Invalid Pointer or Reference",
162
+ "CWE-770": "Allocation of Resources Without Limits or Throttling",
163
+ "CWE-772": "Missing Release of Resource after Effective Lifetime",
164
+ "CWE-776": "XML Entity Expansion (XEE / Billion Laughs)",
165
+ "CWE-787": "Out-of-bounds Write",
166
+ "CWE-789": "Memory Allocation with Excessive Size Value",
167
+ "CWE-798": "Use of Hard-coded Credentials",
168
+ "CWE-829": "Inclusion of Functionality from Untrusted Control Sphere",
169
+ "CWE-834": "Excessive Iteration",
170
+ "CWE-835": "Loop with Unreachable Exit Condition (Infinite Loop)",
171
+ "CWE-838": "Inappropriate Encoding for Output Context",
172
+ "CWE-843": "Type Confusion (Access of Resource Using Incompatible Type)",
173
+ "CWE-862": "Missing Authorization",
174
+ "CWE-863": "Incorrect Authorization",
175
+ "CWE-908": "Use of Uninitialized Resource",
176
+ "CWE-913": "Improper Control of Dynamically-Managed Code Resources",
177
+ "CWE-915": "Mass Assignment",
178
+ "CWE-916": "Use of Password Hash With Insufficient Computational Effort",
179
+ "CWE-917": "Expression Language Injection (EL Injection)",
180
+ "CWE-918": "Server-Side Request Forgery (SSRF)",
181
+ "CWE-920": "Improper Restriction of Power Consumption",
182
+ "CWE-921": "Storage of Sensitive Data in a Mechanism without Access Control",
183
+ "CWE-924": "Improper Enforcement of Message Integrity During Transmission in a Communication Channel",
184
+ "CWE-1004": "Sensitive Cookie Without 'HttpOnly' Flag",
185
+ "CWE-1021": "Improper Restriction of Rendered UI Layers (Clickjacking)",
186
+ "CWE-1188": "Insecure Default Initialization of Resource",
187
+ "CWE-1236": "CSV Formula Injection",
188
+ "CWE-1275": "Sensitive Cookie with Improper SameSite Attribute",
189
+ "CWE-1284": "Improper Validation of Specified Quantity in Input",
190
+ "CWE-1321": "Improperly Controlled Modification of Object Prototype (Prototype Pollution)",
191
+ "CWE-1333": "Inefficient Regular Expression Complexity (ReDoS)"
192
+ }
@@ -30,5 +30,17 @@
30
30
  "org.springframework": { "product": "spring-framework", "label": "Spring Framework" },
31
31
  "org.hibernate": { "product": "hibernate", "label": "Hibernate ORM" },
32
32
  "io.netty": { "product": "netty", "label": "Netty" }
33
+ },
34
+ "by_npm_name": {
35
+ "angular": { "product": "angularjs", "label": "AngularJS" },
36
+ "angularjs": { "product": "angularjs", "label": "AngularJS" },
37
+ "vue": { "product": "vue", "label": "Vue" },
38
+ "react": { "product": "react", "label": "React" },
39
+ "react-dom": { "product": "react", "label": "React" },
40
+ "jquery": { "product": "jquery", "label": "jQuery" },
41
+ "bootstrap": { "product": "bootstrap", "label": "Bootstrap" }
42
+ },
43
+ "by_npm_scope": {
44
+ "@angular/": { "product": "angular", "label": "Angular" }
33
45
  }
34
46
  }
@@ -21,6 +21,7 @@ lib/retire.js retire.js (vendored-JS scanner) wrapper + cache + n
21
21
  lib/scan-completeness.js Warnings for deps we couldn't fully resolve.
22
22
  lib/npm/parse.js package.json, package-lock.json (v1/2/3), yarn.lock v1 parsers.
23
23
  lib/npm/collect.js Merge across JS manifests → unified resolvedDeps Map.
24
+ lib/npm/registry.js npm registry packument query → per-version deprecation + dist-tags.latest.
24
25
  lib/cache-archive.js tar.gz / zip export & import of ~/.fad-checker/.
25
26
  lib/config.js Persistent user config in ~/.fad-checker/config.json (mode 0600).
26
27
  data/ Curated JSON: known-obsolete, eol-mapping, cpe-coord-map, known-public-namespaces.
@@ -77,10 +78,11 @@ The Maven keyspace and npm keyspace never collide — `:lodash` (Maven groupId-l
77
78
  - Confirms the dep version actually falls in the vulnerable range (else `cpeFiltered: true` — likely false positive).
78
79
  - Upgrades match `confidence` from `possible` → `probable` → `exact` when a curated `cpe-coord-map.json` entry confirms vendor:product → dep coord.
79
80
  8. **retire.js** (default on) — shells out to `retire --outputformat json --jspath <src>`. Output normalised to fad-checker match shape, with the vendored file path attached so the report can show where the offending `.js` lives. Cache: `~/.fad-checker/retire-cache/<md5(src)>.json`, 24h TTL.
80
- 9. **EOL / Obsolete / Outdated** — `lib/outdated.js`:
81
- - **EOL**: matches dep coord against `data/eol-mapping.json`, fetches the cycle list from endoflife.date (cached 7d), flags cycles past their EOL date.
82
- - **Obsolete**: lookup in `data/known-obsolete.json` (curated: log4j 1.x, jackson-mapper-asl, joda-time, commons-httpclient 3.x, ).
83
- - **Outdated**: Maven Central Solr query for the latest version. Cache 24h. Concurrency 8.
81
+ 9. **EOL / Obsolete / Outdated** — `lib/outdated.js` (Maven) + `lib/npm/registry.js` (npm):
82
+ - **WebJars** (`org.webjars*` client-side JS shipped as Maven artifacts) are reduced to their npm-equivalent coordinate by `webjarToNpm()` (`lib/npm/collect.js`): `org.webjars.npm` is a deterministic npm mirror (`angular__core` → `@angular/core`); classic `org.webjars`/bower names pass through. They then flow through the **same npm paths** below — no WebJar-specific data.
83
+ - **EOL**: matches dep coord against `data/eol-mapping.json`, fetches the cycle list from endoflife.date (cached 7d), flags cycles past their EOL date. npm packages and WebJars resolve by JS library name via `by_npm_name` / `by_npm_scope` (e.g. npm `angular`/webjar `angularjs` → AngularJS 1.x, `@angular/*` Angular, `react`/`jquery`/`vue`/`bootstrap`).
84
+ - **Obsolete**: Maven via curated `data/known-obsolete.json` (log4j 1.x, jackson-mapper-asl, joda-time, commons-httpclient 3.x, …); npm **and WebJars** via the registry's per-version `deprecated` field (authoritative maintainer data — every dep is checked, nothing curated, nothing skipped).
85
+ - **Outdated**: Maven Central Solr query; npm registry `dist-tags.latest` (npm deps and WebJars). Both gated by `--no-all-libs`. Cache 24h. Concurrency 8.
84
86
  10. **Snyk** (optional, `--snyk`) — runs `snyk test --all-projects --json` against the cleaned target dir. Normalised + merged. Findings in both sources tagged `source: "both"`.
85
87
  11. **Render** — `writeReports()` produces `cve-report.html` (self-contained, inline CSS, no external assets) and `cve-report.doc` (same HTML with Office XML namespace meta tags so Word opens it natively). Default output dir: `./fad-checker-report/`.
86
88
 
@@ -129,9 +131,9 @@ The Maven keyspace and npm keyspace never collide — `:lodash` (Maven groupId-l
129
131
 
130
132
  - The CVE bundle from CVEProject is ~500 MB unpacked. We shell out to `curl + unzip` (Node built-in fallback to `fetch()` + system `unzip` / PowerShell `Expand-Archive`). The extracted JSON is deleted after the index is built.
131
133
  - The bundle ships as `cves.zip.zip` (a zip whose sole content is another zip). `extractZip()` recurses up to 3 levels.
132
- - `endoflife.date` API responses are cached locally for 7 days; Maven Central version lookups for 24 hours.
134
+ - `endoflife.date` API responses are cached locally for 7 days; Maven Central and npm registry version lookups for 24 hours.
133
135
  - **Persistent config**: `~/.fad-checker/config.json` (mode 0600) stores per-user state, currently the NVD API key. Set via `fad-checker --set-nvd-key <KEY>`.
134
- - **`--offline` umbrella flag**: skips every network call (CVE index download, OSV queries, NVD enrichment, endoflife.date lookups, Maven Central version queries, transitive POM fetches, retire.js scans). Falls back to whatever is already cached. Per-source variants (`--cve-offline`, `--no-osv`, `--no-nvd`, `--no-retire`) still work independently.
136
+ - **`--offline` umbrella flag**: skips every network call (CVE index download, OSV queries, NVD enrichment, endoflife.date lookups, Maven Central version queries, npm registry queries, transitive POM fetches, retire.js scans). Falls back to whatever is already cached. Per-source variants (`--cve-offline`, `--no-osv`, `--no-nvd`, `--no-retire`, `--no-js`) still work independently.
135
137
  - `snyk` is not a dependency — we shell out via `execFile`. `snyk` exits 1 when it finds vulnerabilities, which is expected (the JSON is still on stdout).
136
138
  - The cleaned POM is the union of every profile's deps. Counts will therefore be larger than the source POM. This is intentional — verify your reasoning before "reducing" them.
137
139
  - Unresolved `${…}` Maven variables are kept verbatim in the rewritten POM. `lib/cve-match.js` resolves them lazily via `resolveDepVersion()` when collecting deps for the scan. Deps that *still* can't be resolved (external BOM) are surfaced in chapter 0 as `unresolved-versions` warnings.
package/fad-checker.js CHANGED
@@ -464,6 +464,17 @@ async function runReportFlow(allPomMetadata, allPropsByPom, ecoFlags = {}) {
464
464
  catch (err) { console.warn(chalk.yellow("⚠️ Outdated check skipped:"), err.message); }
465
465
  }
466
466
 
467
+ // 4a. npm registry — deprecation (always, authoritative maintainer data) and
468
+ // outdated (gated by --all-libs like Maven Central). Covers npm deps and
469
+ // WebJars (Maven artifacts wrapping npm/bower libs), so it runs even in
470
+ // Maven-only mode. One fetch per package; no-ops when there are no targets.
471
+ try {
472
+ const { checkNpmRegistryDeps } = require("./lib/npm/registry");
473
+ const npmReg = await checkNpmRegistryDeps(resolved, { verbose, offline, allLibs: options.allLibs });
474
+ obsoleteResults = obsoleteResults.concat(npmReg.deprecated);
475
+ outdatedResults = outdatedResults.concat(npmReg.outdated);
476
+ } catch (err) { console.warn(chalk.yellow("⚠️ npm registry check skipped:"), err.message); }
477
+
467
478
  // Cross-section dedup: drop entries from outdated that already appear in EOL/Obsolete
468
479
  const eolKeys = new Set(eolResults.map(r => `${r.dep.groupId}:${r.dep.artifactId}`));
469
480
  const obsKeys = new Set(obsoleteResults.map(r => `${r.dep.groupId}:${r.dep.artifactId}`));
@@ -574,16 +585,19 @@ async function runReportFlow(allPomMetadata, allPropsByPom, ecoFlags = {}) {
574
585
  if (retireMatches.length > 10) console.log(` ... and ${retireMatches.length - 10} more (see report)`);
575
586
  }
576
587
 
588
+ // npm deps have no groupId; show them as "npm:name" rather than ":name".
589
+ const coordOf = d => d.ecosystem === "npm" ? `npm:${d.artifactId}` : `${d.groupId}:${d.artifactId}`;
590
+
577
591
  console.log(chalk.bold.cyan("\n 2. End-of-Life Frameworks"));
578
- for (const e of eolResults) console.log(` ${e.product.padEnd(20)} ${e.dep.groupId}:${e.dep.artifactId}:${e.dep.version} ${e.eol}`);
592
+ for (const e of eolResults) console.log(` ${e.product.padEnd(20)} ${coordOf(e.dep)}:${e.dep.version} ${e.eol}`);
579
593
  if (!eolResults.length) console.log(chalk.gray(" (none)"));
580
594
 
581
595
  console.log(chalk.bold.cyan("\n 3. Obsolete / Deprecated Libraries"));
582
- for (const o of obsoleteResults) console.log(` ${(o.severity || "info").padEnd(8)} ${o.dep.groupId}:${o.dep.artifactId}:${o.dep.version} → ${o.replacement || "n/a"}`);
596
+ for (const o of obsoleteResults) console.log(` ${(o.severity || "info").padEnd(8)} ${coordOf(o.dep)}:${o.dep.version} → ${o.replacement || "n/a"}`);
583
597
  if (!obsoleteResults.length) console.log(chalk.gray(" (none)"));
584
598
 
585
599
  console.log(chalk.bold.cyan("\n 4. Outdated Libraries"));
586
- for (const o of outdatedResults.slice(0, 20)) console.log(` ${o.dep.groupId}:${o.dep.artifactId} ${o.dep.version} → ${o.latest}`);
600
+ for (const o of outdatedResults.slice(0, 20)) console.log(` ${coordOf(o.dep)} ${o.dep.version} → ${o.latest}`);
587
601
  if (outdatedResults.length > 20) console.log(` ... and ${outdatedResults.length - 20} more`);
588
602
  if (!outdatedResults.length && options.allLibs) console.log(chalk.gray(" (none)"));
589
603
  if (!options.allLibs) console.log(chalk.gray(" (re-run with -a/--allLibs to query Maven Central)"));