Files
breakpilot-compliance/backend-compliance/tests/test_playbook.py
T
Benjamin Admin 78f0ffa9de feat(playbook): Implementation Playbooks — the Berater renderer ("wie komme ich dort hin?")
Roadmap item 4. After WHAT applies / WHAT is missing / WHICH first, the GF asks HOW. The
Implementation Playbook renders, for one capability, the full journey — why / which regulations
it closes / tools / process / evidence / controls — and chains the Optimization Roadmap into
per-measure playbooks. Another renderer over the same Capability spine (ADR-003/004), not a new
engine: ~95% of the data already exists, it just needs a different rendering.

- compliance/playbook/: build_playbook() + playbooks_for_plan() (chains optimization -> playbook,
  acyclic; reuses leverage for "closes which regulations"). Capabilities without curated content
  render as honest status:missing stubs — the content-owed signal.
- knowledge/implementation_playbooks/: curated knowledge layer (Reasoning Knowledge Acquisition),
  two deep expert drafts (SBOM, CVD/PSIRT, status draft, expert-draft-not-normative) + README.
  The bottleneck is now CONTENT, not software; Playbook (own knowledge) != regulatory domain.
- ADR-004: Implementation Playbooks = renderer + knowledge layer; content is the bottleneck.
- reference suite: "Implementation Playbook" section renders the SBOM journey + Roadmap->Playbook
  table (high-leverage caps flagged "fehlt (Inhalt)" — content backlog, highest leverage first).
- refactor: extracted markdown helpers to reference_scenarios/_helpers.py to keep generate.py
  under the 500-LOC budget.

9 playbook tests (40 with optimization+transition+company), mypy --strict clean, check-loc 0.
Product code with no app caller + knowledge/ADR/reference = non-runtime -> no deploy (ADR-001).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-27 10:38:13 +02:00

89 lines
3.9 KiB
Python

"""Tests for the Implementation Playbook renderer (the Berater view, "wie komme ich dort hin?").
Acceptance: for one capability, assemble the journey (why / closes-which-regulations / tools /
process / evidence / controls) from curated knowledge + leverage + injected Execution links; chain
the Optimization Roadmap into per-measure playbooks; surface capabilities without content as honest
`missing` stubs. Curated content is an expert draft, never normative.
"""
from __future__ import annotations
from compliance.optimization import regulatory_leverage
from compliance.playbook import Playbook, build_playbook, playbooks_for_plan
SBOM = {
"title": "SBOM aufbauen",
"why": "CRA verlangt ein Komponenten-Inventar.",
"tools": ["CycloneDX", "Syft"],
"process_steps": [{"title": "Format wählen", "detail": "CycloneDX"}, {"title": "In CI erzeugen", "detail": ""}],
"expected_evidence": ["sbom_per_release"],
"how_others_do_it": "CI + Dependency-Track.",
"status": "draft",
}
def test_build_playbook_full_journey():
pb = build_playbook("sbom_creation", SBOM, closes_regulations=["CRA", "MaschinenVO"], control_links=["component_inventory"])
assert pb.title == "SBOM aufbauen" and pb.status == "draft"
assert pb.closes_regulations == ["CRA", "MaschinenVO"] and pb.leverage == 2
assert pb.tools == ["CycloneDX", "Syft"]
assert [s.order for s in pb.process_steps] == [1, 2]
assert pb.process_steps[0].title == "Format wählen"
assert pb.expected_evidence == ["sbom_per_release"]
assert pb.controls == ["component_inventory"] # injected from Execution
assert pb.disclaimer # always carries the expert-draft caveat
def test_missing_knowledge_is_honest_stub():
pb = build_playbook("product_cyber_risk_assessment", None, closes_regulations=["CRA", "MaschinenVO"])
assert pb.status == "missing" # the content-owed signal
assert pb.leverage == 2 and pb.closes_regulations == ["CRA", "MaschinenVO"] # leverage still known
assert pb.tools == [] and pb.process_steps == []
assert "Knowledge Acquisition" in pb.why
def test_closes_regulations_deduped_and_sorted():
pb = build_playbook("x", SBOM, closes_regulations=["MaschinenVO", "CRA", "CRA"])
assert pb.closes_regulations == ["CRA", "MaschinenVO"] and pb.leverage == 2
def test_controls_default_empty_no_execution_data():
pb = build_playbook("x", SBOM, closes_regulations=["CRA"])
assert pb.controls == [] # no Execution data unless injected
def test_playbooks_for_plan_orders_by_leverage_and_stubs_missing():
caps = {"sbom_creation": ["CRA"], "pcra": ["CRA", "MaschinenVO"], "guards": ["MaschinenVO"]}
plan = regulatory_leverage(caps)
pbs = playbooks_for_plan(plan, {"sbom_creation": SBOM}, top_k=3)
assert [p.capability_id for p in pbs][0] == "pcra" # highest leverage first
by = {p.capability_id: p for p in pbs}
assert by["pcra"].status == "missing" and by["pcra"].leverage == 2
assert by["sbom_creation"].status == "draft" # has content
assert by["guards"].status == "missing"
def test_playbooks_for_plan_top_k_and_injected_controls():
caps = {"a": ["CRA", "MaschinenVO"], "b": ["CRA"], "c": ["CRA"]}
plan = regulatory_leverage(caps)
pbs = playbooks_for_plan(plan, {}, top_k=1, control_links_by_cap={"a": ["ctrl_1"]})
assert len(pbs) == 1 and pbs[0].capability_id == "a"
assert pbs[0].controls == ["ctrl_1"]
def test_playbooks_for_plan_empty():
plan = regulatory_leverage({})
assert playbooks_for_plan(plan, {}) == []
def test_deterministic():
caps = {"a": ["CRA", "MaschinenVO"], "b": ["CRA"]}
plan = regulatory_leverage(caps)
a = [p.capability_id for p in playbooks_for_plan(plan, {})]
b = [p.capability_id for p in playbooks_for_plan(plan, {})]
assert a == b
def test_returns_playbook_type():
assert isinstance(build_playbook("x", None), Playbook)