approval-engine/tests/test_examples.py

42 lines
1.4 KiB
Python
Raw Normal View History

State pdp_digest explicitly; decline to publish a vocabulary mapping flex-auth asked whether this engine should publish an action/target mapping between the claim binding's vocabulary (secrets.kv.destroy, {"id": "lane-openbao-root"}) and a policy package's (destroy, lane:...), since their package makes no cross-check that a claim was approved for the action being decided. Answered no. A PIP asserting that one vocabulary's action means another's would author policy semantics it does not own, over vocabularies it does not own, and the failure mode is asymmetric: a wrong mapping silently accepts a claim approved for a different action, which is worse than no mapping. binding.pdp_digest is the correspondence and sidesteps vocabulary entirely -- it compares the PDP's own digest to the PDP's own digest, with no translation by anyone. Implemented the part that was ours. pdp_digest was emitted only when recorded, so a consumer could not distinguish "not issued against a decision" from "we forgot to look". It is now always present and null in that case, required-but-nullable in the schema, and documented as something a PEP on a privileged lane must refuse. This engine states the fact; enforcing the lane's policy stays with the consumer. Both published examples were already contradicting the updated schema by omitting the field -- the same fixture-versus-contract defect flex-auth hit twice this week and that secrets-engine implemented. Fixed both, made them cover the PDP-bound and unbound shapes so neither is inferred from the other, and added tests/test_examples.py to validate every example against the schema so the class cannot recur here. jsonschema added as a dev dependency. 94 tests pass (6 new). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvyJPAaVCGsVheVhcCwNND Assistant: claude-code Assistant-Model: opus Assistant-Process: 411227@bnt-lap001 Assistant-Session: d566f6d3-bcaf-43c3-bc5e-3ddd0f64b535
2026-09-06 09:32:11 +02:00
"""The published examples must satisfy the published schema.
flex-auth shipped two defects in one day from fixtures that contradicted their
own contracts, and secrets-engine built a validator against one of them. A
contract whose examples contradict its prose will be implemented as its
examples, so the examples are tested rather than trusted.
"""
import json
from pathlib import Path
import pytest
jsonschema = pytest.importorskip("jsonschema")
ROOT = Path(__file__).resolve().parent.parent
SCHEMA = json.loads((ROOT / "schemas" / "approval_claim.schema.json").read_text())
EXAMPLES = sorted((ROOT / "examples").glob("claim.*.json"))
def test_examples_exist():
assert EXAMPLES, "no claim examples found to validate"
@pytest.mark.parametrize("path", EXAMPLES, ids=lambda p: p.name)
def test_example_matches_schema(path):
jsonschema.validate(json.loads(path.read_text()), SCHEMA)
@pytest.mark.parametrize("path", EXAMPLES, ids=lambda p: p.name)
def test_example_states_pdp_digest_explicitly(path):
"""Absence must be a stated null, never a missing key."""
assert "pdp_digest" in json.loads(path.read_text())["binding"]
def test_examples_cover_both_pdp_binding_states():
"""An implementer must see both shapes, not infer one from the other."""
states = {
json.loads(p.read_text())["binding"]["pdp_digest"] is None for p in EXAMPLES
}
assert states == {True, False}