Implement P05 checked services and safe selected delivery recovery
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 19s
Account journey acceptance / journeys (push) Successful in 5s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a092fe-13b1-7f12-ac74-7d258af4d79c
This commit is contained in:
tegwick 2026-09-13 22:11:49 +02:00
parent 99618488e0
commit ac0eb14b75
15 changed files with 735 additions and 88 deletions

View file

@ -0,0 +1,172 @@
import time
from unittest.mock import patch
from dataclasses import replace
from user_engine.domain import OutboxEvent, utc_now
from user_engine.adapters.delivery import HTTPOutboxDeliveryAdapter, DeliveryError
from user_engine.operations_status import check_services
from test_journey_roles import JourneyFixture, TENANT
from test_web import invoke
class ServiceOperations(JourneyFixture):
def seed(self):
event = OutboxEvent(
event_id="p05-one",
event_type="family_member.invited",
aggregate_id="person",
tenant=TENANT,
correlation_id="p05-case",
payload={
"primary_email": "fixture@example.test",
"invitation_id": "fixture",
},
)
self.app.service.store.append_outbox(event)
self.calls = []
self.app.outbox_delivery = lambda event: self.calls.append(event.event_id)
return event
def test_one_confirmed_delivery_and_completed_retry_guard(self):
event = self.seed()
self.app.service.store.append_outbox(replace(event, event_id="p05-other"))
response, body = self.post(
"/platform/operations/deliver", who="operator", event_id=event.event_id
)
self.assertIn(b"Confirm change", body)
self.assertEqual([], self.calls)
response, _ = self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
confirmed=True,
)
self.assertEqual("303 See Other", response["status"])
self.assertEqual(["p05-one"], self.calls)
response, _ = self.post(
"/platform/operations/deliver", who="operator", event_id=event.event_id
)
self.assertEqual("409 Conflict", response["status"])
self.assertIsNone(self.app.service.store.outbox_event("p05-other").delivered_at)
def test_role_csrf_and_stale_confirmation_cannot_submit(self):
event = self.seed()
for who in ["member", "admin"]:
response, _ = self.post(
"/platform/operations/deliver", who=who, event_id=event.event_id
)
self.assertEqual("403 Forbidden", response["status"])
response, _ = self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
csrf_token="wrong",
)
self.assertEqual("403 Forbidden", response["status"])
_, body = self.post(
"/platform/operations/deliver", who="operator", event_id=event.event_id
)
token = self.confirm_token(body)
self.app.service.store.save_outbox(replace(event, delivery_attempts=1))
response, _ = self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
confirm_token=token,
)
self.assertEqual("409 Conflict", response["status"])
self.assertEqual([], self.calls)
def test_failure_releases_claim_and_retry_is_available(self):
event = self.seed()
def fail(event):
raise RuntimeError("private-token-in-error")
self.app.outbox_delivery = fail
self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
confirmed=True,
)
failed = self.app.service.store.outbox_event(event.event_id)
self.assertIsNone(failed.claimed_by)
self.assertEqual("delivery_unavailable", failed.failure_reason)
_, body = invoke(self.app, "/platform/operations", cookie="ue_session=operator")
self.assertIn(b"Review delivery attempt", body)
self.assertNotIn(b"private-token", body)
self.app.outbox_delivery = lambda e: self.calls.append(e.event_id)
self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
confirmed=True,
)
self.assertIsNotNone(
self.app.service.store.outbox_event(event.event_id).delivered_at
)
def test_crashed_claim_reconciles_under_event_guard(self):
event = self.seed()
self.app.service.store.save_outbox(
replace(event, claimed_by="crashed", claimed_at=utc_now())
)
self.post(
"/platform/operations/deliver",
who="operator",
event_id=event.event_id,
confirmed=True,
)
self.assertEqual(["p05-one"], self.calls)
def test_missing_mail_lane_never_marks_an_invitation_accepted(self):
event = self.seed()
adapter = HTTPOutboxDeliveryAdapter(
event_url="http://unused", event_bearer_token="fixture"
)
with self.assertRaises(DeliveryError) as error:
adapter(event)
self.assertEqual("mail_unconfigured", error.exception.code)
def test_status_is_checked_bounded_and_never_claims_receipt(self):
class Mail:
def mail_status(self):
return {"checks": {"database": "ok", "smtp_authentication": "failed"}}
class OIDC:
backend_url = "http://fixture"
with patch(
"user_engine.operations_status.sign_in_status",
return_value={
"checks": [
{"name": "factor_reader", "status": "failed"},
{"name": "lldap", "status": "ok"},
]
},
):
html = check_services(OIDC(), Mail())
self.assertIn("Factor-read credential", html)
self.assertIn("Unavailable", html)
self.assertIn("send no email", html)
self.assertIn("do not prove inbox receipt", html)
def test_selected_mail_evidence_is_safe_and_read_only(self):
event = self.seed()
class Mail:
def mail_delivery_status(self, event_id):
return {"state": "unknown", "private": "secret-provider-detail"}
self.app.outbox_delivery = Mail()
_, body = invoke(
self.app,
"/platform/operations",
cookie="ue_session=operator",
query="event_id=" + event.event_id,
)
self.assertIn(b"Automatic resending is blocked", body)
self.assertNotIn(b"secret-provider-detail", body)
self.assertEqual(
0, self.app.service.store.outbox_event(event.event_id).delivery_attempts
)