@blamejs/exceptd-skills 0.12.31 → 0.12.33

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.
@@ -38,33 +38,63 @@ const path = require('node:path');
38
38
 
39
39
  const REPO_ROOT = path.resolve(__dirname, '..');
40
40
  const MANIFEST_PATH = path.join(REPO_ROOT, 'manifest.json');
41
+ const CVE_CATALOG_PATH = path.join(REPO_ROOT, 'data', 'cve-catalog.json');
41
42
  const DATA_DIR = path.join(REPO_ROOT, 'data');
42
43
 
43
44
  /* Per-catalog config:
44
45
  * file relative path under data/
45
- * forwardField manifest.skills[].* array name
46
+ * forwardField source-collection[].* array name
46
47
  * reverseField per-entry reverse field name in the catalog
48
+ * source 'manifest.skills' (default) — walk every skill's forward ref
49
+ * 'cve.entries' — walk every CVE's forward ref (cycle 12 F3
50
+ * extension); contributes CVE-IDs (skipping `_draft: true`
51
+ * entries so the reverse direction tracks operator-queryable
52
+ * truth, not in-progress curation state)
53
+ * entryKey field on the source object used as the reverse-list value
54
+ * ('name' for skills; '<self-id>' for CVE entries via the
55
+ * map key, so the helper substitutes the iterating key)
47
56
  */
48
57
  const CATALOGS = [
49
58
  {
50
59
  file: 'atlas-ttps.json',
51
60
  forwardField: 'atlas_refs',
52
61
  reverseField: 'exceptd_skills',
62
+ source: 'manifest.skills',
63
+ entryKey: 'name',
53
64
  },
54
65
  {
55
66
  file: 'cwe-catalog.json',
56
67
  forwardField: 'cwe_refs',
57
68
  reverseField: 'skills_referencing',
69
+ source: 'manifest.skills',
70
+ entryKey: 'name',
58
71
  },
59
72
  {
60
73
  file: 'd3fend-catalog.json',
61
74
  forwardField: 'd3fend_refs',
62
75
  reverseField: 'skills_referencing',
76
+ source: 'manifest.skills',
77
+ entryKey: 'name',
63
78
  },
64
79
  {
65
80
  file: 'rfc-references.json',
66
81
  forwardField: 'rfc_refs',
67
82
  reverseField: 'skills_referencing',
83
+ source: 'manifest.skills',
84
+ entryKey: 'name',
85
+ },
86
+ // Cycle 12 F3 (v0.12.32): CVE → CWE reverse direction. CWE entries
87
+ // declare `evidence_cves` as the operator-facing "which CVEs land here"
88
+ // index; pre-fix this was hand-maintained and drifted whenever a new
89
+ // CVE landed without the matching CWE's evidence_cves being updated.
90
+ // Now mirrors `cve.cwe_refs` → `cwe.evidence_cves` automatically.
91
+ // Drafts excluded (they're invisible to default consumers anyway).
92
+ {
93
+ file: 'cwe-catalog.json',
94
+ forwardField: 'cwe_refs',
95
+ reverseField: 'evidence_cves',
96
+ source: 'cve.entries',
97
+ entryKey: null, // value is the iterating CVE id
68
98
  },
69
99
  ];
70
100
 
@@ -85,10 +115,33 @@ function buildReverseIndex(skills, forwardField) {
85
115
  return index;
86
116
  }
87
117
 
88
- function rebuildCatalog(cfg, manifest) {
118
+ // Cycle 12 F3 (v0.12.32): build a reverse index keyed by catalog ID from the
119
+ // CVE catalog's forward refs. Each CVE entry has cwe_refs / attack_refs
120
+ // arrays; the reverse side is the CVE ID, indexed by the catalog entry.
121
+ // Draft entries are skipped — drafts are invisible to default consumers
122
+ // via cross-ref-api, so the reverse direction should track operator-
123
+ // queryable truth, not in-progress curation state.
124
+ function buildCveReverseIndex(cveCatalog, forwardField) {
125
+ const index = new Map();
126
+ for (const [cveId, entry] of Object.entries(cveCatalog)) {
127
+ if (cveId === '_meta') continue;
128
+ if (!entry || typeof entry !== 'object') continue;
129
+ if (entry._draft === true) continue;
130
+ const refs = Array.isArray(entry[forwardField]) ? entry[forwardField] : [];
131
+ for (const targetId of refs) {
132
+ if (!index.has(targetId)) index.set(targetId, new Set());
133
+ index.get(targetId).add(cveId);
134
+ }
135
+ }
136
+ return index;
137
+ }
138
+
139
+ function rebuildCatalog(cfg, manifest, cveCatalog) {
89
140
  const filePath = path.join(DATA_DIR, cfg.file);
90
141
  const catalog = readJson(filePath);
91
- const index = buildReverseIndex(manifest.skills, cfg.forwardField);
142
+ const index = cfg.source === 'cve.entries'
143
+ ? buildCveReverseIndex(cveCatalog, cfg.forwardField)
144
+ : buildReverseIndex(manifest.skills, cfg.forwardField);
92
145
  let changed = 0;
93
146
  let added = 0;
94
147
  let removed = 0;
@@ -133,6 +186,8 @@ function rebuildCatalog(cfg, manifest) {
133
186
 
134
187
  return {
135
188
  file: cfg.file,
189
+ source: cfg.source,
190
+ reverseField: cfg.reverseField,
136
191
  changed,
137
192
  added,
138
193
  removed,
@@ -143,14 +198,15 @@ function rebuildCatalog(cfg, manifest) {
143
198
 
144
199
  function main() {
145
200
  const manifest = readJson(MANIFEST_PATH);
201
+ const cveCatalog = readJson(CVE_CATALOG_PATH);
146
202
  const results = [];
147
203
  for (const cfg of CATALOGS) {
148
- results.push(rebuildCatalog(cfg, manifest));
204
+ results.push(rebuildCatalog(cfg, manifest, cveCatalog));
149
205
  }
150
206
  for (const r of results) {
151
207
  process.stdout.write(
152
- `${r.file}: ${r.changed} entries changed ` +
153
- `(+${r.added} / -${r.removed} skill refs), ` +
208
+ `${r.file} (${r.source || 'skills'} → ${r.reverseField}): ${r.changed} entries changed ` +
209
+ `(+${r.added} / -${r.removed} refs), ` +
154
210
  `${r.unchanged} unchanged` +
155
211
  (r.orphans.length
156
212
  ? `, ${r.orphans.length} orphan forward ref(s) [${r.orphans.join(', ')}]`
@@ -163,6 +219,7 @@ function main() {
163
219
  module.exports = {
164
220
  CATALOGS,
165
221
  buildReverseIndex,
222
+ buildCveReverseIndex,
166
223
  rebuildCatalog,
167
224
  };
168
225
 
@@ -402,7 +402,7 @@ Per AGENTS.md optional 8th section. Maps cloud-IAM offensive findings to MITRE D
402
402
  After producing the cloud-IAM incident assessment, chain into the following skills.
403
403
 
404
404
  - **`cloud-security`** — for CSP-specific IAM construct inventory, posture-tool integration, and shared-responsibility framing. This skill scopes the IAM-incident-response workflow; `cloud-security` covers the broader cloud-posture surface.
405
- - **`cred-stores`** — for KMS / Cloud KMS / Key Vault posture, access-key rotation hygiene, and any compromised principal whose blast radius >= 4.
405
+ - **`cred-stores`** *(playbook chain, not a skill)* `_meta.feeds_into` on this playbook routes blast-radius >= 4 findings into the `cred-stores` playbook for KMS / Cloud KMS / Key Vault posture and access-key rotation hygiene. Hand-off is via the playbook chain, not a skill load.
406
406
  - **`identity-assurance`** — for AAL / IAL / FAL framing on human-principal MFA posture, federated-identity assurance levels, and step-up authentication coverage on cloud admin actions.
407
407
  - **`framework-gap-analysis`** — for the per-jurisdiction reconciliation called for in Output Format "Cross-Jurisdiction Framework Gap Summary."
408
408
  - **`compliance-theater`** — to extend the five theater tests above with general-purpose theater detection across the wider GRC posture.
@@ -337,7 +337,7 @@ Per AGENTS.md optional 8th section (required for skills shipped on or after 2026
337
337
  After producing the IdP-tenant compromise assessment, chain into the following skills.
338
338
 
339
339
  - **`identity-assurance`** — for AAL3 / FIDO2 / WebAuthn admin-tier authentication implementation detail, IAL2/IAL3 for high-value workforce identity, FAL constructs for federation, and the cryptographic posture (RFC 7519 JWT, RFC 8725 JWT BCP, RFC 7591 OAuth Dynamic Client Registration, RFC 9421 HTTP Message Signatures) that IdP-tenant control-plane operations reference but framework controls do not specify.
340
- - **`cred-stores`** — for downstream containment: rotate management-API tokens, downstream service-account credentials, session tokens; audit Vault / Secrets Manager / KMS for IdP-derived credentials. Blast-radius >= 4 findings feed directly into `cred-stores`.
340
+ - **`cred-stores`** *(playbook chain, not a skill)* `_meta.feeds_into` on this playbook routes blast-radius >= 4 findings into the `cred-stores` playbook for downstream containment: rotate management-API tokens, downstream service-account credentials, session tokens; audit Vault / Secrets Manager / KMS for IdP-derived credentials. Hand-off is via the playbook chain, not a skill load.
341
341
  - **`framework-gap-analysis`** — for per-jurisdiction reconciliation of IdP-tenant control-plane coverage gaps across NIST + ISO + SOC 2 + UK CAF + AU ISM + AU E8 + NIS2 + DORA + NYDFS.
342
342
  - **`compliance-theater`** — to extend the seven theater tests above with general-purpose theater detection across the wider GRC posture (CISO certification independence, audit-attestation evidence currency, change-control register completeness).
343
343
  - **`coordinated-vuln-disclosure`** — for DORA Art.19 4-hour clock orchestration, NIS2 Art.23 24-hour clock, GDPR Art.33 72-hour clock, NYDFS 500.17 72-hour clock, AU NDB 30-day clock, and the multi-regulator notification when a single IdP-tenant incident triggers multiple clocks across jurisdictions.
@@ -362,8 +362,8 @@ Ransomware response consumes defensive controls across multiple D3FEND categorie
362
362
  Ransomware response is a sub-flow of `incident-response-playbook` with ransomware-specific decision properties. Route to the following on the indicated trigger:
363
363
 
364
364
  - **`incident-response-playbook`** — *parent IR playbook.* All PICERL phase scaffolding, jurisdictional notification matrix, post-incident review template, evidence preservation, and cross-skill hand-off graph are owned by the parent. This skill extends — does not duplicate — the parent.
365
- - **`cred-stores`** — *credential-blast-radius trigger.* When ransomware analysis surfaces lateral movement via valid accounts (T1078) and the blast radius extends to credential stores (AD krbtgt, privileged service accounts, SSO break-glass, OAuth grants, AI-agent service accounts), hand off for credential rotation scope determination and rotation orchestration. The playbook `feeds_into` chain encodes this trigger.
366
- - **`framework`** — *compliance-theater trigger.* When the four ransomware compliance-theater tests in this skill produce a `theater` verdict for the org's pre-incident posture, hand off for cross-framework gap analysis. The playbook `feeds_into` chain encodes this trigger.
365
+ - **`cred-stores`** *(playbook chain, not a skill)* — *credential-blast-radius trigger.* When ransomware analysis surfaces lateral movement via valid accounts (T1078) and the blast radius extends to credential stores (AD krbtgt, privileged service accounts, SSO break-glass, OAuth grants, AI-agent service accounts), the `_meta.feeds_into` chain on this playbook routes into the `cred-stores` playbook for credential rotation scope determination and rotation orchestration. Hand-off is via the playbook chain, not a skill load.
366
+ - **`framework`** *(playbook chain, not a skill)* — *compliance-theater trigger.* When the four ransomware compliance-theater tests in this skill produce a `theater` verdict for the org's pre-incident posture, the `_meta.feeds_into` chain on this playbook routes into the `framework` playbook for cross-framework gap analysis. Hand-off is via the playbook chain, not a skill load. (The `framework-gap-analysis` skill below is a distinct surface — that one IS a real skill and is loaded directly.)
367
367
  - **`sector-healthcare`** — *PHI exfil-before-encrypt trigger.* When PHI is in the exfiltrated scope, hand off for HIPAA Breach Notification Rule sequencing (45 CFR 164.400-414), state AG notification matrix, and business-associate cascade. State-specific extensions to the 60-day federal clock are routed through this skill.
368
368
  - **`sector-financial`** — *financial-entity trigger.* When the affected entity is a DORA-in-scope financial entity, hand off for the 4h initial notification chain to competent authority + ECB / EIOPA / ESMA; for NYDFS 500.17 the 24h ransom-payment notification (if payment is made and sanctions screening cleared) is routed through this skill.
369
369
  - **`framework-gap-analysis`** — *control-gap filing.* When the ransomware response surfaces that one of the four ransomware-specific decision properties (sanctions / decryptor / insurance / immutability / exfil-before-encrypt) failed to operationalize during the incident, file the gap entry against the relevant framework controls (NIST IR-4, ISO A.5.26, SOC 2 CC7.4, HIPAA 164.308(a)(7), AU E8 Backup, UK CAF D1).