v2.6.0 — per-finding suppression + public-repo-safe baselines
The "per-finding suppression + public-repo-safe baselines" release.
Adds the typed-category allowlist surface for false-positive /
test-fixture / mitigated-externally / accepted-risk / deferred
suppression with inline + file-level modes; retires license
findings from the baseline (~73% size drop on real customer repos);
introduces three baseline modes with visibility-aware defaults so
public repos no longer leak file paths, package names, and
advisory IDs through a committed baseline.
Added
- Per-finding allowlist —
vyuh-dxkit allowlist add/list/show/audit/prune.
Typed-category suppression (false-positive,test-fixture,
mitigated-externally,accepted-risk,deferred) with required
reason + (where relevant) expiry. Two surfaces: inline
// dxkit-allow:<category> reason="..."annotations and a
file-level.dxkit/allowlist.json.accepted-riskanddeferred
require expiry (default 90 days). See
docs/commands/allowlist.md. - Strict stale-annotation detection — orphaned
dxkit-allow:
annotations (where the underlying finding is now gone) emit a
newstale-allowbaseline kind on the next scan. The
TypeScript@ts-expect-errorpattern, applied to suppressions —
forces cleanup, prevents the annotation graveyard. Allowlisting
astale-allowfinding is forbidden; only remediation is to
remove the orphaned comment. - Allowlist activity in PR comments — the
dxkit-guardrails.ymlworkflow's sticky PR comment now includes
an "Allowlist activity" section listing every entry added (or
removed) on this branch versus the baseline commit. Reviewers
see new suppressions being introduced and can sanity-check
category + reason + expiry before approving. vyuh-dxkit issue— pre-filled GitHub Issues for false
positives, missing findings, bugs, feature requests, and docs
gaps. Nothing submits automatically — the CLI opens the
customer's browser at a new-issue URL with env metadata
pre-populated, customer reviews + clicks "Submit." See
docs/commands/issue.md.commentSyntaxon language packs — each pack declares its
line-comment marker (#for python/ruby;//for
typescript/go/rust/csharp/kotlin/java). Drives the inline
allowlist-annotation generator across every language uniformly.
Recipe-enforced: scaffolder ships an empty placeholder so
unfilled packs fail the contract test until populated.- Three preemptive architecture rules in
scripts/check-architecture.sh
lock down the allowlist canonical entry points: nocreateHash
insidesrc/allowlist/, no directallowlist.jsonIO outside
the canonical loader, no language-comment fallback literals
(?? '//') anywhere in the module.
Changed
- License findings retired from the baseline. Per-package
license attributions no longer flow through the baseline
producer registry — they were informational, not regression
material, and dominated baselines on real customer repos
(~73% of entries). The canonical license inventory now lives
solely in.dxkit/bom.json(vyuh-dxkit bom), which already
carries richer per-package data (licenseType, licenseText,
sourceUrl, supplier, releaseDate). Lenient migration:
baselines written by older dxkit versions still load — the
reader silently filters retiredlicenseentries on the way
in (no file rewrite until the nextbaseline create --force).
Dependency vulnerability tracking is unchanged —dep-vuln
is a separate identity kind on a separate producer and still
blocks via the guardrail check. - Sanitization machinery for baseline entries. New pure
modulesrc/baseline/sanitize.tsintroduces a stripped
SanitizedBaselineEntryvariant ({ id, kind, sanitized: true })
carrying identity + kind only. ThesanitizeEntry/
sanitizeFilepass collapses every rich field; cross-run
matching still works at full confidence via the fingerprint
multiset pass. Producers now emit the rich
RichBaselineEntryshape (aBaselineEntryexcluding the
sanitized variant); sanitization is a write-time
transformation, never a producer concern. Consumers walking
a baseline narrow via theisSanitizedtype guard before
switching onentry.kind. Write-path wiring + visibility-
aware mode selection ship in a follow-up commit.
Added
- Three baseline modes with visibility-aware defaults.
committed-full(today's behavior, rich entries),committed- sanitized(stripped per-entry payload via the sanitization
pass), andref-based(no committed file; guardrail check
recomputes the prior side from a git ref viagit worktree add). The mode is picked by a single resolver
(src/baseline/modes.ts) with precedence: CLI flag →
.dxkit/policy.json:baseline.mode→ visibility-derived default
(public repos auto-pickref-based; everything else picks
committed-full).committed-sanitizedis never auto-picked
— it's the explicit opt-in for compliance-conscious private
repos. vyuh-dxkit baseline create [--mode <m>] [--ref <r>]and
vyuh-dxkit guardrail check [--mode <m>] [--ref <r>]— flags
overridepolicy.jsonfor one-off runs.gh repo view --json visibilityprobe + per-process cache
insrc/baseline/visibility.ts. Every failure path returns
'unknown'; the resolver treats unknown as private to avoid
surprise sanitization whengh authlapses.- Ref-based gather mechanics in
src/baseline/ref-baseline.ts—
withRefWorktree(opts, fn)is the reusable primitive; tears
down the worktree on success + failure. Mirrors file-mode
.dxkit/saltinto the worktree so secret-HMAC entries pair
across cwd + worktree.
Architectural notes
- New CLAUDE.md rule 11: baseline mode resolution flows through
resolveBaselineMode. Two arch-check rules lock the contract:
nogh repo view --json visibilityoutside
src/baseline/visibility.ts; nogit worktree add/remove
outsidesrc/baseline/ref-baseline.ts. resolvePolicylifted fromcheck.tstopolicy.tsso
createBaselineandrunGuardrailCheckshare one canonical
loader.
Discovery surfaces
- PR-comment markdown now shows the resolved baseline mode in
the sticky footer (_Mode_: \ref-based` (ref: `origin/main`)`).
Reviewers see WHY a guardrail run picked a given posture. - JSON renderer carries
baseline.mode = { value, source, explanation, ref? }so agents + dashboards can read the audit
trail without re-deriving it. vyuh-dxkit doctorhas two new operational checks:- "baseline mode: ref-based" / "baseline captured (mode: ...)" —
the existing baseline-captured check now understands ref-based
mode (where no on-disk file is expected) so the doctor stops
reporting a false-negative on public repos. - "baseline mode aligned with repo visibility" — warns when an
explicitcommitted-fullpin is in use on a public repo (the
posture leaks file paths + package names; the auto-picker
would have chosen ref-based).
- "baseline mode: ref-based" / "baseline captured (mode: ...)" —
dxkit-onboardskill — step 5 now ASKs about disclosure
posture before runningbaseline create, walks customers through
the three modes, and offers a one-shot.dxkit/policy.jsonsnippet
for pinning the choice repo-wide.dxkit-actionskill — new section explains how to act on a
blocked finding when the baseline is sanitized / ref-based
(locator stripped at write time; re-run the analyzer for full
context or allowlist by fingerprint).- README + getting-started.md — call out the public-repo
posture explicitly so customers don't accidentally commit a
rich baseline to an open-source repo.
Architectural notes
- Added
stale-allowas a newIdentityKind(Rule 9 + Rule 10
compliant: identityFor case + producer + fixture row +
removed fromDEFERRED_KINDSonce the gather pass landed). - The hint formatter (block-time guidance for blocked findings)
consumes the canonicalBaselineEntrydiscriminated union
directly — no invented intermediate "BlockingFinding" shape.
TypeScript exhaustiveness across 6+ switches guarantees new
finding kinds can't ship without matching cases. dxkit-actionskill extended with the typed-category +
surfaces description; SAST recipe redirects from semgrep's
// nosemgrep:to dxkit's// dxkit-allow:(single canonical
suppression surface across all scanners).