@blamejs/exceptd-skills 0.11.9 → 0.11.12
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 +75 -0
- package/bin/exceptd.js +90 -20
- package/data/_indexes/_meta.json +2 -2
- package/keys/public.pem +1 -1
- package/lib/playbook-runner.js +35 -3
- package/manifest-snapshot.json +1 -1
- package/manifest.json +39 -39
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,80 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.12 — 2026-05-12
|
|
4
|
+
|
|
5
|
+
**Patch: items 123-126 — content-not-just-shape, exit-code discipline, diff iteration.**
|
|
6
|
+
|
|
7
|
+
Pattern: previous releases shipped the right field names but with empty content (notifications array existed but every entry's metadata was null), and exit-code semantics didn't cover the gates operators actually wanted to wire.
|
|
8
|
+
|
|
9
|
+
### Bugs
|
|
10
|
+
|
|
11
|
+
- **#123 jurisdiction notification entries carry obligation metadata.** Pre-0.11.12 `phases.close.jurisdiction_notifications` produced the right count of entries but each entry shape was `{ obligation_ref, recipient, draft_notification, deadline, ... }` — no `jurisdiction`, no `regulation`, no `window_hours`. The upstream `govern.jurisdiction_obligations` had the real metadata but close didn't carry it forward. Now each notification entry includes `jurisdiction`, `regulation`, `obligation_type`, `window_hours`, `clock_start_event`, `clock_started_at`, `deadline`, `notification_deadline` (alias matching compliance-team vocabulary), and `evidence_required`. Operators running `exceptd ci --block-on-jurisdiction-clock` now get notifications with the metadata they need to route to regulators and put on calendars.
|
|
12
|
+
|
|
13
|
+
- **#124 `--ack` propagates into `phases.govern.operator_consent`.** Consent semantically belongs in govern (it acknowledges the jurisdiction obligations surfaced there). Pre-0.11.12 `--ack` set only `result.operator_consent` at the top level; the govern phase showed `null`. Now `phases.govern.operator_consent` is `{ acked_at, explicit: true }` when `--ack` is passed, `null` otherwise. Top-level `result.operator_consent` retained for backward compat.
|
|
14
|
+
|
|
15
|
+
- **#125 ci exit-code matrix covers BLOCKED.** Pre-0.11.12 ci returned 0 for every non-detected path including blocked runs that never executed (preflight halt, mutex contention, stale threat intel, missing precondition). CI gates couldn't distinguish "ran clean" from "didn't run." Now: `0 PASS`, `2 detected/escalate`, `3 ran-but-no-evidence`, `4 BLOCKED (any ok:false)`, `1 framework error`. BLOCKED takes precedence over no-data because it's a harder gate failure. Help text updated.
|
|
16
|
+
|
|
17
|
+
- **#126 attest diff iterates artifact sets correctly.** Pre-0.11.12 `total_compared` was always 0 on flat-shape submissions because the diff helper called `normalizeSubmission` with an empty playbook stub (`look.artifacts: []`), producing empty maps. Now the diff loads the real playbook from each attestation's `playbook_id` and normalizes against the actual artifact catalog; falls back to direct observation-key mapping when the playbook can't be loaded (renamed/removed). Identical submissions with N observations now correctly report `total_compared: N, unchanged_count: N`.
|
|
18
|
+
|
|
19
|
+
### Tests
|
|
20
|
+
|
|
21
|
+
5 new regression cases. 344 total. Tests assert content shape, not just field presence — every test that checks for a notification array now also asserts the entries carry non-null jurisdiction/regulation/window_hours.
|
|
22
|
+
|
|
23
|
+
### Voice note (internal)
|
|
24
|
+
|
|
25
|
+
Three of the four items (#123, #124, #126) were "added the field but the field was empty." Lesson: when an operator says "field is missing," the next question to ask after "is it on the result?" is "is its content meaningful, or is it a structurally-present null?" Codified in CLAUDE.md.
|
|
26
|
+
|
|
27
|
+
## 0.11.11 — 2026-05-12
|
|
28
|
+
|
|
29
|
+
**Patch: CI test-gate hotfix — emit-then-exit stdout flush.**
|
|
30
|
+
|
|
31
|
+
v0.11.10 #100 used `process.exit(3)` after writing the result JSON to stdout. When stdout is piped (CI, test harnesses, JSON consumers), Node's `process.exit()` can return before the buffered async write drains — so `--json` consumers saw empty stdout despite the structured emit. Fix: switch to `process.exitCode = N; return;` so the event loop ends naturally and stdout drains.
|
|
32
|
+
|
|
33
|
+
### Bugs
|
|
34
|
+
|
|
35
|
+
- **`ci` --json with exit 3 truncated output.** Tests passed locally but the GitHub Actions release workflow's test gate failed on `tests/operator-bugs.test.js:#103` ("ci output should be JSON") because the Linux runner exposed the flush race more reliably than Windows. Fixed in two places:
|
|
36
|
+
- `cmdCi` exit 3 (no evidence + all inconclusive)
|
|
37
|
+
- `cmdCi` exit 2 (FAIL)
|
|
38
|
+
- `cmdRun` `--strict-preconditions` exit 1 (same shape; pre-existing latent risk)
|
|
39
|
+
|
|
40
|
+
### Tests
|
|
41
|
+
|
|
42
|
+
New regression: `#100/#103 ci exit-3 path still flushes JSON to stdout` — asserts both `r.status === 3` AND `tryJson(r.stdout)` parses. This is the test that would have caught v0.11.10 before CI.
|
|
43
|
+
|
|
44
|
+
### Lesson
|
|
45
|
+
|
|
46
|
+
When ending a verb with a non-zero exit AFTER writing structured stdout, prefer `process.exitCode = N; return;` over `process.exit(N)`. The former lets the event loop drain stdout; the latter can truncate. Codified in CLAUDE.md.
|
|
47
|
+
|
|
48
|
+
## 0.11.10 — 2026-05-12
|
|
49
|
+
|
|
50
|
+
**Patch: items 119-122 — field-name alignment with operator expectations.**
|
|
51
|
+
|
|
52
|
+
Pattern recognized across 10 v0.11.x releases: my output field names didn't match what operators were reading for. Several "broken" items were actually present-under-a-different-name. v0.11.10 adds the missing aliases + tightens ci's empty-evidence semantic.
|
|
53
|
+
|
|
54
|
+
### Bugs
|
|
55
|
+
|
|
56
|
+
- **#119 `result.ack` alias.** v0.11.9 surfaced `--ack` as `result.operator_consent.explicit`. Operators reading `result.ack` (matching the flag name) saw `undefined` and concluded the flag was dropped. Now: `result.ack` is a top-level boolean mirroring the consent state. `operator_consent.explicit` retains its richer shape.
|
|
57
|
+
|
|
58
|
+
- **#100 ci with no evidence exits 3.** Pre-0.11.10 `ci --required <pb>` with NO `--evidence`/`--evidence-dir` ran every playbook to inconclusive and exited 0 — operators couldn't distinguish "ran clean" from "never had real data." Now: when no evidence was supplied AND every result is inconclusive, ci exits **3** with a clear stderr warning: "ran but never had real data. Pass --evidence <file> or --evidence-dir <dir>." Exit code matrix: 0 PASS, 2 FAIL (detected/escalate), 3 NO-DATA, 1 framework error.
|
|
59
|
+
|
|
60
|
+
- **#102 `total_compared` field on attest diff.** Pre-0.11.10 `unchanged_count: 0 + added: 0 + removed: 0 + changed: 0` was ambiguous ("0 unchanged of how many?"). Now both `artifact_diff` and `signal_override_diff` include `total_compared` (set size of the union of both sides' keys). Operators can distinguish "no comparison happened" (total_compared: 0) from "everything matched" (total_compared: N, unchanged_count: N).
|
|
61
|
+
|
|
62
|
+
- **#104 `phases.close.jurisdiction_notifications` alias + `jurisdiction_clocks_count`.** The runner emitted `notification_actions`; operators expected `jurisdiction_notifications`. Now both names point to the same array (full list), and `jurisdiction_clocks_count` mirrors the ci-aggregate count of notifications whose clock has actually started. Compliance teams reading `phases.close.jurisdiction_notifications.length` (or filtering by `.clock_started_at != null`) get the expected shape.
|
|
63
|
+
|
|
64
|
+
### Tests
|
|
65
|
+
|
|
66
|
+
5 new cases in `tests/operator-bugs.test.js` for items 119/100/102/104. 338 total.
|
|
67
|
+
|
|
68
|
+
### Verified by direct repro before fix
|
|
69
|
+
|
|
70
|
+
For every item I:
|
|
71
|
+
1. Ran the user's exact CLI invocation
|
|
72
|
+
2. Inspected the actual output shape vs the user's stated expectation
|
|
73
|
+
3. Identified whether the bug was missing logic OR field-name mismatch
|
|
74
|
+
4. Fixed both layers when the answer was "mismatch" (add alias) so subsequent operators reading by either name see the data
|
|
75
|
+
|
|
76
|
+
Pattern documented in CLAUDE.md (project-side contributor guide).
|
|
77
|
+
|
|
3
78
|
## 0.11.9 — 2026-05-12
|
|
4
79
|
|
|
5
80
|
**Patch: items 99-115 — CLI-shim audit, real fixes.**
|
package/bin/exceptd.js
CHANGED
|
@@ -219,7 +219,8 @@ v0.11.0 canonical surface
|
|
|
219
219
|
+ rfc catalog + attestation-signing status.
|
|
220
220
|
--signatures | --currency | --cves | --rfcs
|
|
221
221
|
|
|
222
|
-
ci One-shot CI gate.
|
|
222
|
+
ci One-shot CI gate. Exit codes: 0 PASS, 2 detected/escalate,
|
|
223
|
+
3 ran-but-no-evidence, 4 blocked (ok:false), 1 framework error.
|
|
223
224
|
--all | --scope <type> | (auto-detect)
|
|
224
225
|
--max-rwep <n> cap below playbook default
|
|
225
226
|
--block-on-jurisdiction-clock
|
|
@@ -1297,8 +1298,15 @@ function cmdRun(runner, args, runOpts, pretty) {
|
|
|
1297
1298
|
// v0.11.9 (#113/#114): surface --operator and --ack in the run result so
|
|
1298
1299
|
// operators see the attribution + consent state without inspecting the
|
|
1299
1300
|
// attestation file. Pre-0.11.9 these were persisted to disk only.
|
|
1301
|
+
// v0.11.10 (#119): add result.ack alias for consumers reading the
|
|
1302
|
+
// ack state by that name (`result.ack` is shorter + matches the CLI flag).
|
|
1300
1303
|
if (result && runOpts.operator) result.operator = runOpts.operator;
|
|
1301
|
-
if (result && runOpts.operator_consent)
|
|
1304
|
+
if (result && runOpts.operator_consent) {
|
|
1305
|
+
result.operator_consent = runOpts.operator_consent;
|
|
1306
|
+
result.ack = !!runOpts.operator_consent.explicit;
|
|
1307
|
+
} else if (result) {
|
|
1308
|
+
result.ack = false;
|
|
1309
|
+
}
|
|
1302
1310
|
|
|
1303
1311
|
// Persist attestation for reattest cycles when the run succeeded.
|
|
1304
1312
|
if (result && result.ok && result.session_id) {
|
|
@@ -1355,7 +1363,10 @@ function cmdRun(runner, args, runOpts, pretty) {
|
|
|
1355
1363
|
if (warnIssues.length > 0) {
|
|
1356
1364
|
process.stderr.write(`[exceptd run] --strict-preconditions: ${warnIssues.length} unverified/warn precondition(s) — exit 1.\n`);
|
|
1357
1365
|
emit(result, pretty);
|
|
1358
|
-
process.exit
|
|
1366
|
+
// v0.11.11: exitCode + return so emit()'s stdout flushes (process.exit
|
|
1367
|
+
// can truncate buffered async stdout writes when piped).
|
|
1368
|
+
process.exitCode = 1;
|
|
1369
|
+
return;
|
|
1359
1370
|
}
|
|
1360
1371
|
}
|
|
1361
1372
|
|
|
@@ -2080,12 +2091,12 @@ function cmdAttest(runner, args, runOpts, pretty) {
|
|
|
2080
2091
|
// for flat submissions; the diff returned all zeros even when
|
|
2081
2092
|
// artifacts were present in observations.
|
|
2082
2093
|
artifact_diff: diffArtifacts(
|
|
2083
|
-
normalizedArtifacts(self.submission, runner),
|
|
2084
|
-
normalizedArtifacts(other.submission, runner)
|
|
2094
|
+
normalizedArtifacts(self.submission, runner, self.playbook_id),
|
|
2095
|
+
normalizedArtifacts(other.submission, runner, other.playbook_id)
|
|
2085
2096
|
),
|
|
2086
2097
|
signal_override_diff: diffSignalOverrides(
|
|
2087
|
-
normalizedSignalOverrides(self.submission, runner),
|
|
2088
|
-
normalizedSignalOverrides(other.submission, runner)
|
|
2098
|
+
normalizedSignalOverrides(self.submission, runner, self.playbook_id),
|
|
2099
|
+
normalizedSignalOverrides(other.submission, runner, other.playbook_id)
|
|
2089
2100
|
),
|
|
2090
2101
|
}, pretty);
|
|
2091
2102
|
return;
|
|
@@ -2195,25 +2206,55 @@ function cmdAttest(runner, args, runOpts, pretty) {
|
|
|
2195
2206
|
* canonical nested view of both shapes lets `attest diff` produce meaningful
|
|
2196
2207
|
* counts regardless of which shape the operator submitted.
|
|
2197
2208
|
*/
|
|
2198
|
-
function normalizedArtifacts(submission, runner) {
|
|
2209
|
+
function normalizedArtifacts(submission, runner, playbookId) {
|
|
2199
2210
|
if (!submission || typeof submission !== "object") return {};
|
|
2200
2211
|
if (submission.artifacts) return submission.artifacts;
|
|
2201
2212
|
if (submission.observations) {
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2213
|
+
// v0.11.12 (#126): the prior stub playbook (look.artifacts: []) caused
|
|
2214
|
+
// normalizeSubmission to produce {}, so attest diff reported
|
|
2215
|
+
// total_compared: 0 even when both submissions held real observations.
|
|
2216
|
+
// Try to load the real playbook from the attestation's playbook_id; if
|
|
2217
|
+
// that fails (renamed/removed), fall back to treating each observation
|
|
2218
|
+
// key as its own artifact id with `{ captured: true, value: <indicator|value> }`.
|
|
2219
|
+
if (playbookId) {
|
|
2220
|
+
try {
|
|
2221
|
+
const pb = runner.loadPlaybook ? runner.loadPlaybook(playbookId) : null;
|
|
2222
|
+
if (pb) {
|
|
2223
|
+
const norm = runner.normalizeSubmission({ observations: submission.observations }, pb);
|
|
2224
|
+
if (norm && norm.artifacts && Object.keys(norm.artifacts).length > 0) return norm.artifacts;
|
|
2225
|
+
}
|
|
2226
|
+
} catch { /* fall through to direct mapping */ }
|
|
2227
|
+
}
|
|
2228
|
+
// Direct mapping: observation keys are the artifact ids by convention.
|
|
2229
|
+
const out = {};
|
|
2230
|
+
for (const [k, v] of Object.entries(submission.observations)) {
|
|
2231
|
+
out[k] = (v && typeof v === "object") ? v : { value: v };
|
|
2232
|
+
}
|
|
2233
|
+
return out;
|
|
2206
2234
|
}
|
|
2207
2235
|
return {};
|
|
2208
2236
|
}
|
|
2209
|
-
function normalizedSignalOverrides(submission, runner) {
|
|
2237
|
+
function normalizedSignalOverrides(submission, runner, playbookId) {
|
|
2210
2238
|
if (!submission || typeof submission !== "object") return {};
|
|
2211
2239
|
if (submission.signal_overrides) return submission.signal_overrides;
|
|
2212
2240
|
if (submission.observations) {
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2241
|
+
// v0.11.12 (#126): same fix as normalizedArtifacts — load the real
|
|
2242
|
+
// playbook so look.indicators can map observation results to signal IDs.
|
|
2243
|
+
if (playbookId) {
|
|
2244
|
+
try {
|
|
2245
|
+
const pb = runner.loadPlaybook ? runner.loadPlaybook(playbookId) : null;
|
|
2246
|
+
if (pb) {
|
|
2247
|
+
const norm = runner.normalizeSubmission({ observations: submission.observations }, pb);
|
|
2248
|
+
if (norm && norm.signal_overrides && Object.keys(norm.signal_overrides).length > 0) return norm.signal_overrides;
|
|
2249
|
+
}
|
|
2250
|
+
} catch { /* fall through to direct mapping */ }
|
|
2251
|
+
}
|
|
2252
|
+
// Direct mapping: observation key -> result (canonical hit/miss/inconclusive).
|
|
2253
|
+
const out = {};
|
|
2254
|
+
for (const [k, v] of Object.entries(submission.observations)) {
|
|
2255
|
+
if (v && typeof v === "object" && v.result !== undefined) out[k] = v.result;
|
|
2256
|
+
}
|
|
2257
|
+
return out;
|
|
2217
2258
|
}
|
|
2218
2259
|
return {};
|
|
2219
2260
|
}
|
|
@@ -2226,7 +2267,10 @@ function normalizedSignalOverrides(submission, runner) {
|
|
|
2226
2267
|
function diffArtifacts(a, b) {
|
|
2227
2268
|
a = a || {}; b = b || {};
|
|
2228
2269
|
const allIds = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
2229
|
-
|
|
2270
|
+
// v0.11.10 (#102): total_compared disambiguates the empty-both case.
|
|
2271
|
+
// unchanged_count: 0 + added: 0 + removed: 0 + changed: 0 is ambiguous
|
|
2272
|
+
// ("0 unchanged of how many?"); total_compared answers it.
|
|
2273
|
+
const out = { total_compared: allIds.size, added: [], removed: [], changed: [], unchanged_count: 0 };
|
|
2230
2274
|
for (const id of allIds) {
|
|
2231
2275
|
const av = a[id], bv = b[id];
|
|
2232
2276
|
if (!av && bv) {
|
|
@@ -2252,7 +2296,7 @@ function diffArtifacts(a, b) {
|
|
|
2252
2296
|
function diffSignalOverrides(a, b) {
|
|
2253
2297
|
a = a || {}; b = b || {};
|
|
2254
2298
|
const allIds = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
2255
|
-
const out = { changed: [], unchanged_count: 0 };
|
|
2299
|
+
const out = { total_compared: allIds.size, changed: [], unchanged_count: 0 };
|
|
2256
2300
|
for (const id of allIds) {
|
|
2257
2301
|
if (a[id] !== b[id]) out.changed.push({ id, a: a[id] || null, b: b[id] || null });
|
|
2258
2302
|
else out.unchanged_count++;
|
|
@@ -3376,7 +3420,33 @@ function cmdCi(runner, args, runOpts, pretty) {
|
|
|
3376
3420
|
}
|
|
3377
3421
|
if (fail) {
|
|
3378
3422
|
process.stderr.write(`[exceptd ci] FAIL: ${failReasons.join("; ")}\n`);
|
|
3379
|
-
process.exit(
|
|
3423
|
+
// v0.11.11: use exitCode + return instead of process.exit() so the
|
|
3424
|
+
// structured stdout JSON has a chance to flush when stdout is piped.
|
|
3425
|
+
// process.exit() can truncate buffered async stdout writes.
|
|
3426
|
+
process.exitCode = 2;
|
|
3427
|
+
return;
|
|
3428
|
+
}
|
|
3429
|
+
// v0.11.12 (#125): ci exit code matrix. Pre-0.11.12 every non-detected
|
|
3430
|
+
// path exited 0 including blocked runs that never executed — CI gates
|
|
3431
|
+
// couldn't distinguish ok:false from ok:true. Now:
|
|
3432
|
+
// 0 PASS — every playbook produced a result, none detected/escalating
|
|
3433
|
+
// 2 FAIL — at least one detected or rwep>=escalate (above)
|
|
3434
|
+
// 3 NO-DATA — ran but no --evidence and all inconclusive
|
|
3435
|
+
// 4 BLOCKED — at least one playbook returned ok:false (preflight halt,
|
|
3436
|
+
// stale threat intel, missing precondition, mutex contention, etc.)
|
|
3437
|
+
// 1 FRAMEWORK — engine/parse error (set elsewhere)
|
|
3438
|
+
// BLOCKED takes precedence over NO-DATA because a blocked run is a
|
|
3439
|
+
// harder gate failure than "no real data."
|
|
3440
|
+
if (summary.blocked > 0) {
|
|
3441
|
+
process.stderr.write(`[exceptd ci] BLOCKED: ${summary.blocked}/${summary.total} playbook(s) returned ok:false (preflight/mutex/threat-currency/etc.). Exit 4. Inspect results[].reason for each blocked entry.\n`);
|
|
3442
|
+
process.exitCode = 4;
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
const suppliedEvidence = args.evidence || args["evidence-dir"];
|
|
3446
|
+
const allInconclusive = summary.inconclusive === summary.total && summary.total > 0;
|
|
3447
|
+
if (!suppliedEvidence && allInconclusive) {
|
|
3448
|
+
process.stderr.write(`[exceptd ci] WARN: no --evidence supplied and all ${summary.total} playbook(s) returned inconclusive. CI exit 3 = "ran but never had real data." Pass --evidence <file> or --evidence-dir <dir> for a real gate.\n`);
|
|
3449
|
+
process.exitCode = 3;
|
|
3380
3450
|
}
|
|
3381
3451
|
}
|
|
3382
3452
|
|
package/data/_indexes/_meta.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema_version": "1.1.0",
|
|
3
|
-
"generated_at": "2026-05-
|
|
3
|
+
"generated_at": "2026-05-12T23:57:49.662Z",
|
|
4
4
|
"generator": "scripts/build-indexes.js",
|
|
5
5
|
"source_count": 49,
|
|
6
6
|
"source_hashes": {
|
|
7
|
-
"manifest.json": "
|
|
7
|
+
"manifest.json": "be34fdbfb886861dff2f440d58324bfeba5f0c9188bffc5b6855ad682cc16e7b",
|
|
8
8
|
"data/atlas-ttps.json": "1500b5830dab070c4252496964a8c0948e1052a656e2c7c6e1efaf0350645e13",
|
|
9
9
|
"data/cve-catalog.json": "a81d3e4b491b27ccc084596b063a6108ff10c9eb01d7776922fc393980b534fe",
|
|
10
10
|
"data/cwe-catalog.json": "c3367d469b4b3d31e4c56397dd7a8305a0be338ecd85afa27804c0c9ce12157b",
|
package/keys/public.pem
CHANGED
package/lib/playbook-runner.js
CHANGED
|
@@ -227,7 +227,12 @@ function govern(playbookId, directiveId, runOpts = {}) {
|
|
|
227
227
|
jurisdiction_obligations: g.jurisdiction_obligations || [],
|
|
228
228
|
theater_fingerprints: g.theater_fingerprints || [],
|
|
229
229
|
framework_context: g.framework_context || {},
|
|
230
|
-
skill_preload: g.skill_preload || []
|
|
230
|
+
skill_preload: g.skill_preload || [],
|
|
231
|
+
// v0.11.12 (#124): --ack belongs semantically in govern (it acknowledges
|
|
232
|
+
// the jurisdiction_obligations surfaced here). Carry it forward so
|
|
233
|
+
// phases.govern.operator_consent reflects the consent state. Null when
|
|
234
|
+
// --ack was not passed.
|
|
235
|
+
operator_consent: runOpts.operator_consent || null
|
|
231
236
|
};
|
|
232
237
|
}
|
|
233
238
|
|
|
@@ -640,6 +645,14 @@ function close(playbookId, directiveId, analyzeResult, validateResult, agentSign
|
|
|
640
645
|
const sessionId = runOpts.session_id || crypto.randomBytes(8).toString('hex');
|
|
641
646
|
|
|
642
647
|
// notification_actions — compute ISO deadlines from clock_starts events.
|
|
648
|
+
// v0.11.12 (#123): enrich each entry with the matched obligation's
|
|
649
|
+
// jurisdiction/regulation/window_hours/evidence_required fields. The
|
|
650
|
+
// playbook's notification_actions entry only carries `obligation_ref` +
|
|
651
|
+
// `draft_notification` + `recipient`; without enrichment, operators reading
|
|
652
|
+
// `jurisdiction_notifications[i].jurisdiction` got `undefined`. The
|
|
653
|
+
// upstream `govern.jurisdiction_obligations` has the real data — carry it
|
|
654
|
+
// forward. `notification_deadline` is published as an alias for `deadline`
|
|
655
|
+
// (matches the field name compliance teams expect on a notification record).
|
|
643
656
|
const notificationActions = (c.notification_actions || []).map(na => {
|
|
644
657
|
const obligation = (g.jurisdiction_obligations || []).find(o =>
|
|
645
658
|
`${o.jurisdiction}/${o.regulation} ${o.window_hours}h` === na.obligation_ref
|
|
@@ -650,9 +663,21 @@ function close(playbookId, directiveId, analyzeResult, validateResult, agentSign
|
|
|
650
663
|
: 'pending_clock_start_event';
|
|
651
664
|
return {
|
|
652
665
|
...na,
|
|
653
|
-
|
|
654
|
-
|
|
666
|
+
// Carry obligation metadata forward so each notification entry is
|
|
667
|
+
// operationally usable on its own (calendar deadlines, regulator
|
|
668
|
+
// routing, evidence checklist).
|
|
669
|
+
jurisdiction: obligation?.jurisdiction || null,
|
|
670
|
+
regulation: obligation?.regulation || null,
|
|
671
|
+
obligation_type: obligation?.obligation || null,
|
|
672
|
+
window_hours: obligation?.window_hours ?? null,
|
|
673
|
+
clock_start_event: obligation?.clock_starts || null,
|
|
655
674
|
clock_started_at: clockStart?.toISOString() || null,
|
|
675
|
+
deadline,
|
|
676
|
+
// Alias matching compliance-team vocabulary.
|
|
677
|
+
notification_deadline: deadline,
|
|
678
|
+
// Evidence the regulator expects attached (from the obligation, not
|
|
679
|
+
// just the operator-facing recipient bundle on the notification entry).
|
|
680
|
+
evidence_required: obligation?.evidence_required || na.evidence_attached || [],
|
|
656
681
|
draft_notification: interpolate(na.draft_notification, { ...agentSignals, ...analyzeFindingShape(analyzeResult) })
|
|
657
682
|
};
|
|
658
683
|
});
|
|
@@ -751,6 +776,13 @@ function close(playbookId, directiveId, analyzeResult, validateResult, agentSign
|
|
|
751
776
|
evidence_package: evidencePackage,
|
|
752
777
|
learning_loop: lesson,
|
|
753
778
|
notification_actions: notificationActions,
|
|
779
|
+
// v0.11.10 (#104): operators expected the field name
|
|
780
|
+
// `jurisdiction_notifications`. Surface it as an alias for the full
|
|
781
|
+
// notification_actions list, plus a `jurisdiction_clocks_count` that
|
|
782
|
+
// mirrors `ci.summary.jurisdiction_clocks_started` — the count of
|
|
783
|
+
// notifications whose clock has actually started (clock_started_at != null).
|
|
784
|
+
jurisdiction_notifications: notificationActions,
|
|
785
|
+
jurisdiction_clocks_count: notificationActions.filter(n => n && n.clock_started_at != null).length,
|
|
754
786
|
exception: exception,
|
|
755
787
|
regression_schedule: regressionSchedule,
|
|
756
788
|
feeds_into: feeds
|
package/manifest-snapshot.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Auto-generated by scripts/refresh-manifest-snapshot.js — do not hand-edit. Public skill surface used by check-manifest-snapshot.js to detect breaking removals.",
|
|
3
|
-
"_generated_at": "2026-05-
|
|
3
|
+
"_generated_at": "2026-05-12T23:57:10.646Z",
|
|
4
4
|
"atlas_version": "5.1.0",
|
|
5
5
|
"skill_count": 38,
|
|
6
6
|
"skills": [
|
package/manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "exceptd-security",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.12",
|
|
4
4
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation",
|
|
5
5
|
"homepage": "https://exceptd.com",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
],
|
|
53
53
|
"last_threat_review": "2026-05-01",
|
|
54
54
|
"signature": "Xk593pj7my6wPJbQBE47khpIUrPsp6N1lW7cE2T/VPPF5T+8C1yGKc9B8VphD7Q08yWFcbwF6HoWpA/+4uG9DA==",
|
|
55
|
-
"signed_at": "2026-05-
|
|
55
|
+
"signed_at": "2026-05-12T23:57:10.174Z",
|
|
56
56
|
"cwe_refs": [
|
|
57
57
|
"CWE-125",
|
|
58
58
|
"CWE-362",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
],
|
|
117
117
|
"last_threat_review": "2026-05-01",
|
|
118
118
|
"signature": "nOgUu+LK9fy6ASTCoRGtx3ttgjZCl7WIkKu2wu06JEKVSpL2cKU3ex2tmVAvv11LBmpTH+b/0zvqXlzcxzHnCw==",
|
|
119
|
-
"signed_at": "2026-05-
|
|
119
|
+
"signed_at": "2026-05-12T23:57:10.176Z",
|
|
120
120
|
"cwe_refs": [
|
|
121
121
|
"CWE-1039",
|
|
122
122
|
"CWE-1426",
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
],
|
|
180
180
|
"last_threat_review": "2026-05-01",
|
|
181
181
|
"signature": "7FH1J9PlOyvcRCzRmggmenX9fIR0pi/veXihb3TeStcq1Rpuz1KHdOcJLqA9su4t2goYukKKCXHV6hx8hzplAA==",
|
|
182
|
-
"signed_at": "2026-05-
|
|
182
|
+
"signed_at": "2026-05-12T23:57:10.177Z",
|
|
183
183
|
"cwe_refs": [
|
|
184
184
|
"CWE-22",
|
|
185
185
|
"CWE-345",
|
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
"framework_gaps": [],
|
|
226
226
|
"last_threat_review": "2026-05-01",
|
|
227
227
|
"signature": "FqTRjHfEgw56pyHnyWzNtnhzDMEePBtmuamtW/iyX+h4yqbvP4Fyr7NRjRs3EgqT4j7oHuEZhV9Jt6ZTBgN4AA==",
|
|
228
|
-
"signed_at": "2026-05-
|
|
228
|
+
"signed_at": "2026-05-12T23:57:10.177Z"
|
|
229
229
|
},
|
|
230
230
|
{
|
|
231
231
|
"name": "compliance-theater",
|
|
@@ -256,7 +256,7 @@
|
|
|
256
256
|
],
|
|
257
257
|
"last_threat_review": "2026-05-01",
|
|
258
258
|
"signature": "3fN4yotiIIq76PVTHwozCu28TzDZvWule6vX8SXUT3XXbIBSuvAO0M/euvc3pw3TdZ2UNf78dI18lOCNdJ0aAg==",
|
|
259
|
-
"signed_at": "2026-05-
|
|
259
|
+
"signed_at": "2026-05-12T23:57:10.178Z"
|
|
260
260
|
},
|
|
261
261
|
{
|
|
262
262
|
"name": "exploit-scoring",
|
|
@@ -285,7 +285,7 @@
|
|
|
285
285
|
],
|
|
286
286
|
"last_threat_review": "2026-05-01",
|
|
287
287
|
"signature": "yZfpk4lQMRXegj2ADWjMmZTchUN6Lxpv587O/0JMzbNkXQtD6FrSAQOBWjx8S7uQ/sTntxgGN7aQQDLxL9RWAA==",
|
|
288
|
-
"signed_at": "2026-05-
|
|
288
|
+
"signed_at": "2026-05-12T23:57:10.178Z"
|
|
289
289
|
},
|
|
290
290
|
{
|
|
291
291
|
"name": "rag-pipeline-security",
|
|
@@ -322,7 +322,7 @@
|
|
|
322
322
|
],
|
|
323
323
|
"last_threat_review": "2026-05-01",
|
|
324
324
|
"signature": "ABHkoqee67KdUyDZ3bvF+/DNxjGhPR/ehT6pfOnmUIMmkcQFHpZ0OUVXKiFUANaLgKLP1vg0VEmHOoxpNA3vAA==",
|
|
325
|
-
"signed_at": "2026-05-
|
|
325
|
+
"signed_at": "2026-05-12T23:57:10.178Z",
|
|
326
326
|
"cwe_refs": [
|
|
327
327
|
"CWE-1395",
|
|
328
328
|
"CWE-1426"
|
|
@@ -379,7 +379,7 @@
|
|
|
379
379
|
],
|
|
380
380
|
"last_threat_review": "2026-05-01",
|
|
381
381
|
"signature": "+Nd/2tgBnW+mEGX84QvkgR2To2J7kA+lB63BsADDKeCXeebFv6Vo9H1P4vyUkKHfe4fP0ndpy3agIZcUO/e/Dg==",
|
|
382
|
-
"signed_at": "2026-05-
|
|
382
|
+
"signed_at": "2026-05-12T23:57:10.179Z",
|
|
383
383
|
"d3fend_refs": [
|
|
384
384
|
"D3-CA",
|
|
385
385
|
"D3-CSPP",
|
|
@@ -414,7 +414,7 @@
|
|
|
414
414
|
"framework_gaps": [],
|
|
415
415
|
"last_threat_review": "2026-05-01",
|
|
416
416
|
"signature": "VMNGFvowXLbBjZp5nvWloKkqyqHKhnSzbVRU3gX9quOZJHH56w2M4id+oDsXIjR0CfRRb7eXl/so0Hq4xLBuBQ==",
|
|
417
|
-
"signed_at": "2026-05-
|
|
417
|
+
"signed_at": "2026-05-12T23:57:10.179Z",
|
|
418
418
|
"cwe_refs": [
|
|
419
419
|
"CWE-1188"
|
|
420
420
|
]
|
|
@@ -442,7 +442,7 @@
|
|
|
442
442
|
"framework_gaps": [],
|
|
443
443
|
"last_threat_review": "2026-05-01",
|
|
444
444
|
"signature": "5MaJs7gPCuFlK4oAttLulAPOA1noeV+xD/UqVWaVyRedXZgebBGKjnlE2t1qmTugvxlNIfeAnBZapk+Wz3VAAg==",
|
|
445
|
-
"signed_at": "2026-05-
|
|
445
|
+
"signed_at": "2026-05-12T23:57:10.179Z"
|
|
446
446
|
},
|
|
447
447
|
{
|
|
448
448
|
"name": "global-grc",
|
|
@@ -474,7 +474,7 @@
|
|
|
474
474
|
"framework_gaps": [],
|
|
475
475
|
"last_threat_review": "2026-05-01",
|
|
476
476
|
"signature": "S/YXUpI/mcG2FpdUTgMsccWBtTaR5A4Ph4QFQw31S9w9Hn/z3sOFHLkb1B5YSwlg+mMOtSIxMdet1eLGSZkTDg==",
|
|
477
|
-
"signed_at": "2026-05-
|
|
477
|
+
"signed_at": "2026-05-12T23:57:10.180Z"
|
|
478
478
|
},
|
|
479
479
|
{
|
|
480
480
|
"name": "zeroday-gap-learn",
|
|
@@ -501,7 +501,7 @@
|
|
|
501
501
|
"framework_gaps": [],
|
|
502
502
|
"last_threat_review": "2026-05-01",
|
|
503
503
|
"signature": "AKS+JsmhhBtytY2eIMuydjkZOYprWCmQ+RqxyxcVG9XcEI29ZSM/JbVIINQHozFl7OPPrOu1ouiTnk7LOJ86Bg==",
|
|
504
|
-
"signed_at": "2026-05-
|
|
504
|
+
"signed_at": "2026-05-12T23:57:10.180Z"
|
|
505
505
|
},
|
|
506
506
|
{
|
|
507
507
|
"name": "pqc-first",
|
|
@@ -553,7 +553,7 @@
|
|
|
553
553
|
],
|
|
554
554
|
"last_threat_review": "2026-05-01",
|
|
555
555
|
"signature": "oEkK5bLS/G5RIHnxlNFJYdzhTJbKZnkJv+W4iS9UJ/uszZHgZGoxygELPc4kn3FowV5eE988SQYG4WKlXtNzCg==",
|
|
556
|
-
"signed_at": "2026-05-
|
|
556
|
+
"signed_at": "2026-05-12T23:57:10.181Z",
|
|
557
557
|
"cwe_refs": [
|
|
558
558
|
"CWE-327"
|
|
559
559
|
],
|
|
@@ -600,7 +600,7 @@
|
|
|
600
600
|
],
|
|
601
601
|
"last_threat_review": "2026-05-01",
|
|
602
602
|
"signature": "nPV6YTo1rsNH49qUnZpfoNLEQZXuLNyV05QMUOgXKHYeVDjotYpWhLgyVXlRhjV/fStiA2sWQ0MOnEJ4FBIfDg==",
|
|
603
|
-
"signed_at": "2026-05-
|
|
603
|
+
"signed_at": "2026-05-12T23:57:10.181Z"
|
|
604
604
|
},
|
|
605
605
|
{
|
|
606
606
|
"name": "security-maturity-tiers",
|
|
@@ -637,7 +637,7 @@
|
|
|
637
637
|
],
|
|
638
638
|
"last_threat_review": "2026-05-01",
|
|
639
639
|
"signature": "7rirSEONz6O9Yyf46eTyuwkGizCj9FRcNHe5p7Qz6nhJoZQRW5FwW7n9opL0WlbIw8FDBYn1f22zgNUV87L5AQ==",
|
|
640
|
-
"signed_at": "2026-05-
|
|
640
|
+
"signed_at": "2026-05-12T23:57:10.181Z",
|
|
641
641
|
"cwe_refs": [
|
|
642
642
|
"CWE-1188"
|
|
643
643
|
]
|
|
@@ -672,7 +672,7 @@
|
|
|
672
672
|
"framework_gaps": [],
|
|
673
673
|
"last_threat_review": "2026-05-11",
|
|
674
674
|
"signature": "+evehnd2wSBb8uMTlTr5/aTN4bfLjsKzZJk/+OMLMOJrjCt+OuMU7EQC6xMUGeSc4cPEGajghDvq3xVaacV2Dw==",
|
|
675
|
-
"signed_at": "2026-05-
|
|
675
|
+
"signed_at": "2026-05-12T23:57:10.182Z"
|
|
676
676
|
},
|
|
677
677
|
{
|
|
678
678
|
"name": "attack-surface-pentest",
|
|
@@ -743,7 +743,7 @@
|
|
|
743
743
|
"PTES revision incorporating AI-surface enumeration"
|
|
744
744
|
],
|
|
745
745
|
"signature": "KHOXxloAYf7xqXjm2BaL3HVAZOmb7rMiMh20H/oaIkjN0WD1CnKCrRGPJn867uSFhCh/timkXolaiqD1L/h8Dg==",
|
|
746
|
-
"signed_at": "2026-05-
|
|
746
|
+
"signed_at": "2026-05-12T23:57:10.182Z"
|
|
747
747
|
},
|
|
748
748
|
{
|
|
749
749
|
"name": "fuzz-testing-strategy",
|
|
@@ -803,7 +803,7 @@
|
|
|
803
803
|
"OSS-Fuzz-Gen / AI-assisted harness generation becoming the default expectation for OSS maintainers"
|
|
804
804
|
],
|
|
805
805
|
"signature": "+ELdD+1AY5DymBitH7wU65CS60NY1nDoLowJAFn7cE5Gr/5jy9BTkyxsm7PEXaSlXWMOkTf/HQ+uyzyxUVD/Bw==",
|
|
806
|
-
"signed_at": "2026-05-
|
|
806
|
+
"signed_at": "2026-05-12T23:57:10.182Z"
|
|
807
807
|
},
|
|
808
808
|
{
|
|
809
809
|
"name": "dlp-gap-analysis",
|
|
@@ -878,7 +878,7 @@
|
|
|
878
878
|
"Quebec Law 25, India DPDPA, KSA PDPL enforcement actions naming AI-tool prompt data as in-scope personal information"
|
|
879
879
|
],
|
|
880
880
|
"signature": "8tFAhXAS8zZN3SUOdn+ZIu7lQ48JMOyBQ8SaObR3L/fDyFmDhufqleY2VzI3yigqlT/D4Y8FYxZHKmzXiALjDw==",
|
|
881
|
-
"signed_at": "2026-05-
|
|
881
|
+
"signed_at": "2026-05-12T23:57:10.183Z"
|
|
882
882
|
},
|
|
883
883
|
{
|
|
884
884
|
"name": "supply-chain-integrity",
|
|
@@ -955,7 +955,7 @@
|
|
|
955
955
|
"OpenSSF model-signing — emerging Sigstore-based signing standard for ML model weights; track for production adoption"
|
|
956
956
|
],
|
|
957
957
|
"signature": "8xlk5ZfTKVYqTE2+ifkjTBu/RPqs4MIvX7SpOHl22YDHi7nzJ1ywPhSNYJzoPdPV4AUuWG518EldQJsEIuyuAA==",
|
|
958
|
-
"signed_at": "2026-05-
|
|
958
|
+
"signed_at": "2026-05-12T23:57:10.183Z"
|
|
959
959
|
},
|
|
960
960
|
{
|
|
961
961
|
"name": "defensive-countermeasure-mapping",
|
|
@@ -1012,7 +1012,7 @@
|
|
|
1012
1012
|
],
|
|
1013
1013
|
"last_threat_review": "2026-05-11",
|
|
1014
1014
|
"signature": "AMdLkDx/e3ESI4NAnJhhcaas+Ru8VjrSn6v6RBbmmzoLCGo/vFxGraa1p/qF9udhVG+DdkbwHfbfKK5Im19KDw==",
|
|
1015
|
-
"signed_at": "2026-05-
|
|
1015
|
+
"signed_at": "2026-05-12T23:57:10.183Z"
|
|
1016
1016
|
},
|
|
1017
1017
|
{
|
|
1018
1018
|
"name": "identity-assurance",
|
|
@@ -1079,7 +1079,7 @@
|
|
|
1079
1079
|
"d3fend_refs": [],
|
|
1080
1080
|
"last_threat_review": "2026-05-11",
|
|
1081
1081
|
"signature": "pSMHKkyWoZvRIuVtN7Vue51sP5MIy9lSaQa2YSAMhxjptx81cUnPt3S11/Tb9Ea1/eluMNQ+5F25eF2njr4mBQ==",
|
|
1082
|
-
"signed_at": "2026-05-
|
|
1082
|
+
"signed_at": "2026-05-12T23:57:10.183Z"
|
|
1083
1083
|
},
|
|
1084
1084
|
{
|
|
1085
1085
|
"name": "ot-ics-security",
|
|
@@ -1135,7 +1135,7 @@
|
|
|
1135
1135
|
"d3fend_refs": [],
|
|
1136
1136
|
"last_threat_review": "2026-05-11",
|
|
1137
1137
|
"signature": "qjky+ZTX1DP7uRRMQZq7S7P9/uaJEoB1dy4RZ1l37Q4OO3k2ryfL+7o0Cgm/piuafJfH+dqUeNCRrVefj4r8Dw==",
|
|
1138
|
-
"signed_at": "2026-05-
|
|
1138
|
+
"signed_at": "2026-05-12T23:57:10.184Z"
|
|
1139
1139
|
},
|
|
1140
1140
|
{
|
|
1141
1141
|
"name": "coordinated-vuln-disclosure",
|
|
@@ -1187,7 +1187,7 @@
|
|
|
1187
1187
|
"NYDFS 23 NYCRR 500 amendments potentially adding explicit CVD program requirements"
|
|
1188
1188
|
],
|
|
1189
1189
|
"signature": "F86Zl/I+dBzHYRUuGWsjDQI2F/I/vhzwZUFMqhNfKUzRbMf6mafOX2APCPYTp3eP1DvvvfL3Yc0hb1R5Q4nOAg==",
|
|
1190
|
-
"signed_at": "2026-05-
|
|
1190
|
+
"signed_at": "2026-05-12T23:57:10.184Z"
|
|
1191
1191
|
},
|
|
1192
1192
|
{
|
|
1193
1193
|
"name": "threat-modeling-methodology",
|
|
@@ -1237,7 +1237,7 @@
|
|
|
1237
1237
|
"PASTA v2 updates incorporating AI/ML application threats"
|
|
1238
1238
|
],
|
|
1239
1239
|
"signature": "D/4d5NcJScNH58ADXsSrVzTmLSWZpUZTdyhtDkJlC0twSMNczOiDsXgYFitBaZgGdv5nVd00viR45mNrsaZ4BQ==",
|
|
1240
|
-
"signed_at": "2026-05-
|
|
1240
|
+
"signed_at": "2026-05-12T23:57:10.184Z"
|
|
1241
1241
|
},
|
|
1242
1242
|
{
|
|
1243
1243
|
"name": "webapp-security",
|
|
@@ -1311,7 +1311,7 @@
|
|
|
1311
1311
|
"d3fend_refs": [],
|
|
1312
1312
|
"last_threat_review": "2026-05-11",
|
|
1313
1313
|
"signature": "UOXaUtpcFjXyDQ70z2PaGu6K3pABtXp+7YzO6eGVGpN1CxXpPq/xW/CnTng6B7wk9WSsqD0OORBJp4VCjiVfAQ==",
|
|
1314
|
-
"signed_at": "2026-05-
|
|
1314
|
+
"signed_at": "2026-05-12T23:57:10.185Z"
|
|
1315
1315
|
},
|
|
1316
1316
|
{
|
|
1317
1317
|
"name": "ai-risk-management",
|
|
@@ -1361,7 +1361,7 @@
|
|
|
1361
1361
|
"d3fend_refs": [],
|
|
1362
1362
|
"last_threat_review": "2026-05-11",
|
|
1363
1363
|
"signature": "IVKygsrFjiM64fQVbd2PT6jDjs6fm5nKwJSqGfK53gG0S9wdHC4QYuh+LWlI/2ftvIKjjedLQ6FRyTrqpDEuDw==",
|
|
1364
|
-
"signed_at": "2026-05-
|
|
1364
|
+
"signed_at": "2026-05-12T23:57:10.185Z"
|
|
1365
1365
|
},
|
|
1366
1366
|
{
|
|
1367
1367
|
"name": "sector-healthcare",
|
|
@@ -1421,7 +1421,7 @@
|
|
|
1421
1421
|
"d3fend_refs": [],
|
|
1422
1422
|
"last_threat_review": "2026-05-11",
|
|
1423
1423
|
"signature": "P+CdSu8ZJCNUU4nTa09Voh2PcYF3y/AFJn4v7cjVIGo9FbbqO7MwvGN7cJ+aSRs2/3NMUXX4eupcODslxYyJDw==",
|
|
1424
|
-
"signed_at": "2026-05-
|
|
1424
|
+
"signed_at": "2026-05-12T23:57:10.185Z"
|
|
1425
1425
|
},
|
|
1426
1426
|
{
|
|
1427
1427
|
"name": "sector-financial",
|
|
@@ -1502,7 +1502,7 @@
|
|
|
1502
1502
|
"TIBER-EU framework v2.0 alignment with DORA TLPT RTS (JC 2024/40); cross-recognition with CBEST and iCAST"
|
|
1503
1503
|
],
|
|
1504
1504
|
"signature": "zpEfh181Sc0b0cvRf/31Ir1f8lD4V5tehTogO3TJMxdKmXu06IAK7hrhBcLA/jFBv3xDDwrWW3sHzChVhWDeDA==",
|
|
1505
|
-
"signed_at": "2026-05-
|
|
1505
|
+
"signed_at": "2026-05-12T23:57:10.186Z"
|
|
1506
1506
|
},
|
|
1507
1507
|
{
|
|
1508
1508
|
"name": "sector-federal-government",
|
|
@@ -1571,7 +1571,7 @@
|
|
|
1571
1571
|
"Australia PSPF 2024 revision and ISM quarterly updates — track for Essential Eight Maturity Level requirements for federal entities"
|
|
1572
1572
|
],
|
|
1573
1573
|
"signature": "7NpQlPu1DkpY9f+Frv/LLBHWUUe/qTM80c+xeYDxOzweXhvJGE/dnDCjglYHTjxT82L9cVxzBezvLEne20UpBg==",
|
|
1574
|
-
"signed_at": "2026-05-
|
|
1574
|
+
"signed_at": "2026-05-12T23:57:10.186Z"
|
|
1575
1575
|
},
|
|
1576
1576
|
{
|
|
1577
1577
|
"name": "sector-energy",
|
|
@@ -1636,7 +1636,7 @@
|
|
|
1636
1636
|
"ICS-CERT advisory feed (https://www.cisa.gov/news-events/cybersecurity-advisories/ics-advisories) for vendor CVEs in Siemens, Rockwell, Schneider Electric, ABB, GE Vernova, Hitachi Energy, AVEVA / OSIsoft PI"
|
|
1637
1637
|
],
|
|
1638
1638
|
"signature": "4rhyHN5HykK7MQUmhvaTeDGj6Qf5swDd5ry8foh4KBvTkRKxTI/XyxconFGm5FASnySGPLMxX6m4JZAq5wiNBg==",
|
|
1639
|
-
"signed_at": "2026-05-
|
|
1639
|
+
"signed_at": "2026-05-12T23:57:10.186Z"
|
|
1640
1640
|
},
|
|
1641
1641
|
{
|
|
1642
1642
|
"name": "api-security",
|
|
@@ -1705,7 +1705,7 @@
|
|
|
1705
1705
|
"d3fend_refs": [],
|
|
1706
1706
|
"last_threat_review": "2026-05-11",
|
|
1707
1707
|
"signature": "hS1izPhETclITK7fp6R67dhy+wFDti/YsJ2M5I1gDjeWZYK41WuxeYSyt5xEHbCr3WCGDFJe77jkK1MWkxk2BA==",
|
|
1708
|
-
"signed_at": "2026-05-
|
|
1708
|
+
"signed_at": "2026-05-12T23:57:10.187Z"
|
|
1709
1709
|
},
|
|
1710
1710
|
{
|
|
1711
1711
|
"name": "cloud-security",
|
|
@@ -1786,7 +1786,7 @@
|
|
|
1786
1786
|
"CISA KEV additions for cloud-control-plane CVEs (IMDSv1 abuses, federation token mishandling, cross-tenant boundary failures); CISA Cybersecurity Advisories for cross-cloud advisories"
|
|
1787
1787
|
],
|
|
1788
1788
|
"signature": "kuatqNZoRnv+oeyrxbnk+m37JRBIgRAWnDp0/IYLnoBOybiG09RzLILJraxjhvdSNCgo7WXTeBO3Y6a3Ji9MAA==",
|
|
1789
|
-
"signed_at": "2026-05-
|
|
1789
|
+
"signed_at": "2026-05-12T23:57:10.187Z"
|
|
1790
1790
|
},
|
|
1791
1791
|
{
|
|
1792
1792
|
"name": "container-runtime-security",
|
|
@@ -1848,7 +1848,7 @@
|
|
|
1848
1848
|
"d3fend_refs": [],
|
|
1849
1849
|
"last_threat_review": "2026-05-11",
|
|
1850
1850
|
"signature": "Btb3/7fjPFopFVdxP7+E6n322gnAAwd7OPrnuqatq6c1rXTD9aXKxiBeCmWxs8zYbIbE/lFoe9R2g6uTp8ZDBg==",
|
|
1851
|
-
"signed_at": "2026-05-
|
|
1851
|
+
"signed_at": "2026-05-12T23:57:10.187Z"
|
|
1852
1852
|
},
|
|
1853
1853
|
{
|
|
1854
1854
|
"name": "mlops-security",
|
|
@@ -1919,7 +1919,7 @@
|
|
|
1919
1919
|
"MITRE ATLAS v5.2 — track AML.T0010 sub-technique expansion and any new MLOps-pipeline-specific TTPs"
|
|
1920
1920
|
],
|
|
1921
1921
|
"signature": "TBWnlgdllW7K1F10HCJ7p4dbLeS3lyNWm+7mNNtyZu7jB1V5AauG1P7sb1nLLqwKqeGlHS1F0eh/BNiuAvkABg==",
|
|
1922
|
-
"signed_at": "2026-05-
|
|
1922
|
+
"signed_at": "2026-05-12T23:57:10.188Z"
|
|
1923
1923
|
},
|
|
1924
1924
|
{
|
|
1925
1925
|
"name": "incident-response-playbook",
|
|
@@ -1981,7 +1981,7 @@
|
|
|
1981
1981
|
"NYDFS 23 NYCRR 500.17 amendments tightening ransom-payment 24h disclosure operationalization"
|
|
1982
1982
|
],
|
|
1983
1983
|
"signature": "FVAXpD6sIoOLQSPtZSLLsXQnc2o2hRwiFj4xK8zEWJVkUWGqvAWRrngie7O2DRKIbWqjO5h9EevVYSzhwYHCAA==",
|
|
1984
|
-
"signed_at": "2026-05-
|
|
1984
|
+
"signed_at": "2026-05-12T23:57:10.188Z"
|
|
1985
1985
|
},
|
|
1986
1986
|
{
|
|
1987
1987
|
"name": "email-security-anti-phishing",
|
|
@@ -2034,7 +2034,7 @@
|
|
|
2034
2034
|
"d3fend_refs": [],
|
|
2035
2035
|
"last_threat_review": "2026-05-11",
|
|
2036
2036
|
"signature": "0HDt3Qklee4FQeKoZfwr+8qdq2pVDS0a+c7JxVw1hV/bl8+YTPaPjPTAhQUnbhUCa5cGo7G4MBQ1AifQTMJdDA==",
|
|
2037
|
-
"signed_at": "2026-05-
|
|
2037
|
+
"signed_at": "2026-05-12T23:57:10.189Z"
|
|
2038
2038
|
},
|
|
2039
2039
|
{
|
|
2040
2040
|
"name": "age-gates-child-safety",
|
|
@@ -2102,7 +2102,7 @@
|
|
|
2102
2102
|
"US state adult-site age-verification laws — 19+ states by mid-2026 (TX HB 18 upheld by SCOTUS June 2025 in Free Speech Coalition v. Paxton); track ongoing challenges in remaining states"
|
|
2103
2103
|
],
|
|
2104
2104
|
"signature": "UyPSKUztZI/daHCRTnAh6ryoKLX4xyjuG+EaNMPRVuCz2gANGl1F/NozDsw7R2koMUwSFoiYTzwqDvo1tpuKAg==",
|
|
2105
|
-
"signed_at": "2026-05-
|
|
2105
|
+
"signed_at": "2026-05-12T23:57:10.189Z"
|
|
2106
2106
|
}
|
|
2107
2107
|
]
|
|
2108
2108
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blamejs/exceptd-skills",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.12",
|
|
4
4
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 38 skills, 10 catalogs, 34 jurisdictions, pre-computed indexes, Ed25519-signed.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-security",
|
package/sbom.cdx.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bomFormat": "CycloneDX",
|
|
3
3
|
"specVersion": "1.6",
|
|
4
|
-
"serialNumber": "urn:uuid:
|
|
4
|
+
"serialNumber": "urn:uuid:b2610e1f-020c-4e3e-b5a2-e9ed1431c086",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "2026-05-
|
|
7
|
+
"timestamp": "2026-05-12T23:57:11.194Z",
|
|
8
8
|
"tools": [
|
|
9
9
|
{
|
|
10
10
|
"name": "hand-written",
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
}
|
|
14
14
|
],
|
|
15
15
|
"component": {
|
|
16
|
-
"bom-ref": "pkg:npm/@blamejs/exceptd-skills@0.11.
|
|
16
|
+
"bom-ref": "pkg:npm/@blamejs/exceptd-skills@0.11.12",
|
|
17
17
|
"type": "application",
|
|
18
18
|
"name": "@blamejs/exceptd-skills",
|
|
19
|
-
"version": "0.11.
|
|
19
|
+
"version": "0.11.12",
|
|
20
20
|
"description": "AI security skills grounded in mid-2026 threat reality, not stale framework documentation. 38 skills, 10 catalogs, 34 jurisdictions, pre-computed indexes, Ed25519-signed.",
|
|
21
21
|
"licenses": [
|
|
22
22
|
{
|
|
@@ -25,11 +25,11 @@
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
],
|
|
28
|
-
"purl": "pkg:npm/%40blamejs/exceptd-skills@0.11.
|
|
28
|
+
"purl": "pkg:npm/%40blamejs/exceptd-skills@0.11.12",
|
|
29
29
|
"externalReferences": [
|
|
30
30
|
{
|
|
31
31
|
"type": "distribution",
|
|
32
|
-
"url": "https://www.npmjs.com/package/@blamejs/exceptd-skills/v/0.11.
|
|
32
|
+
"url": "https://www.npmjs.com/package/@blamejs/exceptd-skills/v/0.11.12"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"type": "vcs",
|