@vyuhlabs/dxkit 2.0.1 → 2.2.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.
- package/CHANGELOG.md +223 -0
- package/README.md +21 -15
- package/dist/analyzers/bom/detailed.d.ts +26 -0
- package/dist/analyzers/bom/detailed.d.ts.map +1 -0
- package/dist/analyzers/bom/detailed.js +227 -0
- package/dist/analyzers/bom/detailed.js.map +1 -0
- package/dist/analyzers/bom/gather.d.ts +63 -0
- package/dist/analyzers/bom/gather.d.ts.map +1 -0
- package/dist/analyzers/bom/gather.js +229 -0
- package/dist/analyzers/bom/gather.js.map +1 -0
- package/dist/analyzers/bom/index.d.ts +23 -0
- package/dist/analyzers/bom/index.d.ts.map +1 -0
- package/dist/analyzers/bom/index.js +220 -0
- package/dist/analyzers/bom/index.js.map +1 -0
- package/dist/analyzers/bom/types.d.ts +91 -0
- package/dist/analyzers/bom/types.d.ts.map +1 -0
- package/dist/analyzers/bom/types.js +3 -0
- package/dist/analyzers/bom/types.js.map +1 -0
- package/dist/analyzers/licenses/detailed.d.ts +30 -0
- package/dist/analyzers/licenses/detailed.d.ts.map +1 -0
- package/dist/analyzers/licenses/detailed.js +194 -0
- package/dist/analyzers/licenses/detailed.js.map +1 -0
- package/dist/analyzers/licenses/gather.d.ts +15 -0
- package/dist/analyzers/licenses/gather.d.ts.map +1 -0
- package/dist/analyzers/licenses/gather.js +24 -0
- package/dist/analyzers/licenses/gather.js.map +1 -0
- package/dist/analyzers/licenses/index.d.ts +21 -0
- package/dist/analyzers/licenses/index.d.ts.map +1 -0
- package/dist/analyzers/licenses/index.js +146 -0
- package/dist/analyzers/licenses/index.js.map +1 -0
- package/dist/analyzers/licenses/types.d.ts +30 -0
- package/dist/analyzers/licenses/types.d.ts.map +1 -0
- package/dist/analyzers/licenses/types.js +13 -0
- package/dist/analyzers/licenses/types.js.map +1 -0
- package/dist/analyzers/security/detailed.d.ts +0 -3
- package/dist/analyzers/security/detailed.d.ts.map +1 -1
- package/dist/analyzers/security/detailed.js +37 -6
- package/dist/analyzers/security/detailed.js.map +1 -1
- package/dist/analyzers/security/gather.d.ts.map +1 -1
- package/dist/analyzers/security/gather.js +2 -0
- package/dist/analyzers/security/gather.js.map +1 -1
- package/dist/analyzers/security/index.d.ts.map +1 -1
- package/dist/analyzers/security/index.js +53 -14
- package/dist/analyzers/security/index.js.map +1 -1
- package/dist/analyzers/security/types.d.ts +5 -0
- package/dist/analyzers/security/types.d.ts.map +1 -1
- package/dist/analyzers/security/types.js +0 -3
- package/dist/analyzers/security/types.js.map +1 -1
- package/dist/analyzers/tools/osv.d.ts +49 -5
- package/dist/analyzers/tools/osv.d.ts.map +1 -1
- package/dist/analyzers/tools/osv.js +99 -17
- package/dist/analyzers/tools/osv.js.map +1 -1
- package/dist/analyzers/tools/runner.d.ts +11 -0
- package/dist/analyzers/tools/runner.d.ts.map +1 -1
- package/dist/analyzers/tools/runner.js +54 -0
- package/dist/analyzers/tools/runner.js.map +1 -1
- package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
- package/dist/analyzers/tools/tool-registry.js +77 -0
- package/dist/analyzers/tools/tool-registry.js.map +1 -1
- package/dist/analyzers/xlsx/bom.d.ts +27 -0
- package/dist/analyzers/xlsx/bom.d.ts.map +1 -0
- package/dist/analyzers/xlsx/bom.js +141 -0
- package/dist/analyzers/xlsx/bom.js.map +1 -0
- package/dist/analyzers/xlsx/index.d.ts +27 -0
- package/dist/analyzers/xlsx/index.d.ts.map +1 -0
- package/dist/analyzers/xlsx/index.js +92 -0
- package/dist/analyzers/xlsx/index.js.map +1 -0
- package/dist/analyzers/xlsx/licenses.d.ts +40 -0
- package/dist/analyzers/xlsx/licenses.d.ts.map +1 -0
- package/dist/analyzers/xlsx/licenses.js +140 -0
- package/dist/analyzers/xlsx/licenses.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +178 -1
- package/dist/cli.js.map +1 -1
- package/dist/languages/capabilities/descriptors.d.ts +4 -1
- package/dist/languages/capabilities/descriptors.d.ts.map +1 -1
- package/dist/languages/capabilities/descriptors.js +20 -1
- package/dist/languages/capabilities/descriptors.js.map +1 -1
- package/dist/languages/capabilities/types.d.ts +60 -3
- package/dist/languages/capabilities/types.d.ts.map +1 -1
- package/dist/languages/csharp.d.ts +48 -0
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +418 -33
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts +35 -0
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +367 -26
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/python.d.ts +49 -0
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +372 -11
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/rust.d.ts +28 -0
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +287 -28
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +2 -1
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts +17 -0
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +358 -1
- package/dist/languages/typescript.js.map +1 -1
- package/package.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,229 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.2.0] - 2026-04-23
|
|
11
|
+
|
|
12
|
+
Minor release adding Snyk-style top-level dep attribution across every
|
|
13
|
+
language pack. Answers "which direct manifest dep do I upgrade to fix
|
|
14
|
+
the most advisories" alongside the existing per-leaf-package reporting.
|
|
15
|
+
Drop-in upgrade — additive `topLevelDep?: string[]` field, no schema
|
|
16
|
+
bump required.
|
|
17
|
+
|
|
18
|
+
### Added — top-level dep attribution (Phase 10h.4)
|
|
19
|
+
|
|
20
|
+
- **`DepVulnFinding.topLevelDep?: string[]`** — per-advisory list of
|
|
21
|
+
root manifest entries (direct + dev deps) that transitively pull the
|
|
22
|
+
vulnerable package. Coarse name-level attribution (unions across
|
|
23
|
+
multiple parents when the package is reachable from more than one
|
|
24
|
+
top-level). Enables Snyk-style grouping: one advisory against
|
|
25
|
+
`tar@7.5.9` surfaces as "under `@loopback/cli`" rather than just
|
|
26
|
+
"tar has a CVE".
|
|
27
|
+
|
|
28
|
+
- **TypeScript pack** — BFS over `package-lock.json` (v2/v3) from
|
|
29
|
+
each root `dependencies` / `devDependencies` entry. Pure parser
|
|
30
|
+
`buildTsTopLevelDepIndex` unit-tested; benchmark on
|
|
31
|
+
`vyuhlabs-platform`: 71/71 findings attributed across 31 vulnerable
|
|
32
|
+
packages, `@loopback/cli` rollup = 29 advisories (matches Snyk UI).
|
|
33
|
+
|
|
34
|
+
- **Python pack** — BFS over `pip show` graph from packages with empty
|
|
35
|
+
`Required-by`. Pure parsers `parsePipShowOutput` +
|
|
36
|
+
`buildPyTopLevelDepIndex`. Venv detection now includes poetry
|
|
37
|
+
(`poetry env info --path`), pipenv (`pipenv --venv`), and
|
|
38
|
+
`$VIRTUAL_ENV` env var alongside the existing `.venv`/`venv` fast
|
|
39
|
+
path — poetry with default `virtualenvs.in-project = false` now
|
|
40
|
+
resolves.
|
|
41
|
+
|
|
42
|
+
- **Go pack** — BFS over `go mod graph` output, with `go.mod`'s
|
|
43
|
+
`// indirect` markers filtering the seed set so only user-declared
|
|
44
|
+
direct deps become top-levels. Pure parsers `parseGoModDirectDeps` +
|
|
45
|
+
`buildGoTopLevelDepIndex`.
|
|
46
|
+
|
|
47
|
+
- **Rust pack** — BFS over `cargo metadata --format-version 1` resolve
|
|
48
|
+
graph from each direct dep of `resolve.root`. Pure parser
|
|
49
|
+
`buildRustTopLevelDepIndex`; maps package ids → names, collapses
|
|
50
|
+
version variants.
|
|
51
|
+
|
|
52
|
+
- **C# pack** — **two-part expansion**. First,
|
|
53
|
+
`dotnet list package --vulnerable` now uses `--include-transitive`,
|
|
54
|
+
so transitive vulns (previously invisible) are surfaced. Second,
|
|
55
|
+
attribution comes from walking `obj/project.assets.json` — pure
|
|
56
|
+
parsers `parseProjectAssetsJson` + `buildCsharpTopLevelDepIndex`.
|
|
57
|
+
Direct findings carry self-attribution; transitive findings gain
|
|
58
|
+
`topLevelDep` from the assets-json graph. Degrades gracefully when
|
|
59
|
+
the lockfile is absent (user hasn't run `dotnet restore`).
|
|
60
|
+
|
|
61
|
+
### Added — bom render surfaces top-level grouping
|
|
62
|
+
|
|
63
|
+
- **`BomReport.summary.byTopLevelDep: Record<string, BomTopLevelRollup>`**
|
|
64
|
+
where `BomTopLevelRollup = { advisoryCount, maxSeverity, packages[] }`.
|
|
65
|
+
Multi-parent advisories increment counters for each top-level they
|
|
66
|
+
list, matching Snyk's rollup semantics.
|
|
67
|
+
|
|
68
|
+
- **Markdown "Top-Level Dep Groups" section** in `bom-<date>.md` —
|
|
69
|
+
sorted by severity then advisory count. First row is the single
|
|
70
|
+
upgrade that resolves the most critical/highest-volume issues. Caps
|
|
71
|
+
at 30 top-levels, packages list truncated at 8 with "+N more".
|
|
72
|
+
|
|
73
|
+
- **Xlsx col 12 annotation** — each advisory line gains
|
|
74
|
+
` via <parent>` (single top-level) or ` via <parent> (+N more)`
|
|
75
|
+
(multi-parent). Reviewer sees upgrade guidance directly in the
|
|
76
|
+
spreadsheet cell. No suffix when `topLevelDep` is unset.
|
|
77
|
+
|
|
78
|
+
### Fixed — TS dep-vuln finding dedupe
|
|
79
|
+
|
|
80
|
+
- `gatherTsDepVulnsResult` now de-duplicates findings by
|
|
81
|
+
`(package, installedVersion, id)`. npm-audit inlines the same
|
|
82
|
+
advisory on every consumer's `via[]` across the vulnerability tree
|
|
83
|
+
(e.g. minimatch's ReDoS appearing on `@loopback/cli`, `glob-parent`,
|
|
84
|
+
`picomatch` simultaneously); the advisory-emission loop previously
|
|
85
|
+
pushed N copies of one logical finding. Platform count 94 → 71,
|
|
86
|
+
14 distinct dupe pairs → 0. Pre-existing from 2.1.0; caught during
|
|
87
|
+
10h.4 evaluation.
|
|
88
|
+
|
|
89
|
+
### Notes
|
|
90
|
+
|
|
91
|
+
- Every pack degrades gracefully when its dep-graph source is missing:
|
|
92
|
+
TS without `package-lock.json`, Python without a venv, Go without
|
|
93
|
+
`go.mod`, Rust without `cargo metadata`, C# without
|
|
94
|
+
`obj/project.assets.json`. Findings still emit; `topLevelDep` stays
|
|
95
|
+
unset.
|
|
96
|
+
|
|
97
|
+
- Release validated against `vyuhlabs-platform` TypeScript benchmark.
|
|
98
|
+
Python/Go/Rust/C# packs exercised via fixture-based unit tests
|
|
99
|
+
(+53 new tests across the 4 non-TS language test files); real-world
|
|
100
|
+
validation lands with 2.3.0's cross-ecosystem benchmark fixtures.
|
|
101
|
+
|
|
102
|
+
## [2.1.0] - 2026-04-23
|
|
103
|
+
|
|
104
|
+
Minor release adding two new analyzers and a shared XLSX converter.
|
|
105
|
+
Schema-compatible with 2.0.x for all pre-existing reports; introduces
|
|
106
|
+
two new report kinds (`licenses`, `bom`) and a schema v11 → v12 bump on
|
|
107
|
+
the detailed security report. Drop-in upgrade — no existing consumer
|
|
108
|
+
breaks.
|
|
109
|
+
|
|
110
|
+
### Added — license inventory
|
|
111
|
+
|
|
112
|
+
- **`vyuh-dxkit licenses [path]`** — per-pack dependency license
|
|
113
|
+
inventory across TypeScript (license-checker-rseidelsohn), Python
|
|
114
|
+
(pip-licenses), Go (go-licenses), Rust (cargo-license), and C#
|
|
115
|
+
(nuget-license). Populates 11 fields per package (name, version,
|
|
116
|
+
description, license type, license text, source URL, supplier,
|
|
117
|
+
release date, etc.). Writes `.ai/reports/licenses-<date>.md`; with
|
|
118
|
+
`--detailed` also a risk-categorized JSON + markdown flagging
|
|
119
|
+
strong-copyleft, weak-copyleft, unknown-license, missing-attribution
|
|
120
|
+
packages. TypeScript provider normalizes source URLs through
|
|
121
|
+
`hosted-git-info` so `git+`/SCP/RFC-SSH variants collapse to canonical
|
|
122
|
+
HTTPS.
|
|
123
|
+
- **`vyuh-dxkit bom [path]`** — Bill of Materials joining `licenses`
|
|
124
|
+
with dependency vulnerabilities on `(package, version)`. One row per
|
|
125
|
+
installed package-version with license metadata (cols 1-9, 15 per
|
|
126
|
+
customer spec) AND per-package vulnerability rollup: max severity
|
|
127
|
+
(col 11), per-advisory list with CVSS scores (col 12), and derived
|
|
128
|
+
Tier-1 resolution proposal (col 13 — "Upgrade X to Y" when every
|
|
129
|
+
advisory has a fixedVersion, "Upgrade <parent> (transitive fix)" when
|
|
130
|
+
the fix is in a parent dep, "No fix available" otherwise). Detailed
|
|
131
|
+
mode (`--detailed`) emits a risk-review markdown with 6 triage
|
|
132
|
+
buckets (critical/high × no-fix/actionable, medium, low, license-
|
|
133
|
+
scanner-gap). `--xlsx` / `to-xlsx` produce the 15-column workbook
|
|
134
|
+
the customer's spreadsheet workflow expects, byte-identical headers.
|
|
135
|
+
- **`vyuh-dxkit to-xlsx <json>`** — shared converter. Reads any
|
|
136
|
+
licenses or bom detailed JSON and emits the canonical 15-col XLSX.
|
|
137
|
+
Lets downstream tooling stash JSON and render on demand without re-
|
|
138
|
+
running the analyzer.
|
|
139
|
+
|
|
140
|
+
### Added — dependency-vulnerability per-advisory detail
|
|
141
|
+
|
|
142
|
+
- Every language pack's `depVulns` provider now populates
|
|
143
|
+
`DepVulnFinding[]` alongside the existing per-severity counts. Counts
|
|
144
|
+
remain per-package (for `vulnerabilities` command parity); findings
|
|
145
|
+
are per-advisory with id (GHSA/CVE/PYSEC/GO/RUSTSEC), installed +
|
|
146
|
+
fixed versions, CVSS score, aliases, summary, references, and tool
|
|
147
|
+
attribution. `gatherDepVulns` forwards findings into
|
|
148
|
+
`SecurityReport.summary.dependencies.findings` so the
|
|
149
|
+
`vulnerabilities --detailed` command renders per-advisory inventory
|
|
150
|
+
(previously: counts only).
|
|
151
|
+
- `DepVulnFinding` extended with nine optional fields for tier-layered
|
|
152
|
+
enrichment: `tool` (denormalized producer, renamed from unused
|
|
153
|
+
`source`), `cvssScore`, `upgradeAdvice`, `reachable`, `epssScore`,
|
|
154
|
+
`kev`, `riskScore`, `breakingUpgrade`, `aliases`, `summary`,
|
|
155
|
+
`references`. Per-pack Tier-1 providers populate what their native
|
|
156
|
+
tools emit; Tier-2/3/4 enrichment lands in later 10h sub-phases.
|
|
157
|
+
- Cross-pack OSV enhancement: `enrichOsv` (renamed from
|
|
158
|
+
`enrichSeverities`) now returns `{severity, cvssScore}` pairs, and
|
|
159
|
+
a new `resolveCvssScores` helper does batched alias-fallback
|
|
160
|
+
lookups. Fills the CVSS gap for GO-\* records (bulk of which carry
|
|
161
|
+
no severity but whose CVE aliases do) and PYSEC-\* records. TS pack
|
|
162
|
+
is a no-op via this path (npm-audit already ships CVSS at ~100%);
|
|
163
|
+
Python cvssScore coverage jumped from 0% → 100% on the fixture,
|
|
164
|
+
Go from 0% → 55% on vyuhlabs/Tickit.
|
|
165
|
+
- **Go pack parser fix** — `govulncheck -json` emits pretty-printed
|
|
166
|
+
multi-line JSON, not single-line ndjson. Previous `split('\n')`
|
|
167
|
+
parser silently failed on every invocation; new balanced-brace
|
|
168
|
+
`parseJsonStream` helper in `runner.ts` handles both shapes and
|
|
169
|
+
string-literal escapes. Reusable for any future tool that
|
|
170
|
+
pretty-prints.
|
|
171
|
+
- **Python pack manifest gating** — previously `pip-audit` ran with
|
|
172
|
+
no project context and silently scanned dxkit's own graphify-venv.
|
|
173
|
+
Now routes by manifest: `pip-audit <cwd>` for pyproject.toml/setup.py
|
|
174
|
+
projects, `pip-audit -r requirements.txt` for requirements projects,
|
|
175
|
+
null otherwise. Corrected platform audit: 97 → 94 dep vulns (3
|
|
176
|
+
phantom graphify-venv pip findings removed).
|
|
177
|
+
|
|
178
|
+
### Added — tool registry
|
|
179
|
+
|
|
180
|
+
- TypeScript pack: `license-checker-rseidelsohn` (license inventory)
|
|
181
|
+
- Python pack: `pip-licenses` (license inventory)
|
|
182
|
+
- Go pack: `go-licenses` (license inventory, `go install golang.org/...`)
|
|
183
|
+
- Rust pack: `cargo-license` (license inventory, `cargo install`)
|
|
184
|
+
- C# pack: `nuget-license` (license inventory, `dotnet tool install`)
|
|
185
|
+
|
|
186
|
+
All bundled into per-pack provider commits so `findTool` + provider
|
|
187
|
+
invocation land together (CLAUDE.md rule 1).
|
|
188
|
+
|
|
189
|
+
### Changed
|
|
190
|
+
|
|
191
|
+
- **Vulnerability report labelling** — Executive Summary now cleanly
|
|
192
|
+
separates "Code Findings" (your team patches source) from
|
|
193
|
+
"Dependency Vulnerabilities" (upgrade the dep) into two tables with
|
|
194
|
+
a combined total. Previously a single table labelled just "Severity
|
|
195
|
+
/ Count" implied dep vulns were included, which they weren't. The
|
|
196
|
+
shallow report also now renders a worst-first per-advisory dep-vuln
|
|
197
|
+
table (50-row cap), so `vulnerabilities` without `--detailed` is
|
|
198
|
+
already actionable.
|
|
199
|
+
- **Security detailed schema** — bumps from `"11"` → `"12"` for the
|
|
200
|
+
new `summary.dependencies.findings: DepVulnFinding[]` field in the
|
|
201
|
+
JSON output. Additive — consumers reading just the old keys stay
|
|
202
|
+
compatible.
|
|
203
|
+
- **`DepVulnFinding.source` repurposed to `DepVulnFinding.tool`**.
|
|
204
|
+
The former `'osv.dev' | 'tool-default' | 'tool-reported'` enum was
|
|
205
|
+
dead code (declared, never written or read). Field now holds the
|
|
206
|
+
producer tool name (`npm-audit` / `pip-audit` / `govulncheck` /
|
|
207
|
+
`cargo-audit` / `dotnet-vulnerable`) so per-finding attribution
|
|
208
|
+
survives merges across multiple providers.
|
|
209
|
+
|
|
210
|
+
### Fixed
|
|
211
|
+
|
|
212
|
+
- **npm-audit `fixAvailable` misinterpretation** — `fix.name` is the
|
|
213
|
+
top-level upgrade target, not the vulnerable package itself. Prior
|
|
214
|
+
code blindly assigned `fix.version` as `fixedVersion` on every
|
|
215
|
+
advisory, producing absurd output like "uuid@13.0.0 → Upgrade to
|
|
216
|
+
3.2.1". Now branches on `fix.name === pkgName`: direct fix sets
|
|
217
|
+
`fixedVersion`; transitive fix sets `upgradeAdvice` with parent-
|
|
218
|
+
package guidance ("Upgrade @loopback/cli to 5.0.0 [major]
|
|
219
|
+
(transitive fix)"). Surfaced ~20 false positives on platform audit
|
|
220
|
+
covering uuid/octokit/tar/undici/underscore.
|
|
221
|
+
- **bom xlsx col 11/12/13 fill on non-vulnerable rows** — previously
|
|
222
|
+
blank, creating "scanned-clean vs not-scanned" ambiguity. Now fills
|
|
223
|
+
"None" / "No action required" so reviewers see at a glance which
|
|
224
|
+
rows dxkit actually processed.
|
|
225
|
+
|
|
226
|
+
### Runtime dependencies added
|
|
227
|
+
|
|
228
|
+
- `exceljs ^4.4.0` — XLSX writer. Adds ~80 transitive deps (bumps
|
|
229
|
+
dxkit's own license-checker count 242 → ~325).
|
|
230
|
+
- `hosted-git-info ^9.0.2` + `@types/hosted-git-info ^3.0.5` — URL
|
|
231
|
+
canonicalisation (source URL column of licenses/bom).
|
|
232
|
+
|
|
10
233
|
## [2.0.1] - 2026-04-22
|
|
11
234
|
|
|
12
235
|
Patch release following the 2.0.0 smoke-test. No API or schema changes —
|
package/README.md
CHANGED
|
@@ -32,25 +32,31 @@ The two modes are complementary. The analyzers run anywhere; the scaffolder writ
|
|
|
32
32
|
|
|
33
33
|
## Analyzer CLI (`vyuh-dxkit <command>`)
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Seven deterministic analyzers. Each emits a markdown report to `.ai/reports/` and optional structured JSON.
|
|
36
36
|
|
|
37
|
-
| Command | What it does
|
|
38
|
-
| ----------------- |
|
|
39
|
-
| `health` | 6-dimension score (Testing, Quality, Docs, Security, Maint, DX)
|
|
40
|
-
| `vulnerabilities` | gitleaks + semgrep +
|
|
41
|
-
| `test-gaps` | Coverage artifact → import-graph → filename (strongest wins)
|
|
42
|
-
| `quality` | Slop score + jscpd duplication + eslint/ruff + hygiene
|
|
43
|
-
| `dev-report` | Commits, contributors, hot files, velocity, conventional %
|
|
37
|
+
| Command | What it does | Runtime | Output |
|
|
38
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------ |
|
|
39
|
+
| `health` | 6-dimension score (Testing, Quality, Docs, Security, Maint, DX) | 10–20s | `.ai/reports/health-audit-<date>.md` |
|
|
40
|
+
| `vulnerabilities` | gitleaks + semgrep + per-pack dep-audit (per-advisory detail in `--detailed`) | 5–30s | `.ai/reports/vulnerability-scan-<date>.md` |
|
|
41
|
+
| `test-gaps` | Coverage artifact → import-graph → filename (strongest wins) | <1s | `.ai/reports/test-gaps-<date>.md` |
|
|
42
|
+
| `quality` | Slop score + jscpd duplication + eslint/ruff + hygiene | 5–15s | `.ai/reports/quality-review-<date>.md` |
|
|
43
|
+
| `dev-report` | Commits, contributors, hot files, velocity, conventional % | <1s | `.ai/reports/developer-report-<date>.md` |
|
|
44
|
+
| `licenses` | Dependency license inventory across every active pack (TS/Python/Go/Rust/C#) | 5–20s | `.ai/reports/licenses-<date>.md` |
|
|
45
|
+
| `bom` | **Bill of Materials** — joins licenses + vulnerabilities per package, 15-col XLSX; groups advisories by top-level manifest dep (Snyk-style) | 10–40s | `.ai/reports/bom-<date>.{md,xlsx}` |
|
|
46
|
+
|
|
47
|
+
Plus a converter: `vyuh-dxkit to-xlsx <json-file>` renders any `licenses` or `bom` detailed JSON as the canonical 15-column XLSX.
|
|
44
48
|
|
|
45
49
|
### Flags (apply to all analyzer commands)
|
|
46
50
|
|
|
47
|
-
| Flag | Effect
|
|
48
|
-
| ---------------- |
|
|
49
|
-
| `--detailed` | Also writes `<name>-detailed.md` + `.json` with evidence + ranked remediation actions
|
|
50
|
-
| `--json` | Emit pure JSON on stdout. Logs go to stderr so pipes stay clean
|
|
51
|
-
| `--verbose` | Print per-tool timing to stderr
|
|
52
|
-
| `--no-save` | Skip writing markdown; useful with `--json`
|
|
53
|
-
| `--
|
|
51
|
+
| Flag | Effect |
|
|
52
|
+
| ---------------- | -------------------------------------------------------------------------------------- |
|
|
53
|
+
| `--detailed` | Also writes `<name>-detailed.md` + `.json` with evidence + ranked remediation actions |
|
|
54
|
+
| `--json` | Emit pure JSON on stdout. Logs go to stderr so pipes stay clean |
|
|
55
|
+
| `--verbose` | Print per-tool timing to stderr |
|
|
56
|
+
| `--no-save` | Skip writing markdown; useful with `--json` |
|
|
57
|
+
| `--xlsx` | (`licenses`, `bom` only) Also write 15-col `.xlsx` — drop-in for spreadsheet workflows |
|
|
58
|
+
| `-o <file>` | (`licenses`, `bom`, `to-xlsx`) Override output path for xlsx / converted file |
|
|
59
|
+
| `--since <date>` | (`dev-report` only) Analyze commits on or after `YYYY-MM-DD` |
|
|
54
60
|
|
|
55
61
|
### Detailed mode — evidence + ranked fixes
|
|
56
62
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM analyzer — detailed report.
|
|
3
|
+
*
|
|
4
|
+
* Extends the base BomReport with risk-categorized buckets so the
|
|
5
|
+
* reader can triage the inventory by what needs action first.
|
|
6
|
+
* Mirrors the licenses/detailed pattern (10h.2.2) but the categories
|
|
7
|
+
* are vuln-driven rather than license-driven, since BOM exists
|
|
8
|
+
* primarily to surface upgrade work.
|
|
9
|
+
*/
|
|
10
|
+
import type { BomEntry, BomReport, BomSeverity } from './types';
|
|
11
|
+
export interface BomRiskCategory {
|
|
12
|
+
/** Severity tier for ordering. */
|
|
13
|
+
readonly priority: BomSeverity;
|
|
14
|
+
/** Stable category key — for programmatic filtering / dashboards. */
|
|
15
|
+
readonly id: 'critical-no-fix' | 'critical-actionable' | 'high-no-fix' | 'high-actionable' | 'medium-vulns' | 'low-vulns' | 'vuln-only-license-gap';
|
|
16
|
+
readonly title: string;
|
|
17
|
+
readonly rationale: string;
|
|
18
|
+
readonly recommendation: string;
|
|
19
|
+
readonly affected: ReadonlyArray<BomEntry>;
|
|
20
|
+
}
|
|
21
|
+
export interface BomDetailedReport extends BomReport {
|
|
22
|
+
riskCategories: ReadonlyArray<BomRiskCategory>;
|
|
23
|
+
}
|
|
24
|
+
export declare function buildBomDetailed(report: BomReport): BomDetailedReport;
|
|
25
|
+
export declare function formatBomDetailedMarkdown(detailed: BomDetailedReport, elapsed: string): string;
|
|
26
|
+
//# sourceMappingURL=detailed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detailed.d.ts","sourceRoot":"","sources":["../../../src/analyzers/bom/detailed.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,EACP,iBAAiB,GACjB,qBAAqB,GACrB,aAAa,GACb,iBAAiB,GACjB,cAAc,GACd,WAAW,GACX,uBAAuB,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,cAAc,EAAE,aAAa,CAAC,eAAe,CAAC,CAAC;CAChD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,iBAAiB,CA8HrE;AASD,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA6G9F"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* BOM analyzer — detailed report.
|
|
4
|
+
*
|
|
5
|
+
* Extends the base BomReport with risk-categorized buckets so the
|
|
6
|
+
* reader can triage the inventory by what needs action first.
|
|
7
|
+
* Mirrors the licenses/detailed pattern (10h.2.2) but the categories
|
|
8
|
+
* are vuln-driven rather than license-driven, since BOM exists
|
|
9
|
+
* primarily to surface upgrade work.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.buildBomDetailed = buildBomDetailed;
|
|
13
|
+
exports.formatBomDetailedMarkdown = formatBomDetailedMarkdown;
|
|
14
|
+
function buildBomDetailed(report) {
|
|
15
|
+
const categories = [];
|
|
16
|
+
// Buckets keyed by (severity, has-fix). The `actionable` axis matters
|
|
17
|
+
// because "critical with no fix" is qualitatively different from
|
|
18
|
+
// "critical with a one-line upgrade" — same severity, different
|
|
19
|
+
// remediation cost.
|
|
20
|
+
const buckets = new Map();
|
|
21
|
+
for (const e of report.entries) {
|
|
22
|
+
if (!e.maxSeverity)
|
|
23
|
+
continue;
|
|
24
|
+
const actionable = e.upgradeAdvice.startsWith('PROPOSAL:');
|
|
25
|
+
const key = `${e.maxSeverity}|${actionable ? 'fix' : 'nofix'}`;
|
|
26
|
+
const arr = buckets.get(key) ?? [];
|
|
27
|
+
arr.push(e);
|
|
28
|
+
buckets.set(key, arr);
|
|
29
|
+
}
|
|
30
|
+
const criticalNoFix = buckets.get('critical|nofix') ?? [];
|
|
31
|
+
if (criticalNoFix.length > 0) {
|
|
32
|
+
categories.push({
|
|
33
|
+
priority: 'critical',
|
|
34
|
+
id: 'critical-no-fix',
|
|
35
|
+
title: 'Critical vulns with no published fix',
|
|
36
|
+
rationale: 'These packages have one or more critical-severity advisories ' +
|
|
37
|
+
'with no upstream fix version. Upgrading the dep does not resolve ' +
|
|
38
|
+
'them — replacement or vendor pressure is the only remediation path.',
|
|
39
|
+
recommendation: 'Evaluate replacement packages, contact maintainers, or accept ' +
|
|
40
|
+
'and document the risk. Do not ship to production untreated.',
|
|
41
|
+
affected: criticalNoFix,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
const criticalActionable = buckets.get('critical|fix') ?? [];
|
|
45
|
+
if (criticalActionable.length > 0) {
|
|
46
|
+
categories.push({
|
|
47
|
+
priority: 'critical',
|
|
48
|
+
id: 'critical-actionable',
|
|
49
|
+
title: 'Critical vulns with an upgrade path',
|
|
50
|
+
rationale: 'These packages have critical advisories AND a published fixed ' +
|
|
51
|
+
'version. The upgrade is the highest-leverage security action ' +
|
|
52
|
+
'available for this codebase right now.',
|
|
53
|
+
recommendation: 'Schedule the upgrades immediately. Prefer the Tier-1 PROPOSAL ' +
|
|
54
|
+
'target unless a major-version bump introduces compat risk.',
|
|
55
|
+
affected: criticalActionable,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const highNoFix = buckets.get('high|nofix') ?? [];
|
|
59
|
+
if (highNoFix.length > 0) {
|
|
60
|
+
categories.push({
|
|
61
|
+
priority: 'high',
|
|
62
|
+
id: 'high-no-fix',
|
|
63
|
+
title: 'High-severity vulns with no published fix',
|
|
64
|
+
rationale: 'High-severity advisories without an upstream fix. Less urgent ' +
|
|
65
|
+
'than critical-no-fix but still warrants a documented decision.',
|
|
66
|
+
recommendation: 'Plan replacement evaluation alongside critical-no-fix items. ' +
|
|
67
|
+
'Track the upstream advisory for fix availability.',
|
|
68
|
+
affected: highNoFix,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const highActionable = buckets.get('high|fix') ?? [];
|
|
72
|
+
if (highActionable.length > 0) {
|
|
73
|
+
categories.push({
|
|
74
|
+
priority: 'high',
|
|
75
|
+
id: 'high-actionable',
|
|
76
|
+
title: 'High-severity vulns with an upgrade path',
|
|
77
|
+
rationale: 'High-severity advisories with a published fixed version.',
|
|
78
|
+
recommendation: 'Schedule upgrades within the next sprint.',
|
|
79
|
+
affected: highActionable,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const mediumVulns = [
|
|
83
|
+
...(buckets.get('medium|fix') ?? []),
|
|
84
|
+
...(buckets.get('medium|nofix') ?? []),
|
|
85
|
+
];
|
|
86
|
+
if (mediumVulns.length > 0) {
|
|
87
|
+
categories.push({
|
|
88
|
+
priority: 'medium',
|
|
89
|
+
id: 'medium-vulns',
|
|
90
|
+
title: 'Medium-severity vulnerabilities',
|
|
91
|
+
rationale: 'Medium-severity advisories. Plan into routine dep maintenance.',
|
|
92
|
+
recommendation: 'Batch into a recurring "dependency upgrade week" cadence. ' +
|
|
93
|
+
'Watch for severity bumps — OSV/CVSS revisions can promote ' +
|
|
94
|
+
'these into the high bucket.',
|
|
95
|
+
affected: mediumVulns,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
const lowVulns = [...(buckets.get('low|fix') ?? []), ...(buckets.get('low|nofix') ?? [])];
|
|
99
|
+
if (lowVulns.length > 0) {
|
|
100
|
+
categories.push({
|
|
101
|
+
priority: 'low',
|
|
102
|
+
id: 'low-vulns',
|
|
103
|
+
title: 'Low-severity vulnerabilities',
|
|
104
|
+
rationale: 'Low-severity advisories. Track but not blocking.',
|
|
105
|
+
recommendation: 'Bundle into routine maintenance; no urgency.',
|
|
106
|
+
affected: lowVulns,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
const vulnOnly = report.entries.filter((e) => !e.joinedFromBoth);
|
|
110
|
+
if (vulnOnly.length > 0) {
|
|
111
|
+
categories.push({
|
|
112
|
+
priority: 'medium',
|
|
113
|
+
id: 'vuln-only-license-gap',
|
|
114
|
+
title: 'License-scanner gap (vuln-only entries)',
|
|
115
|
+
rationale: 'These packages were reported by a vulnerability scanner but ' +
|
|
116
|
+
'not by the license scanner. The license is shown as UNKNOWN; ' +
|
|
117
|
+
'the most likely cause is a workspace / sub-package the license ' +
|
|
118
|
+
'tool did not traverse.',
|
|
119
|
+
recommendation: 'Verify the licenses manually before shipping. If the package ' +
|
|
120
|
+
'lives in a workspace, surface it in the root manifest or use ' +
|
|
121
|
+
'the workspace-aware license tool flag.',
|
|
122
|
+
affected: vulnOnly,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return { ...report, riskCategories: categories };
|
|
126
|
+
}
|
|
127
|
+
const SEV_LABEL = {
|
|
128
|
+
critical: 'CRITICAL',
|
|
129
|
+
high: 'HIGH',
|
|
130
|
+
medium: 'MEDIUM',
|
|
131
|
+
low: 'LOW',
|
|
132
|
+
};
|
|
133
|
+
function formatBomDetailedMarkdown(detailed, elapsed) {
|
|
134
|
+
const L = [];
|
|
135
|
+
const s = detailed.summary;
|
|
136
|
+
L.push('# Bill of Materials (BOM) — Detailed');
|
|
137
|
+
L.push('');
|
|
138
|
+
L.push(`**Date:** ${detailed.analyzedAt.slice(0, 10)}`);
|
|
139
|
+
L.push(`**Repository:** ${detailed.repo}`);
|
|
140
|
+
L.push(`**Branch:** ${detailed.branch} (${detailed.commitSha})`);
|
|
141
|
+
L.push(`**Schema version:** ${detailed.schemaVersion}`);
|
|
142
|
+
L.push('');
|
|
143
|
+
L.push('---');
|
|
144
|
+
L.push('');
|
|
145
|
+
L.push('## Summary');
|
|
146
|
+
L.push('');
|
|
147
|
+
L.push(`- **Total packages:** ${s.totalPackages}`);
|
|
148
|
+
L.push(`- **Vulnerable packages:** ${s.vulnerablePackages}`);
|
|
149
|
+
L.push(`- **Total advisories:** ${s.totalAdvisories} (one package can have many)`);
|
|
150
|
+
L.push(`- **Actionable upgrades (Tier-1 proposals):** ${s.actionableVulns}`);
|
|
151
|
+
if (s.vulnOnlyPackages > 0) {
|
|
152
|
+
L.push(`- **Vuln-only entries (license gap):** ${s.vulnOnlyPackages}`);
|
|
153
|
+
}
|
|
154
|
+
L.push('');
|
|
155
|
+
L.push(`> Reconciles with \`vyuh-dxkit vulnerabilities\`: that command counts ` +
|
|
156
|
+
`per-advisory (${s.totalAdvisories}); bom collapses per-package ` +
|
|
157
|
+
`(${s.vulnerablePackages}) so each xlsx row is one upgrade decision.`);
|
|
158
|
+
L.push('');
|
|
159
|
+
L.push('---');
|
|
160
|
+
L.push('');
|
|
161
|
+
L.push('## Risk Review');
|
|
162
|
+
L.push('');
|
|
163
|
+
if (detailed.riskCategories.length === 0) {
|
|
164
|
+
L.push('No vulnerable packages — nothing to triage.');
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
for (const cat of detailed.riskCategories) {
|
|
168
|
+
L.push(`### ${SEV_LABEL[cat.priority]}: ${cat.title} (${cat.affected.length})`);
|
|
169
|
+
L.push('');
|
|
170
|
+
L.push(`**Why this matters:** ${cat.rationale}`);
|
|
171
|
+
L.push('');
|
|
172
|
+
L.push(`**Recommendation:** ${cat.recommendation}`);
|
|
173
|
+
L.push('');
|
|
174
|
+
L.push('| Package@Version | License | # Vulns | Resolution |');
|
|
175
|
+
L.push('|-----------------|---------|--------:|------------|');
|
|
176
|
+
for (const e of cat.affected) {
|
|
177
|
+
const advice = e.upgradeAdvice.replace(/\|/g, '\\|');
|
|
178
|
+
L.push(`| \`${e.package}@${e.version}\` | ${e.licenseType} | ${e.vulns.length} | ${advice} |`);
|
|
179
|
+
}
|
|
180
|
+
L.push('');
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
L.push('---');
|
|
184
|
+
L.push('');
|
|
185
|
+
// Per-advisory inventory across every vuln in every entry. Lets the
|
|
186
|
+
// reader drill from "this package has 3 vulns" up to the actual CVE
|
|
187
|
+
// ids without leaving the markdown.
|
|
188
|
+
L.push('## Per-Advisory Inventory');
|
|
189
|
+
L.push('');
|
|
190
|
+
const SEV_RANK = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
191
|
+
const flat = detailed.entries
|
|
192
|
+
.filter((e) => e.vulns.length > 0)
|
|
193
|
+
.flatMap((e) => e.vulns.map((v) => ({
|
|
194
|
+
severity: v.severity,
|
|
195
|
+
package: e.package,
|
|
196
|
+
version: e.version,
|
|
197
|
+
id: v.id,
|
|
198
|
+
fixedVersion: v.fixedVersion,
|
|
199
|
+
cvssScore: v.cvssScore,
|
|
200
|
+
tool: v.tool,
|
|
201
|
+
summary: v.summary,
|
|
202
|
+
})))
|
|
203
|
+
.sort((a, b) => SEV_RANK[a.severity] - SEV_RANK[b.severity] || a.package.localeCompare(b.package));
|
|
204
|
+
if (flat.length === 0) {
|
|
205
|
+
L.push('No vulnerabilities — empty inventory.');
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
L.push(`${flat.length} advisories total.`);
|
|
209
|
+
L.push('');
|
|
210
|
+
L.push('| Severity | Package@Version | ID | Fix | CVSS | Tool | Summary |');
|
|
211
|
+
L.push('|----------|-----------------|----|-----|-----:|------|---------|');
|
|
212
|
+
for (const v of flat) {
|
|
213
|
+
const summary = (v.summary || '').replace(/\|/g, '\\|').replace(/\n/g, ' ').slice(0, 100);
|
|
214
|
+
const cvss = v.cvssScore !== undefined ? v.cvssScore.toFixed(1) : '—';
|
|
215
|
+
L.push(`| ${SEV_LABEL[v.severity]} | \`${v.package}@${v.version}\` | \`${v.id}\` | ${v.fixedVersion ?? '—'} | ${cvss} | ${v.tool} | ${summary} |`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
L.push('');
|
|
219
|
+
L.push('---');
|
|
220
|
+
L.push('');
|
|
221
|
+
L.push(`**Tools used:** ${detailed.toolsUsed.join(', ') || '(none)'}`);
|
|
222
|
+
L.push(`**Analysis time:** ${elapsed}s`);
|
|
223
|
+
L.push('');
|
|
224
|
+
L.push('*Generated by [VyuhLabs DXKit](https://www.npmjs.com/package/@vyuhlabs/dxkit) — detailed mode*');
|
|
225
|
+
return L.join('\n');
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=detailed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detailed.js","sourceRoot":"","sources":["../../../src/analyzers/bom/detailed.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BOM analyzer data-gather. Joins LICENSES + DEP_VULNS via the
|
|
3
|
+
* existing capability gather functions — no new tool invocation logic
|
|
4
|
+
* (CLAUDE.md rule 2). The gather just calls each, then walks both
|
|
5
|
+
* result sets to build a per-package join keyed by `package@version`.
|
|
6
|
+
*/
|
|
7
|
+
import type { DepVulnFinding } from '../../languages/capabilities/types';
|
|
8
|
+
import type { BomEntry, BomTopLevelRollup } from './types';
|
|
9
|
+
/**
|
|
10
|
+
* Compare two version strings as semver triples. Strips a leading
|
|
11
|
+
* 'v' (Go-pack convention) and compares dot-separated numeric
|
|
12
|
+
* components. Falls back to lexicographic comparison when either
|
|
13
|
+
* input isn't a parseable triple — preserves a deterministic
|
|
14
|
+
* ordering for non-semver versions (e.g. cargo's "0.10.55+echo.1").
|
|
15
|
+
*/
|
|
16
|
+
export declare function compareSemver(a: string, b: string): number;
|
|
17
|
+
/** Highest version in `versions` per compareSemver. Returns the input
|
|
18
|
+
* unchanged when only one version is supplied. */
|
|
19
|
+
export declare function maxSemver(versions: string[]): string;
|
|
20
|
+
/**
|
|
21
|
+
* Tier-1 resolution proposal derived purely from `fixedVersion`
|
|
22
|
+
* data shipped by each pack's depVulns provider. Per checkpoint §9:
|
|
23
|
+
* - no vulns → empty
|
|
24
|
+
* - every vuln has fixedVersion → "PROPOSAL: Upgrade to <maxFix> (resolves N)"
|
|
25
|
+
* - some vuln lacks fixedVersion → "No fix available — evaluate replacement"
|
|
26
|
+
*
|
|
27
|
+
* Higher tiers (10h.4 Snyk, 10h.6 osv-scanner fix) populate
|
|
28
|
+
* `upgradeAdvice` directly on each finding; the bom render layer
|
|
29
|
+
* picks the richest available value per package.
|
|
30
|
+
*/
|
|
31
|
+
export declare function deriveTier1Resolution(vulns: DepVulnFinding[]): string;
|
|
32
|
+
/**
|
|
33
|
+
* Build the per-top-level-dep rollup from a flat list of entries.
|
|
34
|
+
* Walks every advisory under every entry; increments the counter for
|
|
35
|
+
* each top-level the advisory lists (a vuln reachable from two
|
|
36
|
+
* top-levels increments both, matching Snyk's grouping semantics).
|
|
37
|
+
*
|
|
38
|
+
* Entries with no topLevelDep attribution contribute nothing — the
|
|
39
|
+
* rollup is best-effort based on what each pack populates. Pure
|
|
40
|
+
* function; unit-testable.
|
|
41
|
+
*/
|
|
42
|
+
export declare function buildByTopLevelDep(entries: BomEntry[]): Record<string, BomTopLevelRollup>;
|
|
43
|
+
/**
|
|
44
|
+
* Join LICENSES + DEP_VULNS by (package, version). Strategy:
|
|
45
|
+
* - Primary index: package@version. Both LicenseFinding and
|
|
46
|
+
* DepVulnFinding usually carry both — match exact.
|
|
47
|
+
* - Fallback: package only. DepVulnFindings without
|
|
48
|
+
* installedVersion fall back to package-name match against
|
|
49
|
+
* the licenses list (joins to the single matching version
|
|
50
|
+
* when unambiguous, all matching versions when not).
|
|
51
|
+
*
|
|
52
|
+
* License-only packages emit BomEntry with empty `vulns`. Vuln-only
|
|
53
|
+
* packages (rare — license scanner gap) emit a row with empty
|
|
54
|
+
* license fields and `joinedFromBoth: false` so the detailed report
|
|
55
|
+
* can flag the gap.
|
|
56
|
+
*/
|
|
57
|
+
export interface BomGatherResult {
|
|
58
|
+
entries: BomEntry[];
|
|
59
|
+
toolsUsed: string[];
|
|
60
|
+
toolsUnavailable: string[];
|
|
61
|
+
}
|
|
62
|
+
export declare function gatherBomEntries(cwd: string): Promise<BomGatherResult>;
|
|
63
|
+
//# sourceMappingURL=gather.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gather.d.ts","sourceRoot":"","sources":["../../../src/analyzers/bom/gather.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,oCAAoC,CAAC;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAe,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAIxE;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAgB1D;AAED;mDACmD;AACnD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAGpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,CAQrE;AAYD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAkCzF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAiF5E"}
|