@vyuhlabs/dxkit 2.5.1 → 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 +318 -0
- package/README.md +150 -28
- 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/analyzers/tools/tool-registry.d.ts.map +1 -1
- package/dist/analyzers/tools/tool-registry.js +25 -8
- package/dist/analyzers/tools/tool-registry.js.map +1 -1
- 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 +154 -13
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +0 -10
- package/dist/constants.js.map +1 -1
- package/dist/detect.d.ts.map +1 -1
- package/dist/detect.js +0 -15
- package/dist/detect.js.map +1 -1
- package/dist/doctor.d.ts +78 -1
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +590 -101
- package/dist/doctor.js.map +1 -1
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +15 -0
- package/dist/generator.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 +2 -0
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +2 -0
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/index.d.ts +25 -0
- package/dist/languages/index.d.ts.map +1 -1
- package/dist/languages/index.js +44 -0
- package/dist/languages/index.js.map +1 -1
- package/dist/languages/java.d.ts.map +1 -1
- package/dist/languages/java.js +2 -0
- package/dist/languages/java.js.map +1 -1
- package/dist/languages/kotlin.d.ts.map +1 -1
- package/dist/languages/kotlin.js +2 -0
- package/dist/languages/kotlin.js.map +1 -1
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +11 -1
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/ruby.d.ts.map +1 -1
- package/dist/languages/ruby.js +2 -0
- package/dist/languages/ruby.js.map +1 -1
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +2 -0
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +45 -0
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +2 -0
- package/dist/languages/typescript.js.map +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +0 -5
- package/dist/prompts.js.map +1 -1
- package/dist/setup-branch-protection.d.ts +34 -0
- package/dist/setup-branch-protection.d.ts.map +1 -0
- package/dist/setup-branch-protection.js +190 -0
- package/dist/setup-branch-protection.js.map +1 -0
- package/dist/setup-gh.d.ts +75 -0
- package/dist/setup-gh.d.ts.map +1 -0
- package/dist/setup-gh.js +213 -0
- package/dist/setup-gh.js.map +1 -0
- package/dist/setup-prebuild.d.ts +34 -0
- package/dist/setup-prebuild.d.ts.map +1 -0
- package/dist/setup-prebuild.js +181 -0
- package/dist/setup-prebuild.js.map +1 -0
- package/dist/ship-installers.d.ts.map +1 -1
- package/dist/ship-installers.js +19 -4
- package/dist/ship-installers.js.map +1 -1
- package/dist/types.d.ts +24 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/update.d.ts +41 -0
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +154 -15
- package/dist/update.js.map +1 -1
- package/dist/upgrade.d.ts +88 -0
- package/dist/upgrade.d.ts.map +1 -0
- package/dist/upgrade.js +324 -0
- package/dist/upgrade.js.map +1 -0
- package/package.json +1 -1
- package/templates/.claude/skills/dxkit-action/SKILL.md +111 -17
- package/templates/.claude/skills/dxkit-config/SKILL.md +7 -7
- package/templates/.claude/skills/dxkit-fix/SKILL.md +165 -0
- package/templates/.claude/skills/dxkit-hooks/SKILL.md +8 -8
- package/templates/.claude/skills/dxkit-init/SKILL.md +3 -3
- package/templates/.claude/skills/dxkit-learn/SKILL.md +9 -9
- package/templates/.claude/skills/dxkit-onboard/SKILL.md +274 -0
- package/templates/.claude/skills/dxkit-reports/SKILL.md +18 -18
- package/templates/.claude/skills/dxkit-update/SKILL.md +164 -0
- package/templates/.devcontainer/devcontainer.json +6 -15
- package/templates/.devcontainer/post-create.sh +19 -4
- 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,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Inline allowlist annotation gather pass.
|
|
4
|
+
*
|
|
5
|
+
* Walks the source tree looking for `<lineComment> dxkit-allow:<category>`
|
|
6
|
+
* comments and records each occurrence as a `(file, line, category)`
|
|
7
|
+
* tuple. The `stale-allow` producer uses this list together with the
|
|
8
|
+
* current scan's secret/code/config findings to detect orphaned
|
|
9
|
+
* annotations — annotations whose underlying finding is no longer
|
|
10
|
+
* present, which the developer should remove.
|
|
11
|
+
*
|
|
12
|
+
* Architectural posture:
|
|
13
|
+
*
|
|
14
|
+
* - File walk goes through the canonical `walkSourceFiles` helper
|
|
15
|
+
* so `.gitignore` + `.dxkit-ignore` + bundled defaults are
|
|
16
|
+
* honored uniformly. No custom recursion / exclusion logic
|
|
17
|
+
* (per CLAUDE.md G_v4_7).
|
|
18
|
+
* - Per-language comment marker comes from each pack's
|
|
19
|
+
* `LanguageSupport.commentSyntax` via the inline annotation
|
|
20
|
+
* parser. No hardcoded `'//'` / `'#'` literals in this module
|
|
21
|
+
* (arch-check rule 2 enforces).
|
|
22
|
+
* - Annotation parsing reuses `parseAnnotation` from `inline.ts`
|
|
23
|
+
* — single source of grammar truth.
|
|
24
|
+
*
|
|
25
|
+
* Test files ARE walked (intentional — annotations often live in
|
|
26
|
+
* test fixtures suppressing scanner findings against deliberate
|
|
27
|
+
* placeholder credentials). Auto-generated files are NOT walked
|
|
28
|
+
* (the developer doesn't author annotations in generated code, and
|
|
29
|
+
* `walkSourceFiles` already excludes them by default).
|
|
30
|
+
*/
|
|
31
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
32
|
+
if (k2 === undefined) k2 = k;
|
|
33
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
34
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
35
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
36
|
+
}
|
|
37
|
+
Object.defineProperty(o, k2, desc);
|
|
38
|
+
}) : (function(o, m, k, k2) {
|
|
39
|
+
if (k2 === undefined) k2 = k;
|
|
40
|
+
o[k2] = m[k];
|
|
41
|
+
}));
|
|
42
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
43
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
44
|
+
}) : function(o, v) {
|
|
45
|
+
o["default"] = v;
|
|
46
|
+
});
|
|
47
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
48
|
+
var ownKeys = function(o) {
|
|
49
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
50
|
+
var ar = [];
|
|
51
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
52
|
+
return ar;
|
|
53
|
+
};
|
|
54
|
+
return ownKeys(o);
|
|
55
|
+
};
|
|
56
|
+
return function (mod) {
|
|
57
|
+
if (mod && mod.__esModule) return mod;
|
|
58
|
+
var result = {};
|
|
59
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
60
|
+
__setModuleDefault(result, mod);
|
|
61
|
+
return result;
|
|
62
|
+
};
|
|
63
|
+
})();
|
|
64
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
|
+
exports.gatherInlineAllowlistAnnotations = gatherInlineAllowlistAnnotations;
|
|
66
|
+
const fs = __importStar(require("fs"));
|
|
67
|
+
const path = __importStar(require("path"));
|
|
68
|
+
const languages_1 = require("../languages");
|
|
69
|
+
const walk_source_files_1 = require("../analyzers/tools/walk-source-files");
|
|
70
|
+
const inline_1 = require("./inline");
|
|
71
|
+
/**
|
|
72
|
+
* Walk source files under `cwd` and collect every inline allowlist
|
|
73
|
+
* annotation occurrence. Cheap on small repos; on large ones the
|
|
74
|
+
* `walkSourceFiles` cache amortizes the cost across multiple gather
|
|
75
|
+
* passes within a single baseline-create run.
|
|
76
|
+
*
|
|
77
|
+
* Returns occurrences in stable order (file path lexicographic, then
|
|
78
|
+
* line ascending) so downstream deterministic-output requirements
|
|
79
|
+
* are satisfied automatically.
|
|
80
|
+
*/
|
|
81
|
+
function gatherInlineAllowlistAnnotations(cwd, opts = {}) {
|
|
82
|
+
const includeTests = opts.includeTests ?? true;
|
|
83
|
+
const files = (0, walk_source_files_1.walkSourceFiles)(cwd, { includeTests });
|
|
84
|
+
const out = [];
|
|
85
|
+
// Build an extension → language lookup once per call. Cheap; the
|
|
86
|
+
// LANGUAGES registry is small (8 packs today).
|
|
87
|
+
const langByExt = buildLanguageByExtension();
|
|
88
|
+
for (const relPath of files) {
|
|
89
|
+
const ext = path.extname(relPath).toLowerCase();
|
|
90
|
+
const lang = langByExt.get(ext);
|
|
91
|
+
if (!lang || !lang.commentSyntax)
|
|
92
|
+
continue;
|
|
93
|
+
const abs = path.join(cwd, relPath);
|
|
94
|
+
let raw;
|
|
95
|
+
try {
|
|
96
|
+
raw = fs.readFileSync(abs, 'utf8');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
// File disappeared mid-walk (race) or unreadable — skip.
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
// Fast path: source has no `dxkit-allow:` substring at all.
|
|
103
|
+
// Avoids per-line regex on the vast majority of files.
|
|
104
|
+
if (!raw.includes('dxkit-allow:'))
|
|
105
|
+
continue;
|
|
106
|
+
const lines = raw.split(/\r?\n/);
|
|
107
|
+
for (let i = 0; i < lines.length; i++) {
|
|
108
|
+
const line = lines[i];
|
|
109
|
+
const parsed = (0, inline_1.parseAnnotation)(line, lang);
|
|
110
|
+
if (!parsed)
|
|
111
|
+
continue;
|
|
112
|
+
// `parseAnnotation` returns the category + reason but not
|
|
113
|
+
// the position. Determine position by inspecting whether the
|
|
114
|
+
// line is standalone (only whitespace + comment marker + body)
|
|
115
|
+
// or has source code preceding the comment.
|
|
116
|
+
const position = (0, inline_1.isStandaloneAnnotationLine)(line, lang)
|
|
117
|
+
? 'above'
|
|
118
|
+
: 'same-line';
|
|
119
|
+
out.push({
|
|
120
|
+
file: relPath,
|
|
121
|
+
line: i + 1,
|
|
122
|
+
category: parsed.category,
|
|
123
|
+
position,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return out;
|
|
128
|
+
}
|
|
129
|
+
// ─── Internals ────────────────────────────────────────────────────────────
|
|
130
|
+
function buildLanguageByExtension() {
|
|
131
|
+
const map = new Map();
|
|
132
|
+
for (const lang of languages_1.LANGUAGES) {
|
|
133
|
+
for (const ext of lang.sourceExtensions) {
|
|
134
|
+
const lower = ext.toLowerCase();
|
|
135
|
+
// First pack wins on duplicate extensions (none today, but
|
|
136
|
+
// the deterministic-order guarantee survives a future overlap).
|
|
137
|
+
if (!map.has(lower))
|
|
138
|
+
map.set(lower, lang);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return map;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=gather.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gather.js","sourceRoot":"","sources":["../../src/allowlist/gather.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCH,4EAkDC;AAxFD,uCAAyB;AACzB,2CAA6B;AAC7B,4CAAyC;AAEzC,4EAAuE;AACvE,qCAAgG;AAuBhG;;;;;;;;;GASG;AACH,SAAgB,gCAAgC,CAC9C,GAAW,EACX,OAAyB,EAAE;IAE3B,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,IAAI,IAAI,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAA,mCAAe,EAAC,GAAG,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACrD,MAAM,GAAG,GAAgC,EAAE,CAAC;IAE5C,iEAAiE;IACjE,+CAA+C;IAC/C,MAAM,SAAS,GAAG,wBAAwB,EAAE,CAAC;IAE7C,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QAChD,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,aAAa;YAAE,SAAS;QAE3C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACpC,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACH,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;YACzD,SAAS;QACX,CAAC;QACD,4DAA4D;QAC5D,uDAAuD;QACvD,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC;YAAE,SAAS;QAE5C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACtB,MAAM,MAAM,GAAG,IAAA,wBAAe,EAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,MAAM;gBAAE,SAAS;YACtB,0DAA0D;YAC1D,6DAA6D;YAC7D,+DAA+D;YAC/D,4CAA4C;YAC5C,MAAM,QAAQ,GAAuB,IAAA,mCAA0B,EAAC,IAAI,EAAE,IAAI,CAAC;gBACzE,CAAC,CAAC,OAAO;gBACT,CAAC,CAAC,WAAW,CAAC;YAChB,GAAG,CAAC,IAAI,CAAC;gBACP,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,CAAC,GAAG,CAAC;gBACX,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,QAAQ;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,6EAA6E;AAE7E,SAAS,wBAAwB;IAC/B,MAAM,GAAG,GAAG,IAAI,GAAG,EAA2B,CAAC;IAC/C,KAAK,MAAM,IAAI,IAAI,qBAAS,EAAE,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACxC,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;YAChC,2DAA2D;YAC3D,gEAAgE;YAChE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Block-time hint generation.
|
|
3
|
+
*
|
|
4
|
+
* When the guardrail check rejects a finding, the developer needs
|
|
5
|
+
* three things to act on it:
|
|
6
|
+
*
|
|
7
|
+
* 1. **Remediation** — the recommended fix (rotate the secret,
|
|
8
|
+
* upgrade the package, split the file, etc.). Generic per-kind
|
|
9
|
+
* prose; the conversational `dxkit-fix` skill produces
|
|
10
|
+
* LLM-backed, code-aware fixes when available.
|
|
11
|
+
* 2. **Inline example** — the exact annotation comment to paste
|
|
12
|
+
* when the finding has a stable single-line attachment point
|
|
13
|
+
* and the chosen category is inline-compatible.
|
|
14
|
+
* 3. **CLI command** — the exact `npx vyuh-dxkit allowlist add`
|
|
15
|
+
* invocation that handles the mutation without the developer
|
|
16
|
+
* typing annotation syntax.
|
|
17
|
+
*
|
|
18
|
+
* # Canonical input shape (CLAUDE.md Rule 9)
|
|
19
|
+
*
|
|
20
|
+
* This module consumes `BaselineEntry` directly — the canonical
|
|
21
|
+
* per-kind discriminated union from `src/baseline/types.ts`. NO
|
|
22
|
+
* intermediate "BlockingFinding" projection. The discriminated
|
|
23
|
+
* union flows into the switch statements below so TypeScript's
|
|
24
|
+
* exhaustiveness check fails the build when a new `IdentityKind`
|
|
25
|
+
* variant is added without matching `case` branches here.
|
|
26
|
+
*
|
|
27
|
+
* Language is inferred from the entry's file path (when present)
|
|
28
|
+
* via the canonical `LANGUAGES` registry. No language-specific
|
|
29
|
+
* branches; pack additions auto-propagate.
|
|
30
|
+
*
|
|
31
|
+
* The returned `BlockHint` is a plain data object so callers can
|
|
32
|
+
* render it as terminal output, emit it as JSON for the skill /
|
|
33
|
+
* future MCP surface, etc. Rendering text lives at the call site,
|
|
34
|
+
* NOT here.
|
|
35
|
+
*/
|
|
36
|
+
import type { BaselineEntry, FindingSeverity } from '../baseline/types';
|
|
37
|
+
import { type AllowlistCategory } from './categories';
|
|
38
|
+
export interface BlockHint {
|
|
39
|
+
/** Generic per-kind remediation text. Always present. */
|
|
40
|
+
readonly remediation: string;
|
|
41
|
+
/** Categories that semantically apply to this kind. Empty for
|
|
42
|
+
* `license` (which drops out of the baseline producer registry
|
|
43
|
+
* in 2.6+). */
|
|
44
|
+
readonly applicableCategories: readonly AllowlistCategory[];
|
|
45
|
+
/** Inline annotation example. Populated only when the entry has
|
|
46
|
+
* a stable single-line attachment, the kind's first applicable
|
|
47
|
+
* category is inline-compatible, and the language is inferable
|
|
48
|
+
* from the file extension. */
|
|
49
|
+
readonly inlineExample?: string;
|
|
50
|
+
/** Shell command for the CLI write path. Always present. */
|
|
51
|
+
readonly cliCommand: string;
|
|
52
|
+
/** True when the kind has no inline-compatible category
|
|
53
|
+
* applicable (e.g. hygiene — only accepted-risk + deferred,
|
|
54
|
+
* both file-only). The CLI / skill routes the dev directly to
|
|
55
|
+
* the file-level surface when true. */
|
|
56
|
+
readonly fileLevelOnly: boolean;
|
|
57
|
+
/** Pointer to the file-level allowlist surface when an expiring
|
|
58
|
+
* category (accepted-risk / deferred) might apply. */
|
|
59
|
+
readonly fileLevelHint?: string;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Build the structured block-time hint from a baseline entry.
|
|
63
|
+
* Pure function — no IO, no side effects. The caller renders the
|
|
64
|
+
* fields into its medium of choice.
|
|
65
|
+
*
|
|
66
|
+
* The optional `severity` parameter is reserved for future
|
|
67
|
+
* remediation-prose tuning (e.g. "rotate IMMEDIATELY" for
|
|
68
|
+
* critical-severity secrets). Currently unused but threaded
|
|
69
|
+
* through so callers don't need to refactor when the prose
|
|
70
|
+
* starts varying on severity.
|
|
71
|
+
*/
|
|
72
|
+
export declare function formatBlockHint(entry: BaselineEntry, severity?: FindingSeverity): BlockHint;
|
|
73
|
+
/**
|
|
74
|
+
* Generic per-kind remediation text. Exhaustive switch on the
|
|
75
|
+
* canonical `BaselineEntry['kind']` union — TypeScript enforces
|
|
76
|
+
* every variant has prose so a new kind can't ship without
|
|
77
|
+
* matching `case` branches.
|
|
78
|
+
*/
|
|
79
|
+
export declare function remediationFor(kind: BaselineEntry['kind']): string;
|
|
80
|
+
//# sourceMappingURL=hint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hint.d.ts","sourceRoot":"","sources":["../../src/allowlist/hint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAGxE,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAStB,MAAM,WAAW,SAAS;IACxB,yDAAyD;IACzD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;oBAEgB;IAChB,QAAQ,CAAC,oBAAoB,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC5D;;;mCAG+B;IAC/B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,4DAA4D;IAC5D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;4CAGwC;IACxC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC;2DACuD;IACvD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,eAAe,GAAG,SAAS,CAyB3F;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAsFlE"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Block-time hint generation.
|
|
4
|
+
*
|
|
5
|
+
* When the guardrail check rejects a finding, the developer needs
|
|
6
|
+
* three things to act on it:
|
|
7
|
+
*
|
|
8
|
+
* 1. **Remediation** — the recommended fix (rotate the secret,
|
|
9
|
+
* upgrade the package, split the file, etc.). Generic per-kind
|
|
10
|
+
* prose; the conversational `dxkit-fix` skill produces
|
|
11
|
+
* LLM-backed, code-aware fixes when available.
|
|
12
|
+
* 2. **Inline example** — the exact annotation comment to paste
|
|
13
|
+
* when the finding has a stable single-line attachment point
|
|
14
|
+
* and the chosen category is inline-compatible.
|
|
15
|
+
* 3. **CLI command** — the exact `npx vyuh-dxkit allowlist add`
|
|
16
|
+
* invocation that handles the mutation without the developer
|
|
17
|
+
* typing annotation syntax.
|
|
18
|
+
*
|
|
19
|
+
* # Canonical input shape (CLAUDE.md Rule 9)
|
|
20
|
+
*
|
|
21
|
+
* This module consumes `BaselineEntry` directly — the canonical
|
|
22
|
+
* per-kind discriminated union from `src/baseline/types.ts`. NO
|
|
23
|
+
* intermediate "BlockingFinding" projection. The discriminated
|
|
24
|
+
* union flows into the switch statements below so TypeScript's
|
|
25
|
+
* exhaustiveness check fails the build when a new `IdentityKind`
|
|
26
|
+
* variant is added without matching `case` branches here.
|
|
27
|
+
*
|
|
28
|
+
* Language is inferred from the entry's file path (when present)
|
|
29
|
+
* via the canonical `LANGUAGES` registry. No language-specific
|
|
30
|
+
* branches; pack additions auto-propagate.
|
|
31
|
+
*
|
|
32
|
+
* The returned `BlockHint` is a plain data object so callers can
|
|
33
|
+
* render it as terminal output, emit it as JSON for the skill /
|
|
34
|
+
* future MCP surface, etc. Rendering text lives at the call site,
|
|
35
|
+
* NOT here.
|
|
36
|
+
*/
|
|
37
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
38
|
+
if (k2 === undefined) k2 = k;
|
|
39
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
40
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
41
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
42
|
+
}
|
|
43
|
+
Object.defineProperty(o, k2, desc);
|
|
44
|
+
}) : (function(o, m, k, k2) {
|
|
45
|
+
if (k2 === undefined) k2 = k;
|
|
46
|
+
o[k2] = m[k];
|
|
47
|
+
}));
|
|
48
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
49
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
50
|
+
}) : function(o, v) {
|
|
51
|
+
o["default"] = v;
|
|
52
|
+
});
|
|
53
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
54
|
+
var ownKeys = function(o) {
|
|
55
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
56
|
+
var ar = [];
|
|
57
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
58
|
+
return ar;
|
|
59
|
+
};
|
|
60
|
+
return ownKeys(o);
|
|
61
|
+
};
|
|
62
|
+
return function (mod) {
|
|
63
|
+
if (mod && mod.__esModule) return mod;
|
|
64
|
+
var result = {};
|
|
65
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
66
|
+
__setModuleDefault(result, mod);
|
|
67
|
+
return result;
|
|
68
|
+
};
|
|
69
|
+
})();
|
|
70
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
71
|
+
exports.formatBlockHint = formatBlockHint;
|
|
72
|
+
exports.remediationFor = remediationFor;
|
|
73
|
+
const path = __importStar(require("path"));
|
|
74
|
+
const sanitize_1 = require("../baseline/sanitize");
|
|
75
|
+
const languages_1 = require("../languages");
|
|
76
|
+
const categories_1 = require("./categories");
|
|
77
|
+
const inline_1 = require("./inline");
|
|
78
|
+
/**
|
|
79
|
+
* Subcommand string used in every `cliCommand` rendered by this
|
|
80
|
+
* module. One place to update if the subcommand ever renames.
|
|
81
|
+
*/
|
|
82
|
+
const ALLOWLIST_ADD_CMD = 'npx vyuh-dxkit allowlist add';
|
|
83
|
+
/**
|
|
84
|
+
* Build the structured block-time hint from a baseline entry.
|
|
85
|
+
* Pure function — no IO, no side effects. The caller renders the
|
|
86
|
+
* fields into its medium of choice.
|
|
87
|
+
*
|
|
88
|
+
* The optional `severity` parameter is reserved for future
|
|
89
|
+
* remediation-prose tuning (e.g. "rotate IMMEDIATELY" for
|
|
90
|
+
* critical-severity secrets). Currently unused but threaded
|
|
91
|
+
* through so callers don't need to refactor when the prose
|
|
92
|
+
* starts varying on severity.
|
|
93
|
+
*/
|
|
94
|
+
function formatBlockHint(entry, severity) {
|
|
95
|
+
const applicableCategories = categories_1.CATEGORIES_BY_KIND[entry.kind];
|
|
96
|
+
const inlineCompatibleApplicable = applicableCategories.filter((c) => categories_1.INLINE_COMPATIBLE_CATEGORIES.has(c));
|
|
97
|
+
const fileLevelOnly = !categories_1.INLINE_COMPATIBLE_KINDS.has(entry.kind) || inlineCompatibleApplicable.length === 0;
|
|
98
|
+
const firstInlineCategory = inlineCompatibleApplicable[0];
|
|
99
|
+
const inlineExample = buildInlineExample(entry, firstInlineCategory);
|
|
100
|
+
const cliCommand = buildCliCommand(entry, applicableCategories);
|
|
101
|
+
const fileLevelHint = buildFileLevelHint(applicableCategories);
|
|
102
|
+
// Severity threaded for future use; not consumed yet — declare it
|
|
103
|
+
// touched so an unused-parameter rule doesn't complain.
|
|
104
|
+
void severity;
|
|
105
|
+
return {
|
|
106
|
+
remediation: remediationFor(entry.kind),
|
|
107
|
+
applicableCategories,
|
|
108
|
+
inlineExample,
|
|
109
|
+
cliCommand,
|
|
110
|
+
fileLevelOnly,
|
|
111
|
+
fileLevelHint,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Generic per-kind remediation text. Exhaustive switch on the
|
|
116
|
+
* canonical `BaselineEntry['kind']` union — TypeScript enforces
|
|
117
|
+
* every variant has prose so a new kind can't ship without
|
|
118
|
+
* matching `case` branches.
|
|
119
|
+
*/
|
|
120
|
+
function remediationFor(kind) {
|
|
121
|
+
switch (kind) {
|
|
122
|
+
case 'secret':
|
|
123
|
+
case 'secret-hmac':
|
|
124
|
+
return ('Rotate this credential immediately and load it from an environment variable ' +
|
|
125
|
+
'or secret manager instead of source. Do not commit the replacement to git ' +
|
|
126
|
+
'history — clean previous commits with git-filter-repo if necessary.');
|
|
127
|
+
case 'code':
|
|
128
|
+
return ('Review the flagged code pattern. If the scanner is wrong (false positive), ' +
|
|
129
|
+
'suppress via the allowlist with category=false-positive. Otherwise fix the ' +
|
|
130
|
+
'underlying issue — the scanner caught it for a reason.');
|
|
131
|
+
case 'config':
|
|
132
|
+
return ('Review the configuration setting. Many config-level findings ' +
|
|
133
|
+
'(TLS validation disabled, debug mode in production, etc.) reflect ' +
|
|
134
|
+
'operational risk; fix at the deployment / infrastructure layer where ' +
|
|
135
|
+
'possible rather than in source.');
|
|
136
|
+
case 'dep-vuln':
|
|
137
|
+
return ('Upgrade the vulnerable dependency to the patched version. Run ' +
|
|
138
|
+
'`npx vyuh-dxkit vulnerabilities` to see the suggested install command ' +
|
|
139
|
+
'for this ecosystem.');
|
|
140
|
+
case 'duplication':
|
|
141
|
+
return ('Extract the duplicated logic into a shared helper or accept the ' +
|
|
142
|
+
'duplication via the allowlist when it is intentional ' +
|
|
143
|
+
'(e.g., parallel test fixtures, generated code that must stay literal).');
|
|
144
|
+
case 'coverage-gap':
|
|
145
|
+
return ('Add a test covering the uncovered region. If the code path is ' +
|
|
146
|
+
'intentionally untested (build-time only, defensive error paths that ' +
|
|
147
|
+
'cannot be reached from tests), accept the gap via the allowlist.');
|
|
148
|
+
case 'test-gap':
|
|
149
|
+
return ('Create a test file for this source file. The convention follows the ' +
|
|
150
|
+
"language's standard (e.g., `*_test.go` for go, `*.test.ts` for " +
|
|
151
|
+
'typescript, `test_*.py` for python).');
|
|
152
|
+
case 'test-file-degradation':
|
|
153
|
+
return ('Restore the test body. Empty or fully commented-out test functions pass ' +
|
|
154
|
+
'silently in the test runner but provide no real coverage signal — they ' +
|
|
155
|
+
'are worse than no test because they hide gaps from view.');
|
|
156
|
+
case 'hygiene':
|
|
157
|
+
return ('Resolve the hygiene marker (TODO, FIXME, HACK, debug-print, or loose ' +
|
|
158
|
+
'`any` type). Complete the work it points at, file it as a tracked issue ' +
|
|
159
|
+
'in your task management system, or remove the marker if the underlying ' +
|
|
160
|
+
'concern is already addressed.');
|
|
161
|
+
case 'god-file':
|
|
162
|
+
return ('Split this file. It has grown beyond the maintainability threshold for ' +
|
|
163
|
+
'this codebase — large files concentrate change risk and make focused ' +
|
|
164
|
+
'review difficult. Extract cohesive subsets (related functions, related ' +
|
|
165
|
+
'types) into separate modules.');
|
|
166
|
+
case 'large-file':
|
|
167
|
+
return ('Split this file into smaller modules. Long files concentrate ' +
|
|
168
|
+
'cognitive load and make change risk harder to assess; smaller ' +
|
|
169
|
+
'modules with clear boundaries are easier to maintain.');
|
|
170
|
+
case 'stale-file':
|
|
171
|
+
return ('Remove the stale on-disk artifact (typically `.swp`, `.bak`, `.orig`, ' +
|
|
172
|
+
'or editor backup files). These should not be tracked in git — add the ' +
|
|
173
|
+
'pattern to `.gitignore` and untrack the file.');
|
|
174
|
+
case 'stale-allow':
|
|
175
|
+
return ('Remove the orphaned `dxkit-allow:` annotation — the finding it ' +
|
|
176
|
+
'suppressed is no longer present, so the annotation is dead code. ' +
|
|
177
|
+
'Allowlisting THIS finding is not supported; the only remediation is ' +
|
|
178
|
+
'to delete the annotation comment.');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// ─── Internals ───────────────────────────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* Project a `BaselineEntry` to the file + line locator the hint
|
|
184
|
+
* formatter needs. Exhaustive switch on entry.kind — TypeScript
|
|
185
|
+
* enforces every variant is handled. Adding a new kind requires
|
|
186
|
+
* extending this projection.
|
|
187
|
+
*
|
|
188
|
+
* Kinds without a stable file:line locator (`dep-vuln`, `duplication`,
|
|
189
|
+
* `secret-hmac`) return `{}` and route to the `--fingerprint=<id>`
|
|
190
|
+
* CLI form. Sanitized entries also return `{}` — the location was
|
|
191
|
+
* stripped at write time and can only be addressed by fingerprint.
|
|
192
|
+
*/
|
|
193
|
+
function entryLocator(entry) {
|
|
194
|
+
if ((0, sanitize_1.isSanitized)(entry))
|
|
195
|
+
return {};
|
|
196
|
+
switch (entry.kind) {
|
|
197
|
+
case 'secret':
|
|
198
|
+
case 'code':
|
|
199
|
+
case 'config':
|
|
200
|
+
case 'hygiene':
|
|
201
|
+
case 'stale-allow':
|
|
202
|
+
return { file: entry.file, line: entry.line };
|
|
203
|
+
case 'coverage-gap':
|
|
204
|
+
case 'test-gap':
|
|
205
|
+
case 'test-file-degradation':
|
|
206
|
+
case 'god-file':
|
|
207
|
+
case 'large-file':
|
|
208
|
+
case 'stale-file':
|
|
209
|
+
return { file: entry.file };
|
|
210
|
+
case 'secret-hmac':
|
|
211
|
+
case 'dep-vuln':
|
|
212
|
+
case 'duplication':
|
|
213
|
+
return {};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Look up the language pack matching a file's extension. Reads
|
|
218
|
+
* from the canonical `LANGUAGES` registry — no per-language
|
|
219
|
+
* branching here. A new language pack auto-propagates.
|
|
220
|
+
*/
|
|
221
|
+
function inferLanguage(file) {
|
|
222
|
+
const ext = path.extname(file).toLowerCase();
|
|
223
|
+
if (!ext)
|
|
224
|
+
return undefined;
|
|
225
|
+
for (const lang of languages_1.LANGUAGES) {
|
|
226
|
+
if (lang.sourceExtensions.includes(ext))
|
|
227
|
+
return lang;
|
|
228
|
+
}
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
function buildInlineExample(entry, firstInlineCategory) {
|
|
232
|
+
if (!firstInlineCategory)
|
|
233
|
+
return undefined;
|
|
234
|
+
if (!categories_1.INLINE_COMPATIBLE_KINDS.has(entry.kind))
|
|
235
|
+
return undefined;
|
|
236
|
+
const loc = entryLocator(entry);
|
|
237
|
+
if (!loc.file || loc.line === undefined)
|
|
238
|
+
return undefined;
|
|
239
|
+
const lang = inferLanguage(loc.file);
|
|
240
|
+
if (!lang || !lang.commentSyntax)
|
|
241
|
+
return undefined;
|
|
242
|
+
return (0, inline_1.renderAnnotation)({ category: firstInlineCategory, reason: '<your reason here>' }, lang);
|
|
243
|
+
}
|
|
244
|
+
function buildCliCommand(entry, applicableCategories) {
|
|
245
|
+
const firstCategory = applicableCategories[0];
|
|
246
|
+
const reasonArg = `--reason="<rationale here>"`;
|
|
247
|
+
const categoryArg = firstCategory ? `--category=${firstCategory}` : '--category=<category>';
|
|
248
|
+
const loc = entryLocator(entry);
|
|
249
|
+
// Two CLI forms, matching the two paths the `allowlist add` command
|
|
250
|
+
// accepts. Both are directly executable — no inferred missing args.
|
|
251
|
+
//
|
|
252
|
+
// 1. `<file>:<line>` — inline annotation insertion (kind-agnostic,
|
|
253
|
+
// grammar-driven). Only chosen when the kind supports inline
|
|
254
|
+
// attachment AND the entry carries file + line.
|
|
255
|
+
// 2. `--fingerprint=<id> --kind=<kind>` — file-level allowlist
|
|
256
|
+
// entry. The fingerprint is the identity; the kind is needed
|
|
257
|
+
// so the validator can apply per-kind rules.
|
|
258
|
+
if (categories_1.INLINE_COMPATIBLE_KINDS.has(entry.kind) && loc.file && loc.line !== undefined) {
|
|
259
|
+
return `${ALLOWLIST_ADD_CMD} ${loc.file}:${loc.line} ${categoryArg} ${reasonArg}`;
|
|
260
|
+
}
|
|
261
|
+
return `${ALLOWLIST_ADD_CMD} --fingerprint=${entry.id} --kind=${entry.kind} ${categoryArg} ${reasonArg}`;
|
|
262
|
+
}
|
|
263
|
+
function buildFileLevelHint(applicableCategories) {
|
|
264
|
+
const hasExpiringCategory = applicableCategories.some((c) => categories_1.EXPIRING_CATEGORIES.has(c));
|
|
265
|
+
if (!hasExpiringCategory)
|
|
266
|
+
return undefined;
|
|
267
|
+
return ('For accepted-risk or deferred suppression (both require an expiry date), ' +
|
|
268
|
+
'use --category=accepted-risk or --category=deferred with --expires=YYYY-MM-DD, ' +
|
|
269
|
+
'or edit .dxkit/allowlist.json directly.');
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=hint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hint.js","sourceRoot":"","sources":["../../src/allowlist/hint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline allowlist annotations.
|
|
3
|
+
*
|
|
4
|
+
* Grammar:
|
|
5
|
+
*
|
|
6
|
+
* <lineComment> dxkit-allow:<category> reason="<text>"
|
|
7
|
+
*
|
|
8
|
+
* Examples:
|
|
9
|
+
*
|
|
10
|
+
* # dxkit-allow:test-fixture reason="placeholder in unit test"
|
|
11
|
+
* // dxkit-allow:false-positive reason="regex matches our intentional placeholder"
|
|
12
|
+
*
|
|
13
|
+
* Two positions:
|
|
14
|
+
*
|
|
15
|
+
* - **Same-line** — annotation appears on the same source line as
|
|
16
|
+
* the finding, separated by at least one space:
|
|
17
|
+
*
|
|
18
|
+
* api_key = "sk_test_xxxx" # dxkit-allow:test-fixture reason="..."
|
|
19
|
+
*
|
|
20
|
+
* - **Above-line** — annotation occupies its own line, immediately
|
|
21
|
+
* preceding the finding (matching its indentation):
|
|
22
|
+
*
|
|
23
|
+
* # dxkit-allow:test-fixture reason="..."
|
|
24
|
+
* api_key = "sk_test_xxxx"
|
|
25
|
+
*
|
|
26
|
+
* The position is chosen at insert time by `insertAnnotation`: short
|
|
27
|
+
* source lines (under the configurable threshold) get same-line
|
|
28
|
+
* annotation; longer lines get above-line so the result stays
|
|
29
|
+
* readable.
|
|
30
|
+
*
|
|
31
|
+
* The grammar applies uniformly across every language; only the
|
|
32
|
+
* `<lineComment>` token varies (`#` for python/ruby, `//` for
|
|
33
|
+
* typescript/go/rust/csharp/kotlin/java). Each language pack
|
|
34
|
+
* declares its token via `LanguageSupport.commentSyntax`.
|
|
35
|
+
*
|
|
36
|
+
* # Quoting + escaping
|
|
37
|
+
*
|
|
38
|
+
* The reason is a JSON-style string. To embed a literal `"`, escape
|
|
39
|
+
* as `\"`; to embed a literal `\`, escape as `\\`. The parser
|
|
40
|
+
* un-escapes both on read; the writer escapes both on insert. No
|
|
41
|
+
* other escape sequences are supported (no `\n`, `\t`, etc.) — keep
|
|
42
|
+
* the reason single-line for human review.
|
|
43
|
+
*/
|
|
44
|
+
import type { LanguageSupport } from '../languages/types';
|
|
45
|
+
import { type AllowlistCategory } from './categories';
|
|
46
|
+
export type AnnotationPosition = 'same-line' | 'above';
|
|
47
|
+
export interface InlineAnnotation {
|
|
48
|
+
readonly category: AllowlistCategory;
|
|
49
|
+
/** Free-form rationale. `undefined` when the annotation is
|
|
50
|
+
* syntactically valid but the `reason="..."` clause was omitted —
|
|
51
|
+
* callers typically treat this as a "malformed annotation"
|
|
52
|
+
* warning. */
|
|
53
|
+
readonly reason?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface AnnotationMatch {
|
|
56
|
+
readonly annotation: InlineAnnotation;
|
|
57
|
+
readonly position: AnnotationPosition;
|
|
58
|
+
/** 1-indexed line where the annotation comment LIVES (not the
|
|
59
|
+
* finding's line — though they're the same for `same-line`). */
|
|
60
|
+
readonly annotationLine: number;
|
|
61
|
+
}
|
|
62
|
+
export interface InsertOptions {
|
|
63
|
+
/**
|
|
64
|
+
* Maximum source-line length that still gets a same-line annotation.
|
|
65
|
+
* Longer lines get above-line annotation to keep the result
|
|
66
|
+
* readable. The annotation itself is typically 50-80 characters,
|
|
67
|
+
* so totaling source + annotation around 120-140 characters at
|
|
68
|
+
* this threshold.
|
|
69
|
+
*/
|
|
70
|
+
readonly sameLineThreshold?: number;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Render a complete annotation comment for a given language.
|
|
74
|
+
* Exposed so callers (the CLI, the block-time hint formatter) can
|
|
75
|
+
* surface the exact string a developer would paste, without going
|
|
76
|
+
* through the file-mutation path.
|
|
77
|
+
*/
|
|
78
|
+
export declare function renderAnnotation(annotation: InlineAnnotation, lang: LanguageSupport): string;
|
|
79
|
+
/**
|
|
80
|
+
* Parse a single line for an allowlist annotation. Returns `null`
|
|
81
|
+
* when no annotation marker is found OR when the category isn't
|
|
82
|
+
* one of the canonical values.
|
|
83
|
+
*
|
|
84
|
+
* Tolerates the `reason="..."` clause being absent — callers decide
|
|
85
|
+
* whether a missing reason invalidates the suppression.
|
|
86
|
+
*
|
|
87
|
+
* False-positive surface: a string literal containing the literal
|
|
88
|
+
* substring `<lineComment> dxkit-allow:<category>` would match.
|
|
89
|
+
* Discriminating "is this inside a string" requires real language
|
|
90
|
+
* parsing and isn't worth the complexity — the worst case is a
|
|
91
|
+
* legitimate finding gets suppressed when a developer wrote the
|
|
92
|
+
* grammar literally inside a string. Vanishingly rare in practice.
|
|
93
|
+
*/
|
|
94
|
+
export declare function parseAnnotation(line: string, lang: LanguageSupport): InlineAnnotation | null;
|
|
95
|
+
/**
|
|
96
|
+
* Look for an annotation matching a finding at `filePath:lineNumber`
|
|
97
|
+
* (1-indexed). Checks two positions:
|
|
98
|
+
*
|
|
99
|
+
* 1. Same-line: the finding's line itself carries the annotation.
|
|
100
|
+
* 2. Above-line: the immediately-preceding line is a standalone
|
|
101
|
+
* annotation comment.
|
|
102
|
+
*
|
|
103
|
+
* Returns `null` when neither position has a parseable annotation.
|
|
104
|
+
* Throws when the file doesn't exist or `lineNumber` is out of
|
|
105
|
+
* range — callers are typically operating on findings whose line
|
|
106
|
+
* numbers came from a fresh scan, so an out-of-range value
|
|
107
|
+
* indicates a bug worth surfacing.
|
|
108
|
+
*/
|
|
109
|
+
export declare function findAnnotationAt(filePath: string, lineNumber: number, lang: LanguageSupport): AnnotationMatch | null;
|
|
110
|
+
/**
|
|
111
|
+
* Insert an allowlist annotation at `filePath:lineNumber`. Chooses
|
|
112
|
+
* same-line vs above-line based on the target line's length:
|
|
113
|
+
*
|
|
114
|
+
* - Target shorter than `sameLineThreshold` → append to target.
|
|
115
|
+
* - Target longer than threshold → prepend a new comment line
|
|
116
|
+
* above target, copying its indentation.
|
|
117
|
+
*
|
|
118
|
+
* Returns the chosen position + the 1-indexed line where the
|
|
119
|
+
* annotation comment ended up (useful for the CLI to print "added
|
|
120
|
+
* at file:line").
|
|
121
|
+
*
|
|
122
|
+
* Refuses to insert when the category is not inline-compatible —
|
|
123
|
+
* the caller should route accepted-risk + deferred suppressions
|
|
124
|
+
* through the file-level allowlist instead.
|
|
125
|
+
*
|
|
126
|
+
* Preserves CRLF vs LF line endings: the file is read, split, and
|
|
127
|
+
* re-joined using the detected style. Files without a trailing
|
|
128
|
+
* newline keep that property.
|
|
129
|
+
*/
|
|
130
|
+
export declare function insertAnnotation(filePath: string, lineNumber: number, annotation: InlineAnnotation, lang: LanguageSupport, options?: InsertOptions): {
|
|
131
|
+
position: AnnotationPosition;
|
|
132
|
+
annotationLine: number;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* Whether a line is a "standalone annotation comment" — meaning it
|
|
136
|
+
* contains nothing but leading whitespace + the comment marker +
|
|
137
|
+
* the annotation body. Used to distinguish an above-line annotation
|
|
138
|
+
* from a same-line annotation on a different finding's line.
|
|
139
|
+
*
|
|
140
|
+
* Exported because the gather pass (`src/allowlist/gather.ts`) needs
|
|
141
|
+
* the same predicate to label per-occurrence `position`. Single
|
|
142
|
+
* source of truth for the "what counts as standalone" rule.
|
|
143
|
+
*
|
|
144
|
+
* Example (python):
|
|
145
|
+
* ` # dxkit-allow:test-fixture reason="..."` ← standalone
|
|
146
|
+
* `x = 1 # dxkit-allow:test-fixture reason="..."` ← NOT standalone
|
|
147
|
+
*/
|
|
148
|
+
export declare function isStandaloneAnnotationLine(line: string, lang: LanguageSupport): boolean;
|
|
149
|
+
//# sourceMappingURL=inline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/allowlist/inline.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAgD,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AASpG,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,OAAO,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC;;;mBAGe;IACf,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC;qEACiE;IACjE,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAiBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,gBAAgB,EAAE,IAAI,EAAE,eAAe,GAAG,MAAM,CAQ5F;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,gBAAgB,GAAG,IAAI,CAwB5F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,eAAe,GACpB,eAAe,GAAG,IAAI,CA6BxB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,gBAAgB,EAC5B,IAAI,EAAE,eAAe,EACrB,OAAO,GAAE,aAAkB,GAC1B;IAAE,QAAQ,EAAE,kBAAkB,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAoD1D;AAQD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAOvF"}
|