Record native receiver custody and prepare actual Approval lifecycle readback
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a13eab-1e6a-7b33-9c37-372e90ada3a2
This commit is contained in:
codex 2026-10-15 21:40:48 +02:00
parent ce5344da69
commit 6e24b09eaa
8 changed files with 372 additions and 40 deletions

View file

@ -36,12 +36,15 @@ def stamp(value):
def paths(source, tenant, instance, since, until, event_ids):
require(SCOPES.get(source) == tenant, "exact_source_tenant_required")
require(
isinstance(instance, str)
and 1 <= len(instance) <= 256
and instance.strip() == instance,
"exact_instance_required",
)
if source == "qonto-assistant":
require(
isinstance(instance, str)
and 1 <= len(instance) <= 256
and instance.strip() == instance,
"exact_instance_required",
)
else:
require(instance is None, "approval_has_no_declared_instance_filter")
require(
stamp(since) <= stamp(until) <= datetime.now(timezone.utc),
"invalid_acceptance_window",
@ -57,15 +60,10 @@ def paths(source, tenant, instance, since, until, event_ids):
),
"invalid_event_id",
)
query = urlencode(
dict(
source=source,
tenant=tenant,
stream_instance_id=instance,
since=since,
until=until,
)
)
query_values = dict(source=source, tenant=tenant, since=since, until=until)
if instance is not None:
query_values["stream_instance_id"] = instance
query = urlencode(query_values)
return ["/v1/reconciliation?" + query, "/v1/stream-findings"] + [
"/v1/events/" + x for x in event_ids
]
@ -95,11 +93,15 @@ def sanitize_record(record, source, tenant, instance, event_id, since, until):
"record_source_tenant_id_mismatch",
)
detail = record["details"]["data"]
require(detail.get("stream_instance_id") == instance, "record_instance_mismatch")
require(
type(detail.get("stream_sequence")) is int and detail["stream_sequence"] > 0,
"record_sequence_missing",
)
if source == "qonto-assistant":
require(
detail.get("stream_instance_id") == instance, "record_instance_mismatch"
)
require(
type(detail.get("stream_sequence")) is int
and detail["stream_sequence"] > 0,
"record_sequence_missing",
)
accepted = record["accepted_at"]
require(
stamp(since) <= stamp(accepted) < stamp(until),
@ -118,12 +120,25 @@ def sanitize_record(record, source, tenant, instance, event_id, since, until):
)
if action == "audit-core.heartbeat":
require(coverage == ["audit.deny"], "record_heartbeat_scope_mismatch")
if source == "approval-engine":
names = {"issuance", "use", "supersession", "revocation"}
require(
action in {"approval." + name for name in names} | {"audit-core.heartbeat"},
"record_undeclared_class",
)
if action == "audit-core.heartbeat":
require(
len(coverage) == 1 and coverage[0] in names,
"record_heartbeat_scope_mismatch",
)
return {
"event_id": event_id,
"source": source,
"tenant": tenant,
"stream_instance_id": instance,
"stream_sequence": detail["stream_sequence"],
"stream_sequence": detail.get("stream_sequence")
if instance is not None
else None,
"type": action,
"accepted_at": accepted,
"observed_at": record["observed_at"],
@ -136,16 +151,11 @@ def readback(origin, token, source, tenant, instance, since, until, event_ids):
allowed = paths(source, tenant, instance, since, until, event_ids)
reconciliation = read_http(origin, token, allowed[0], allowed)
require(
all(
reconciliation.get(k) == v
for k, v in (
("source", source),
("tenant", tenant),
("stream_instance_id", instance),
("since", since),
("until", until),
)
),
reconciliation.get("source") == source
and reconciliation.get("tenant") == tenant
and reconciliation.get("stream_instance_id") == instance
and stamp(reconciliation["since"]) == stamp(since)
and stamp(reconciliation["until"]) == stamp(until),
"reconciliation_scope_window_mismatch",
)
raw_findings = read_http(origin, token, allowed[1], allowed)
@ -183,7 +193,11 @@ def readback(origin, token, source, tenant, instance, since, until, event_ids):
"reconciliation": reconciliation,
"stream_findings": safe_findings,
"events": records,
"scope": "bounded same-instance accepted custody; source-global findings require active-instance interpretation",
"scope": (
"bounded same-instance accepted custody; source-global findings require active-instance interpretation"
if instance is not None
else "bounded source lifecycle acceptance window; no process-instance completeness claim"
),
}
@ -192,7 +206,6 @@ def main():
p.add_argument("--source", choices=SCOPES, required=True)
for key in (
"tenant",
"instance",
"since",
"until",
"kubeconfig",
@ -200,6 +213,10 @@ def main():
"expected-receiver-image",
):
p.add_argument("--" + key, required=True)
p.add_argument(
"--instance",
help="Required only for Qonto; Approval has no declared instance field",
)
p.add_argument("--event-id", action="append", required=True)
p.add_argument("--receipt", type=Path, required=True)
a = p.parse_args()