Implement TEN-WP-0011 security layer conformance
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 37s
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 37s
Engine/PIP declaration is now checkable (layer.yaml plus a Tooling-client scan). Writes persist a decision record or the published fail-closed stance, live-lookup freshness is published, events_for is tenant-scoped, and mutation evidence drains to audit-core from a local outbox without blocking the mutation. Sender registration is requested as AUDIT-IN-0002. Boundary-contract amendment is requested as NET-IN-0002. Assistant: grok Assistant-Session: 01a04cea-e5e8-7081-a0fc-808ebbc35fa9
This commit is contained in:
parent
80961af91e
commit
672cf4da6e
40 changed files with 2285 additions and 361 deletions
|
|
@ -140,7 +140,7 @@ def test_the_audit_trail_is_append_only(store, tenant):
|
|||
|
||||
def test_a_guardrail_change_emits_a_domain_event(store, tenant):
|
||||
set_override(store, tenant, eur(9_000))
|
||||
events = [e for e in store.events() if e.event_type == "guardrail_changed"]
|
||||
events = [e for e in store.events_for(tenant.tenant_id) if e.event_type == "guardrail_changed"]
|
||||
assert len(events) == 1
|
||||
assert events[0].payload["limit_key"] == KEY
|
||||
assert events[0].payload["correlation_id"] == "corr-1"
|
||||
|
|
@ -161,9 +161,11 @@ def test_unlimited_survives_a_round_trip_as_an_explicit_value(store, tenant):
|
|||
entity = LimitValue(kind=LimitKind.ENTITY_COUNT, amount=UNLIMITED)
|
||||
# spend.monthly is the only registered key, so use it to prove the
|
||||
# sentinel serialises; the kind check lives in the domain tests
|
||||
set_override(store, tenant, LimitValue(
|
||||
kind=LimitKind.SPEND, amount=UNLIMITED, currency="EUR", period="P1M"
|
||||
))
|
||||
set_override(
|
||||
store,
|
||||
tenant,
|
||||
LimitValue(kind=LimitKind.SPEND, amount=UNLIMITED, currency="EUR", period="P1M"),
|
||||
)
|
||||
stored = store.guardrail_overrides(tenant.tenant_id)[KEY]
|
||||
assert stored.is_unlimited
|
||||
assert entity.is_unlimited
|
||||
|
|
@ -175,8 +177,9 @@ def test_unlimited_survives_a_round_trip_as_an_explicit_value(store, tenant):
|
|||
def test_a_stale_version_conflicts(store, tenant):
|
||||
set_override(store, tenant, eur(9_000))
|
||||
with pytest.raises(VersionConflictError):
|
||||
set_override(store, tenant, eur(1_000), version=1, change_id="c-2",
|
||||
idempotency_key="idem-2")
|
||||
set_override(
|
||||
store, tenant, eur(1_000), version=1, change_id="c-2", idempotency_key="idem-2"
|
||||
)
|
||||
|
||||
|
||||
def test_replay_returns_the_original_result_without_reapplying(store, tenant):
|
||||
|
|
@ -204,8 +207,7 @@ def test_an_unregistered_key_is_rejected_before_anything_is_written(store, tenan
|
|||
def test_a_failed_write_leaves_no_audit_record_and_no_version_bump(store, tenant):
|
||||
set_override(store, tenant, eur(9_000))
|
||||
with pytest.raises(VersionConflictError):
|
||||
set_override(store, tenant, eur(1), version=99, change_id="c-2",
|
||||
idempotency_key="idem-2")
|
||||
set_override(store, tenant, eur(1), version=99, change_id="c-2", idempotency_key="idem-2")
|
||||
assert store.get_tenant(tenant.tenant_id).version == 2
|
||||
assert len(store.guardrail_changes(tenant.tenant_id)) == 1
|
||||
assert store.guardrail_overrides(tenant.tenant_id)[KEY].amount == 9_000
|
||||
|
|
@ -265,6 +267,5 @@ def test_clearing_an_override_that_would_loosen_is_refused_while_retired(store,
|
|||
)
|
||||
# clearing would fall back to small's 25_000 default -- a loosening
|
||||
with pytest.raises(TenantRetiredError):
|
||||
set_override(store, tenant, None, version=3, change_id="c-3",
|
||||
idempotency_key="idem-3")
|
||||
set_override(store, tenant, None, version=3, change_id="c-3", idempotency_key="idem-3")
|
||||
assert store.guardrail_overrides(tenant.tenant_id)[KEY].amount == 100
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue