@blamejs/exceptd-skills 0.11.7 → 0.11.9
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 +61 -0
- package/bin/exceptd.js +203 -32
- package/data/_indexes/_meta.json +2 -2
- package/keys/public.pem +1 -1
- 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,66 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.11.9 — 2026-05-12
|
|
4
|
+
|
|
5
|
+
**Patch: items 99-115 — CLI-shim audit, real fixes.**
|
|
6
|
+
|
|
7
|
+
User audit identified the common root cause across 8 releases of "fixed" bugs that operators kept re-finding: the CLI shim layer between arg parsing and result rendering. v0.11.9 audits that layer end to end.
|
|
8
|
+
|
|
9
|
+
### Critical
|
|
10
|
+
|
|
11
|
+
- **#99 default human output, unconditionally.** Pre-0.11.9 default was conditional on `process.stdout.isTTY`. Under most automation harnesses (Claude Code's Bash tool, GitHub Actions, CI runners, subprocess pipes) `isTTY` is false, so operators saw JSON everywhere "default human" was advertised. Now: when a human renderer is supplied AND no `--json`/`--pretty`/`--json-stdout-only` is passed, emit human. `--json` to opt back into JSON. Closes the longest-standing UX gap.
|
|
12
|
+
|
|
13
|
+
### Bugs
|
|
14
|
+
|
|
15
|
+
- **#100 cmdRunMulti exits non-zero on any blocked run.** Pre-0.11.9 the aggregate result had `{ok: false}` in the body but exit code stayed 0 for multi-playbook runs (cmdRunMulti was missing the exit-non-zero gate that cmdRun had). CI gates couldn't distinguish "ran clean" from "any blocked." Now: cmdRunMulti checks `results.some(r => r.ok === false)` and exits 1 when true, matching cmdRun's single-playbook contract.
|
|
16
|
+
|
|
17
|
+
- **#113 `--operator` surfaces in run result top-level.** Pre-0.11.9 `--operator` was persisted to the attestation file but the run result didn't echo it back. Operators thought the flag was dropped. Now: `result.operator = runOpts.operator` so `exceptd run … --operator … --json | jq .operator` returns the supplied value.
|
|
18
|
+
|
|
19
|
+
- **#114 `--ack` surfaces in run result top-level.** Same shape as #113. `result.operator_consent = { acked_at, explicit: true }` echoes back in the run result.
|
|
20
|
+
|
|
21
|
+
- **#115 `ci --required <list>` actually filters.** Pre-0.11.9 the flag was silently ignored — `ci --required secrets,sbom` ran the default scope set anyway. Now: `--required` takes precedence over `--scope` and `--all`, runs exactly the named set, rejects unknown playbook IDs with a structured error.
|
|
22
|
+
|
|
23
|
+
- **#102 `attest diff` unchanged_count for identical hashes** — already fixed in v0.11.8 (verified by new regression test in this release).
|
|
24
|
+
|
|
25
|
+
- **#104 jurisdiction clocks on detected** — verified working: `ci --required secrets --evidence <detected-submission>` returns `jurisdiction_clocks_started: 3` (for secrets' 3 detect_confirmed obligations). The user's earlier report was on a pre-canonicalize-fix version where `detection_classification: detected` wasn't propagating.
|
|
26
|
+
|
|
27
|
+
### Tests
|
|
28
|
+
|
|
29
|
+
5 new cases for items 104, 113, 114, 115. 333 total.
|
|
30
|
+
|
|
31
|
+
### Deferred
|
|
32
|
+
|
|
33
|
+
- **#116** `ci --explain` dry-run mode
|
|
34
|
+
- **#117** `diff <playbook> --since <window>`
|
|
35
|
+
- **#118** `attest sign <id>` retroactive signing
|
|
36
|
+
|
|
37
|
+
## 0.11.8 — 2026-05-12
|
|
38
|
+
|
|
39
|
+
**Patch: items 99-104 + 6 new regression tests (328 total).**
|
|
40
|
+
|
|
41
|
+
### Critical
|
|
42
|
+
|
|
43
|
+
- **#99 default human-readable output for `brief` + `run`.** Closed across 8 releases of operator reports. `emit()`'s third arg now accepts a human renderer; both verbs supply one. When stdout is a TTY and no `--json`/`--pretty` is passed, operators get a digest (jurisdictions + threat context + RWEP threshold + required/optional artifacts + indicators for `brief`; classification + RWEP delta + matched CVEs + indicator hits + remediation + notification clocks for `run`). Piped output stays JSON for AI consumers and CI scripts.
|
|
44
|
+
|
|
45
|
+
- **#103 CI no longer fails on inconclusive baseline RWEP.** Fresh-repo `ci --scope code` with no operator evidence previously exited 2 with `fail_reasons: ["sbom: rwep=90 >= cap=80"]` because catalog-baseline RWEP exceeded the default cap. The asymmetry between operator expectation ("no evidence = no fail") and tool behavior ("inconclusive ≠ pass") was the biggest first-impression surprise. Fix: only RWEP DELTA (adjusted - base) counts against the cap on inconclusive classifications. Detected classifications still gate on absolute RWEP. Baseline + zero evidence → PASS.
|
|
46
|
+
|
|
47
|
+
### Bugs
|
|
48
|
+
|
|
49
|
+
- **#101 `ai-run --no-stream` shape unified with `run`.** Both now return `{ok, playbook_id, directive_id, session_id, evidence_hash, phases: {govern, direct, look, detect, analyze, validate, close}}`. Pre-0.11.8 ai-run flattened phases to top-level while `run` nested them — operators writing JSONPath had to know which verb produced the payload.
|
|
50
|
+
|
|
51
|
+
- **#102 `attest diff` `unchanged_count` now correct.** Two issues fixed: (a) the diff function had a branch that prevented counting both-sides-present-and-identical entries; (b) the diff didn't normalize flat-shape submissions, so artifact comparisons against `undefined` returned 0 even for non-empty observations. Now: submissions are normalized via the runner's `normalizeSubmission` before comparison, and identical entries correctly increment the counter.
|
|
52
|
+
|
|
53
|
+
- **#100 exit code contract** — verified correct + locked with regression tests. `result.ok === false` → exit 1 (preflight halt). `result.ok === true` with warn-level preflight_issues → exit 0 (run completed). `--strict-preconditions` escalates warn-level to exit 1 (already shipped v0.11.6). Three named test cases lock the contract in.
|
|
54
|
+
|
|
55
|
+
### Tests
|
|
56
|
+
|
|
57
|
+
6 new regression cases for items 99-103. 328 cases total in `tests/operator-bugs.test.js`.
|
|
58
|
+
|
|
59
|
+
### Deferred
|
|
60
|
+
|
|
61
|
+
- **#104** `--block-on-jurisdiction-clock` trigger condition unclear in help — clock_starts events fire on `detect_confirmed` etc; without a detected classification no clock fires. Help text wording deferred to v0.11.9.
|
|
62
|
+
- **#105-108** `ci --explain`, `diff <playbook> --since 7d`, `ci --required`, `attest sign <id>` — features deferred to v0.11.9.
|
|
63
|
+
|
|
3
64
|
## 0.11.7 — 2026-05-12
|
|
4
65
|
|
|
5
66
|
**Republish of v0.11.6 (which failed CI publish). Adds CI publish-gate fix.**
|
package/bin/exceptd.js
CHANGED
|
@@ -437,17 +437,22 @@ function parseArgs(argv, opts) {
|
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
function emit(obj, pretty, humanRenderer) {
|
|
440
|
-
// v0.11.
|
|
441
|
-
//
|
|
442
|
-
//
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
440
|
+
// v0.11.9 (#99): default to HUMAN-readable unconditionally when a renderer
|
|
441
|
+
// is provided. Pre-0.11.9 the default depended on process.stdout.isTTY,
|
|
442
|
+
// which is false under most automation harnesses (Claude Code's Bash tool,
|
|
443
|
+
// GitHub Actions, CI runners, subprocess pipes). Operators saw JSON
|
|
444
|
+
// everywhere "default human" was advertised. Now:
|
|
445
|
+
// --json or --json-stdout-only → compact JSON
|
|
446
|
+
// --pretty → indented JSON
|
|
447
|
+
// default (no flag, renderer present) → HUMAN
|
|
448
|
+
// default (no flag, no renderer) → indented JSON when TTY else compact
|
|
449
|
+
// This closes the longest-standing UX gap across 8 releases.
|
|
450
|
+
const wantJson = !!global.__exceptdWantJson || !!process.env.EXCEPTD_RAW_JSON;
|
|
451
|
+
if (humanRenderer && !wantJson && !pretty) {
|
|
448
452
|
process.stdout.write(humanRenderer(obj) + "\n");
|
|
449
453
|
return;
|
|
450
454
|
}
|
|
455
|
+
const interactive = process.stdout.isTTY && !process.env.EXCEPTD_RAW_JSON;
|
|
451
456
|
const indent = pretty || (interactive && !pretty);
|
|
452
457
|
const s = indent ? JSON.stringify(obj, null, 2) : JSON.stringify(obj);
|
|
453
458
|
process.stdout.write(s + "\n");
|
|
@@ -999,7 +1004,42 @@ function cmdBrief(runner, args, runOpts, pretty) {
|
|
|
999
1004
|
detect_indicators_preview: (pb.phases?.detect?.indicators || []).map(i => ({
|
|
1000
1005
|
id: i.id, type: i.type, confidence: i.confidence, deterministic: !!i.deterministic
|
|
1001
1006
|
})),
|
|
1002
|
-
}, pretty)
|
|
1007
|
+
}, pretty, (obj) => {
|
|
1008
|
+
// v0.11.8 (#99) — human renderer for `brief`. Used on TTY when --json /
|
|
1009
|
+
// --pretty are NOT set. Structured digest covering the three info phases.
|
|
1010
|
+
const lines = [];
|
|
1011
|
+
lines.push(`brief: ${obj.playbook_id} (${obj.directive_id})`);
|
|
1012
|
+
lines.push(` scope: ${obj.scope || "n/a"} threat_currency_score: ${obj.threat_currency_score}`);
|
|
1013
|
+
if (obj.jurisdiction_obligations?.length) {
|
|
1014
|
+
lines.push(`\nJurisdiction obligations (${obj.jurisdiction_obligations.length}):`);
|
|
1015
|
+
for (const j of obj.jurisdiction_obligations.slice(0, 6)) {
|
|
1016
|
+
lines.push(` ${j.jurisdiction} ${j.regulation} → ${j.window_hours}h on ${j.clock_starts}`);
|
|
1017
|
+
}
|
|
1018
|
+
if (obj.jurisdiction_obligations.length > 6) lines.push(` … ${obj.jurisdiction_obligations.length - 6} more`);
|
|
1019
|
+
}
|
|
1020
|
+
if (obj.threat_context) {
|
|
1021
|
+
const first = obj.threat_context.split(/(?<=[.!?])\s+/)[0] || "";
|
|
1022
|
+
lines.push(`\nThreat context: ${first.slice(0, 200)}${first.length > 200 ? "…" : ""}`);
|
|
1023
|
+
}
|
|
1024
|
+
if (obj.rwep_threshold) {
|
|
1025
|
+
lines.push(`\nRWEP threshold: escalate ${obj.rwep_threshold.escalate} · monitor ${obj.rwep_threshold.monitor} · close ${obj.rwep_threshold.close}`);
|
|
1026
|
+
}
|
|
1027
|
+
const required = (obj.artifacts || []).filter(a => a.required);
|
|
1028
|
+
const optional = (obj.artifacts || []).filter(a => !a.required);
|
|
1029
|
+
lines.push(`\nRequired artifacts (${required.length}): ${required.map(a => a.id).join(", ") || "(none)"}`);
|
|
1030
|
+
if (optional.length) lines.push(`Optional artifacts (${optional.length}): ${optional.map(a => a.id).slice(0, 8).join(", ")}${optional.length > 8 ? ", …" : ""}`);
|
|
1031
|
+
const indicators = obj.detect_indicators_preview || [];
|
|
1032
|
+
lines.push(`\nIndicators (${indicators.length}): ${indicators.map(i => i.id).slice(0, 8).join(", ")}${indicators.length > 8 ? ", …" : ""}`);
|
|
1033
|
+
if (obj.preconditions?.length) {
|
|
1034
|
+
lines.push(`\nPreconditions (${obj.preconditions.length}):`);
|
|
1035
|
+
for (const p of obj.preconditions) {
|
|
1036
|
+
lines.push(` ${p.id} (${p.on_fail}): ${p.description?.slice(0, 80) || p.check}`);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
lines.push(`\nRun: exceptd run ${obj.playbook_id} --evidence <file|-> --json`);
|
|
1040
|
+
lines.push(`Full structured doc: --json or --pretty`);
|
|
1041
|
+
return lines.join("\n");
|
|
1042
|
+
});
|
|
1003
1043
|
}
|
|
1004
1044
|
|
|
1005
1045
|
/** `run-all` alias for `run --all`. */
|
|
@@ -1254,6 +1294,12 @@ function cmdRun(runner, args, runOpts, pretty) {
|
|
|
1254
1294
|
|
|
1255
1295
|
const result = runner.run(playbookId, directiveId, submission, runOpts);
|
|
1256
1296
|
|
|
1297
|
+
// v0.11.9 (#113/#114): surface --operator and --ack in the run result so
|
|
1298
|
+
// operators see the attribution + consent state without inspecting the
|
|
1299
|
+
// attestation file. Pre-0.11.9 these were persisted to disk only.
|
|
1300
|
+
if (result && runOpts.operator) result.operator = runOpts.operator;
|
|
1301
|
+
if (result && runOpts.operator_consent) result.operator_consent = runOpts.operator_consent;
|
|
1302
|
+
|
|
1257
1303
|
// Persist attestation for reattest cycles when the run succeeded.
|
|
1258
1304
|
if (result && result.ok && result.session_id) {
|
|
1259
1305
|
const persistResult = persistAttestation({
|
|
@@ -1448,7 +1494,52 @@ function cmdRun(runner, args, runOpts, pretty) {
|
|
|
1448
1494
|
// Fallback: full result
|
|
1449
1495
|
}
|
|
1450
1496
|
|
|
1451
|
-
emit(result, pretty)
|
|
1497
|
+
emit(result, pretty, (obj) => {
|
|
1498
|
+
// v0.11.8 (#99) — human renderer for `run`. Used on TTY when --json /
|
|
1499
|
+
// --pretty are NOT set. One-screen digest of the run; full JSON via --json.
|
|
1500
|
+
const lines = [];
|
|
1501
|
+
lines.push(`run: ${obj.playbook_id} (${obj.directive_id})`);
|
|
1502
|
+
lines.push(` session-id: ${obj.session_id}`);
|
|
1503
|
+
lines.push(` evidence-hash: ${obj.evidence_hash}`);
|
|
1504
|
+
const cls = obj.phases?.detect?.classification || "n/a";
|
|
1505
|
+
const rwep = obj.phases?.analyze?.rwep;
|
|
1506
|
+
const adj = rwep?.adjusted ?? 0;
|
|
1507
|
+
const base = rwep?.base ?? 0;
|
|
1508
|
+
const top = rwep?.threshold?.escalate ?? "n/a";
|
|
1509
|
+
const verdictIcon = cls === "detected" ? "[!! DETECTED]" : cls === "inconclusive" ? "[i INCONCLUSIVE]" : "[ok]";
|
|
1510
|
+
lines.push(`\n${verdictIcon} classification=${cls} RWEP ${adj}/${top}${adj !== base ? ` (Δ${adj - base} from operator evidence)` : " (catalog baseline)"} blast_radius=${obj.phases?.analyze?.blast_radius_score ?? "n/a"}/5`);
|
|
1511
|
+
const cves = obj.phases?.analyze?.matched_cves || [];
|
|
1512
|
+
if (cves.length) {
|
|
1513
|
+
lines.push(`\nMatched CVEs (${cves.length}):`);
|
|
1514
|
+
for (const c of cves.slice(0, 6)) lines.push(` ${c.cve_id} RWEP ${c.rwep} KEV=${c.cisa_kev} ${c.active_exploitation || ""}`);
|
|
1515
|
+
if (cves.length > 6) lines.push(` … ${cves.length - 6} more`);
|
|
1516
|
+
}
|
|
1517
|
+
const indicators = obj.phases?.detect?.indicators || [];
|
|
1518
|
+
const hits = indicators.filter(i => i.verdict === "hit");
|
|
1519
|
+
if (hits.length) {
|
|
1520
|
+
lines.push(`\nIndicators that fired (${hits.length}):`);
|
|
1521
|
+
for (const i of hits.slice(0, 8)) lines.push(` ${i.id} (${i.confidence}${i.deterministic ? "/deterministic" : ""})`);
|
|
1522
|
+
}
|
|
1523
|
+
const rem = obj.phases?.validate?.selected_remediation;
|
|
1524
|
+
if (rem) {
|
|
1525
|
+
lines.push(`\nRecommended remediation: ${rem.id} (priority ${rem.priority})`);
|
|
1526
|
+
lines.push(` ${rem.description?.slice(0, 200) || ""}`);
|
|
1527
|
+
}
|
|
1528
|
+
const notif = (obj.phases?.close?.notification_actions || []).filter(n => n.clock_started_at);
|
|
1529
|
+
if (notif.length) {
|
|
1530
|
+
lines.push(`\nNotification clocks started (${notif.length}):`);
|
|
1531
|
+
for (const n of notif) lines.push(` ${n.obligation_ref} → deadline ${n.deadline}`);
|
|
1532
|
+
}
|
|
1533
|
+
const feeds = obj.phases?.close?.feeds_into || [];
|
|
1534
|
+
if (feeds.length) lines.push(`\nNext playbooks suggested: ${feeds.join(", ")}`);
|
|
1535
|
+
const issues = obj.preflight_issues || [];
|
|
1536
|
+
if (issues.length) {
|
|
1537
|
+
lines.push(`\nPreflight warnings (${issues.length}):`);
|
|
1538
|
+
for (const i of issues) lines.push(` [${i.on_fail}] ${i.id}: ${i.check || ""}`);
|
|
1539
|
+
}
|
|
1540
|
+
lines.push(`\nFull structured result: --json (or --pretty for indented).`);
|
|
1541
|
+
return lines.join("\n");
|
|
1542
|
+
});
|
|
1452
1543
|
}
|
|
1453
1544
|
|
|
1454
1545
|
/**
|
|
@@ -1546,6 +1637,12 @@ function cmdRunMulti(runner, ids, args, runOpts, pretty, meta) {
|
|
|
1546
1637
|
},
|
|
1547
1638
|
results,
|
|
1548
1639
|
}, pretty);
|
|
1640
|
+
// v0.11.9 (#100): cmdRunMulti exits non-zero when any individual run
|
|
1641
|
+
// returned ok:false. Pre-0.11.9 the aggregate result had {ok:false} in
|
|
1642
|
+
// the body but exit code stayed 0 — CI gates couldn't distinguish "ran
|
|
1643
|
+
// clean" from "blocked." Now matches cmdRun's single-playbook contract.
|
|
1644
|
+
const anyBlocked = results.some(r => r.ok === false);
|
|
1645
|
+
if (anyBlocked) process.exit(1);
|
|
1549
1646
|
}
|
|
1550
1647
|
|
|
1551
1648
|
function cmdIngest(runner, args, runOpts, pretty) {
|
|
@@ -1977,8 +2074,19 @@ function cmdAttest(runner, args, runOpts, pretty) {
|
|
|
1977
2074
|
a_evidence_hash: self.evidence_hash,
|
|
1978
2075
|
b_evidence_hash: other.evidence_hash,
|
|
1979
2076
|
status: self.evidence_hash === other.evidence_hash ? "unchanged" : "drifted",
|
|
1980
|
-
|
|
1981
|
-
|
|
2077
|
+
// v0.11.8 (#102): normalize submissions before diffing so flat-shape
|
|
2078
|
+
// (observations + verdict) submissions emit meaningful artifact_diff
|
|
2079
|
+
// counts. Pre-0.11.8 (self.submission||{}).artifacts was undefined
|
|
2080
|
+
// for flat submissions; the diff returned all zeros even when
|
|
2081
|
+
// artifacts were present in observations.
|
|
2082
|
+
artifact_diff: diffArtifacts(
|
|
2083
|
+
normalizedArtifacts(self.submission, runner),
|
|
2084
|
+
normalizedArtifacts(other.submission, runner)
|
|
2085
|
+
),
|
|
2086
|
+
signal_override_diff: diffSignalOverrides(
|
|
2087
|
+
normalizedSignalOverrides(self.submission, runner),
|
|
2088
|
+
normalizedSignalOverrides(other.submission, runner)
|
|
2089
|
+
),
|
|
1982
2090
|
}, pretty);
|
|
1983
2091
|
return;
|
|
1984
2092
|
}
|
|
@@ -2080,6 +2188,36 @@ function cmdAttest(runner, args, runOpts, pretty) {
|
|
|
2080
2188
|
return emitError(`attest: unknown subverb "${subverb}". Try export | verify | show.`, null, pretty);
|
|
2081
2189
|
}
|
|
2082
2190
|
|
|
2191
|
+
/**
|
|
2192
|
+
* v0.11.8 (#102): extract normalized artifacts/signal_overrides from a stored
|
|
2193
|
+
* attestation submission. Flat-shape submissions store `observations` only;
|
|
2194
|
+
* nested submissions store `artifacts` + `signal_overrides`. Returning the
|
|
2195
|
+
* canonical nested view of both shapes lets `attest diff` produce meaningful
|
|
2196
|
+
* counts regardless of which shape the operator submitted.
|
|
2197
|
+
*/
|
|
2198
|
+
function normalizedArtifacts(submission, runner) {
|
|
2199
|
+
if (!submission || typeof submission !== "object") return {};
|
|
2200
|
+
if (submission.artifacts) return submission.artifacts;
|
|
2201
|
+
if (submission.observations) {
|
|
2202
|
+
try {
|
|
2203
|
+
const norm = runner.normalizeSubmission({ observations: submission.observations }, { _meta: {}, phases: { look: { artifacts: [] } } });
|
|
2204
|
+
return norm.artifacts || {};
|
|
2205
|
+
} catch { return {}; }
|
|
2206
|
+
}
|
|
2207
|
+
return {};
|
|
2208
|
+
}
|
|
2209
|
+
function normalizedSignalOverrides(submission, runner) {
|
|
2210
|
+
if (!submission || typeof submission !== "object") return {};
|
|
2211
|
+
if (submission.signal_overrides) return submission.signal_overrides;
|
|
2212
|
+
if (submission.observations) {
|
|
2213
|
+
try {
|
|
2214
|
+
const norm = runner.normalizeSubmission({ observations: submission.observations }, { _meta: {}, phases: { look: { artifacts: [] } } });
|
|
2215
|
+
return norm.signal_overrides || {};
|
|
2216
|
+
} catch { return {}; }
|
|
2217
|
+
}
|
|
2218
|
+
return {};
|
|
2219
|
+
}
|
|
2220
|
+
|
|
2083
2221
|
/**
|
|
2084
2222
|
* Per-artifact diff between two submissions. Returns { added, removed, changed }
|
|
2085
2223
|
* keyed by artifact id. Used by `attest diff` (bug #34 fix) so operators get
|
|
@@ -2091,15 +2229,22 @@ function diffArtifacts(a, b) {
|
|
|
2091
2229
|
const out = { added: [], removed: [], changed: [], unchanged_count: 0 };
|
|
2092
2230
|
for (const id of allIds) {
|
|
2093
2231
|
const av = a[id], bv = b[id];
|
|
2094
|
-
if (!av && bv)
|
|
2095
|
-
|
|
2096
|
-
else if (
|
|
2232
|
+
if (!av && bv) {
|
|
2233
|
+
out.added.push({ id, captured: !!bv.captured, value_preview: previewValue(bv.value) });
|
|
2234
|
+
} else if (av && !bv) {
|
|
2235
|
+
out.removed.push({ id, captured: !!av.captured, value_preview: previewValue(av.value) });
|
|
2236
|
+
} else if (av && bv && JSON.stringify(av) !== JSON.stringify(bv)) {
|
|
2097
2237
|
out.changed.push({
|
|
2098
2238
|
id,
|
|
2099
2239
|
a_captured: !!av.captured, b_captured: !!bv.captured,
|
|
2100
2240
|
a_value_preview: previewValue(av.value), b_value_preview: previewValue(bv.value),
|
|
2101
2241
|
});
|
|
2102
|
-
} else
|
|
2242
|
+
} else if (av && bv) {
|
|
2243
|
+
// v0.11.8 (#102): both sides have the entry AND they're identical →
|
|
2244
|
+
// unchanged. Pre-0.11.8 the unchanged path was unreachable because the
|
|
2245
|
+
// !av && bv guards short-circuited when both existed.
|
|
2246
|
+
out.unchanged_count++;
|
|
2247
|
+
}
|
|
2103
2248
|
}
|
|
2104
2249
|
return out;
|
|
2105
2250
|
}
|
|
@@ -2767,20 +2912,28 @@ function cmdAiRun(runner, args, runOpts, pretty) {
|
|
|
2767
2912
|
process.stderr.write((pretty ? JSON.stringify(result || {}, null, 2) : JSON.stringify(result || {})) + "\n");
|
|
2768
2913
|
process.exit(1);
|
|
2769
2914
|
}
|
|
2915
|
+
// v0.11.8 (#101): unify ai-run --no-stream shape with `run`. Pre-0.11.8
|
|
2916
|
+
// ai-run flattened phases to top-level (`govern`, `direct`, `look`, ...),
|
|
2917
|
+
// while `run` nested them under `phases.*`. Operators writing JSONPath
|
|
2918
|
+
// queries had to know which verb produced the payload. Now both share
|
|
2919
|
+
// `{ok, playbook_id, directive_id, session_id, evidence_hash, phases: {...}}`.
|
|
2770
2920
|
emit({
|
|
2921
|
+
ok: result.ok !== false,
|
|
2771
2922
|
verb: "ai-run",
|
|
2772
2923
|
mode: "no-stream",
|
|
2773
2924
|
playbook_id: playbookId,
|
|
2774
2925
|
directive_id: directiveId,
|
|
2775
|
-
govern: governEvent,
|
|
2776
|
-
direct: directEvent,
|
|
2777
|
-
look: lookEvent,
|
|
2778
|
-
detect: result.phases?.detect || null,
|
|
2779
|
-
analyze: result.phases?.analyze || null,
|
|
2780
|
-
validate: result.phases?.validate || null,
|
|
2781
|
-
close: result.phases?.close || null,
|
|
2782
2926
|
session_id: result.session_id,
|
|
2783
2927
|
evidence_hash: result.evidence_hash,
|
|
2928
|
+
phases: {
|
|
2929
|
+
govern: governEvent,
|
|
2930
|
+
direct: directEvent,
|
|
2931
|
+
look: lookEvent,
|
|
2932
|
+
detect: result.phases?.detect || null,
|
|
2933
|
+
analyze: result.phases?.analyze || null,
|
|
2934
|
+
validate: result.phases?.validate || null,
|
|
2935
|
+
close: result.phases?.close || null,
|
|
2936
|
+
},
|
|
2784
2937
|
}, pretty);
|
|
2785
2938
|
return;
|
|
2786
2939
|
}
|
|
@@ -3051,14 +3204,20 @@ function cmdCi(runner, args, runOpts, pretty) {
|
|
|
3051
3204
|
const maxRwep = args["max-rwep"] !== undefined ? Number(args["max-rwep"]) : null;
|
|
3052
3205
|
const blockOnClock = !!args["block-on-jurisdiction-clock"];
|
|
3053
3206
|
|
|
3054
|
-
// v0.11.
|
|
3055
|
-
//
|
|
3056
|
-
//
|
|
3057
|
-
// applies to any repo). Operators expect ci to run "what discover would
|
|
3058
|
-
// recommend"; pre-0.11.2 ci ran scope=X only, which dropped framework +
|
|
3059
|
-
// missed sbom-on-repo.
|
|
3207
|
+
// v0.11.9 (#115): --required <playbook,playbook,...> takes precedence over
|
|
3208
|
+
// --scope and --all. Operators specifying an explicit set get exactly that
|
|
3209
|
+
// set, no more, no less. Pre-0.11.9 the flag was silently ignored.
|
|
3060
3210
|
let ids;
|
|
3061
|
-
if (args.
|
|
3211
|
+
if (args.required) {
|
|
3212
|
+
const requestedRaw = Array.isArray(args.required) ? args.required.join(",") : args.required;
|
|
3213
|
+
const requested = requestedRaw.split(",").map(s => s.trim()).filter(Boolean);
|
|
3214
|
+
const all = runner.listPlaybooks();
|
|
3215
|
+
const unknown = requested.filter(r => !all.includes(r));
|
|
3216
|
+
if (unknown.length > 0) {
|
|
3217
|
+
return emitError(`ci --required: unknown playbook ID(s) ${JSON.stringify(unknown)}. Known: ${all.join(", ")}.`, null, pretty);
|
|
3218
|
+
}
|
|
3219
|
+
ids = requested;
|
|
3220
|
+
} else if (args.all) {
|
|
3062
3221
|
ids = runner.listPlaybooks();
|
|
3063
3222
|
} else if (scope) {
|
|
3064
3223
|
ids = filterPlaybooksByScope(runner, scope);
|
|
@@ -3133,19 +3292,31 @@ function cmdCi(runner, args, runOpts, pretty) {
|
|
|
3133
3292
|
continue;
|
|
3134
3293
|
}
|
|
3135
3294
|
const cls = result.phases?.detect?.classification;
|
|
3295
|
+
const rwepBase = result.phases?.analyze?.rwep?.base ?? 0;
|
|
3136
3296
|
const rwepAdj = result.phases?.analyze?.rwep?.adjusted ?? 0;
|
|
3137
3297
|
const cap = maxRwep !== null
|
|
3138
3298
|
? maxRwep
|
|
3139
3299
|
: (result.phases?.analyze?.rwep?.threshold?.escalate ?? 90);
|
|
3140
3300
|
const clockStarted = (result.phases?.close?.notification_actions || [])
|
|
3141
3301
|
.some(n => n && n.clock_started_at != null);
|
|
3302
|
+
|
|
3142
3303
|
if (cls === "detected") {
|
|
3143
3304
|
fail = true;
|
|
3144
3305
|
failReasons.push(`${id}: classification=detected`);
|
|
3145
3306
|
}
|
|
3146
|
-
|
|
3307
|
+
// v0.11.8 (#103): only count RWEP against the cap when the operator's
|
|
3308
|
+
// signals actually moved the score, OR classification reached "detected".
|
|
3309
|
+
// Pre-0.11.8 a fresh `ci --scope code` run with NO operator evidence
|
|
3310
|
+
// failed because catalog-baseline RWEP (e.g. 90 for KEV-listed kernel
|
|
3311
|
+
// CVEs) exceeded the default cap (80). That penalized inconclusive runs
|
|
3312
|
+
// for catalogue facts the operator hadn't yet weighed in on. Now: only
|
|
3313
|
+
// RWEP DELTA (adjusted - base) counts against the cap on inconclusive
|
|
3314
|
+
// classifications. Detected runs still fail on absolute RWEP.
|
|
3315
|
+
if (cls === "detected" && rwepAdj >= cap) {
|
|
3316
|
+
// Already failed above; this branch documents the rationale.
|
|
3317
|
+
} else if (cls === "inconclusive" && rwepAdj - rwepBase >= cap) {
|
|
3147
3318
|
fail = true;
|
|
3148
|
-
failReasons.push(`${id}:
|
|
3319
|
+
failReasons.push(`${id}: rwep_delta=${rwepAdj - rwepBase} >= cap=${cap} (classification=inconclusive; operator evidence raised the score)`);
|
|
3149
3320
|
}
|
|
3150
3321
|
if (blockOnClock && clockStarted) {
|
|
3151
3322
|
fail = true;
|
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-12T22:31:50.263Z",
|
|
4
4
|
"generator": "scripts/build-indexes.js",
|
|
5
5
|
"source_count": 49,
|
|
6
6
|
"source_hashes": {
|
|
7
|
-
"manifest.json": "
|
|
7
|
+
"manifest.json": "6d71ff7bba13b2ac8fb51d6b351b05378dd3f598080fff000b9db1ea9bdc5431",
|
|
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/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-12T22:30:56.549Z",
|
|
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.9",
|
|
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-12T22:30:56.134Z",
|
|
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-12T22:30:56.136Z",
|
|
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-12T22:30:56.136Z",
|
|
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-12T22:30:56.136Z"
|
|
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-12T22:30:56.137Z"
|
|
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-12T22:30:56.137Z"
|
|
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-12T22:30:56.138Z",
|
|
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-12T22:30:56.138Z",
|
|
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-12T22:30:56.138Z",
|
|
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-12T22:30:56.139Z"
|
|
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-12T22:30:56.139Z"
|
|
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-12T22:30:56.139Z"
|
|
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-12T22:30:56.140Z",
|
|
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-12T22:30:56.140Z"
|
|
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-12T22:30:56.140Z",
|
|
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-12T22:30:56.141Z"
|
|
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-12T22:30:56.141Z"
|
|
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-12T22:30:56.141Z"
|
|
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-12T22:30:56.141Z"
|
|
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-12T22:30:56.142Z"
|
|
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-12T22:30:56.142Z"
|
|
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-12T22:30:56.142Z"
|
|
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-12T22:30:56.142Z"
|
|
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-12T22:30:56.143Z"
|
|
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-12T22:30:56.143Z"
|
|
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-12T22:30:56.143Z"
|
|
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-12T22:30:56.144Z"
|
|
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-12T22:30:56.144Z"
|
|
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-12T22:30:56.144Z"
|
|
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-12T22:30:56.145Z"
|
|
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-12T22:30:56.145Z"
|
|
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-12T22:30:56.145Z"
|
|
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-12T22:30:56.146Z"
|
|
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-12T22:30:56.146Z"
|
|
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-12T22:30:56.146Z"
|
|
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-12T22:30:56.147Z"
|
|
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-12T22:30:56.147Z"
|
|
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-12T22:30:56.147Z"
|
|
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.9",
|
|
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:1370612e-bb38-413e-9e02-f1b64d6786e0",
|
|
5
5
|
"version": 1,
|
|
6
6
|
"metadata": {
|
|
7
|
-
"timestamp": "2026-05-
|
|
7
|
+
"timestamp": "2026-05-12T22:30:56.981Z",
|
|
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.9",
|
|
17
17
|
"type": "application",
|
|
18
18
|
"name": "@blamejs/exceptd-skills",
|
|
19
|
-
"version": "0.11.
|
|
19
|
+
"version": "0.11.9",
|
|
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.9",
|
|
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.9"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"type": "vcs",
|