@vyuhlabs/dxkit 2.9.0 → 2.9.2

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 (63) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/README.md +3 -2
  3. package/dist/allowlist/cli.d.ts +38 -1
  4. package/dist/allowlist/cli.d.ts.map +1 -1
  5. package/dist/allowlist/cli.js +190 -3
  6. package/dist/allowlist/cli.js.map +1 -1
  7. package/dist/allowlist/file.d.ts +18 -0
  8. package/dist/allowlist/file.d.ts.map +1 -1
  9. package/dist/allowlist/file.js +10 -1
  10. package/dist/allowlist/file.js.map +1 -1
  11. package/dist/analyzers/security/aggregator.d.ts +6 -0
  12. package/dist/analyzers/security/aggregator.d.ts.map +1 -1
  13. package/dist/analyzers/security/aggregator.js +41 -0
  14. package/dist/analyzers/security/aggregator.js.map +1 -1
  15. package/dist/analyzers/security/gather.d.ts.map +1 -1
  16. package/dist/analyzers/security/gather.js +8 -1
  17. package/dist/analyzers/security/gather.js.map +1 -1
  18. package/dist/analyzers/tools/fingerprint.d.ts.map +1 -1
  19. package/dist/analyzers/tools/fingerprint.js +10 -1
  20. package/dist/analyzers/tools/fingerprint.js.map +1 -1
  21. package/dist/baseline/check-renderers.d.ts +12 -0
  22. package/dist/baseline/check-renderers.d.ts.map +1 -1
  23. package/dist/baseline/check-renderers.js +60 -4
  24. package/dist/baseline/check-renderers.js.map +1 -1
  25. package/dist/baseline/check.d.ts +42 -0
  26. package/dist/baseline/check.d.ts.map +1 -1
  27. package/dist/baseline/check.js +83 -2
  28. package/dist/baseline/check.js.map +1 -1
  29. package/dist/baseline/producers/security.d.ts.map +1 -1
  30. package/dist/baseline/producers/security.js +9 -0
  31. package/dist/baseline/producers/security.js.map +1 -1
  32. package/dist/baseline/types.d.ts +7 -0
  33. package/dist/baseline/types.d.ts.map +1 -1
  34. package/dist/cli.d.ts.map +1 -1
  35. package/dist/cli.js +23 -4
  36. package/dist/cli.js.map +1 -1
  37. package/dist/doctor.d.ts.map +1 -1
  38. package/dist/doctor.js +55 -0
  39. package/dist/doctor.js.map +1 -1
  40. package/dist/generator.d.ts.map +1 -1
  41. package/dist/generator.js +7 -1
  42. package/dist/generator.js.map +1 -1
  43. package/dist/ingest/env-file.d.ts +40 -0
  44. package/dist/ingest/env-file.d.ts.map +1 -0
  45. package/dist/ingest/env-file.js +163 -0
  46. package/dist/ingest/env-file.js.map +1 -0
  47. package/dist/ingest/sarif.d.ts.map +1 -1
  48. package/dist/ingest/sarif.js +22 -0
  49. package/dist/ingest/sarif.js.map +1 -1
  50. package/dist/ingest/snyk-policy.d.ts +60 -0
  51. package/dist/ingest/snyk-policy.d.ts.map +1 -0
  52. package/dist/ingest/snyk-policy.js +104 -0
  53. package/dist/ingest/snyk-policy.js.map +1 -0
  54. package/dist/ingest-cli.d.ts +4 -0
  55. package/dist/ingest-cli.d.ts.map +1 -1
  56. package/dist/ingest-cli.js +23 -4
  57. package/dist/ingest-cli.js.map +1 -1
  58. package/package.json +1 -1
  59. package/templates/.claude/skills/dxkit-action/SKILL.md +5 -3
  60. package/templates/.claude/skills/dxkit-allowlist/SKILL.md +107 -0
  61. package/templates/.claude/skills/dxkit-config/SKILL.md +4 -4
  62. package/templates/.claude/skills/dxkit-fix/SKILL.md +1 -1
  63. package/templates/.claude/skills/dxkit-ingest/SKILL.md +2 -0
@@ -0,0 +1,107 @@
1
+ ---
2
+ name: dxkit-allowlist
3
+ description: Manage the dxkit allowlist over its whole lifecycle — list, inspect, audit (including orphaned entries after a re-baseline), remove stale entries, prune expired ones, and export Snyk-originated suppressions to a .snyk policy. Use when the user says "review our allowlist", "what suppressions do we have", "this allowlist entry is stale", "remove this fingerprint", "the allowlist drifted after re-baselining", "audit our accepted-risk entries", or "push our Snyk ignores back to Snyk". For the fix-vs-suppress DECISION and adding a new entry, defer to dxkit-action.
4
+ ---
5
+
6
+ # dxkit-allowlist
7
+
8
+ The allowlist is dxkit's per-finding suppression surface: a reviewed finding that the team has categorized (`false-positive`, `test-fixture`, `mitigated-externally`, `accepted-risk`, `deferred`) with a reason, so the guardrail lets it pass on future runs. It's the single source of truth across every scanner — native semgrep/gitleaks and ingested Snyk Code / CodeQL findings alike, all keyed on one fingerprint.
9
+
10
+ This skill manages the allowlist's **lifecycle**: reviewing what's there, keeping it honest, and propagating decisions outward. For the upstream question — *should this be fixed instead of suppressed, and how do I add an entry* — that decision and the `add` path live in **dxkit-action**. Fix first; suppress second.
11
+
12
+ ## The lifecycle at a glance
13
+
14
+ ```
15
+ add ──▶ list / show ──▶ audit ──▶ { renew | remove | prune } ──▶ export --snyk
16
+ (dxkit-action) inspect keep honest clean up propagate to Snyk
17
+ ```
18
+
19
+ ## Review what's suppressed
20
+
21
+ ```bash
22
+ npx vyuh-dxkit allowlist list # every entry (text); --json for structured
23
+ npx vyuh-dxkit allowlist show <fingerprint> # one entry's full detail
24
+ ```
25
+
26
+ Reading is always safe — no mutation. Use these to brief the team on the overall suppression posture before a release or audit.
27
+
28
+ ## Audit — keep the allowlist honest
29
+
30
+ ```bash
31
+ npx vyuh-dxkit allowlist audit # expired / soon-to-expire / missing-rationale
32
+ npx vyuh-dxkit allowlist audit --soon-days=30 # widen the soon-to-expire window
33
+ npx vyuh-dxkit allowlist audit --against-baseline # ALSO flag orphaned entries
34
+ ```
35
+
36
+ `audit` partitions entries into actionable buckets:
37
+
38
+ - **expired** — past their `expiresAt`. The suppression no longer applies; the finding will re-flag on the next scan. Prune or renew.
39
+ - **soon-to-expire** — within the window (default 14 days). `accepted-risk` / `deferred` entries approaching expiry should be re-justified or removed.
40
+ - **missing-rationale** — no reason on the entry (only happens in sanitized mode when the gitignored reasons sidecar is absent).
41
+ - **orphaned** — *only with `--against-baseline`*. The entry's fingerprint matches no finding in the committed baseline.
42
+
43
+ ### Orphaned entries — flag, never bulk-remove
44
+
45
+ `--against-baseline` reads the committed baseline and reports entries whose fingerprint isn't present in the current finding set (it counts both each finding's own fingerprint and any cross-tool fingerprints absorbed into it, so an entry keyed on a collapsed contributor is *not* falsely flagged).
46
+
47
+ **An orphan is not automatically stale.** Two things produce orphans:
48
+
49
+ 1. **The finding is genuinely gone** (fixed, file deleted) → the entry is dead weight; remove it.
50
+ 2. **Re-baselining churned the fingerprint** — semgrep is nondeterministic run-to-run, and cross-tool dedup can shift which tool's fingerprint represents a merged finding. The suppressed finding may still exist intermittently. Removing the entry would let it block a future PR.
51
+
52
+ So treat the orphaned bucket as a **review queue**: confirm each finding is truly gone (re-run the analyzer and check the fingerprint is absent), *then* remove. Never script a bulk-remove of the orphaned set.
53
+
54
+ ## Remove a single entry
55
+
56
+ ```bash
57
+ npx vyuh-dxkit allowlist remove <fingerprint>
58
+ ```
59
+
60
+ Deletes one file-level entry. Use this for a confirmed-orphaned entry, or any stale-but-unexpired entry (which `prune` won't touch — `prune` removes only *expired* entries). No more hand-editing `.dxkit/allowlist.json`.
61
+
62
+ ## Prune expired entries
63
+
64
+ ```bash
65
+ npx vyuh-dxkit allowlist prune --dry-run # preview what would go
66
+ npx vyuh-dxkit allowlist prune # remove all expired entries
67
+ ```
68
+
69
+ `prune` is the bulk counterpart to `remove`, scoped to expired entries only (those are unambiguously inactive). Run it periodically; renew anything still relevant before pruning.
70
+
71
+ ## The re-baseline → re-point flow (self-serve)
72
+
73
+ After a baseline refresh, some fingerprints churn and a few valid suppressions orphan. The self-serve recovery:
74
+
75
+ ```bash
76
+ npx vyuh-dxkit allowlist audit --against-baseline # 1. discover orphans
77
+ # 2. for each orphan: re-run the analyzer, confirm the finding is truly gone
78
+ npx vyuh-dxkit vulnerabilities # (grep output for the fingerprint)
79
+ npx vyuh-dxkit allowlist remove <fingerprint> # 3a. gone → remove
80
+ npx vyuh-dxkit allowlist add --fingerprint=<new> … # 3b. churned → re-point to the new fp (see dxkit-action)
81
+ ```
82
+
83
+ > **Refresh the baseline in CI, not on your laptop.** A local `baseline create --force` bakes your machine's scanner versions into the committed baseline, which produces spurious tooling-drift warnings and phantom "resolved" findings on the next PR — and *causes* exactly this fingerprint churn. Use the bundled `dxkit-baseline-refresh` workflow (workflow_dispatch) so the canonical baseline is captured with CI's scanner versions. See **dxkit-ingest** for the refresh-job pattern.
84
+
85
+ ## Export to Snyk — propagate suppressions outward
86
+
87
+ ```bash
88
+ npx vyuh-dxkit allowlist export --snyk # writes ./.snyk
89
+ npx vyuh-dxkit allowlist export --snyk --out=path/to/.snyk
90
+ ```
91
+
92
+ When the team allowlists a **Snyk-originated** finding (one ingested via `dxkit-ingest`, `tool: snyk-code`), the decision lives only in dxkit by default — Snyk's own gate (`snyk code test`, the Snyk UI) still reports it as open. `export --snyk` closes that loop: it writes a `.snyk` policy ignoring every Snyk Code finding that maps to an *active* allowlist entry, keyed on the Snyk rule id + path, carrying the entry's reason + expiry. Expired entries are skipped; native semgrep/gitleaks findings don't export (no Snyk equivalent).
93
+
94
+ This is the outbound mirror of the inbound sync dxkit already does (it honors Snyk's SARIF `result.suppressions` at ingest). The two are round-trip stable — an exported ignore re-read from Snyk's SARIF is suppressed, not double-counted.
95
+
96
+ **Prerequisite:** Snyk Code (SAST) honors `.snyk` ignores only when the org has Snyk's "consistent ignores" feature enabled; SCA/dependency ignores are standard. Commit the `.snyk` so it applies in CI. It's opt-in — if dxkit is the only gate, you don't need it.
97
+
98
+ ## Stale inline annotations
99
+
100
+ Inline `dxkit-allow:` annotations are a different surface (source-anchored, managed by `dxkit-action`'s `add` path). If the underlying finding is fixed but the annotation lingers, the next scan emits a `stale-allow` finding pointing at the orphaned comment. The fix is always to delete the comment — dxkit refuses to allowlist a stale-allow.
101
+
102
+ ## Hand-offs
103
+
104
+ - For the **fix-vs-suppress decision** and **adding** a new entry (inline or file-level, the typed-category table, the canonical `add` path) → **dxkit-action**.
105
+ - For **ingesting** Snyk/CodeQL findings in the first place, and the **CI baseline/deep-SAST refresh** jobs → **dxkit-ingest**.
106
+ - For **ignore-file** (`.dxkit-ignore`) edits and policy tuning → **dxkit-config**.
107
+ - For a **broken install** (guardrail not firing, command not found) → **dxkit-fix**.
@@ -155,7 +155,7 @@ A `npx vyuh-dxkit doctor` or `tools list` showing tools as missing **when they a
155
155
  1. Create / edit `.dxkit/tools.json` and add that directory to `probePaths`.
156
156
  2. Re-run `npx vyuh-dxkit tools list` — the tool should now show as available.
157
157
  3. If the user wants dxkit to *install* tools into a specific dir, set `installDir`, then `npx vyuh-dxkit tools install`.
158
- 4. Regenerate the baseline so it reflects the now-available scanners: `npx vyuh-dxkit baseline create --force`.
158
+ 4. Regenerate the baseline so it reflects the now-available scanners — through the `dxkit-baseline-refresh` CI workflow, not a local `baseline create --force` (see "What NOT to do" for why).
159
159
 
160
160
  ## Workflow
161
161
 
@@ -163,11 +163,11 @@ When the user asks for a config change:
163
163
 
164
164
  1. Identify which file owns the concern (path exclusion → `.dxkit-ignore`; severity routing → `.dxkit/policy.json`; detection override → `.npx vyuh-dxkit.json`).
165
165
  2. Open the file, propose the edit, confirm.
166
- 3. After writing, run `npx vyuh-dxkit baseline create --force` if exclusions changed (so the baseline doesn't carry stale findings from the now-excluded paths).
167
- 4. Commit both: the config file + the regenerated baseline.
166
+ 3. If exclusions changed, refresh the baseline so it doesn't carry stale findings from the now-excluded paths — via the `dxkit-baseline-refresh` CI workflow, not a local `baseline create --force` (see "What NOT to do").
167
+ 4. Commit the config file; let CI refresh + commit the baseline.
168
168
 
169
169
  ## What NOT to do
170
170
 
171
171
  - Don't edit `.dxkit/cache/` or `.dxkit/reports/` — they're regenerated on every run (gitignored).
172
- - Don't manually mutate `.dxkit/baselines/main.json` — use `baseline create --force` to regenerate.
172
+ - Don't manually mutate `.dxkit/baselines/main.json` — regenerate it. And regenerate it in CI (the `dxkit-baseline-refresh` workflow), NOT with a local `baseline create --force`: a local refresh bakes your machine's scanner versions into the committed baseline, so the next PR's guardrail emits spurious `TOOLING-DRIFT` warnings and phantom "resolved" findings when CI's versions differ. A local `--force` is fine only for the first capture or a throwaway experiment.
173
173
  - Don't add `.dxkit/` to `.dxkit-ignore` — dxkit itself doesn't scan its own outputs.
@@ -91,7 +91,7 @@ If doctor flags a tool (git, dotnet, node, npm, a scanner) as missing but the cu
91
91
  2. Add that directory to `.dxkit/tools.json` `probePaths` (hand off to **dxkit-config**, which documents the file).
92
92
  3. Re-run `npx vyuh-dxkit doctor` to confirm it now resolves.
93
93
 
94
- This matters: an undetected scanner means `baseline create` silently captured ZERO findings for that tool's category — re-baseline (`baseline create --force`) once detection is fixed.
94
+ This matters: an undetected scanner means `baseline create` silently captured ZERO findings for that tool's category — refresh the baseline once detection is fixed. Do that through the `dxkit-baseline-refresh` CI workflow, not a local `baseline create --force`: a local refresh records your machine's scanner versions in the committed baseline, so the next PR's guardrail emits spurious `TOOLING-DRIFT` warnings and phantom "resolved" findings when CI's versions differ.
95
95
 
96
96
  ## Capturing the FIRST baseline — be deliberate
97
97
 
@@ -88,6 +88,8 @@ Compiled languages (Java, C#, Kotlin, Go) need a working build for CodeQL extrac
88
88
 
89
89
  Ingested findings flow through the same aggregate as native findings, so they appear in the vulnerability report (with the engine as the `tool`), get a stable fingerprint, dedupe against any overlapping semgrep finding, and — with `--graph-context` — carry the enclosing symbol + blast radius the agent needs to fix safely. That graph enrichment is the part the source engine's own autofix doesn't have.
90
90
 
91
+ > **Step [4] belongs in CI, not on your laptop.** Adding ingested findings changes the finding set, so the baseline must be refreshed to pick them up. Do that through the bundled `dxkit-baseline-refresh` workflow (workflow_dispatch / post-merge), NOT a local `baseline create --force`. A local refresh bakes your machine's scanner versions into the committed baseline; when they differ from CI's, the next PR gets spurious `TOOLING-DRIFT` warnings and phantom "resolved" findings. Refresh the snapshot AND the baseline from CI so both are captured with CI's tool versions.
92
+
91
93
  ## Keeping it fresh (CI)
92
94
 
93
95
  Add a scheduled refresh (mirrors `dxkit-baseline-refresh`): a CI job with the `SNYK_TOKEN` secret runs `ingest --from-snyk` and commits the updated snapshot. The bundled `--with-deep-sast-refresh` workflow (`workflow_dispatch`) does exactly this; its `method` input picks `api` (Enterprise, quota-free) or `cli` (free/team, one test per run). The ingested findings are a point-in-time snapshot of the engine's last scan — re-ingest after the engine re-scans.