@vyuhlabs/dxkit 2.5.2 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +164 -0
- package/README.md +102 -0
- package/dist/allowlist/categories.d.ts +120 -0
- package/dist/allowlist/categories.d.ts.map +1 -0
- package/dist/allowlist/categories.js +194 -0
- package/dist/allowlist/categories.js.map +1 -0
- package/dist/allowlist/cli.d.ts +95 -0
- package/dist/allowlist/cli.d.ts.map +1 -0
- package/dist/allowlist/cli.js +454 -0
- package/dist/allowlist/cli.js.map +1 -0
- package/dist/allowlist/diff.d.ts +67 -0
- package/dist/allowlist/diff.d.ts.map +1 -0
- package/dist/allowlist/diff.js +147 -0
- package/dist/allowlist/diff.js.map +1 -0
- package/dist/allowlist/file.d.ts +249 -0
- package/dist/allowlist/file.d.ts.map +1 -0
- package/dist/allowlist/file.js +497 -0
- package/dist/allowlist/file.js.map +1 -0
- package/dist/allowlist/gather.d.ts +61 -0
- package/dist/allowlist/gather.d.ts.map +1 -0
- package/dist/allowlist/gather.js +143 -0
- package/dist/allowlist/gather.js.map +1 -0
- package/dist/allowlist/hint.d.ts +80 -0
- package/dist/allowlist/hint.d.ts.map +1 -0
- package/dist/allowlist/hint.js +271 -0
- package/dist/allowlist/hint.js.map +1 -0
- package/dist/allowlist/inline.d.ts +149 -0
- package/dist/allowlist/inline.d.ts.map +1 -0
- package/dist/allowlist/inline.js +306 -0
- package/dist/allowlist/inline.js.map +1 -0
- package/dist/baseline/baseline-file.d.ts +7 -0
- package/dist/baseline/baseline-file.d.ts.map +1 -1
- package/dist/baseline/baseline-file.js +22 -1
- package/dist/baseline/baseline-file.js.map +1 -1
- package/dist/baseline/check-renderers.d.ts +13 -1
- package/dist/baseline/check-renderers.d.ts.map +1 -1
- package/dist/baseline/check-renderers.js +67 -1
- package/dist/baseline/check-renderers.js.map +1 -1
- package/dist/baseline/check.d.ts +33 -7
- package/dist/baseline/check.d.ts.map +1 -1
- package/dist/baseline/check.js +90 -64
- package/dist/baseline/check.js.map +1 -1
- package/dist/baseline/create.d.ts +35 -7
- package/dist/baseline/create.d.ts.map +1 -1
- package/dist/baseline/create.js +43 -5
- package/dist/baseline/create.js.map +1 -1
- package/dist/baseline/entry-to-located.d.ts +6 -1
- package/dist/baseline/entry-to-located.d.ts.map +1 -1
- package/dist/baseline/entry-to-located.js +20 -2
- package/dist/baseline/entry-to-located.js.map +1 -1
- package/dist/baseline/finding-identity.d.ts.map +1 -1
- package/dist/baseline/finding-identity.js +15 -13
- package/dist/baseline/finding-identity.js.map +1 -1
- package/dist/baseline/modes.d.ts +140 -0
- package/dist/baseline/modes.d.ts.map +1 -0
- package/dist/baseline/modes.js +179 -0
- package/dist/baseline/modes.js.map +1 -0
- package/dist/baseline/policy.d.ts +64 -0
- package/dist/baseline/policy.d.ts.map +1 -1
- package/dist/baseline/policy.js +102 -1
- package/dist/baseline/policy.js.map +1 -1
- package/dist/baseline/producers/health.d.ts +2 -2
- package/dist/baseline/producers/health.d.ts.map +1 -1
- package/dist/baseline/producers/health.js.map +1 -1
- package/dist/baseline/producers/index.d.ts +11 -5
- package/dist/baseline/producers/index.d.ts.map +1 -1
- package/dist/baseline/producers/index.js +12 -9
- package/dist/baseline/producers/index.js.map +1 -1
- package/dist/baseline/producers/quality.d.ts +3 -3
- package/dist/baseline/producers/quality.d.ts.map +1 -1
- package/dist/baseline/producers/quality.js.map +1 -1
- package/dist/baseline/producers/secret-hmac.d.ts +2 -2
- package/dist/baseline/producers/secret-hmac.d.ts.map +1 -1
- package/dist/baseline/producers/secret-hmac.js.map +1 -1
- package/dist/baseline/producers/security.d.ts +2 -2
- package/dist/baseline/producers/security.d.ts.map +1 -1
- package/dist/baseline/producers/security.js.map +1 -1
- package/dist/baseline/producers/stale-allow.d.ts +70 -0
- package/dist/baseline/producers/stale-allow.d.ts.map +1 -0
- package/dist/baseline/producers/stale-allow.js +111 -0
- package/dist/baseline/producers/stale-allow.js.map +1 -0
- package/dist/baseline/producers/tests.d.ts +2 -2
- package/dist/baseline/producers/tests.d.ts.map +1 -1
- package/dist/baseline/producers/tests.js.map +1 -1
- package/dist/baseline/ref-baseline.d.ts +114 -0
- package/dist/baseline/ref-baseline.d.ts.map +1 -0
- package/dist/baseline/ref-baseline.js +260 -0
- package/dist/baseline/ref-baseline.js.map +1 -0
- package/dist/baseline/sanitize.d.ts +80 -0
- package/dist/baseline/sanitize.d.ts.map +1 -0
- package/dist/baseline/sanitize.js +91 -0
- package/dist/baseline/sanitize.js.map +1 -0
- package/dist/baseline/show.d.ts.map +1 -1
- package/dist/baseline/show.js +9 -3
- package/dist/baseline/show.js.map +1 -1
- package/dist/baseline/types.d.ts +73 -26
- package/dist/baseline/types.d.ts.map +1 -1
- package/dist/baseline/types.js +7 -1
- package/dist/baseline/types.js.map +1 -1
- package/dist/baseline/visibility.d.ts +61 -0
- package/dist/baseline/visibility.d.ts.map +1 -0
- package/dist/baseline/visibility.js +121 -0
- package/dist/baseline/visibility.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +88 -3
- package/dist/cli.js.map +1 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +106 -16
- package/dist/doctor.js.map +1 -1
- package/dist/issue-cli.d.ts +62 -0
- package/dist/issue-cli.d.ts.map +1 -0
- package/dist/issue-cli.js +252 -0
- package/dist/issue-cli.js.map +1 -0
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +1 -0
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +1 -0
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/java.d.ts.map +1 -1
- package/dist/languages/java.js +1 -0
- package/dist/languages/java.js.map +1 -1
- package/dist/languages/kotlin.d.ts.map +1 -1
- package/dist/languages/kotlin.js +1 -0
- package/dist/languages/kotlin.js.map +1 -1
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +1 -0
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/ruby.d.ts.map +1 -1
- package/dist/languages/ruby.js +1 -0
- package/dist/languages/ruby.js.map +1 -1
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +1 -0
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +25 -0
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +1 -0
- package/dist/languages/typescript.js.map +1 -1
- package/package.json +1 -1
- package/templates/.claude/skills/dxkit-action/SKILL.md +105 -11
- package/templates/.claude/skills/dxkit-onboard/SKILL.md +31 -3
- package/dist/baseline/producers/licenses.d.ts +0 -23
- package/dist/baseline/producers/licenses.d.ts.map +0 -1
- package/dist/baseline/producers/licenses.js +0 -46
- package/dist/baseline/producers/licenses.js.map +0 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Allowlist delta — what changed between two repo states.
|
|
4
|
+
*
|
|
5
|
+
* The guardrail check posts a PR comment whenever new allowlist
|
|
6
|
+
* entries appear on the PR branch. Reviewers see the suppressions
|
|
7
|
+
* being introduced and can sanity-check the typed category / reason
|
|
8
|
+
* / expiry without manually grepping for `dxkit-allow:` lines.
|
|
9
|
+
*
|
|
10
|
+
* # Two-state comparison
|
|
11
|
+
*
|
|
12
|
+
* `computeAllowlistDelta` compares the current on-disk allowlist
|
|
13
|
+
* (loaded via the canonical `loadAllowlist`) against the allowlist
|
|
14
|
+
* at the baseline's commit SHA (read via `git show <sha>:.dxkit/...`).
|
|
15
|
+
* Each entry's identity is its `fingerprint`; the delta is the
|
|
16
|
+
* symmetric difference of the two fingerprint sets, hydrated back
|
|
17
|
+
* to the full entries on each side.
|
|
18
|
+
*
|
|
19
|
+
* added — entries present in current but not at the baseline SHA
|
|
20
|
+
* removed — entries present at the baseline SHA but not in current
|
|
21
|
+
*
|
|
22
|
+
* # Graceful degradation
|
|
23
|
+
*
|
|
24
|
+
* When the baseline SHA isn't reachable (shallow clone, force-push
|
|
25
|
+
* orphaned base), the delta reports `baselineAccessible: false` and
|
|
26
|
+
* an empty `added` / `removed`. Callers (the renderer) treat that
|
|
27
|
+
* as "delta unavailable" rather than "no changes" — surfacing the
|
|
28
|
+
* incident so the customer can either deepen the clone or accept
|
|
29
|
+
* the missing review signal.
|
|
30
|
+
*
|
|
31
|
+
* Architectural posture:
|
|
32
|
+
* - All IO goes through `loadAllowlist` (CLAUDE.md arch rule 1).
|
|
33
|
+
* - `git show` is the only direct git interaction; failure modes
|
|
34
|
+
* return null without throwing.
|
|
35
|
+
* - Pure function over both inputs (current allowlist + git-resolved
|
|
36
|
+
* baseline allowlist) — testable independently of git state.
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.computeAllowlistDelta = computeAllowlistDelta;
|
|
40
|
+
exports.diffEntries = diffEntries;
|
|
41
|
+
const child_process_1 = require("child_process");
|
|
42
|
+
const file_1 = require("./file");
|
|
43
|
+
/**
|
|
44
|
+
* Compute the delta between the current on-disk allowlist and the
|
|
45
|
+
* allowlist at the baseline's commit SHA. Returns a structurally
|
|
46
|
+
* empty delta with `baselineAccessible: false` when the baseline
|
|
47
|
+
* SHA can't be read.
|
|
48
|
+
*
|
|
49
|
+
* `baselineCommitSha` must be a non-empty hex SHA; an empty string
|
|
50
|
+
* (the canonical "no commit" value baseline-create uses outside a
|
|
51
|
+
* git repo) yields `baselineAccessible: false` immediately.
|
|
52
|
+
*/
|
|
53
|
+
function computeAllowlistDelta(cwd, baselineCommitSha) {
|
|
54
|
+
const current = (0, file_1.loadAllowlist)(cwd);
|
|
55
|
+
const empty = { added: [], removed: [], baselineAccessible: false };
|
|
56
|
+
if (!baselineCommitSha)
|
|
57
|
+
return empty;
|
|
58
|
+
const baselineFile = readAllowlistAtSha(cwd, baselineCommitSha);
|
|
59
|
+
if (baselineFile === null) {
|
|
60
|
+
// git unreachable OR file genuinely didn't exist at the
|
|
61
|
+
// baseline SHA. We can still produce a useful delta in the
|
|
62
|
+
// "file didn't exist" case — every current entry is "added"
|
|
63
|
+
// (the customer adopted the allowlist after baseline-create).
|
|
64
|
+
// Distinguish the two cases by checking whether the SHA is at
|
|
65
|
+
// least resolvable.
|
|
66
|
+
if (!shaReachable(cwd, baselineCommitSha))
|
|
67
|
+
return empty;
|
|
68
|
+
// SHA reachable but file absent → current entries are all new.
|
|
69
|
+
return {
|
|
70
|
+
added: current?.entries ?? [],
|
|
71
|
+
removed: [],
|
|
72
|
+
baselineAccessible: true,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
const currentEntries = current?.entries ?? [];
|
|
76
|
+
return diffEntries(baselineFile.entries, currentEntries);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Pure delta over two entry arrays. Exposed for testability —
|
|
80
|
+
* callers without git state can synthesize before/after fixtures
|
|
81
|
+
* directly. Uses fingerprint equality (the canonical identity
|
|
82
|
+
* predicate) for set diff.
|
|
83
|
+
*/
|
|
84
|
+
function diffEntries(prior, current) {
|
|
85
|
+
const priorByFp = new Map();
|
|
86
|
+
for (const e of prior)
|
|
87
|
+
priorByFp.set(e.fingerprint, e);
|
|
88
|
+
const currentByFp = new Map();
|
|
89
|
+
for (const e of current)
|
|
90
|
+
currentByFp.set(e.fingerprint, e);
|
|
91
|
+
const added = [];
|
|
92
|
+
for (const [fp, e] of currentByFp) {
|
|
93
|
+
if (!priorByFp.has(fp))
|
|
94
|
+
added.push(e);
|
|
95
|
+
}
|
|
96
|
+
const removed = [];
|
|
97
|
+
for (const [fp, e] of priorByFp) {
|
|
98
|
+
if (!currentByFp.has(fp))
|
|
99
|
+
removed.push(e);
|
|
100
|
+
}
|
|
101
|
+
return { added, removed, baselineAccessible: true };
|
|
102
|
+
}
|
|
103
|
+
// ─── Internals ────────────────────────────────────────────────────────────
|
|
104
|
+
function readAllowlistAtSha(cwd, sha) {
|
|
105
|
+
const gitPath = `${file_1.ALLOWLIST_DIR}/${file_1.ALLOWLIST_FILENAME}`;
|
|
106
|
+
let raw;
|
|
107
|
+
try {
|
|
108
|
+
raw = (0, child_process_1.execFileSync)('git', ['show', `${sha}:${gitPath}`], {
|
|
109
|
+
cwd,
|
|
110
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
let parsed;
|
|
118
|
+
try {
|
|
119
|
+
parsed = JSON.parse(raw);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// File existed at the SHA but isn't valid JSON. Treat the same
|
|
123
|
+
// as "absent" — no useful delta computable.
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
127
|
+
return null;
|
|
128
|
+
const obj = parsed;
|
|
129
|
+
if (obj.schemaVersion !== file_1.ALLOWLIST_SCHEMA_VERSION)
|
|
130
|
+
return null;
|
|
131
|
+
if (!Array.isArray(obj.entries))
|
|
132
|
+
return null;
|
|
133
|
+
return parsed;
|
|
134
|
+
}
|
|
135
|
+
function shaReachable(cwd, sha) {
|
|
136
|
+
try {
|
|
137
|
+
(0, child_process_1.execFileSync)('git', ['cat-file', '-e', sha], {
|
|
138
|
+
cwd,
|
|
139
|
+
stdio: ['ignore', 'ignore', 'ignore'],
|
|
140
|
+
});
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/allowlist/diff.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;;AAkCH,sDAyBC;AAQD,kCAkBC;AAnFD,iDAA6C;AAC7C,iCAOgB;AAchB;;;;;;;;;GASG;AACH,SAAgB,qBAAqB,CAAC,GAAW,EAAE,iBAAyB;IAC1E,MAAM,OAAO,GAAG,IAAA,oBAAa,EAAC,GAAG,CAAC,CAAC;IACnC,MAAM,KAAK,GAAmB,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;IAEpF,IAAI,CAAC,iBAAiB;QAAE,OAAO,KAAK,CAAC;IAErC,MAAM,YAAY,GAAG,kBAAkB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;IAChE,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,wDAAwD;QACxD,2DAA2D;QAC3D,4DAA4D;QAC5D,8DAA8D;QAC9D,8DAA8D;QAC9D,oBAAoB;QACpB,IAAI,CAAC,YAAY,CAAC,GAAG,EAAE,iBAAiB,CAAC;YAAE,OAAO,KAAK,CAAC;QACxD,+DAA+D;QAC/D,OAAO;YACL,KAAK,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE;YAC7B,OAAO,EAAE,EAAE;YACX,kBAAkB,EAAE,IAAI;SACzB,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;IAC9C,OAAO,WAAW,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,SAAgB,WAAW,CACzB,KAAoC,EACpC,OAAsC;IAEtC,MAAM,SAAS,GAAG,IAAI,GAAG,EAA0B,CAAC;IACpD,KAAK,MAAM,CAAC,IAAI,KAAK;QAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,IAAI,GAAG,EAA0B,CAAC;IACtD,KAAK,MAAM,CAAC,IAAI,OAAO;QAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAE3D,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,OAAO,GAAqB,EAAE,CAAC;IACrC,KAAK,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,IAAI,EAAE,CAAC;AACtD,CAAC;AAED,6EAA6E;AAE7E,SAAS,kBAAkB,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,OAAO,GAAG,GAAG,oBAAa,IAAI,yBAAkB,EAAE,CAAC;IACzD,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,OAAO,EAAE,CAAC,EAAE;YACvD,GAAG;YACH,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;YACnC,QAAQ,EAAE,MAAM;SACjB,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,4CAA4C;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChF,MAAM,GAAG,GAAG,MAAgC,CAAC;IAC7C,IAAI,GAAG,CAAC,aAAa,KAAK,+BAAwB;QAAE,OAAO,IAAI,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,OAAO,MAAuB,CAAC;AACjC,CAAC;AAED,SAAS,YAAY,CAAC,GAAW,EAAE,GAAW;IAC5C,IAAI,CAAC;QACH,IAAA,4BAAY,EAAC,KAAK,EAAE,CAAC,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,EAAE;YAC3C,GAAG;YACH,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC;SACtC,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-disk allowlist file — `.dxkit/allowlist.json` + optional sidecar
|
|
3
|
+
* `.dxkit/allowlist-reasons.local.json`.
|
|
4
|
+
*
|
|
5
|
+
* The allowlist file is the durable contract for per-finding
|
|
6
|
+
* suppressions: customer has reviewed this fingerprint, categorized
|
|
7
|
+
* the reason, and accepts that the guardrail should let the finding
|
|
8
|
+
* pass on future runs.
|
|
9
|
+
*
|
|
10
|
+
* Identity is the 16-char hex fingerprint from
|
|
11
|
+
* `src/analyzers/tools/fingerprint.ts` (CLAUDE.md Rule 9). An entry
|
|
12
|
+
* matches a finding when their fingerprint strings are byte-equal.
|
|
13
|
+
*
|
|
14
|
+
* # Two modes, one schema
|
|
15
|
+
*
|
|
16
|
+
* The mode is recorded in `.dxkit/policy.json` (out of scope for this
|
|
17
|
+
* module — consumers pass it in via `AllowlistMode`). Both modes use
|
|
18
|
+
* the same `AllowlistFile` shape on disk; sanitized mode just drops
|
|
19
|
+
* the human-readable fields and pushes them to a sidecar:
|
|
20
|
+
*
|
|
21
|
+
* `'full'` — every field present on the entry. Default for
|
|
22
|
+
* private repos. The committed file carries the full audit trail.
|
|
23
|
+
*
|
|
24
|
+
* `'sanitized'` — entries carry `fingerprint + kind + category +
|
|
25
|
+
* addedAt + expiresAt + acknowledgedSeverity` only. The
|
|
26
|
+
* `reason` + `addedBy` fields live in the gitignored sidecar
|
|
27
|
+
* `.dxkit/allowlist-reasons.local.json`, keyed by fingerprint.
|
|
28
|
+
* Default for public repos. Loaders merge the sidecar back when
|
|
29
|
+
* present; readers tolerate its absence (no reason field, but
|
|
30
|
+
* the suppression still applies because matching is by
|
|
31
|
+
* fingerprint).
|
|
32
|
+
*
|
|
33
|
+
* # Validation surface
|
|
34
|
+
*
|
|
35
|
+
* `validateAllowlistFile` enforces every Sprint-0-locked rule:
|
|
36
|
+
* - `reason` is required (full mode) / required in sidecar
|
|
37
|
+
* (sanitized mode)
|
|
38
|
+
* - `category` is one of the five canonical values
|
|
39
|
+
* - `category` is valid for the entry's `kind`
|
|
40
|
+
* - `requiresExpiry(category)` ⇒ `expiresAt` is present + parseable
|
|
41
|
+
* - `acknowledgedSeverity` is required when `category` is
|
|
42
|
+
* `accepted-risk` AND `severity` is `high`/`critical`
|
|
43
|
+
*/
|
|
44
|
+
import type { IdentityKind } from '../baseline/producers';
|
|
45
|
+
import type { FindingSeverity } from '../baseline/types';
|
|
46
|
+
import { type AllowlistCategory } from './categories';
|
|
47
|
+
export declare const ALLOWLIST_SCHEMA_VERSION: "dxkit-allowlist/v1";
|
|
48
|
+
export type AllowlistSchemaVersion = typeof ALLOWLIST_SCHEMA_VERSION;
|
|
49
|
+
export declare const ALLOWLIST_REASONS_SCHEMA_VERSION: "dxkit-allowlist-reasons/v1";
|
|
50
|
+
export type AllowlistReasonsSchemaVersion = typeof ALLOWLIST_REASONS_SCHEMA_VERSION;
|
|
51
|
+
export declare const ALLOWLIST_DIR = ".dxkit";
|
|
52
|
+
export declare const ALLOWLIST_FILENAME = "allowlist.json";
|
|
53
|
+
export declare const ALLOWLIST_REASONS_FILENAME = "allowlist-reasons.local.json";
|
|
54
|
+
/**
|
|
55
|
+
* Single source of truth for mode values. The `AllowlistMode` union
|
|
56
|
+
* is derived from this array via `(typeof ...)[number]`, so adding
|
|
57
|
+
* a new mode means appending one string here — the runtime checks
|
|
58
|
+
* below pick it up via `ALL_MODES.includes(...)` without any
|
|
59
|
+
* literal-value drift between type and runtime.
|
|
60
|
+
*/
|
|
61
|
+
export declare const ALL_MODES: readonly ["full", "sanitized"];
|
|
62
|
+
export type AllowlistMode = (typeof ALL_MODES)[number];
|
|
63
|
+
/**
|
|
64
|
+
* One allowlist entry. Two-shape contract:
|
|
65
|
+
* - Full mode: every optional field may be present on disk.
|
|
66
|
+
* - Sanitized mode on disk: `reason` + `addedBy` are absent; the
|
|
67
|
+
* loader merges them in from the sidecar when present.
|
|
68
|
+
*
|
|
69
|
+
* The TypeScript type allows the union so a single in-memory shape
|
|
70
|
+
* serves both modes; the validator enforces shape invariants.
|
|
71
|
+
*/
|
|
72
|
+
export interface AllowlistEntry {
|
|
73
|
+
/** SHA-1[0:16] canonical fingerprint matching the target finding. */
|
|
74
|
+
readonly fingerprint: string;
|
|
75
|
+
/** Identity kind of the target finding (matches CLAUDE.md Rule 9
|
|
76
|
+
* canonical kinds). */
|
|
77
|
+
readonly kind: IdentityKind;
|
|
78
|
+
/** Suppression category — one of the five Sprint-0-locked enum
|
|
79
|
+
* values. */
|
|
80
|
+
readonly category: AllowlistCategory;
|
|
81
|
+
/** Human-readable rationale. Required in full mode; lives in
|
|
82
|
+
* sidecar in sanitized mode. */
|
|
83
|
+
readonly reason?: string;
|
|
84
|
+
/** Who added the entry. Required in full mode; lives in sidecar
|
|
85
|
+
* in sanitized mode. Free-form (typically email, git user, or
|
|
86
|
+
* Slack handle). */
|
|
87
|
+
readonly addedBy?: string;
|
|
88
|
+
/** ISO `YYYY-MM-DD` of when the entry was added. */
|
|
89
|
+
readonly addedAt: string;
|
|
90
|
+
/** ISO `YYYY-MM-DD` after which the entry stops suppressing the
|
|
91
|
+
* finding. Required for `accepted-risk` + `deferred` categories;
|
|
92
|
+
* optional otherwise. */
|
|
93
|
+
readonly expiresAt?: string;
|
|
94
|
+
/** Severity at which the suppression was acknowledged. Required
|
|
95
|
+
* when `category` is `accepted-risk` and the finding's severity
|
|
96
|
+
* is `high` or `critical` — see `validateAllowlistEntry`. */
|
|
97
|
+
readonly acknowledgedSeverity?: FindingSeverity;
|
|
98
|
+
}
|
|
99
|
+
export interface AllowlistFile {
|
|
100
|
+
readonly schemaVersion: AllowlistSchemaVersion;
|
|
101
|
+
readonly mode: AllowlistMode;
|
|
102
|
+
readonly entries: ReadonlyArray<AllowlistEntry>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The gitignored sidecar that carries the human-readable fields in
|
|
106
|
+
* sanitized mode. Sparse — only the fields that need to live
|
|
107
|
+
* outside the committed file appear. Loaders are lenient when the
|
|
108
|
+
* sidecar is absent (no entry merges; suppression still works by
|
|
109
|
+
* fingerprint).
|
|
110
|
+
*/
|
|
111
|
+
export interface AllowlistReasonsSidecar {
|
|
112
|
+
readonly schemaVersion: AllowlistReasonsSchemaVersion;
|
|
113
|
+
readonly reasons: Readonly<Record<string, {
|
|
114
|
+
readonly reason: string;
|
|
115
|
+
readonly addedBy: string;
|
|
116
|
+
}>>;
|
|
117
|
+
}
|
|
118
|
+
export interface ValidationError {
|
|
119
|
+
readonly fingerprint?: string;
|
|
120
|
+
readonly field: string;
|
|
121
|
+
readonly message: string;
|
|
122
|
+
}
|
|
123
|
+
export declare function pathForAllowlist(cwd: string): string;
|
|
124
|
+
export declare function pathForAllowlistReasons(cwd: string): string;
|
|
125
|
+
/**
|
|
126
|
+
* Create an empty allowlist file in the requested mode. Useful for
|
|
127
|
+
* the `vyuh-dxkit allowlist add` CLI path when no file exists yet.
|
|
128
|
+
*/
|
|
129
|
+
export declare function emptyAllowlistFile(mode?: AllowlistMode): AllowlistFile;
|
|
130
|
+
/**
|
|
131
|
+
* Read the on-disk allowlist + (when present) merge the sidecar
|
|
132
|
+
* reasons. Returns `null` when the main file doesn't exist —
|
|
133
|
+
* callers treat that as "no allowlist configured."
|
|
134
|
+
*
|
|
135
|
+
* Throws on:
|
|
136
|
+
* - Malformed JSON in either file
|
|
137
|
+
* - Unrecognized `schemaVersion`
|
|
138
|
+
* - Root is not an object
|
|
139
|
+
*
|
|
140
|
+
* The sidecar's absence is NOT an error: customers in sanitized
|
|
141
|
+
* mode may have a committed allowlist on disk without the sidecar
|
|
142
|
+
* cloned (CI checkout, fresh teammate clone). The fingerprint-only
|
|
143
|
+
* file is still functional as a suppression list.
|
|
144
|
+
*/
|
|
145
|
+
export declare function loadAllowlist(cwd: string): AllowlistFile | null;
|
|
146
|
+
/**
|
|
147
|
+
* Load the gitignored reasons sidecar. Returns `null` when missing.
|
|
148
|
+
* Throws on malformed JSON or wrong schemaVersion.
|
|
149
|
+
*/
|
|
150
|
+
export declare function loadAllowlistReasons(cwd: string): AllowlistReasonsSidecar | null;
|
|
151
|
+
/**
|
|
152
|
+
* Persist the allowlist to disk. Writes the sidecar separately in
|
|
153
|
+
* sanitized mode: the committed file gets the structural fields;
|
|
154
|
+
* the sidecar gets `reason` + `addedBy`.
|
|
155
|
+
*
|
|
156
|
+
* Validation runs before writing — invalid input throws and the
|
|
157
|
+
* file isn't touched. Use `validateAllowlistFile` directly when
|
|
158
|
+
* you want non-throwing error reporting.
|
|
159
|
+
*/
|
|
160
|
+
export declare function saveAllowlist(cwd: string, file: AllowlistFile): void;
|
|
161
|
+
/** Find an entry by fingerprint. */
|
|
162
|
+
export declare function findEntry(file: AllowlistFile, fingerprint: string): AllowlistEntry | undefined;
|
|
163
|
+
/**
|
|
164
|
+
* Add an entry. Returns a NEW `AllowlistFile` (immutable update).
|
|
165
|
+
* Throws if `entry.fingerprint` already exists.
|
|
166
|
+
*/
|
|
167
|
+
export declare function addEntry(file: AllowlistFile, entry: AllowlistEntry): AllowlistFile;
|
|
168
|
+
/**
|
|
169
|
+
* Remove an entry by fingerprint. Returns a NEW `AllowlistFile`.
|
|
170
|
+
* Silently no-ops when the fingerprint isn't present (CLI surfaces
|
|
171
|
+
* the "not found" case through a separate read step).
|
|
172
|
+
*/
|
|
173
|
+
export declare function removeEntry(file: AllowlistFile, fingerprint: string): AllowlistFile;
|
|
174
|
+
/**
|
|
175
|
+
* Whether the allowlist suppresses a given finding. Pure
|
|
176
|
+
* fingerprint match. Expiry handling is layered on top by
|
|
177
|
+
* `isEntryActive` (kept separate so the guardrail can distinguish
|
|
178
|
+
* "matched but expired" from "no match").
|
|
179
|
+
*/
|
|
180
|
+
export declare function matchesFinding(file: AllowlistFile, fingerprint: string): boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Whether an entry is currently active (within its expiry window).
|
|
183
|
+
* Entries without `expiresAt` are always active. Entries past their
|
|
184
|
+
* expiry are inactive — guardrail treats the underlying finding as
|
|
185
|
+
* un-allowlisted and the next run flags the suppression as stale.
|
|
186
|
+
*/
|
|
187
|
+
export declare function isEntryActive(entry: AllowlistEntry, now?: Date): boolean;
|
|
188
|
+
/**
|
|
189
|
+
* Days remaining until an entry expires, or `null` when it has no
|
|
190
|
+
* expiry. Negative values mean already expired by that many days.
|
|
191
|
+
*/
|
|
192
|
+
export declare function daysUntilExpiry(entry: AllowlistEntry, now?: Date): number | null;
|
|
193
|
+
/** One entry in a soon-to-expire audit bucket, with the days
|
|
194
|
+
* remaining so callers can render time-to-expiry context. */
|
|
195
|
+
export interface SoonToExpire {
|
|
196
|
+
readonly entry: AllowlistEntry;
|
|
197
|
+
readonly daysRemaining: number;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Audit report partitioning the file's entries into the three
|
|
201
|
+
* actionable categories the `vyuh-dxkit allowlist audit` subcommand
|
|
202
|
+
* surfaces. Pure function — no I/O, no side effects.
|
|
203
|
+
*
|
|
204
|
+
* - `expired` — entries past their `expiresAt`. Prune candidates.
|
|
205
|
+
* The underlying suppression no longer applies on the next
|
|
206
|
+
* guardrail run.
|
|
207
|
+
* - `soonToExpire` — entries whose `expiresAt` is within
|
|
208
|
+
* `soonToExpireDays` (default 14). Customer should review whether
|
|
209
|
+
* the deferred work is still in plan and either fix the finding,
|
|
210
|
+
* extend the expiry, or remove the entry.
|
|
211
|
+
* - `missingRationale` — entries with empty / whitespace-only
|
|
212
|
+
* reason. In full mode this should never happen (validator
|
|
213
|
+
* rejects); in sanitized mode it may occur when the sidecar is
|
|
214
|
+
* missing or stale.
|
|
215
|
+
*/
|
|
216
|
+
export interface AuditReport {
|
|
217
|
+
readonly expired: ReadonlyArray<AllowlistEntry>;
|
|
218
|
+
readonly soonToExpire: ReadonlyArray<SoonToExpire>;
|
|
219
|
+
readonly missingRationale: ReadonlyArray<AllowlistEntry>;
|
|
220
|
+
}
|
|
221
|
+
export interface AuditOptions {
|
|
222
|
+
readonly now?: Date;
|
|
223
|
+
/** Window in days within which `expiresAt` is considered "soon."
|
|
224
|
+
* Default 14 — chosen to match a typical sprint cadence. */
|
|
225
|
+
readonly soonToExpireDays?: number;
|
|
226
|
+
}
|
|
227
|
+
export declare function auditAllowlist(file: AllowlistFile, options?: AuditOptions): AuditReport;
|
|
228
|
+
/**
|
|
229
|
+
* Remove expired entries from the file. Returns a new file (immutable)
|
|
230
|
+
* plus the list of removed entries so the CLI can render what changed.
|
|
231
|
+
* Pure function — no I/O.
|
|
232
|
+
*/
|
|
233
|
+
export declare function pruneExpired(file: AllowlistFile, now?: Date): {
|
|
234
|
+
kept: AllowlistFile;
|
|
235
|
+
removed: ReadonlyArray<AllowlistEntry>;
|
|
236
|
+
};
|
|
237
|
+
/**
|
|
238
|
+
* Validate every entry in the file against the canonical taxonomy
|
|
239
|
+
* + Sprint-0-locked rules. Pure function; returns an array of
|
|
240
|
+
* `ValidationError` rather than throwing so callers can render
|
|
241
|
+
* structured error messages.
|
|
242
|
+
*/
|
|
243
|
+
export declare function validateAllowlistFile(file: AllowlistFile): ReadonlyArray<ValidationError>;
|
|
244
|
+
/**
|
|
245
|
+
* Validate a single entry. Exposed independently so the CLI's
|
|
246
|
+
* `allowlist add` can pre-flight before mutating the file.
|
|
247
|
+
*/
|
|
248
|
+
export declare function validateAllowlistEntry(entry: AllowlistEntry, mode: AllowlistMode): ReadonlyArray<ValidationError>;
|
|
249
|
+
//# sourceMappingURL=file.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../../src/allowlist/file.ts"],"names":[],"mappings":"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"}
|