@vyuhlabs/dxkit 2.9.1 → 2.9.3
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 +77 -0
- package/README.md +14 -11
- package/dist/allowlist/cli.d.ts +38 -1
- package/dist/allowlist/cli.d.ts.map +1 -1
- package/dist/allowlist/cli.js +190 -3
- package/dist/allowlist/cli.js.map +1 -1
- package/dist/allowlist/file.d.ts +18 -0
- package/dist/allowlist/file.d.ts.map +1 -1
- package/dist/allowlist/file.js +10 -1
- package/dist/allowlist/file.js.map +1 -1
- package/dist/analyzers/tests/actions.d.ts +18 -1
- package/dist/analyzers/tests/actions.d.ts.map +1 -1
- package/dist/analyzers/tests/actions.js +37 -1
- package/dist/analyzers/tests/actions.js.map +1 -1
- package/dist/analyzers/tests/detailed.d.ts.map +1 -1
- package/dist/analyzers/tests/detailed.js +15 -3
- package/dist/analyzers/tests/detailed.js.map +1 -1
- package/dist/analyzers/tests/types.d.ts +10 -0
- package/dist/analyzers/tests/types.d.ts.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +23 -4
- package/dist/cli.js.map +1 -1
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +19 -1
- package/dist/generator.js.map +1 -1
- package/dist/ingest/env-file.d.ts +40 -0
- package/dist/ingest/env-file.d.ts.map +1 -0
- package/dist/ingest/env-file.js +163 -0
- package/dist/ingest/env-file.js.map +1 -0
- package/dist/ingest/snyk-policy.d.ts +60 -0
- package/dist/ingest/snyk-policy.d.ts.map +1 -0
- package/dist/ingest/snyk-policy.js +104 -0
- package/dist/ingest/snyk-policy.js.map +1 -0
- package/dist/ingest-cli.d.ts +4 -0
- package/dist/ingest-cli.d.ts.map +1 -1
- package/dist/ingest-cli.js +23 -4
- package/dist/ingest-cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/.claude/skills/dxkit-action/SKILL.md +45 -4
- package/templates/.claude/skills/dxkit-allowlist/SKILL.md +107 -0
- package/templates/.claude/skills/dxkit-config/SKILL.md +4 -4
- package/templates/.claude/skills/dxkit-docs/SKILL.md +2 -0
- package/templates/.claude/skills/dxkit-feature/SKILL.md +14 -3
- package/templates/.claude/skills/dxkit-fix/SKILL.md +1 -1
- package/templates/.claude/skills/dxkit-ingest/SKILL.md +2 -0
- package/templates/.claude/skills/dxkit-init/SKILL.md +1 -1
- package/templates/.claude/skills/dxkit-onboard/SKILL.md +2 -2
- package/templates/.claude/skills/dxkit-pr/SKILL.md +142 -0
- package/templates/.claude/skills/dxkit-reports/SKILL.md +1 -1
- package/templates/.claude/skills/dxkit-test/SKILL.md +130 -0
- package/templates/.claude/skills/dxkit-update/SKILL.md +4 -0
- package/templates/AGENTS.md.template +9 -3
- package/templates/CLAUDE.md.template +9 -3
|
@@ -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
|
|
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.
|
|
167
|
-
4. Commit
|
|
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` —
|
|
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.
|
|
@@ -146,3 +146,5 @@ npx vyuh-dxkit guardrail check
|
|
|
146
146
|
should leave the new surface documented).
|
|
147
147
|
- Slop findings outside docs (AI-generated code prose, CHANGELOG slop) →
|
|
148
148
|
`dxkit-action`'s slop recipe.
|
|
149
|
+
- Closing test gaps / raising the Tests score (the sibling generator skill) →
|
|
150
|
+
`dxkit-test`.
|
|
@@ -154,8 +154,7 @@ Exit 0 = the feature added no net-new regressions. Exit 1 = something new
|
|
|
154
154
|
appeared — **a finding you introduced.** Address it before pushing:
|
|
155
155
|
|
|
156
156
|
- A real finding in your new code → fix it now (hand off to `dxkit-action`
|
|
157
|
-
for the fix recipes — secret rotation, dep upgrade,
|
|
158
|
-
test, etc.).
|
|
157
|
+
for the fix recipes — secret rotation, dep upgrade, SAST, etc.).
|
|
159
158
|
- A genuine false positive / intentional pattern → allowlist with a typed
|
|
160
159
|
category + reason (see `dxkit-action`'s allowlisting section). Fix first;
|
|
161
160
|
allowlist second.
|
|
@@ -163,6 +162,15 @@ appeared — **a finding you introduced.** Address it before pushing:
|
|
|
163
162
|
The feature isn't done when it works — it's done when it works **and** the
|
|
164
163
|
guardrail is green.
|
|
165
164
|
|
|
165
|
+
### Offer to test the new surface
|
|
166
|
+
|
|
167
|
+
A new feature is the most common source of a fresh test gap. When step [5]'s
|
|
168
|
+
`test-gaps` shows the code you just added is untested — especially if it has
|
|
169
|
+
callers (a non-trivial blast radius) — **offer to write tests for it, and on
|
|
170
|
+
the user's confirmation hand off to `dxkit-test`** to write them grounded in
|
|
171
|
+
the behavior you just built. Keep it an offer: don't auto-generate tests the
|
|
172
|
+
user didn't ask for, but don't let a new untested surface ship silently either.
|
|
173
|
+
|
|
166
174
|
## [6] Baseline decision
|
|
167
175
|
|
|
168
176
|
| Scenario | Action |
|
|
@@ -180,7 +188,10 @@ own feature introduced.
|
|
|
180
188
|
## Hand-offs
|
|
181
189
|
|
|
182
190
|
- A finding the guardrail blocked needs fixing → `dxkit-action` (the fix-loop
|
|
183
|
-
recipes for secrets, dep-vulns, SAST
|
|
191
|
+
recipes for secrets, dep-vulns, SAST).
|
|
192
|
+
- Writing tests for the new (or any untested) surface → `dxkit-test`.
|
|
193
|
+
- Raising the PR once the feature is built + green → `dxkit-pr` (title + body
|
|
194
|
+
from the diff, dxkit signals, reviewer checklist).
|
|
184
195
|
- Re-running reports between iterations → `dxkit-reports`.
|
|
185
196
|
- Ignore-file / config edits as part of the feature → `dxkit-config`.
|
|
186
197
|
- Hook problems on the verify push → `dxkit-hooks`.
|
|
@@ -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 —
|
|
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.
|
|
@@ -21,7 +21,7 @@ Ask the user what they want, then pick the right invocation:
|
|
|
21
21
|
|
|
22
22
|
| Flag | What it ships | Default under `--full`? |
|
|
23
23
|
|---|---|---|
|
|
24
|
-
| `--with-dxkit-agents` | The
|
|
24
|
+
| `--with-dxkit-agents` | The dxkit-* skills + AGENTS.md + CLAUDE.md shim | Yes |
|
|
25
25
|
| `--with-hooks` | `.githooks/pre-push` + postinstall activation wire-up | Yes |
|
|
26
26
|
| `--with-precommit-hook` | Adds `.githooks/pre-commit` (slow on large repos) | No (still opt-in) |
|
|
27
27
|
| `--with-devcontainer` | `.devcontainer/devcontainer.json` (per-stack features) + post-create.sh | Yes |
|
|
@@ -82,7 +82,7 @@ Before running, ASK:
|
|
|
82
82
|
|
|
83
83
|
Optional flags worth surfacing if the customer pushes back on "full":
|
|
84
84
|
|
|
85
|
-
- `--with-dxkit-agents` — just the
|
|
85
|
+
- `--with-dxkit-agents` — just the dxkit-* skills (no hooks, no CI)
|
|
86
86
|
- `--with-hooks --with-dxkit-agents` — skills + pre-push hook
|
|
87
87
|
- `--with-precommit-hook` — also pre-commit (slow on large repos)
|
|
88
88
|
|
|
@@ -262,7 +262,7 @@ When in doubt, dxkit-onboard handles the full first-install journey and delegate
|
|
|
262
262
|
```
|
|
263
263
|
✓ Fresh dxkit install complete:
|
|
264
264
|
• Binary: 2.5.X installed globally + project-local
|
|
265
|
-
• Scaffold:
|
|
265
|
+
• Scaffold: dxkit-* skills, AGENTS.md, CLAUDE.md, devcontainer, hooks, CI workflows
|
|
266
266
|
• Doctor: 14/14 (Reports + Agent DX + Operational health)
|
|
267
267
|
• Baseline: N findings locked in (or "skipped — you're triaging first")
|
|
268
268
|
• Pre-commit: yes/no (your choice)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dxkit-pr
|
|
3
|
+
description: Open a pull request with a title + body grounded in the branch's real commits and diff — what changed, features implemented, findings fixed — plus a reviewer checklist and the dxkit guardrail/allowlist/score signals a reviewer needs. Use when the user says "raise a PR", "open a pull request", "create the PR", "write the PR description", or after dxkit-feature / dxkit-action finishes a change and it's ready to push for review.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dxkit-pr
|
|
7
|
+
|
|
8
|
+
This skill turns a finished branch into a **reviewable** pull request: a title
|
|
9
|
+
and body grounded in what actually changed (not a generic template), and a
|
|
10
|
+
checklist that guides the reviewer through what to verify. It's the natural
|
|
11
|
+
close of `dxkit-feature` (built something) and `dxkit-action` (fixed findings) —
|
|
12
|
+
both hand off here when the work is ready for review.
|
|
13
|
+
|
|
14
|
+
A good PR description is written from the diff, not from memory. This skill
|
|
15
|
+
reads the branch, summarizes it honestly, and attaches the dxkit signals
|
|
16
|
+
(guardrail verdict, allowlist activity, score movement) a reviewer would
|
|
17
|
+
otherwise have to reconstruct by hand.
|
|
18
|
+
|
|
19
|
+
## The PR loop
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
[1] Survey → branch vs base: commits, diff stat, files touched
|
|
23
|
+
[2] Classify → features / fixes / refactors / docs / findings closed
|
|
24
|
+
[3] Signals → guardrail verdict + allowlist activity + score deltas
|
|
25
|
+
[4] Draft → title + body grounded in [1]–[3] + a reviewer checklist
|
|
26
|
+
[5] Confirm → show the user the draft; open with `gh pr create` on yes
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Don't skip [5]. A PR is outward-facing — show the draft and get a yes before
|
|
30
|
+
opening it.
|
|
31
|
+
|
|
32
|
+
## [1] Survey — read the branch, don't guess
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
git fetch origin
|
|
36
|
+
BASE=origin/main # or the repo's default branch
|
|
37
|
+
git log --oneline $BASE..HEAD # every commit on this branch
|
|
38
|
+
git diff --stat $BASE...HEAD # files + churn
|
|
39
|
+
git diff $BASE...HEAD # the actual change, when you need detail
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Read the commit messages first — on a well-kept branch they already narrate the
|
|
43
|
+
work. Use the diff to verify and fill gaps, not to re-derive everything.
|
|
44
|
+
|
|
45
|
+
## [2] Classify — group the change for a reviewer
|
|
46
|
+
|
|
47
|
+
Sort the commits/diff into the buckets a reviewer cares about:
|
|
48
|
+
|
|
49
|
+
- **Features** — new capability, with the entry point / surface it adds.
|
|
50
|
+
- **Fixes** — bugs or findings closed (name the finding if it came from a dxkit
|
|
51
|
+
report: rule, file, severity).
|
|
52
|
+
- **Refactors** — behavior-preserving structure changes (flag these — they're
|
|
53
|
+
where "looks big, reads safe" lives).
|
|
54
|
+
- **Docs / tests / chore** — supporting changes.
|
|
55
|
+
|
|
56
|
+
Lead the body with the *why* (the problem) and the *what* (the approach), then
|
|
57
|
+
the bucketed change list. Keep it proportional — a one-commit fix gets a short
|
|
58
|
+
body; a multi-commit feature gets sections.
|
|
59
|
+
|
|
60
|
+
## [3] Signals — attach what dxkit knows
|
|
61
|
+
|
|
62
|
+
Run the guardrail so the PR states its own verdict, and surface any suppression
|
|
63
|
+
activity a reviewer must sign off on:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx vyuh-dxkit guardrail check # PASS/FAIL the PR will get in CI
|
|
67
|
+
npx vyuh-dxkit allowlist audit # any new/expiring suppressions?
|
|
68
|
+
npx vyuh-dxkit health --detailed | head -40 # score movement, if relevant
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Put in the body:
|
|
72
|
+
|
|
73
|
+
- **Guardrail verdict** — PASS, or FAIL with the net-new findings named (a
|
|
74
|
+
reviewer should know before CI tells them).
|
|
75
|
+
- **Allowlist activity** — any suppression added on this branch, with its
|
|
76
|
+
category + reason + expiry, called out for explicit review (suppressions are
|
|
77
|
+
the highest-trust thing a reviewer approves).
|
|
78
|
+
- **Score deltas** — only when the change targeted a dimension (e.g. "Tests
|
|
79
|
+
62 → 71 after closing the auth gaps"). Don't pad with unchanged scores.
|
|
80
|
+
|
|
81
|
+
## [4] Draft — title, body, reviewer checklist
|
|
82
|
+
|
|
83
|
+
**Title** — imperative, scoped, specific. `feat(auth): add refresh-token
|
|
84
|
+
rotation`, not `Updates`. Match the repo's existing PR/commit convention
|
|
85
|
+
(check `git log` on the base branch).
|
|
86
|
+
|
|
87
|
+
**Body** — structure:
|
|
88
|
+
|
|
89
|
+
```markdown
|
|
90
|
+
## What & why
|
|
91
|
+
<the problem this solves, in 1–3 sentences>
|
|
92
|
+
|
|
93
|
+
## Changes
|
|
94
|
+
- **Feature:** …
|
|
95
|
+
- **Fix:** … (closes <finding/issue>)
|
|
96
|
+
- **Refactor:** … (behavior-preserving)
|
|
97
|
+
|
|
98
|
+
## dxkit signals
|
|
99
|
+
- Guardrail: ✅ PASS (or ❌ + the net-new findings)
|
|
100
|
+
- Allowlist: <new suppressions + reason + expiry, or "no changes">
|
|
101
|
+
- Scores: <dimension deltas, if the change targeted one>
|
|
102
|
+
|
|
103
|
+
## Reviewer checklist
|
|
104
|
+
- [ ] Change matches the description; scope isn't broader than stated
|
|
105
|
+
- [ ] <feature>: behavior verified (how to exercise it)
|
|
106
|
+
- [ ] Refactors are behavior-preserving (no silent semantic change)
|
|
107
|
+
- [ ] New/changed code is tested; test gaps addressed or noted
|
|
108
|
+
- [ ] Any allowlist suppression is justified (category + reason + expiry)
|
|
109
|
+
- [ ] No secrets/keys/tokens in the diff
|
|
110
|
+
- [ ] Docs updated if behavior or interfaces changed
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Tailor the checklist to the *actual* change — drop rows that don't apply, add
|
|
114
|
+
specific ones (a migration step, a config flag to set, a caller to re-test from
|
|
115
|
+
the blast radius). A generic checklist is noise; a targeted one guides the review.
|
|
116
|
+
|
|
117
|
+
## [5] Confirm + open
|
|
118
|
+
|
|
119
|
+
Show the user the full draft (title + body) and confirm. On yes:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
git push -u origin HEAD # if not already pushed
|
|
123
|
+
gh pr create --base main --title "<title>" --body "<body>"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If `gh` isn't authenticated, print the title + body for the user to paste, and
|
|
127
|
+
point them at `gh auth login`. Never open a PR the user hasn't seen.
|
|
128
|
+
|
|
129
|
+
## Scope — what NOT to do
|
|
130
|
+
|
|
131
|
+
- Don't invent changes the diff doesn't show, or claim a finding is fixed
|
|
132
|
+
without having verified it (re-run the analyzer first — see `dxkit-action`).
|
|
133
|
+
- Don't open the PR before the guardrail is green, unless the user explicitly
|
|
134
|
+
wants a draft PR for early review — and then mark it draft and say so in the body.
|
|
135
|
+
- Don't restate every commit verbatim — synthesize. The commit log is one click
|
|
136
|
+
away; the body's job is the narrative + the review guidance.
|
|
137
|
+
|
|
138
|
+
## Hand-offs
|
|
139
|
+
|
|
140
|
+
- A guardrail FAIL blocking the PR → `dxkit-action` to fix the net-new findings first.
|
|
141
|
+
- Writing the feature being PR'd → `dxkit-feature`; closing test gaps it opened → `dxkit-test`.
|
|
142
|
+
- Branch-protection / required-check setup so the PR is actually gated → `dxkit-hooks` / repo settings.
|
|
@@ -103,7 +103,7 @@ Surface those three when summarizing a dep-vuln finding. The detailed JSON has t
|
|
|
103
103
|
|
|
104
104
|
## When the user wants to ACT on findings
|
|
105
105
|
|
|
106
|
-
Hand off to the `dxkit-action` skill — that's the workflow for prioritizing + fixing + re-baselining. This skill stops at "here's what's wrong."
|
|
106
|
+
Hand off to the `dxkit-action` skill — that's the workflow for prioritizing + fixing + re-baselining. This skill stops at "here's what's wrong." For a dimension-focused push, hand to the specialist generator skills instead: **dxkit-test** to close test-gaps / raise the Tests score, **dxkit-docs** to write missing documentation.
|
|
107
107
|
|
|
108
108
|
## Troubleshooting
|
|
109
109
|
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dxkit-test
|
|
3
|
+
description: Write the tests a repo is missing — read the test-gaps report (blast-radius-weighted), orient on what the untested code actually does via the graph, then write real tests that close the highest-risk gaps and move the Tests score without coverage theater. Use when the user says "write tests", "add tests for this module", "improve the test coverage / Tests score", "close the test gaps", "cover the untested files", or after a health report flags Testing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# dxkit-test
|
|
7
|
+
|
|
8
|
+
This skill closes the gap `dxkit-action` doesn't: it **writes** the missing
|
|
9
|
+
tests rather than fixing flagged findings. It is the testing mirror of
|
|
10
|
+
`dxkit-docs` — same shape, different dimension. It's built around one hard
|
|
11
|
+
constraint: a test that doesn't actually exercise behavior (an empty `expect(true)`,
|
|
12
|
+
a snapshot of nothing, a call with no assertion) raises the coverage number
|
|
13
|
+
while proving nothing. The whole point of this skill is tests that are
|
|
14
|
+
**grounded in real behavior** and **catch real regressions** — not coverage
|
|
15
|
+
theater.
|
|
16
|
+
|
|
17
|
+
## The testing loop
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
[1] Read the gap → test-gaps: the blast-radius-weighted untested worklist
|
|
21
|
+
[2] Orient → graph: what the file does, who depends on it, what to assert
|
|
22
|
+
[3] Generate → write real tests in the repo's framework + patterns
|
|
23
|
+
[4] Verify → run the suite + coverage; Tests up, nothing red
|
|
24
|
+
[5] Guardrail → guardrail check before pushing
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Don't skip [2] or [4]. [2] is what makes the tests meaningful; [4] is what
|
|
28
|
+
proves they pass and the coverage actually moved.
|
|
29
|
+
|
|
30
|
+
## [1] Read the gap — what's actually untested, worst-first
|
|
31
|
+
|
|
32
|
+
Run the test-gaps report with graph context so the worklist is ranked by
|
|
33
|
+
**blast radius** (how many files depend on each untested file), not just size:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx vyuh-dxkit test-gaps --detailed --graph-context
|
|
37
|
+
npx vyuh-dxkit test-gaps --detailed --graph-context --json | jq '.actions, .gaps[0:10]'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The report partitions untested files into CRITICAL / HIGH / MEDIUM / LOW risk
|
|
41
|
+
tiers, and **within each tier the most-depended-on files surface first** (the
|
|
42
|
+
`Graph context` column shows `role · N caller files`). Work top-down: a
|
|
43
|
+
30-caller untested file is a bigger liability than a 500-line leaf nothing
|
|
44
|
+
calls. The `actions` array names the top-K per tier with projected
|
|
45
|
+
score uplift — that's your queue.
|
|
46
|
+
|
|
47
|
+
A `blast radius n/a` cell means graphify couldn't resolve that language's call
|
|
48
|
+
graph (C# is the known case) — treat it as *unknown*, not "no callers," and
|
|
49
|
+
fall back to the file's role + size to judge its risk.
|
|
50
|
+
|
|
51
|
+
## [2] Orient — understand the behavior before you assert on it
|
|
52
|
+
|
|
53
|
+
A test is only as good as your understanding of what the code should do.
|
|
54
|
+
Before writing, learn the real shape from the graph (cheap, structural):
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx vyuh-dxkit context src/payments/refund.ts # the file's symbols, callers, callees
|
|
58
|
+
npx vyuh-dxkit explore file src/payments/refund.ts # its structural neighborhood
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Use it to decide three things:
|
|
62
|
+
|
|
63
|
+
- **What the public contract is** — the exported symbols are what callers rely
|
|
64
|
+
on; test those, not private helpers.
|
|
65
|
+
- **What the callers expect** — the caller files (blast radius) tell you the
|
|
66
|
+
real usage shapes to cover, including the edge cases they pass.
|
|
67
|
+
- **What's risky** — error paths, branching, boundary conditions. Then **read
|
|
68
|
+
the actual code** — the graph points you at it; it doesn't replace reading
|
|
69
|
+
it.
|
|
70
|
+
|
|
71
|
+
## [3] Generate — real tests, the repo's way
|
|
72
|
+
|
|
73
|
+
- **Match the existing framework + conventions.** Detect what the repo already
|
|
74
|
+
uses (vitest/jest, pytest, go test, JUnit, RSpec, …) from the existing test
|
|
75
|
+
files and `test-gaps` output — never introduce a new test framework. Copy the
|
|
76
|
+
nearest existing test's structure, naming, fixtures, and assertion style so
|
|
77
|
+
the new tests read like the repo's.
|
|
78
|
+
- **Assert behavior, not existence.** Each test must exercise a real path and
|
|
79
|
+
assert a real outcome — return values, side effects, error handling,
|
|
80
|
+
boundaries. A test that calls a function and asserts nothing is slop.
|
|
81
|
+
- **Cover the contract + the edges.** Happy path, the error/edge cases the
|
|
82
|
+
callers actually hit, and at least one boundary. Prioritize branches over
|
|
83
|
+
lines.
|
|
84
|
+
- **Don't fake it.** No mocking the unit under test into a tautology; no
|
|
85
|
+
asserting on a stub you wrote. Mock external boundaries (network, clock,
|
|
86
|
+
fs) the way the repo already does.
|
|
87
|
+
|
|
88
|
+
## [4] Verify — Tests up, suite green, no coverage theater
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
# Run the repo's real test command (from package.json / Makefile / etc.)
|
|
92
|
+
<the repo's test command> # e.g. npm test, pytest, go test ./...
|
|
93
|
+
|
|
94
|
+
# Re-materialize coverage + the gap report
|
|
95
|
+
npx vyuh-dxkit coverage # runs the suite to produce real line coverage
|
|
96
|
+
npx vyuh-dxkit test-gaps --detailed # the targeted gap should be gone / downgraded
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The work is done when:
|
|
100
|
+
|
|
101
|
+
- The new tests **pass** (a failing or skipped test is not coverage).
|
|
102
|
+
- The targeted file is no longer in the gap worklist (or dropped a risk tier).
|
|
103
|
+
- `effectiveCoverage` rose from a real signal — prefer line-coverage truth
|
|
104
|
+
(`coverage`) over the filename-match heuristic; a name-matched 5-line test on
|
|
105
|
+
a 200-line file is exactly the theater this skill exists to avoid.
|
|
106
|
+
|
|
107
|
+
## [5] Guardrail — before pushing
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx vyuh-dxkit guardrail check
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Exit 0 = your new tests didn't introduce a net-new regression (e.g. a flaky
|
|
114
|
+
test, a slop finding in test prose). Address anything it flags before pushing.
|
|
115
|
+
|
|
116
|
+
## Scope — what NOT to test
|
|
117
|
+
|
|
118
|
+
- Don't test auto-generated, vendored, or trivial pass-through code just to
|
|
119
|
+
move the number — credit comes from covering the files that carry risk.
|
|
120
|
+
- Don't write tests you can't make pass; a `.skip` is a gap, not a closure.
|
|
121
|
+
- Don't assert on implementation details that will break on every refactor —
|
|
122
|
+
test the contract, not the internals.
|
|
123
|
+
|
|
124
|
+
## Hand-offs
|
|
125
|
+
|
|
126
|
+
- Running / interpreting the health or test-gaps report → `dxkit-reports`.
|
|
127
|
+
- A test gap surfaced as one finding inside a broader fix pass → `dxkit-action`.
|
|
128
|
+
- Testing a feature you're building → `dxkit-feature` (it offers to hand the
|
|
129
|
+
new surface here once the feature lands).
|
|
130
|
+
- Documentation gaps (the sibling generator skill) → `dxkit-docs`.
|
|
@@ -135,6 +135,10 @@ Iterate optional steps in the plan:
|
|
|
135
135
|
| "Doctor says X is broken" | `dxkit-fix` |
|
|
136
136
|
| "I want to run a report" | `dxkit-reports` |
|
|
137
137
|
| "Fix these findings" | `dxkit-action` |
|
|
138
|
+
| "Write the missing tests" | `dxkit-test` |
|
|
139
|
+
| "Write the missing docs" | `dxkit-docs` |
|
|
140
|
+
| "Manage / audit the allowlist" | `dxkit-allowlist` |
|
|
141
|
+
| "Raise the PR" | `dxkit-pr` |
|
|
138
142
|
| "Configure dxkit" | `dxkit-config` |
|
|
139
143
|
| "Set up hooks" | `dxkit-hooks` |
|
|
140
144
|
| "Explain dxkit" | `dxkit-learn` |
|
|
@@ -12,14 +12,20 @@ For agent-specific config, see the editor-specific files alongside this one —
|
|
|
12
12
|
|
|
13
13
|
This repo is managed by [`@vyuhlabs/dxkit`](https://github.com/vyuh-labs/dxkit). dxkit measures code health across 6 dimensions, captures a per-finding baseline, and gates PRs on net-new regressions.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
The `dxkit-*` skills are installed under `.claude/skills/` (Claude Code auto-discovers via skill frontmatter):
|
|
16
16
|
|
|
17
17
|
- **dxkit-learn** — explains dxkit concepts (baselines, dimensions, scanners)
|
|
18
|
-
- **dxkit-init** — interactive setup
|
|
18
|
+
- **dxkit-onboard** — fresh-install walkthrough; **dxkit-init** — interactive setup
|
|
19
19
|
- **dxkit-config** — edit `.dxkit-ignore`, `.vyuh-dxkit.json`, policy
|
|
20
20
|
- **dxkit-hooks** — install / troubleshoot git hooks
|
|
21
21
|
- **dxkit-reports** — run analyzers, explain output, dashboard
|
|
22
|
-
- **dxkit-action** — prioritize + fix + verify + re-baseline
|
|
22
|
+
- **dxkit-action** — prioritize + fix + verify + re-baseline (scoped to one category if asked)
|
|
23
|
+
- **dxkit-test** — write the missing tests to close gaps; **dxkit-docs** — write the missing docs
|
|
24
|
+
- **dxkit-feature** — graph-guided net-new development
|
|
25
|
+
- **dxkit-ingest** — bring external SAST (Snyk Code / CodeQL / SARIF) into dxkit
|
|
26
|
+
- **dxkit-allowlist** — manage the suppression lifecycle (audit / remove / prune / export to Snyk)
|
|
27
|
+
- **dxkit-pr** — open a PR with a diff-grounded body + reviewer checklist
|
|
28
|
+
- **dxkit-update** — upgrade an existing install; **dxkit-fix** — repair a broken one
|
|
23
29
|
|
|
24
30
|
Reach for the relevant skill when working in this repo. They wrap the `vyuh-dxkit` CLI with workflow guidance.
|
|
25
31
|
|
|
@@ -6,14 +6,20 @@ Whenever Claude Code starts a session in this repo, it reads BOTH files: this on
|
|
|
6
6
|
|
|
7
7
|
## dxkit skills
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The `dxkit-*` skills are installed under `.claude/skills/`. Claude Code auto-discovers them via their frontmatter `description` fields:
|
|
10
10
|
|
|
11
11
|
- `dxkit-learn` — explain what dxkit does, what scores mean, what scanners run
|
|
12
|
-
- `dxkit-init` —
|
|
12
|
+
- `dxkit-onboard` / `dxkit-init` — fresh-install walkthrough / `init` flag choices
|
|
13
13
|
- `dxkit-config` — edit `.dxkit-ignore` / `.vyuh-dxkit.json` / policy
|
|
14
14
|
- `dxkit-hooks` — install / troubleshoot git hooks
|
|
15
15
|
- `dxkit-reports` — run analyzers + read output
|
|
16
|
-
- `dxkit-action` — prioritize + fix + verify + re-baseline
|
|
16
|
+
- `dxkit-action` — prioritize + fix + verify + re-baseline (scoped to one category if asked)
|
|
17
|
+
- `dxkit-test` / `dxkit-docs` — write the missing tests / docs to move a dimension
|
|
18
|
+
- `dxkit-feature` — graph-guided net-new development
|
|
19
|
+
- `dxkit-ingest` — bring external SAST (Snyk Code / CodeQL / SARIF) into dxkit
|
|
20
|
+
- `dxkit-allowlist` — manage the suppression lifecycle (audit / remove / prune / export)
|
|
21
|
+
- `dxkit-pr` — open a PR with a diff-grounded body + reviewer checklist
|
|
22
|
+
- `dxkit-update` / `dxkit-fix` — upgrade / repair an install
|
|
17
23
|
|
|
18
24
|
When the user asks about dxkit concepts or wants to run an analyzer, reach for the matching skill before improvising.
|
|
19
25
|
|