"""The digest join against a REAL request, not one rebuilt from the binding. tests/test_decision_replay.py passes every digest assertion because ``_request_from()`` reconstructs the request out of ``envelope["binding"]`` -- which is the *enriched* form the evaluator hashed. That is a self-consistent fake agreeing with itself, and it hid the gap below through three rounds of digest work. This module builds the request the way the engine actually builds it and compares it to a decision the engine actually received, so the gap is pinned until flex-auth publishes the enrichment rule. """ from __future__ import annotations import json from pathlib import Path import pytest from secrets_engine.authorization import ( build_action_request, canonical_check_request, request_digest, validate_decision_envelope, ) from secrets_engine.catalog import load_catalog from secrets_engine.errors import DecisionError LIVE = Path(__file__).parent / "fixtures" / "flex-auth-live" / "decision_rotate_glas_live.json" CATALOG = Path(__file__).resolve().parents[1] / "catalog" PACKAGE = "secrets-engine.catalog-lane.lifecycle" VERSION = "v2" def _live(): return json.loads(LIVE.read_text()) def _our_request(): entry = load_catalog(CATALOG)["glas-claude-agent-dev-anthropic"] return build_action_request( entry, "rotate", subject_id="secrets-engine", subject_type="service", purpose="live-adoption-proof", fields=["api_key"], request_id="check:secrets-engine-adoption-proof", ) def test_the_live_decision_is_a_real_v2_allow(): """Provenance of the artifact these assertions rest on.""" env = _live() assert env["effect"] == "allow" assert env["reason"] == "catalog_lane_policy_matched" provenance = env["provenance"] assert provenance["policy_package"] == PACKAGE assert provenance["policy_version"] == VERSION assert env["binding"]["tenant"] == "tenant:platform" def test_the_evaluator_enriches_subject_and_resource_before_hashing(): """Names exactly which fields appeared that we never sent. If flex-auth publishes an enrichment rule that differs from this, this test fails and tells us the shape moved -- which is the point. It asserts the observed gap, not a rule we invented. """ sent = _our_request() bound = _live()["binding"] assert "attributes" not in sent["subject"] assert set(bound["subject"]["attributes"]) == { "description", "display_name", "groups", "organization_relation", "roles", } assert "tenant" not in sent["subject"] assert bound["subject"]["tenant"] == sent["tenant"] assert "tenant" not in sent["resource"] assert bound["resource"]["tenant"] == sent["tenant"] # Everything we DID send survived unchanged. The enrichment is additive, so # the decision is about the action we proposed -- which is why staying # fail-closed here costs correctness nothing today. assert bound["action"] == sent["action"] assert bound["tenant"] == sent["tenant"] assert bound["context"] == sent["context"] assert bound["subject"]["id"] == sent["subject"]["id"] assert bound["subject"]["type"] == sent["subject"]["type"] for key in ("id", "type", "system", "attributes"): assert bound["resource"][key] == sent["resource"][key] def test_our_digest_cannot_match_a_real_binding(): """The join is unsatisfiable against a real request, not merely mismatched. We hash what we sent; the evaluator hashed what it enriched. No amount of care on our side closes that, because the registry material is not ours. """ sent = _our_request() bound = _live()["binding"] assert bound["request_digest"] != request_digest(sent) assert canonical_check_request(bound) != canonical_check_request(sent) def test_we_currently_reject_every_real_allow_and_that_is_fail_closed(): """Pins today's behaviour honestly rather than asserting it is correct. Rejecting a valid allow is wrong, but it is wrong in the safe direction, so it stays until flex-auth publishes which fields may be enriched. Guessing the rule would mean accepting a binding that differs from our proposal in some way we decided was benign -- the fail-open shape GH-DEC-2026-008 rejected for vocabularies and FLEX-DEC-2026-007 rejected for digests. """ with pytest.raises(DecisionError, match="binding does not match request"): validate_decision_envelope( _live(), _our_request(), accepted_policy_packages={PACKAGE}, accepted_policy_versions={VERSION}, )