"""The process this brick serves is the process the customer signed (module.yaml, signed 2026-10-18: item v3 2319d429
— a manager may also record acceptance, and whoever submitted the work records its acceptance only with pj:item:accept_own; project v1 afc6da20). A change to process.yaml that changes the process breaks this test — the
change goes through `erp-compose change propose` and a new signature first, then the code.
erp-platform 0.9.1 hashes a new canonical form and still verifies a signature recorded before it (`matches` says
which form matched). Before 0.9.1 the generated BPMN's documentation named its source file inside the hash, so the
view is drawn under the spec's name, module.yaml, to compare."""
import pathlib
import pytest
import yaml
from erp_platform import bpmn, signoff
PROCESS = pathlib.Path(__file__).resolve().parents[1] / "src" / "brick_projects" / "application" / "process.yaml"
SIGNED = {"item": "2319d429529a1847fd054f7b85b410f8248aec82d80e811a27d30e58ed769b96",
"project": "afc6da208a353e5ef29572b0227bd67032286700cdfd4f0307fadb58060150f6"}
def drawn(entity: str, source: str) -> str:
spec = bpmn.from_module(yaml.safe_load(PROCESS.read_text()), source)
spec.workflows = [w for w in spec.workflows if w.entity == entity]
return bpmn.to_bpmn(spec)
SIGNED_FORM = {"item": "v2", "project": "legacy"} # item v3 is canonical v2, recorded by erp-platform 0.9.1, project v1 before it
@pytest.mark.parametrize("entity", sorted(SIGNED))
def test_the_served_process_is_the_signed_one(entity):
if hasattr(signoff, "matches"): # erp-platform >= 0.9.1
assert signoff.matches(SIGNED[entity], drawn(entity, "process.yaml"), "module.yaml") is not None
elif SIGNED_FORM[entity] == "legacy":
assert signoff.content_hash(drawn(entity, "module.yaml")) == SIGNED[entity]
else:
pytest.skip(f"{entity} was signed in erp-platform 0.9.1's canonical form, which this platform cannot "
"compute: verified on >= 0.9.1")
def test_a_changed_process_does_not_match():
"""The guard is real: one renamed step and the signature no longer matches, in either form."""
data = yaml.safe_load(PROCESS.read_text())
data["workflows"][0]["transitions"][0]["name"] = "Plan whatever we like"
spec = bpmn.from_module(data, "module.yaml")
spec.workflows = [w for w in spec.workflows if w.entity == "item"]
xml = bpmn.to_bpmn(spec)
if hasattr(signoff, "matches"):
assert signoff.matches(SIGNED["item"], xml, "module.yaml") is None
else:
assert signoff.content_hash(xml) != SIGNED["item"]