@vyuhlabs/dxkit 2.5.2 → 2.7.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.
Files changed (264) hide show
  1. package/CHANGELOG.md +218 -13
  2. package/README.md +220 -369
  3. package/dist/allowlist/categories.d.ts +120 -0
  4. package/dist/allowlist/categories.d.ts.map +1 -0
  5. package/dist/allowlist/categories.js +194 -0
  6. package/dist/allowlist/categories.js.map +1 -0
  7. package/dist/allowlist/cli.d.ts +95 -0
  8. package/dist/allowlist/cli.d.ts.map +1 -0
  9. package/dist/allowlist/cli.js +454 -0
  10. package/dist/allowlist/cli.js.map +1 -0
  11. package/dist/allowlist/diff.d.ts +67 -0
  12. package/dist/allowlist/diff.d.ts.map +1 -0
  13. package/dist/allowlist/diff.js +147 -0
  14. package/dist/allowlist/diff.js.map +1 -0
  15. package/dist/allowlist/file.d.ts +249 -0
  16. package/dist/allowlist/file.d.ts.map +1 -0
  17. package/dist/allowlist/file.js +497 -0
  18. package/dist/allowlist/file.js.map +1 -0
  19. package/dist/allowlist/gather.d.ts +61 -0
  20. package/dist/allowlist/gather.d.ts.map +1 -0
  21. package/dist/allowlist/gather.js +143 -0
  22. package/dist/allowlist/gather.js.map +1 -0
  23. package/dist/allowlist/hint.d.ts +80 -0
  24. package/dist/allowlist/hint.d.ts.map +1 -0
  25. package/dist/allowlist/hint.js +271 -0
  26. package/dist/allowlist/hint.js.map +1 -0
  27. package/dist/allowlist/inline.d.ts +149 -0
  28. package/dist/allowlist/inline.d.ts.map +1 -0
  29. package/dist/allowlist/inline.js +306 -0
  30. package/dist/allowlist/inline.js.map +1 -0
  31. package/dist/analyzers/bom/discovery.d.ts +3 -4
  32. package/dist/analyzers/bom/discovery.d.ts.map +1 -1
  33. package/dist/analyzers/bom/discovery.js +3 -4
  34. package/dist/analyzers/bom/discovery.js.map +1 -1
  35. package/dist/analyzers/bom/types.d.ts +1 -1
  36. package/dist/analyzers/dashboard/index.d.ts.map +1 -1
  37. package/dist/analyzers/dashboard/index.js +42 -5
  38. package/dist/analyzers/dashboard/index.js.map +1 -1
  39. package/dist/analyzers/quality/detailed.d.ts +8 -1
  40. package/dist/analyzers/quality/detailed.d.ts.map +1 -1
  41. package/dist/analyzers/quality/detailed.js +43 -10
  42. package/dist/analyzers/quality/detailed.js.map +1 -1
  43. package/dist/analyzers/security/detailed.d.ts +8 -1
  44. package/dist/analyzers/security/detailed.d.ts.map +1 -1
  45. package/dist/analyzers/security/detailed.js +14 -1
  46. package/dist/analyzers/security/detailed.js.map +1 -1
  47. package/dist/analyzers/tests/detailed.d.ts +8 -1
  48. package/dist/analyzers/tests/detailed.d.ts.map +1 -1
  49. package/dist/analyzers/tests/detailed.js +26 -7
  50. package/dist/analyzers/tests/detailed.js.map +1 -1
  51. package/dist/analyzers/tools/cloc.js +3 -3
  52. package/dist/analyzers/tools/cloc.js.map +1 -1
  53. package/dist/analyzers/tools/exclusions.d.ts +12 -12
  54. package/dist/analyzers/tools/exclusions.d.ts.map +1 -1
  55. package/dist/analyzers/tools/exclusions.js +27 -13
  56. package/dist/analyzers/tools/exclusions.js.map +1 -1
  57. package/dist/analyzers/tools/graphify.d.ts +39 -5
  58. package/dist/analyzers/tools/graphify.d.ts.map +1 -1
  59. package/dist/analyzers/tools/graphify.js +609 -45
  60. package/dist/analyzers/tools/graphify.js.map +1 -1
  61. package/dist/analyzers/tools/nuget-package-reference.d.ts +4 -4
  62. package/dist/analyzers/tools/nuget-package-reference.js +4 -4
  63. package/dist/analyzers/tools/osv-scanner-fix.d.ts +4 -5
  64. package/dist/analyzers/tools/osv-scanner-fix.d.ts.map +1 -1
  65. package/dist/analyzers/tools/osv-scanner-fix.js +4 -5
  66. package/dist/analyzers/tools/osv-scanner-fix.js.map +1 -1
  67. package/dist/analyzers/tools/parallel.d.ts.map +1 -1
  68. package/dist/analyzers/tools/parallel.js +7 -0
  69. package/dist/analyzers/tools/parallel.js.map +1 -1
  70. package/dist/analyzers/tools/vendored-advisor.d.ts.map +1 -1
  71. package/dist/analyzers/tools/vendored-advisor.js +3 -4
  72. package/dist/analyzers/tools/vendored-advisor.js.map +1 -1
  73. package/dist/analyzers/xlsx/licenses.d.ts +7 -7
  74. package/dist/analyzers/xlsx/licenses.js +7 -7
  75. package/dist/baseline/baseline-file.d.ts +7 -0
  76. package/dist/baseline/baseline-file.d.ts.map +1 -1
  77. package/dist/baseline/baseline-file.js +22 -1
  78. package/dist/baseline/baseline-file.js.map +1 -1
  79. package/dist/baseline/check-renderers.d.ts +13 -1
  80. package/dist/baseline/check-renderers.d.ts.map +1 -1
  81. package/dist/baseline/check-renderers.js +67 -1
  82. package/dist/baseline/check-renderers.js.map +1 -1
  83. package/dist/baseline/check.d.ts +33 -7
  84. package/dist/baseline/check.d.ts.map +1 -1
  85. package/dist/baseline/check.js +90 -64
  86. package/dist/baseline/check.js.map +1 -1
  87. package/dist/baseline/create.d.ts +35 -7
  88. package/dist/baseline/create.d.ts.map +1 -1
  89. package/dist/baseline/create.js +43 -5
  90. package/dist/baseline/create.js.map +1 -1
  91. package/dist/baseline/entry-to-located.d.ts +6 -1
  92. package/dist/baseline/entry-to-located.d.ts.map +1 -1
  93. package/dist/baseline/entry-to-located.js +20 -2
  94. package/dist/baseline/entry-to-located.js.map +1 -1
  95. package/dist/baseline/finding-identity.d.ts.map +1 -1
  96. package/dist/baseline/finding-identity.js +15 -13
  97. package/dist/baseline/finding-identity.js.map +1 -1
  98. package/dist/baseline/modes.d.ts +140 -0
  99. package/dist/baseline/modes.d.ts.map +1 -0
  100. package/dist/baseline/modes.js +179 -0
  101. package/dist/baseline/modes.js.map +1 -0
  102. package/dist/baseline/policy.d.ts +64 -0
  103. package/dist/baseline/policy.d.ts.map +1 -1
  104. package/dist/baseline/policy.js +102 -1
  105. package/dist/baseline/policy.js.map +1 -1
  106. package/dist/baseline/producers/health.d.ts +2 -2
  107. package/dist/baseline/producers/health.d.ts.map +1 -1
  108. package/dist/baseline/producers/health.js.map +1 -1
  109. package/dist/baseline/producers/index.d.ts +11 -5
  110. package/dist/baseline/producers/index.d.ts.map +1 -1
  111. package/dist/baseline/producers/index.js +12 -9
  112. package/dist/baseline/producers/index.js.map +1 -1
  113. package/dist/baseline/producers/quality.d.ts +3 -3
  114. package/dist/baseline/producers/quality.d.ts.map +1 -1
  115. package/dist/baseline/producers/quality.js.map +1 -1
  116. package/dist/baseline/producers/secret-hmac.d.ts +2 -2
  117. package/dist/baseline/producers/secret-hmac.d.ts.map +1 -1
  118. package/dist/baseline/producers/secret-hmac.js.map +1 -1
  119. package/dist/baseline/producers/security.d.ts +2 -2
  120. package/dist/baseline/producers/security.d.ts.map +1 -1
  121. package/dist/baseline/producers/security.js.map +1 -1
  122. package/dist/baseline/producers/stale-allow.d.ts +70 -0
  123. package/dist/baseline/producers/stale-allow.d.ts.map +1 -0
  124. package/dist/baseline/producers/stale-allow.js +111 -0
  125. package/dist/baseline/producers/stale-allow.js.map +1 -0
  126. package/dist/baseline/producers/tests.d.ts +2 -2
  127. package/dist/baseline/producers/tests.d.ts.map +1 -1
  128. package/dist/baseline/producers/tests.js.map +1 -1
  129. package/dist/baseline/ref-baseline.d.ts +114 -0
  130. package/dist/baseline/ref-baseline.d.ts.map +1 -0
  131. package/dist/baseline/ref-baseline.js +260 -0
  132. package/dist/baseline/ref-baseline.js.map +1 -0
  133. package/dist/baseline/sanitize.d.ts +80 -0
  134. package/dist/baseline/sanitize.d.ts.map +1 -0
  135. package/dist/baseline/sanitize.js +91 -0
  136. package/dist/baseline/sanitize.js.map +1 -0
  137. package/dist/baseline/show.d.ts.map +1 -1
  138. package/dist/baseline/show.js +9 -3
  139. package/dist/baseline/show.js.map +1 -1
  140. package/dist/baseline/types.d.ts +73 -26
  141. package/dist/baseline/types.d.ts.map +1 -1
  142. package/dist/baseline/types.js +7 -1
  143. package/dist/baseline/types.js.map +1 -1
  144. package/dist/baseline/visibility.d.ts +61 -0
  145. package/dist/baseline/visibility.d.ts.map +1 -0
  146. package/dist/baseline/visibility.js +121 -0
  147. package/dist/baseline/visibility.js.map +1 -0
  148. package/dist/cli.d.ts.map +1 -1
  149. package/dist/cli.js +168 -6
  150. package/dist/cli.js.map +1 -1
  151. package/dist/dashboard/graph-adapter.d.ts +151 -0
  152. package/dist/dashboard/graph-adapter.d.ts.map +1 -0
  153. package/dist/dashboard/graph-adapter.js +415 -0
  154. package/dist/dashboard/graph-adapter.js.map +1 -0
  155. package/dist/dashboard/graph-tab.d.ts +109 -0
  156. package/dist/dashboard/graph-tab.d.ts.map +1 -0
  157. package/dist/dashboard/graph-tab.js +297 -0
  158. package/dist/dashboard/graph-tab.js.map +1 -0
  159. package/dist/dashboard/vendor/vis-network.min.js +34 -0
  160. package/dist/doctor.d.ts.map +1 -1
  161. package/dist/doctor.js +106 -16
  162. package/dist/doctor.js.map +1 -1
  163. package/dist/explore/cli/api-surface.d.ts +12 -0
  164. package/dist/explore/cli/api-surface.d.ts.map +1 -0
  165. package/dist/explore/cli/api-surface.js +57 -0
  166. package/dist/explore/cli/api-surface.js.map +1 -0
  167. package/dist/explore/cli/communities.d.ts +10 -0
  168. package/dist/explore/cli/communities.d.ts.map +1 -0
  169. package/dist/explore/cli/communities.js +47 -0
  170. package/dist/explore/cli/communities.js.map +1 -0
  171. package/dist/explore/cli/context.d.ts +16 -0
  172. package/dist/explore/cli/context.d.ts.map +1 -0
  173. package/dist/explore/cli/context.js +118 -0
  174. package/dist/explore/cli/context.js.map +1 -0
  175. package/dist/explore/cli/entry-points.d.ts +12 -0
  176. package/dist/explore/cli/entry-points.d.ts.map +1 -0
  177. package/dist/explore/cli/entry-points.js +85 -0
  178. package/dist/explore/cli/entry-points.js.map +1 -0
  179. package/dist/explore/cli/feature.d.ts +16 -0
  180. package/dist/explore/cli/feature.d.ts.map +1 -0
  181. package/dist/explore/cli/feature.js +89 -0
  182. package/dist/explore/cli/feature.js.map +1 -0
  183. package/dist/explore/cli/file.d.ts +12 -0
  184. package/dist/explore/cli/file.d.ts.map +1 -0
  185. package/dist/explore/cli/file.js +139 -0
  186. package/dist/explore/cli/file.js.map +1 -0
  187. package/dist/explore/cli/hot-files.d.ts +11 -0
  188. package/dist/explore/cli/hot-files.d.ts.map +1 -0
  189. package/dist/explore/cli/hot-files.js +63 -0
  190. package/dist/explore/cli/hot-files.js.map +1 -0
  191. package/dist/explore/context-hook.d.ts +42 -0
  192. package/dist/explore/context-hook.d.ts.map +1 -0
  193. package/dist/explore/context-hook.js +131 -0
  194. package/dist/explore/context-hook.js.map +1 -0
  195. package/dist/explore/finding-context.d.ts +69 -0
  196. package/dist/explore/finding-context.d.ts.map +1 -0
  197. package/dist/explore/finding-context.js +102 -0
  198. package/dist/explore/finding-context.js.map +1 -0
  199. package/dist/explore/format.d.ts +64 -0
  200. package/dist/explore/format.d.ts.map +1 -0
  201. package/dist/explore/format.js +99 -0
  202. package/dist/explore/format.js.map +1 -0
  203. package/dist/explore/load.d.ts +50 -0
  204. package/dist/explore/load.d.ts.map +1 -0
  205. package/dist/explore/load.js +197 -0
  206. package/dist/explore/load.js.map +1 -0
  207. package/dist/explore/queries.d.ts +413 -0
  208. package/dist/explore/queries.d.ts.map +1 -0
  209. package/dist/explore/queries.js +855 -0
  210. package/dist/explore/queries.js.map +1 -0
  211. package/dist/explore/types.d.ts +130 -0
  212. package/dist/explore/types.d.ts.map +1 -0
  213. package/dist/explore/types.js +28 -0
  214. package/dist/explore/types.js.map +1 -0
  215. package/dist/explore-cli.d.ts +45 -0
  216. package/dist/explore-cli.d.ts.map +1 -0
  217. package/dist/explore-cli.js +213 -0
  218. package/dist/explore-cli.js.map +1 -0
  219. package/dist/generator.d.ts.map +1 -1
  220. package/dist/generator.js +19 -0
  221. package/dist/generator.js.map +1 -1
  222. package/dist/issue-cli.d.ts +62 -0
  223. package/dist/issue-cli.d.ts.map +1 -0
  224. package/dist/issue-cli.js +252 -0
  225. package/dist/issue-cli.js.map +1 -0
  226. package/dist/languages/csharp.d.ts.map +1 -1
  227. package/dist/languages/csharp.js +32 -11
  228. package/dist/languages/csharp.js.map +1 -1
  229. package/dist/languages/go.d.ts.map +1 -1
  230. package/dist/languages/go.js +5 -0
  231. package/dist/languages/go.js.map +1 -1
  232. package/dist/languages/index.d.ts +27 -0
  233. package/dist/languages/index.d.ts.map +1 -1
  234. package/dist/languages/index.js +35 -0
  235. package/dist/languages/index.js.map +1 -1
  236. package/dist/languages/java.d.ts.map +1 -1
  237. package/dist/languages/java.js +5 -0
  238. package/dist/languages/java.js.map +1 -1
  239. package/dist/languages/kotlin.d.ts.map +1 -1
  240. package/dist/languages/kotlin.js +5 -0
  241. package/dist/languages/kotlin.js.map +1 -1
  242. package/dist/languages/python.d.ts.map +1 -1
  243. package/dist/languages/python.js +5 -0
  244. package/dist/languages/python.js.map +1 -1
  245. package/dist/languages/ruby.d.ts.map +1 -1
  246. package/dist/languages/ruby.js +5 -0
  247. package/dist/languages/ruby.js.map +1 -1
  248. package/dist/languages/rust.d.ts.map +1 -1
  249. package/dist/languages/rust.js +5 -0
  250. package/dist/languages/rust.js.map +1 -1
  251. package/dist/languages/types.d.ts +79 -0
  252. package/dist/languages/types.d.ts.map +1 -1
  253. package/dist/languages/typescript.d.ts.map +1 -1
  254. package/dist/languages/typescript.js +6 -1
  255. package/dist/languages/typescript.js.map +1 -1
  256. package/package.json +2 -1
  257. package/templates/.claude/skills/dxkit-action/SKILL.md +126 -12
  258. package/templates/.claude/skills/dxkit-onboard/SKILL.md +31 -3
  259. package/templates/.claude/skills/dxkit-reports/SKILL.md +3 -1
  260. package/templates/AGENTS.md.template +8 -1
  261. package/dist/baseline/producers/licenses.d.ts +0 -23
  262. package/dist/baseline/producers/licenses.d.ts.map +0 -1
  263. package/dist/baseline/producers/licenses.js +0 -46
  264. package/dist/baseline/producers/licenses.js.map +0 -1
@@ -11,7 +11,7 @@ This skill takes a dxkit report and drives the fix loop with the user. Reach for
11
11
 
12
12
  ```
13
13
  [1] Read the report → understand what's flagged
14
- [2] Prioritize → severity + reachability + cost
14
+ [2] Prioritize → severity + reachability + blast radius + cost
15
15
  [3] Plan → ordered list of edits
16
16
  [4] Execute → fix one finding at a time
17
17
  [5] Verify → re-run the analyzer, confirm score moved
@@ -20,6 +20,14 @@ This skill takes a dxkit report and drives the fix loop with the user. Reach for
20
20
 
21
21
  Don't skip [5]. Re-running the analyzer is the only way to confirm the fix landed correctly.
22
22
 
23
+ For the richest input, read the **detailed** report with graph context attached:
24
+
25
+ ```bash
26
+ npx vyuh-dxkit vulnerabilities --detailed --graph-context # or test-gaps / quality
27
+ ```
28
+
29
+ `--graph-context` adds a "Graph context" column (the module a finding lives in + its blast radius — how many files call into it) so you can plan the fix without separately discovering structure. It's a structural HINT, not ground truth — read "Graph context" below for how to use it safely.
30
+
23
31
  ## Priority order
24
32
 
25
33
  Walk findings in this order (highest to lowest):
@@ -33,6 +41,18 @@ Walk findings in this order (highest to lowest):
33
41
 
34
42
  Skip items where reachability is "no" (graphify can't find a call path) UNLESS the finding is a secret leak (those don't depend on reachability).
35
43
 
44
+ ## Graph context (structural blast radius)
45
+
46
+ When the report was generated with `--graph-context`, each finding carries a "Graph context" cell: the module/role it belongs to and its **blast radius** (`role · N caller files`) — how many other files call into the finding's file. Use it to sharpen prioritization and planning, under three hard rules.
47
+
48
+ **1. Additive only — it never overrides severity or reachability.** Blast radius is a tie-breaker between findings of similar severity, not a re-ranking of the priority list above. Among two HIGH findings, fix the one with the larger blast radius first (more depends on it). A LOW finding never jumps a HIGH one because its blast radius is bigger.
49
+
50
+ **2. A blank or zero blast radius is NOT "safe to change".** The cell reads `blast radius n/a (call graph)` for languages whose call graph the analyzer can't resolve (C# is the known case — cross-assembly references aren't followed, so heavily-used files look like they have zero callers). Treat n/a — and even a literal `0 caller files` — as **unknown**, never as evidence the file is safe to edit freely. When blast radius is n/a, fall back to the module/role label (that part is reliable) and verify callers the normal way (grep / read) before a risky edit. Do **not** deprioritize a real finding just because its blast radius is empty.
51
+
52
+ **3. Confirm the symbol before you act on it.** The context may name an enclosing symbol (the function the finding sits in). It's a best-effort guess (the graph stores declaration lines, not end lines), so open the file and confirm the finding is actually inside that symbol before editing or writing a test against it.
53
+
54
+ Used within those rules, the win is concrete: a high blast radius tells you which caller files to re-check and re-test in step [5] after the fix, and the module label orients you fast. Same-name symbols can inflate the count — a suspiciously huge number is usually conflation, not reality.
55
+
36
56
  ## Common fix recipes
37
57
 
38
58
  ### Secret in code
@@ -47,15 +67,17 @@ npx vyuh-dxkit vulnerabilities --json | jq '.summary.findings'
47
67
 
48
68
  Don't try to redact the secret in place — the git history still has it. Rotation is the only true fix.
49
69
 
70
+ If the "secret" is actually a placeholder in test code (e.g., `"sk_test_xxxxxxxxxxxx"` with no real credential value), confirm with the developer and allowlist via `dxkit-allow:test-fixture` — see "Allowlisting (when fix is not viable)" below.
71
+
50
72
  ### SAST finding (semgrep)
51
73
 
52
74
  ```bash
53
75
  # 1. Read the finding's rule + line range from the report
54
76
  # 2. Open the file, understand why semgrep flagged it
55
- # 3. Either FIX (preferred) or SUPPRESS (carefully)
77
+ # 3. Either FIX (preferred) or ALLOWLIST (carefully — see below)
56
78
  ```
57
79
 
58
- Suppression is `// nosemgrep: <rule-id>` on the offending line. Use sparingly every suppression is a future maintenance burden. Better: fix the underlying issue.
80
+ If the finding is a true false positive or intentional pattern (test fixture, mitigated externally), suppress via dxkit's allowlist — NOT via semgrep's `// nosemgrep:`. The dxkit allowlist is the canonical surface (single source of truth across every scanner), carries a typed category + reason, and is audit-trackable through `vyuh-dxkit allowlist audit`. See "Allowlisting (when fix is not viable)" below.
59
81
 
60
82
  ### Dependency vulnerability
61
83
 
@@ -70,6 +92,8 @@ For peer-dep conflicts: `npm install <pkg>@<patched-version> --legacy-peer-deps`
70
92
 
71
93
  For Python: `pip install --upgrade <pkg>=<patched>` then re-pip-freeze. For Go: `go get <pkg>@<patched>` then `go mod tidy`. For Ruby: edit Gemfile, `bundle update <pkg>`. For Rust: `cargo update -p <pkg> --precise <patched>`.
72
94
 
95
+ If no patched version exists OR the upgrade breaks other constraints AND the risk is mitigated externally (network policy, WAF, runtime guard), allowlist with `category=mitigated-externally` and a reason describing the mitigation. If the team is accepting the risk while waiting on a fix, `category=accepted-risk` + an expiry tied to the fix deadline.
96
+
73
97
  ### Test gap
74
98
 
75
99
  ```bash
@@ -93,6 +117,88 @@ Don't write tests that just import the module — write tests that exercise beha
93
117
 
94
118
  If the finding is a false positive, add `// slop-ok: <reason>` on the offending line (or `# slop-ok` for non-JS).
95
119
 
120
+ ## Allowlisting (when fix is not viable)
121
+
122
+ **Fix first.** The allowlist is the SECOND option, not the first. When you reach for it, choose deliberately — every allowlist entry is a future maintenance burden the customer's team will revisit.
123
+
124
+ Five typed categories signal WHY the suppression is in place:
125
+
126
+ | Category | Meaning | Where it lives |
127
+ |---|---|---|
128
+ | `false-positive` | Scanner is wrong about this code | Inline annotation OR file-level |
129
+ | `test-fixture` | Intentional pattern in a fixture / test file | Inline annotation OR file-level |
130
+ | `mitigated-externally` | Real risk but neutralized at runtime (WAF, env, etc.) | Inline annotation OR file-level |
131
+ | `accepted-risk` | Real risk, accepted by the team, signed off | File-level only (needs expiry + acknowledged severity) |
132
+ | `deferred` | Real, will fix later, tracked work | File-level only (needs expiry) |
133
+
134
+ `accepted-risk` and `deferred` require an `expiresAt` date because they describe assertions that should age out — by default the CLI sets 90 days. `false-positive`, `test-fixture`, and `mitigated-externally` describe assertions that don't naturally stale; they may omit expiry.
135
+
136
+ ### The two surfaces
137
+
138
+ **Inline annotation** is the natural fit for source-anchored findings (secrets, code, config, dep-vuln, hygiene) with an inline-compatible category. The annotation lives next to the line it suppresses:
139
+
140
+ ```python
141
+ api_key = "sk_test_xxxx" # dxkit-allow:test-fixture reason="placeholder in unit test"
142
+ ```
143
+
144
+ Or, for long source lines, above:
145
+
146
+ ```typescript
147
+ // dxkit-allow:false-positive reason="regex matches intentional placeholder"
148
+ const apiKey = "sk_test_xxxx";
149
+ ```
150
+
151
+ The grammar is uniform across every language; only the comment marker varies (`#` for python/ruby, `//` for typescript/go/rust/csharp/kotlin/java). Don't type it by hand — let dxkit insert it for you (see CLI below).
152
+
153
+ **File-level allowlist** lives at `.dxkit/allowlist.json` and is the surface for:
154
+
155
+ - Cross-file or whole-file findings (duplication, coverage-gap, test-gap, god-file, large-file, stale-file)
156
+ - Findings with no stable single-line attachment (dep-vuln, secret-hmac)
157
+ - Any `accepted-risk` or `deferred` suppression regardless of kind
158
+
159
+ ### Add an allowlist entry (canonical path)
160
+
161
+ Don't hand-edit the annotation comment or the JSON file — let the CLI insert it correctly:
162
+
163
+ ```bash
164
+ # Inline annotation at file:line — for source-anchored findings
165
+ # with an inline-compatible category
166
+ npx vyuh-dxkit allowlist add src/auth/oauth.ts:42 \
167
+ --category=test-fixture --reason="placeholder in unit test"
168
+
169
+ # File-level entry — for everything else (kind + fingerprint required;
170
+ # both come straight from the guardrail check's output)
171
+ npx vyuh-dxkit allowlist add --fingerprint=a3f9c0e8b7d2e1f4 \
172
+ --kind=dep-vuln --category=accepted-risk \
173
+ --reason="WAF rule X mitigates this CVE" --expires=2026-08-22
174
+ ```
175
+
176
+ The guardrail's block message gives you the exact command to paste for every blocked finding — file path + line for inline-compatible kinds, fingerprint + kind for everything else. Just copy-paste.
177
+
178
+ ### When the finding only carries an id (sanitized / ref-based baseline)
179
+
180
+ If you're seeing a blocked finding labelled `<sanitized>` (in `baseline show` output) OR with no `file`/`line` columns in the PR-comment table, the repo's baseline mode is `committed-sanitized` or `ref-based` and the human-readable locator was stripped at write time. Two options:
181
+
182
+ - **Inspect the finding in the current scan.** The fingerprint pairs against the live scan's output, which is rich (always). Re-run the matching analyzer (`vyuh-dxkit vulnerabilities`, `vyuh-dxkit health`, etc.) and grep the JSON output for the fingerprint — that finding has full file:line context.
183
+ - **Allowlist by fingerprint anyway.** File-level allowlist entries only need fingerprint + kind, both of which the guardrail message still provides. The category + reason apply regardless of whether the locator is visible at baseline time.
184
+
185
+ The fingerprint contract is preserved across all three modes — `committed-full`, `committed-sanitized`, `ref-based` all produce the same identity bytes for the same finding. Sanitization only strips the human-readable rendering; it doesn't change which findings pair across runs.
186
+
187
+ ### Review what's allowlisted
188
+
189
+ ```bash
190
+ npx vyuh-dxkit allowlist list # all entries (text)
191
+ npx vyuh-dxkit allowlist show <fingerprint> # one entry's full detail
192
+ npx vyuh-dxkit allowlist audit # expired / soon-to-expire / missing-rationale
193
+ npx vyuh-dxkit allowlist prune # remove expired entries
194
+ ```
195
+
196
+ Run `audit` periodically — `accepted-risk` and `deferred` entries that pass their expiry should either be re-justified (renew expiry) or pruned (remove the entry; the underlying finding will re-flag on the next scan).
197
+
198
+ ### Stale annotations
199
+
200
+ If the underlying finding is fixed but the inline annotation lingers, the next scan emits a `stale-allow` finding pointing at the orphaned comment. The remediation is always to remove the annotation — dxkit refuses to allowlist a stale-allow finding (allowlisting the warning that an annotation is stale would defeat the entire model).
201
+
96
202
  ## Verification — never skip
97
203
 
98
204
  After each fix:
@@ -111,14 +217,19 @@ If the finding's still there: the fix didn't work, try again.
111
217
 
112
218
  ## Baseline decisions
113
219
 
114
- Once a finding is fixed AND verified gone, the workflow depends on what changed:
220
+ Once a finding is processed (fixed, allowlisted, or accepted), the workflow depends on which path you took:
115
221
 
116
222
  | Scenario | Action |
117
223
  |---|---|
118
- | Fix landed via a code change | Commit the code. Baseline is unchanged. Future scans confirm the fix held. |
224
+ | Fix landed via a code change | Commit the code. Baseline + allowlist are unchanged. Future scans confirm the fix held. |
225
+ | Genuine false positive OR intentional pattern | `vyuh-dxkit allowlist add` with `category=false-positive` or `test-fixture`. Commit the annotation / allowlist file. Baseline is unchanged. |
226
+ | Real risk neutralized externally (WAF, runtime guard) | `vyuh-dxkit allowlist add` with `category=mitigated-externally` + a reason describing the mitigation. Baseline unchanged. |
227
+ | Real risk, accepted by team, won't fix | `vyuh-dxkit allowlist add` with `category=accepted-risk` + `--expires=YYYY-MM-DD` (defaults 90 days). Acknowledged-severity required for high/critical. |
228
+ | Real risk, will fix later (tracked work) | `vyuh-dxkit allowlist add` with `category=deferred` + `--expires=YYYY-MM-DD`. The expiry forces re-review when the deadline passes. |
119
229
  | Fix landed via a config change (e.g., new entry in `.dxkit-ignore`) | Re-baseline: `npx vyuh-dxkit baseline create --force`. Commit both `.dxkit-ignore` and the new baseline. |
120
- | Finding accepted as known + not blocking | Re-baseline with explicit reason in the commit message. Future scans treat it as pre-existing, not net-new. |
121
- | Finding is genuinely a false positive | First try suppression on the offending line. If you can't suppress, re-baseline. |
230
+ | Brownfield acceptance (the whole CURRENT state is known mess; future regressions must be net-new) | Re-baseline with an explicit reason in the commit message. Reserve this for the deliberate "draw a line here" moment, not per-finding suppression. |
231
+
232
+ **Prefer the allowlist over re-baselining for per-finding decisions.** The allowlist carries a typed category + reason + (when relevant) expiry; the baseline carries only "this finding was here." Future maintainers reading `vyuh-dxkit allowlist show <fingerprint>` see WHY the suppression is in place; reading the baseline file shows only that the finding existed at capture time. Per-finding decisions belong in the allowlist; codebase-wide brownfield acceptance belongs in the baseline.
122
233
 
123
234
  **Never** re-baseline a finding silently — the commit message should explain why the regression is accepted. Future maintainers reading `git log .dxkit/baselines/` should see the rationale.
124
235
 
@@ -134,17 +245,20 @@ Exit 0 = your fixes didn't introduce any net-new regressions (you only removed/f
134
245
 
135
246
  ## When fixes get expensive
136
247
 
137
- Sometimes the right call is: don't fix, accept as baseline.
248
+ Sometimes the right call is: don't fix, allowlist (or re-baseline if it's brownfield-wide).
138
249
 
139
250
  Examples:
140
- - Legacy code on a deprecation path (sunset > fix)
141
- - A SAST finding in vendored code you don't maintain
142
- - A test gap on a one-off script that doesn't merit tests
251
+ - Legacy code on a deprecation path (sunset > fix) → `accepted-risk` with expiry matching the sunset date
252
+ - A SAST finding in vendored code you don't maintain → `mitigated-externally` if the vendor patches separately, else `accepted-risk`
253
+ - A test gap on a one-off script that doesn't merit tests → `accepted-risk`
254
+ - An import line flagged by a scanner that you've reviewed and confirmed safe → `false-positive` inline annotation at the import
143
255
 
144
- In those cases: accept-as-baseline with a commit message explaining the call. dxkit's baseline IS designed to support this the brownfield contract is "today's mess is acknowledged; tomorrow's must be a real improvement." Use it.
256
+ In those cases: `vyuh-dxkit allowlist add` is the right tool for per-finding decisions (typed reason + expiry where relevant). Reserve "accept as baseline" for the deliberate one-shot brownfield moment ("this entire current state is known mess; today's findings are the new baseline"). The two surfaces complement each other — allowlist for individual judgment calls, baseline for the codebase-wide line in the sand.
145
257
 
146
258
  ## Hand-offs
147
259
 
148
260
  - For ignore-file edits as part of a fix → `dxkit-config` skill
149
261
  - For hook-related issues during a fix push → `dxkit-hooks` skill
150
262
  - For re-running reports between fixes → `dxkit-reports` skill
263
+ - For broken dxkit install (hooks not firing, vyuh-dxkit not on PATH) → `dxkit-fix` skill
264
+ - For allowlist management beyond the per-finding `add` path (auditing existing entries, pruning expired ones, reviewing the team's overall suppression posture) → run `npx vyuh-dxkit allowlist audit` / `list` / `prune` directly; no separate skill yet
@@ -113,7 +113,19 @@ Don't auto-execute baseline capture here — step 5 has a values-laden warning t
113
113
 
114
114
  This is the step with permanent consequences. The baseline records the fingerprint of every finding currently in the repo and tells future scans "these are pre-existing — don't block on them."
115
115
 
116
- Before running `baseline create` on a fresh customer:
116
+ Before running `baseline create` on a fresh customer, ASK about disclosure posture (the baseline file is committed to git):
117
+
118
+ > **About to capture the first baseline. One quick choice first — which posture fits this repo?**
119
+ >
120
+ > The baseline file lives at `.dxkit/baselines/main.json`. Three modes trade disclosure for diagnostic richness:
121
+ >
122
+ > - **`committed-full`** (default for private repos) — Rich entries with file paths, package names, advisory IDs. Best diagnostic quality. Fine when only your team reads the repo.
123
+ > - **`committed-sanitized`** (compliance-conscious private) — Stripped to fingerprint + kind only. Hides location detail; matching still works. Good when many people have repo read access.
124
+ > - **`ref-based`** (default for public repos) — No baseline file at all. Each guardrail check recomputes the prior side from a git ref (e.g. `origin/main`). Zero disclosure.
125
+ >
126
+ > Auto-pick: run `vyuh-dxkit baseline create` and dxkit picks the right default by probing `gh repo view`. Or pin explicitly via `--mode=<X>` or `.dxkit/policy.json`.
127
+
128
+ Then the standard "lock-in" warning:
117
129
 
118
130
  > **About to capture the first baseline.**
119
131
  >
@@ -125,14 +137,30 @@ Before running `baseline create` on a fresh customer:
125
137
 
126
138
  If they want to triage first, hand off to `dxkit-action` — that skill prioritizes findings before baseline lock-in. Come back to step 5 after triage.
127
139
 
128
- If they confirm baseline:
140
+ If they confirm baseline (and they're happy with auto-picked mode):
129
141
 
130
142
  ```bash
131
143
  npx vyuh-dxkit baseline create
132
- git add .dxkit/baselines/
144
+ git add .dxkit/baselines/ # only if mode wrote a file (committed-*)
133
145
  git commit -m "chore: capture dxkit baseline"
134
146
  ```
135
147
 
148
+ If they want to PIN the mode explicitly (so every developer + CI run agrees), write `.dxkit/policy.json`:
149
+
150
+ ```bash
151
+ mkdir -p .dxkit
152
+ cat > .dxkit/policy.json <<'JSON'
153
+ {
154
+ "baseline": {
155
+ "mode": "ref-based",
156
+ "ref": "origin/main"
157
+ }
158
+ }
159
+ JSON
160
+ git add .dxkit/policy.json
161
+ git commit -m "chore: pin baseline mode in policy.json"
162
+ ```
163
+
136
164
  ### 6. Pre-commit ASK
137
165
 
138
166
  Pre-commit is opt-in even under `--full` because it re-runs every analyzer on every commit (~1-3 min on 500+ file repos). Most teams skip it.
@@ -19,7 +19,9 @@ This skill runs dxkit analyzers and reads their output back to the user. It's th
19
19
  | "License inventory" | `npx vyuh-dxkit licenses` | Every dependency's declared license |
20
20
  | "Bill of materials" | `npx vyuh-dxkit bom` | Licenses + dep vulnerabilities joined (15-col XLSX-ready output) |
21
21
  | "Run everything" | `npx vyuh-dxkit report` | Every analyzer in one shot, ~3-5 min |
22
- | "Show me the dashboard" | `npx vyuh-dxkit dashboard` | Single HTML view of all reports — opens at `.dxkit/reports/dashboard.html` |
22
+ | "Show me the dashboard" | `npx vyuh-dxkit dashboard` | Single HTML view of all reports — opens at `.dxkit/reports/dashboard.html`, incl. an interactive **Graph** tab (code structure) |
23
+ | "What does this repo do / where is X" | `npx vyuh-dxkit explore <sub>` | Query the code graph: entry-points / hot-files / communities / file / feature / api-surface |
24
+ | "Token-efficient context for a query" | `npx vyuh-dxkit context <query>` | Slim structural slice for an LLM (also a fix-time hint via `--graph-context`) |
23
25
 
24
26
  ## Where output lands
25
27
 
@@ -114,12 +114,19 @@ Reach for the relevant skill when working in this repo. They wrap the `vyuh-dxki
114
114
  | Test coverage gaps | `npx vyuh-dxkit test-gaps` |
115
115
  | Code quality + slop | `npx vyuh-dxkit quality` |
116
116
  | Bill of materials | `npx vyuh-dxkit bom` |
117
- | Dashboard (HTML) | `npx vyuh-dxkit dashboard` |
117
+ | Dashboard (HTML, incl. interactive Graph tab) | `npx vyuh-dxkit dashboard` |
118
+ | What does this repo do / where does X live | `npx vyuh-dxkit explore <sub>` |
119
+ | Token-efficient structural context for a query | `npx vyuh-dxkit context <query>` |
118
120
  | Guardrail check (baseline diff) | `npx vyuh-dxkit guardrail check` |
119
121
  | Doctor (verify setup) | `npx vyuh-dxkit doctor` |
120
122
 
121
123
  The pre-push hook runs `guardrail check` automatically — blocks net-new regressions before they leave your machine.
122
124
 
125
+ When fixing findings, run the detailed report with `--graph-context`
126
+ (e.g. `npx vyuh-dxkit vulnerabilities --detailed --graph-context`) — it
127
+ attaches each finding's module + blast radius so you can navigate by the
128
+ code graph instead of repeated whole-file reads.
129
+
123
130
  ## Security rules — never violate
124
131
 
125
132
  1. **Never output, log, or commit secrets** — no API keys, tokens, passwords, or credentials in code, commits, or files Claude writes
@@ -1,23 +0,0 @@
1
- /**
2
- * Licenses → baseline-entry producer.
3
- *
4
- * One kind: `license` — per-package license attribution.
5
- * `(package, version, licenseType)` is the identity tuple, so a
6
- * re-licensing event on the same pinned version (compliance teams'
7
- * canonical concern) registers as a fresh finding even when no
8
- * version bump happened.
9
- *
10
- * Reads from `CapabilityReport.licenses.findings` — already in the
11
- * cached `AnalysisResult`, no extra gather work needed. Pure
12
- * function over its input.
13
- */
14
- import type { BaselineEntry } from '../types';
15
- import type { LicensesResult } from '../../languages/capabilities/types';
16
- /**
17
- * Build `license` entries from a licenses capability envelope.
18
- * Findings with an empty `licenseType` are emitted with the literal
19
- * `'UNKNOWN'` so identity stays stable across runs even when the
20
- * underlying tool can't resolve the SPDX id.
21
- */
22
- export declare function licensesToBaselineEntries(licenses: LicensesResult | undefined): BaselineEntry[];
23
- //# sourceMappingURL=licenses.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"licenses.d.ts","sourceRoot":"","sources":["../../../src/baseline/producers/licenses.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAwB,MAAM,UAAU,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,cAAc,GAAG,SAAS,GAAG,aAAa,EAAE,CAoB/F"}
@@ -1,46 +0,0 @@
1
- "use strict";
2
- /**
3
- * Licenses → baseline-entry producer.
4
- *
5
- * One kind: `license` — per-package license attribution.
6
- * `(package, version, licenseType)` is the identity tuple, so a
7
- * re-licensing event on the same pinned version (compliance teams'
8
- * canonical concern) registers as a fresh finding even when no
9
- * version bump happened.
10
- *
11
- * Reads from `CapabilityReport.licenses.findings` — already in the
12
- * cached `AnalysisResult`, no extra gather work needed. Pure
13
- * function over its input.
14
- */
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.licensesToBaselineEntries = licensesToBaselineEntries;
17
- const finding_identity_1 = require("../finding-identity");
18
- /**
19
- * Build `license` entries from a licenses capability envelope.
20
- * Findings with an empty `licenseType` are emitted with the literal
21
- * `'UNKNOWN'` so identity stays stable across runs even when the
22
- * underlying tool can't resolve the SPDX id.
23
- */
24
- function licensesToBaselineEntries(licenses) {
25
- if (!licenses)
26
- return [];
27
- const out = [];
28
- for (const f of licenses.findings) {
29
- const licenseType = f.licenseType.length > 0 ? f.licenseType : 'UNKNOWN';
30
- const input = {
31
- kind: 'license',
32
- package: f.package,
33
- version: f.version,
34
- licenseType,
35
- };
36
- out.push({
37
- id: (0, finding_identity_1.identityFor)(input),
38
- kind: 'license',
39
- package: f.package,
40
- version: f.version,
41
- licenseType,
42
- });
43
- }
44
- return out;
45
- }
46
- //# sourceMappingURL=licenses.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"licenses.js","sourceRoot":"","sources":["../../../src/baseline/producers/licenses.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;AAYH,8DAoBC;AA9BD,0DAAkD;AAIlD;;;;;GAKG;AACH,SAAgB,yBAAyB,CAAC,QAAoC;IAC5E,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IACzB,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,WAAW,GAAG,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;QACzE,MAAM,KAAK,GAAyB;YAClC,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,WAAW;SACZ,CAAC;QACF,GAAG,CAAC,IAAI,CAAC;YACP,EAAE,EAAE,IAAA,8BAAW,EAAC,KAAK,CAAC;YACtB,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}