@blamejs/exceptd-skills 0.18.25 → 0.18.26
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 +4 -0
- package/data/_indexes/_meta.json +4 -4
- package/data/_indexes/chains.json +80598 -9208
- package/data/cve-catalog.json +1601 -483
- package/data/framework-control-gaps.json +1134 -12
- package/lib/validate-package.js +5 -2
- package/manifest.json +53 -53
- package/package.json +1 -1
- package/sbom.cdx.json +35 -20
- package/scripts/check-framework-gap-coverage.js +103 -0
- package/scripts/predeploy.js +11 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*
|
|
3
|
+
* scripts/check-framework-gap-coverage.js
|
|
4
|
+
*
|
|
5
|
+
* AGENTS.md Hard Rule #5 (global-first) enforcement gate. Every curated CVE
|
|
6
|
+
* in data/cve-catalog.json must declare a framework_control_gaps statement
|
|
7
|
+
* for all five jurisdiction buckets:
|
|
8
|
+
*
|
|
9
|
+
* NIST — NIST-800-53-* / NIST-800-63*
|
|
10
|
+
* EU — NIS2-* / DORA-* / EU-AI-* / GDPR-*
|
|
11
|
+
* UK — UK-CAF-*
|
|
12
|
+
* AU — AU-Essential-8-* / AU-ISM-*
|
|
13
|
+
* ISO — ISO-27001-2022-*
|
|
14
|
+
*
|
|
15
|
+
* A multi-jurisdiction operator reading the offline catalog's framework-gap
|
|
16
|
+
* output must get coverage for every required jurisdiction on every CVE, not
|
|
17
|
+
* a US-centric subset. Before this gate, two-thirds of the corpus mapped only
|
|
18
|
+
* a subset; a codex review surfaced it, the corpus was completed, and this
|
|
19
|
+
* gate keeps it from regressing when new CVEs are curated.
|
|
20
|
+
*
|
|
21
|
+
* Draft entries (_auto_imported === true) are exempt — they carry raw NVD
|
|
22
|
+
* data that has not been through curation yet. The curation bar (elsewhere)
|
|
23
|
+
* requires drafts to be promoted before shipping, at which point this gate
|
|
24
|
+
* applies.
|
|
25
|
+
*
|
|
26
|
+
* Exit code: 0 when every curated entry is complete, 1 when any entry omits a
|
|
27
|
+
* required bucket (the list is printed). Uses process.exitCode (not
|
|
28
|
+
* process.exit) so buffered stdout drains before the process ends.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
'use strict';
|
|
32
|
+
|
|
33
|
+
const fs = require('node:fs');
|
|
34
|
+
const path = require('node:path');
|
|
35
|
+
|
|
36
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
37
|
+
// Catalog path is overridable (argv[2]) so the gate's own test can point it at
|
|
38
|
+
// a fixture; defaults to the shipped catalog for the real predeploy run.
|
|
39
|
+
const CATALOG = process.argv[2] || path.join(ROOT, 'data', 'cve-catalog.json');
|
|
40
|
+
|
|
41
|
+
const REQUIRED = ['NIST', 'EU', 'UK', 'AU', 'ISO'];
|
|
42
|
+
|
|
43
|
+
function bucketOf(key) {
|
|
44
|
+
if (/^NIST/i.test(key)) return 'NIST';
|
|
45
|
+
// EU bucket is the security-regulation family AGENTS.md Hard Rule #5 names:
|
|
46
|
+
// NIS2, DORA, the EU AI Act, and the EU Cyber Resilience Act. GDPR / EU-GDPR
|
|
47
|
+
// (data-protection) is NOT sufficient on its own — an entry mapped only to
|
|
48
|
+
// GDPR still owes NIS2/DORA/EU-AI coverage, so GDPR does not satisfy this
|
|
49
|
+
// bucket. Note EU-AI / EU-CRA match here; EU-GDPR deliberately does not.
|
|
50
|
+
if (/^(NIS2|DORA|EU-AI|EU-CRA)/i.test(key)) return 'EU';
|
|
51
|
+
if (/^UK-CAF/i.test(key)) return 'UK';
|
|
52
|
+
if (/^(AU-Essential-?8|AU-ISM|Essential-?8)/i.test(key)) return 'AU';
|
|
53
|
+
if (/^ISO-?27001/i.test(key)) return 'ISO';
|
|
54
|
+
return 'OTHER';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function main() {
|
|
58
|
+
let catalog;
|
|
59
|
+
try {
|
|
60
|
+
catalog = JSON.parse(fs.readFileSync(CATALOG, 'utf8'));
|
|
61
|
+
} catch (e) {
|
|
62
|
+
process.stdout.write(`[check-framework-gap-coverage] cannot read ${CATALOG}: ${e.message}\n`);
|
|
63
|
+
process.exitCode = 1;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const partial = [];
|
|
68
|
+
let checked = 0;
|
|
69
|
+
for (const id of Object.keys(catalog)) {
|
|
70
|
+
if (id === '_meta') continue;
|
|
71
|
+
const entry = catalog[id];
|
|
72
|
+
if (!entry || entry._auto_imported === true) continue;
|
|
73
|
+
checked++;
|
|
74
|
+
const gaps = entry.framework_control_gaps || {};
|
|
75
|
+
const have = new Set(Object.keys(gaps).map(bucketOf));
|
|
76
|
+
const missing = REQUIRED.filter((b) => !have.has(b));
|
|
77
|
+
if (missing.length) partial.push({ id, missing });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (partial.length === 0) {
|
|
81
|
+
process.stdout.write(
|
|
82
|
+
`[check-framework-gap-coverage] ok — all ${checked} curated entries declare framework-gap coverage for every required jurisdiction (${REQUIRED.join(', ')}).\n`
|
|
83
|
+
);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
process.stdout.write(
|
|
88
|
+
`[check-framework-gap-coverage] FAIL: ${partial.length} of ${checked} curated entries omit at least one required jurisdiction bucket (Hard Rule #5, global-first):\n`
|
|
89
|
+
);
|
|
90
|
+
for (const p of partial.slice(0, 40)) {
|
|
91
|
+
process.stdout.write(` ${p.id}: missing ${p.missing.join(', ')}\n`);
|
|
92
|
+
}
|
|
93
|
+
if (partial.length > 40) {
|
|
94
|
+
process.stdout.write(` ... and ${partial.length - 40} more\n`);
|
|
95
|
+
}
|
|
96
|
+
process.stdout.write(
|
|
97
|
+
'Add a CVE-specific framework_control_gaps statement for each missing bucket ' +
|
|
98
|
+
'(NIST/EU/UK/AU/ISO). Keys must resolve to a real control in data/framework-control-gaps.json.\n'
|
|
99
|
+
);
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
main();
|
package/scripts/predeploy.js
CHANGED
|
@@ -211,6 +211,17 @@ const GATES = [
|
|
|
211
211
|
args: [path.join(ROOT, "scripts", "check-catalog-gap-budget.js")],
|
|
212
212
|
ciJobName: "Data integrity (catalog + manifest snapshot)",
|
|
213
213
|
},
|
|
214
|
+
{
|
|
215
|
+
// Global-first framework-gap coverage gate (AGENTS.md Hard Rule #5).
|
|
216
|
+
// Every curated CVE must declare a framework_control_gaps statement for
|
|
217
|
+
// all five jurisdiction buckets (NIST, EU, UK, AU, ISO). Drafts are
|
|
218
|
+
// exempt. Prevents a US-centric subset from shipping in the offline
|
|
219
|
+
// catalog's framework-gap output for multi-jurisdiction operators.
|
|
220
|
+
name: "Framework-gap jurisdiction coverage (Hard Rule #5)",
|
|
221
|
+
command: process.execPath,
|
|
222
|
+
args: [path.join(ROOT, "scripts", "check-framework-gap-coverage.js")],
|
|
223
|
+
ciJobName: "Data integrity (catalog + manifest snapshot)",
|
|
224
|
+
},
|
|
214
225
|
{
|
|
215
226
|
// Version-tag drift gate. Compares the tracked tree against a
|
|
216
227
|
// baseline snapshot of pre-existing `// vX.Y.Z` comments and
|