@blamejs/exceptd-skills 0.10.1 → 0.10.3
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/AGENTS.md +51 -0
- package/CHANGELOG.md +72 -0
- package/bin/exceptd.js +468 -37
- package/data/_indexes/_meta.json +2 -2
- package/data/playbooks/crypto-codebase.json +1387 -0
- package/data/playbooks/kernel.json +1 -1
- package/data/playbooks/library-author.json +1792 -0
- package/lib/framework-gap.js +17 -1
- package/lib/playbook-runner.js +146 -11
- package/lib/prefetch.js +9 -1
- package/manifest-snapshot.json +1 -1
- package/manifest.json +39 -39
- package/orchestrator/index.js +98 -8
- package/package.json +2 -1
- package/sbom.cdx.json +6 -6
- package/sources/README.md +170 -0
- package/sources/validators/atlas-validator.js +158 -0
- package/sources/validators/cve-validator.js +277 -0
- package/sources/validators/index.js +86 -0
- package/sources/validators/rfc-validator.js +165 -0
- package/sources/validators/version-pin-validator.js +144 -0
package/AGENTS.md
CHANGED
|
@@ -77,6 +77,57 @@ Operator asks: "is this host vulnerable to Copy Fail?" AI invokes `node lib/play
|
|
|
77
77
|
|
|
78
78
|
Schema reference: `lib/schemas/playbook.schema.json`. Reference playbook (read this before authoring a new one): `data/playbooks/kernel.json`.
|
|
79
79
|
|
|
80
|
+
### feeds_into threshold matrix
|
|
81
|
+
|
|
82
|
+
Each playbook's `_meta.feeds_into[]` declares downstream playbooks the host AI should consider chaining into after this run, and the condition that fires the chain. The condition expressions evaluate at `close()` against `analyze` + `validate` + `agentSignals` context. AI assistants surface the suggested next playbook to the operator but never auto-execute; the operator decides.
|
|
83
|
+
|
|
84
|
+
The current (v0.10.x) matrix:
|
|
85
|
+
|
|
86
|
+
| From | Triggers | To | Why |
|
|
87
|
+
|---|---|---|---|
|
|
88
|
+
| ai-api | `analyze.compliance_theater_check.verdict == 'theater'` | framework | dotfile-cred-exposure theater pattern |
|
|
89
|
+
| ai-api | `analyze.blast_radius_score >= 4` | sbom | broad blast radius → inventory check |
|
|
90
|
+
| ai-api | `finding.includes_mcp_server_credential_exposure == true` | mcp | MCP creds leaked → MCP fleet audit |
|
|
91
|
+
| containers | `finding.severity >= 'high'` | kernel | container escape → kernel surface |
|
|
92
|
+
| containers | `always` | secrets | manifests routinely embed secrets |
|
|
93
|
+
| cred-stores | `finding.severity >= 'high'` | secrets | leaked creds in store → repo grep |
|
|
94
|
+
| cred-stores | `finding.severity == 'critical'` | runtime | critical exposure → listening-surface audit |
|
|
95
|
+
| crypto | `analyze.compliance_theater_check.verdict == 'theater'` | framework | FIPS-claim vs reality |
|
|
96
|
+
| crypto | `analyze.blast_radius_score >= 4` | sbom | crypto blast → SBOM-cve match |
|
|
97
|
+
| framework | `any compliance_theater_check.verdict == 'theater' AND blast_radius_score >= 4` | sbom | theater + breadth → inventory |
|
|
98
|
+
| hardening | `always` | kernel | hardening is corroborator for kernel finding |
|
|
99
|
+
| hardening | `finding.severity >= 'high'` | runtime | weak hardening → check actual exposure |
|
|
100
|
+
| kernel | `finding.severity == 'critical' OR analyze.blast_radius_score >= 4` | sbom | critical kernel → SBOM cross-ref |
|
|
101
|
+
| kernel | `analyze.compliance_theater_check.verdict == 'theater'` | framework | patch-SLA theater |
|
|
102
|
+
| mcp | `finding.severity == 'critical' OR analyze.blast_radius_score >= 4` | sbom | broad MCP impact → inventory |
|
|
103
|
+
| mcp | `analyze.compliance_theater_check.verdict == 'theater'` | framework | MCP-trust theater |
|
|
104
|
+
| mcp | `finding.includes_credential_exposure == true` | ai-api | MCP cred → AI-API cred audit |
|
|
105
|
+
| runtime | `always` | kernel | listener finding always informs kernel triage |
|
|
106
|
+
| runtime | `always` | hardening | runtime exposure pairs with hardening posture |
|
|
107
|
+
| runtime | `finding.severity == 'critical' OR analyze.blast_radius_score >= 3` | cred-stores | critical runtime → check cred stores |
|
|
108
|
+
| sbom | `analyze.compliance_theater_check.verdict == 'theater'` | framework | SBOM-signing theater |
|
|
109
|
+
| sbom | `any matched_cve.attack_class == 'kernel-lpe'` | kernel | kernel CVE in inventory → kernel playbook |
|
|
110
|
+
| sbom | `any matched_cve.attack_class == 'mcp-supply-chain'` | mcp | MCP CVE in inventory → MCP playbook |
|
|
111
|
+
| sbom | `any matched_cve.attack_class IN ['ai-c2', 'prompt-injection']` | ai-api | AI CVE → AI-API playbook |
|
|
112
|
+
| secrets | `finding.severity >= 'high'` | cred-stores | leaked secret in repo → check store posture |
|
|
113
|
+
|
|
114
|
+
Cross-cutting playbook `framework` is the natural correlation layer — many playbooks chain into it on a theater verdict. `sbom` is the breadth-of-impact follow-up most playbooks suggest when blast radius crosses 4. `kernel` + `hardening` + `runtime` form a tightly-coupled triangle (any one finding raises questions in the other two). When a playbook lists `always` as a feeds_into condition, the chain runs unconditionally — the AI should always at least offer the next playbook to the operator.
|
|
115
|
+
|
|
116
|
+
### CLI reference
|
|
117
|
+
|
|
118
|
+
| Verb | What it does |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `exceptd plan` | Default: grouped-by-scope summary of all 13 playbooks. `--scope <type>` filters. `--directives` expands directive IDs/titles per playbook. `--flat` for non-grouped. |
|
|
121
|
+
| `exceptd govern <pb>` | Phase 1 — jurisdiction obligations, theater fingerprints, framework gaps, skills to preload. |
|
|
122
|
+
| `exceptd direct <pb>` | Phase 2 — threat context, RWEP thresholds, skill chain, token budget. |
|
|
123
|
+
| `exceptd look <pb>` | Phase 3 — typed artifact-collection spec + `preconditions` array + submission-shape hint. |
|
|
124
|
+
| `exceptd run <pb>` | Phases 4-7 from agent evidence. Auto-detect cwd when no playbook positional. `--scope <type>` or `--all` for multi-playbook. `--vex <file>` to drop CycloneDX/OpenVEX `not_affected` CVEs. `--ci` for exit-code gating. `--diff-from-latest` for drift mode. `--force-stale` to override currency hard-block. |
|
|
125
|
+
| `exceptd ingest` | Alias for `run`; submission JSON may carry `playbook_id` + `directive_id`. |
|
|
126
|
+
| `exceptd reattest [<sid> \| --latest]` | Replay prior session, diff evidence_hash. `--latest [--playbook <id>] [--since <ISO>]` finds the most recent attestation automatically. |
|
|
127
|
+
| `exceptd list-attestations` | Inventory `.exceptd/attestations/<sid>/` — every prior session, newest first. `--playbook <id>` filters. |
|
|
128
|
+
|
|
129
|
+
All verbs support `--help` for per-verb usage. JSON output by default; `--pretty` for indented.
|
|
130
|
+
|
|
80
131
|
---
|
|
81
132
|
|
|
82
133
|
## Recurring Drift Rules
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,77 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.3 — 2026-05-12
|
|
4
|
+
|
|
5
|
+
**Patch: 14 operator-reported items — 5 bugs + 9 features.**
|
|
6
|
+
|
|
7
|
+
### Bugs
|
|
8
|
+
|
|
9
|
+
1. **`exceptd validate-cves` crashed with `MODULE_NOT_FOUND`** in the installed npm package because `sources/` wasn't in the `files` allowlist. Two-part fix: (a) `sources/validators/` added to `package.json` `files`; (b) `runValidateCves` now wraps the require in the same try/catch graceful-fallback pattern `runValidateRfcs` was already using, so the command degrades to offline mode instead of crashing.
|
|
10
|
+
2. **Inconsistent error shapes across verbs.** `exceptd <unknown>` and `exceptd skill <missing>` emitted plain stderr text while seven-phase verbs emitted structured JSON. Unified: every CLI verb now emits `{ok:false,error,hint,verb}` JSON on error so operators piping through `jq` get one shape.
|
|
11
|
+
3. **`prefetch --no-network --quiet` was completely silent on success.** Now emits a one-line `prefetch summary: …` unconditionally; `--quiet` suppresses only the per-entry chatter.
|
|
12
|
+
4. **`plan --directives` exposed `id + title + applies_to` only — no `description`.** Now also surfaces a `description` field (falls back through explicit `directive.description` → `phase_overrides.direct.threat_context` → playbook-level `direct.threat_context` first sentence → `domain.name`) plus a `threat_context_preview`. Operators / AIs get operator-facing prose, not just an ID + enum.
|
|
13
|
+
5. **Analyst verbs (`scan`/`dispatch`/`currency`/`watchlist`/`report`) defaulted to human-readable text** while every seven-phase verb defaulted to JSON. Added `--json` flag passthrough across all analyst verbs. Operators scripting around both surfaces now have a consistent switch.
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
6. **`run --explain` dry-run** — emits preconditions, required + optional artifacts (with fallback notes), recognized signal keys with types + deterministic flags, and a `submission_skeleton` JSON the operator can fill in. No detect/analyze/validate/close happens. Lets operators preview before assembling evidence.
|
|
18
|
+
7. **`attest <subverb> <session-id>`** — `attest export` emits redacted JSON for audit submission (strips raw artifact values, preserves evidence_hash + signature + classification + RWEP + remediation choice + residual risk acceptance). `--format csaf` wraps the export in a CSAF envelope. `attest verify` checks the `.sig` sidecar against `keys/public.pem` and reports tamper status. `attest show` emits the full unredacted attestation.
|
|
19
|
+
8. **`run --signal-list`** — lighter than `--explain`; enumerates only the signal_overrides keys the detect phase recognizes plus the four valid `detection_classification` values. Closes the "agent submits a key and runner silently ignores it" gap (v0.10.1 bug #5).
|
|
20
|
+
9. **Continuous-compliance: `run --evidence-dir <dir>`** — each `<playbook-id>.json` under the directory becomes that playbook's submission in a multi-playbook run. One cron job → full posture in one CSAF bundle. Pairs with `run --all`.
|
|
21
|
+
10. **`validate-cves` + `validate-rfcs` gained `--since <ISO|YYYY-MM-DD>`** — scope-limit validation to entries whose `last_updated` / `cisa_kev_date` / `last_verified` / `published` is on or after the date. Cuts upstream calls for fleet operators running cron.
|
|
22
|
+
11. **Ed25519-signed attestations** — every `attestation.json` now gets a `<file>.sig` sidecar. With `.keys/private.pem` present, the runner signs (matches the existing skill-signing convention). Without a private key, writes an `unsigned` marker file so downstream tooling can distinguish "operator declined signing" from "the .sig file was deleted by an attacker." `attest verify` cross-checks the signature against `keys/public.pem`.
|
|
23
|
+
12. **`run --operator <name>`** — binds the attestation to a specific human or service identity. Persisted under `attestation.operator` for multi-operator audit-trail accountability.
|
|
24
|
+
13. **`run --ack`** — explicit operator consent to the jurisdiction obligations surfaced by `govern`. Persisted under `attestation.operator_consent = { acked_at, explicit: true }`. Without `--ack`, the field is null (consent implicit / unverified).
|
|
25
|
+
14. **`run --format <fmt>` repeatable** — emit the close.evidence_package in additional formats alongside the playbook-declared primary. Supported: `csaf-2.0` (primary), `sarif` (2.1.0 — GitHub Code Scanning / VS Code SARIF Viewer / Azure DevOps), `openvex` (0.2.0 — sigstore / in-toto / GUAC consumers), `markdown` (human review). Extras populate `close.evidence_package.bundles_by_format`.
|
|
26
|
+
|
|
27
|
+
### Internal
|
|
28
|
+
|
|
29
|
+
- `lib/playbook-runner.js` `buildEvidenceBundle` now handles `csaf-2.0`, `sarif` (with per-CVE rules + properties), `openvex` (with status derived from active_exploitation + live_patch_available), and `markdown`.
|
|
30
|
+
- `bin/exceptd.js` `maybeSignAttestation` helper uses the same Ed25519 primitive as `lib/sign.js` against `.keys/private.pem`.
|
|
31
|
+
- CSAF envelope cvss_v3.base_score now reflects the catalog's real cvss_score (previously hardcoded 0).
|
|
32
|
+
- `submission.signals._bundle_formats` is the agent-side hook for requesting extra formats.
|
|
33
|
+
|
|
34
|
+
## 0.10.2 — 2026-05-12
|
|
35
|
+
|
|
36
|
+
**Patch: v0.10.1 deferred set — framework-gap filter fix, VEX consumption, CI gating, drift mode, 2 new playbooks (13 total), feeds_into matrix.**
|
|
37
|
+
|
|
38
|
+
### Bug fix (carried from v0.9.x)
|
|
39
|
+
|
|
40
|
+
**`exceptd framework-gap NIST-800-53 <cve-id>` returned 0 matches** while `framework-gap all <cve-id>` correctly found the same gap. Root cause: catalog stores `g.framework = "NIST SP 800-53 Rev 5"` (spaces) but operators pass `NIST-800-53` (hyphens), and `.includes()` is case + format sensitive. Fix: normalize both sides via `.toLowerCase().replace(/[\s_-]/g, '')` then substring-match against `g.framework` value AND prefix-match against the gap KEY (e.g. `NIST-800-53-SI-2`).
|
|
41
|
+
|
|
42
|
+
### New CLI flags
|
|
43
|
+
|
|
44
|
+
- **`run --vex <file>`** — load a CycloneDX or OpenVEX document. CVEs marked `not_affected | resolved | false_positive` (CycloneDX) or `not_affected | fixed` (OpenVEX) drop out of `analyze.matched_cves`. Dropped CVEs surface under `analyze.vex.dropped_cves` so the disposition is preserved for the audit trail.
|
|
45
|
+
- **`run --ci`** — machine-readable verdict for CI gates. Exits 2 when `phases.detect.classification === 'detected'` OR (`classification === 'inconclusive'` AND `rwep.adjusted >= rwep_threshold.escalate`). Logs PASS/FAIL reason to stderr. Pure not_detected runs exit 0 even when the playbook's catalogued CVEs carry high baseline RWEP — the gate is about the host-specific verdict, not the catalog.
|
|
46
|
+
- **`run --diff-from-latest`** — compare evidence_hash against the most recent prior attestation for the same playbook in `.exceptd/attestations/`. Drift mode for cron baselines. Result includes `prior_session_id`, `prior_captured_at`, `prior_evidence_hash`, `new_evidence_hash`, `status: unchanged | drifted | no_prior_attestation_for_playbook`.
|
|
47
|
+
- **`reattest --latest [--playbook <id>] [--since <ISO>]`** — find the most-recent attestation automatically. No session-id required.
|
|
48
|
+
|
|
49
|
+
### New playbooks (12 → 13)
|
|
50
|
+
|
|
51
|
+
- **`crypto-codebase`** (scope: code, attack_class: pqc-exposure) — complements the host-side `crypto` playbook. Walks the codebase for in-source crypto choices: weak hash imports (MD5/SHA1), `Math.random()` in security context, PBKDF2 iteration counts, ECDSA curve choices, RSA bit-size constants, PQC adoption signals. Theater fingerprints include `pqc-ready-feature-flag-without-ml-kem` (config toggle with zero ML-KEM call sites), `fips-validated-by-linking-openssl` (link-time vs runtime FIPS provider), `pbkdf2-iterations-set-in-2015` (10k defaults in published packages).
|
|
52
|
+
- **`library-author`** (scope: code, attack_class: supply-chain) — audits what you SHIP, not what you run. Vendored deps, SBOM signing posture, SLSA provenance attestation, VEX issuance, npm provenance, Rekor entries, cosign signing, branch protection, OIDC vs static publish tokens, EU CRA Art.13/14 conformity. Distinct from `sbom` (install-side); this is publish-side. Mutex with `secrets` since both compete for repo-walk cycles.
|
|
53
|
+
|
|
54
|
+
### feeds_into threshold matrix (v0.10.2 doc pass)
|
|
55
|
+
|
|
56
|
+
AGENTS.md now ships the full feeds_into matrix — 25 chains across 12 playbooks. Documents what triggers what, so operators understand the suggested-next-playbook routing rather than treating it as opaque magic. Highlights:
|
|
57
|
+
|
|
58
|
+
- `framework` is the natural correlation layer — many playbooks chain into it on `analyze.compliance_theater_check.verdict == 'theater'`.
|
|
59
|
+
- `sbom` is the breadth-of-impact follow-up most playbooks suggest when `analyze.blast_radius_score >= 4`.
|
|
60
|
+
- `kernel + hardening + runtime` form a tightly-coupled triangle (any one raises questions in the other two).
|
|
61
|
+
- `always` conditions on `hardening → kernel`, `runtime → kernel`, `runtime → hardening`, `containers → secrets` — the AI should always at least offer the next playbook to the operator.
|
|
62
|
+
|
|
63
|
+
### Internal
|
|
64
|
+
|
|
65
|
+
- **kernel.json feeds_into typo fix** — `compliance-theater` referent (no such playbook ID) corrected to `framework` (the playbook carrying the compliance-theater attack class). Test updated to assert the corrected chain.
|
|
66
|
+
- **`vexFilterFromDoc` helper** in `lib/playbook-runner.js` — parses CycloneDX VEX or OpenVEX documents into a `Set<string>` of CVE IDs whose disposition is "not_affected" or equivalent.
|
|
67
|
+
- **AGENTS.md** — new "feeds_into threshold matrix" section + "CLI reference" table.
|
|
68
|
+
|
|
69
|
+
### Still deferred (next pass)
|
|
70
|
+
|
|
71
|
+
- crypto-codebase playbook ships `eu-ai-act` and `cmmc` in `frameworks_in_scope` but doesn't thread either into `framework_gap_mapping` — Hard Rule #4 (no orphaned references) tidy. Either drop the entries or add concrete mapping in a follow-up.
|
|
72
|
+
- Crypto-codebase byte size (95 KB) is above the 50-60 KB target for new playbooks — load-bearing content but worth a depth audit.
|
|
73
|
+
- `_meta.feeds_into[].condition` parser supports a limited DSL — some playbooks use expressions like `any matched_cve.attack_class IN ['ai-c2', 'prompt-injection']` that the current parser doesn't fully support. Conditions degrade silently to false. Worth a parser pass to either expand the DSL or warn on unknown shapes.
|
|
74
|
+
|
|
3
75
|
## 0.10.1 — 2026-05-12
|
|
4
76
|
|
|
5
77
|
**Patch: operator-reported bugs from v0.10.0 first contact + scope-aware `run` default.**
|