fix(sre): close bounded runtime contract gaps
All checks were successful
CD Pipeline / workflow-shape (push) Successful in 1s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 4m41s
CD Pipeline / build-and-deploy (push) Successful in 15m36s
CD Pipeline / post-deploy-checks (push) Successful in 4m19s

This commit is contained in:
ogt
2026-07-16 21:21:43 +08:00
parent c7d33572a9
commit 08f3a70ce6
32 changed files with 3041 additions and 157 deletions

View File

@@ -5,6 +5,7 @@ import base64
import hashlib
import os
import struct
from pathlib import Path
from unittest.mock import AsyncMock
os.environ.setdefault("DATABASE_URL", "postgresql+asyncpg://test:test@localhost/test")
@@ -70,6 +71,36 @@ def app_client() -> TestClient:
return TestClient(app)
def test_agent99_client_retries_one_202_with_exact_db_only_receipt() -> None:
source = (
Path(__file__).resolve().parents[3] / "agent99-control-plane.ps1"
).read_text(encoding="utf-8-sig")
send_section = source.split("function Send-AgentTelegram {", 1)[1].split(
"function Record-AgentEvent {",
1,
)[0]
assert send_section.count("Invoke-AgentCanonicalLifecycleIngress ") == 2
assert 'if ([int]$ingress.statusCode -eq 202)' in send_section
assert '"agent99_telegram_lifecycle_reconcile_v1"' in send_section
assert '$payload["reconcile_receipt"] = $reconcileReceipt' in send_section
assert "Start-Sleep -Seconds ([int]$ingress.retryAfterSeconds)" in send_section
assert "[int]$ingress.retryAfterSeconds -le 2" in send_section
assert "canonicalIngressAttemptCount = 2" in send_section
assert "reconcileProviderSendPerformed" in send_section
assert "provider_message_id" in send_section
assert "destination_binding" in send_section
assert "X-Agent99-Lifecycle-Token" not in send_section
selftest_section = source.split(
"function Invoke-AgentTelegramDeliverySelfTest {",
1,
)[1].split("function Invoke-AgentSensorGateSelfTest {", 1)[0]
assert 'id = $testId' in selftest_section
assert selftest_section.count(
'Send-AgentTelegram "warning" "telegram_delivery_test"'
) == 1
def test_lifecycle_payload_rejects_unbounded_content() -> None:
with pytest.raises(ValidationError):
Agent99TelegramLifecycleRequest.model_validate(
@@ -90,6 +121,22 @@ def test_lifecycle_payload_rejects_unbounded_content() -> None:
"visual": {**visual_payload(), "sha256": "0" * 64},
}
)
with pytest.raises(ValidationError, match="reconcile_identity_mismatch"):
Agent99TelegramLifecycleRequest.model_validate(
{
**payload(),
"reconcile_receipt": {
"schema_version": (
"agent99_telegram_lifecycle_reconcile_v1"
),
"delivery_id": payload()["delivery_id"],
"incident_id": "INC-WRONG",
"state_key": payload()["state_key"],
"provider_message_id": "8123",
"destination_binding": "a" * 64,
},
}
)
def test_visual_caption_stays_within_telegram_limit_without_broken_html() -> None:
@@ -208,6 +255,91 @@ def test_lifecycle_endpoint_returns_same_delivery_receipt(monkeypatch) -> None:
assert response.json()["provider_message_id"] == "8123"
def test_lifecycle_endpoint_202_retry_is_db_only_and_returns_200(
monkeypatch,
) -> None:
monkeypatch.setattr(settings, "AGENT99_SRE_ALERT_RELAY_TOKEN", "expected")
destination_binding = "a" * 64
calls = {"deliver": 0, "reconcile": 0}
async def pending_delivery(request):
calls["deliver"] += 1
assert request.reconcile_receipt is None
return {
"schema_version": "agent99_telegram_lifecycle_receipt_v1",
"ok": False,
"delivery_id": request.delivery_id,
"incident_id": request.incident_id,
"delivery_status": "pending_unknown",
"provider_message_id": "8124",
"destination_binding": destination_binding,
"provider_send_performed": True,
"reconcile_receipt": {
"schema_version": "agent99_telegram_lifecycle_reconcile_v1",
"delivery_id": request.delivery_id,
"incident_id": request.incident_id,
"state_key": request.state_key,
"provider_message_id": "8124",
"destination_binding": destination_binding,
},
}
async def durable_reconcile(request):
calls["reconcile"] += 1
assert request.reconcile_receipt is not None
assert request.reconcile_receipt.provider_message_id == "8124"
assert (
request.reconcile_receipt.destination_binding
== destination_binding
)
return {
"schema_version": "agent99_telegram_lifecycle_receipt_v1",
"ok": True,
"delivery_id": request.delivery_id,
"incident_id": request.incident_id,
"delivery_status": "sent_reused",
"provider_message_id": "8124",
"destination_binding": destination_binding,
"durable_outbound_acknowledged": True,
"destination_binding_verified": True,
"provider_send_performed": False,
}
monkeypatch.setattr(
agents_api,
"deliver_agent99_telegram_lifecycle",
pending_delivery,
)
monkeypatch.setattr(
agents_api,
"reconcile_agent99_telegram_lifecycle",
durable_reconcile,
)
client = app_client()
first = client.post(
"/api/v1/agents/agent99/telegram-lifecycle",
headers={"X-Agent99-Lifecycle-Token": "expected"},
json=payload(),
)
assert first.status_code == 202
assert first.headers["retry-after"] == "2"
retry_payload = {
**payload(),
"reconcile_receipt": first.json()["reconcile_receipt"],
}
second = client.post(
"/api/v1/agents/agent99/telegram-lifecycle",
headers={"X-Agent99-Lifecycle-Token": "expected"},
json=retry_payload,
)
assert second.status_code == 200
assert second.json()["delivery_status"] == "sent_reused"
assert second.json()["provider_send_performed"] is False
assert calls == {"deliver": 1, "reconcile": 1}
def test_lifecycle_outbox_identity_is_stable_and_separate() -> None:
base = {
"callback_reply": {
@@ -249,15 +381,42 @@ def test_lifecycle_outbox_identity_is_stable_and_separate() -> None:
) != gateway_service._controlled_apply_result_delivery_run_id(controlled_identity)
def test_lifecycle_outbox_persists_destination_and_visual_bindings() -> None:
destination_binding = "a" * 64
envelope = gateway_service._merge_outbound_source_envelope_extra(
{"adapter": "legacy_telegram_gateway"},
{
"canonical_route_receipt": {
"destination_binding": destination_binding,
},
"visual_delivery": {
"requested": True,
"raw_visual_stored": False,
},
},
)
assert envelope["canonical_route_receipt"] == {
"destination_binding": destination_binding,
}
assert envelope["visual_delivery"] == {
"requested": True,
"raw_visual_stored": False,
}
@pytest.mark.asyncio
async def test_lifecycle_durable_readback_binds_exact_identity_without_egress(
monkeypatch,
) -> None:
gateway = object.__new__(gateway_service.TelegramGateway)
destination_binding = "a" * 64
reconcile = AsyncMock(
return_value={
"status": "sent",
"provider_message_id": "8124",
"destination_binding": destination_binding,
"visual_requested": True,
}
)
@@ -272,12 +431,18 @@ async def test_lifecycle_durable_readback_binds_exact_identity_without_egress(
incident_id=payload()["incident_id"],
state_key=payload()["state_key"],
expected_provider_message_id="8124",
expected_destination_binding=destination_binding,
)
assert result["ok"] is True
assert result["_awooop_delivery_status"] == "sent_reused"
assert result["_awooop_provider_send_performed"] is False
assert result["_awooop_durable_readback_performed"] is True
assert result["_awooop_delivery_context"] == {
"destination_binding": destination_binding,
"destination_binding_verified": True,
"durable_exact_row_readback": True,
}
reconcile.assert_awaited_once_with(
identity={
"project_id": "awoooi",
@@ -287,9 +452,116 @@ async def test_lifecycle_durable_readback_binds_exact_identity_without_egress(
"delivery_kind": "agent99_lifecycle",
},
expected_provider_message_id="8124",
expected_destination_binding=destination_binding,
)
@pytest.mark.asyncio
async def test_lifecycle_reconcile_destination_mismatch_never_finalizes(
monkeypatch,
) -> None:
gateway = object.__new__(gateway_service.TelegramGateway)
readback = AsyncMock(
return_value={
"status": "pending_unknown",
"run_id": "00000000-0000-0000-0000-000000000201",
"message_id": "00000000-0000-0000-0000-000000000202",
"destination_binding": "a" * 64,
}
)
finalize = AsyncMock(return_value=True)
monkeypatch.setattr(
gateway,
"_read_controlled_apply_result_outbound",
readback,
)
monkeypatch.setattr(
gateway,
"_finalize_controlled_apply_result_outbound",
finalize,
)
result = await gateway._reconcile_controlled_apply_result_outbound(
identity={
"project_id": "awoooi",
"automation_run_id": payload()["delivery_id"],
"incident_id": payload()["incident_id"],
"apply_op_id": payload()["state_key"],
"delivery_kind": "agent99_lifecycle",
},
expected_provider_message_id="8124",
expected_destination_binding="b" * 64,
)
assert result["status"] == "destination_binding_mismatch"
finalize.assert_not_awaited()
@pytest.mark.asyncio
async def test_lifecycle_reconcile_service_never_enters_provider_sender(
monkeypatch,
) -> None:
destination_binding = "a" * 64
calls: list[dict] = []
class Gateway:
async def send_agent99_lifecycle_receipt(self, **_kwargs):
raise AssertionError("provider sender must not run during reconcile")
async def reconcile_agent99_lifecycle_receipt(self, **kwargs):
calls.append(kwargs)
return {
"ok": True,
"result": {"message_id": "8124"},
"_awooop_outbound_mirror_acknowledged": True,
"_awooop_delivery_status": "sent_reused",
"_awooop_provider_send_performed": False,
"_awooop_delivery_context": {
"destination_binding": destination_binding,
"destination_binding_verified": True,
"durable_exact_row_readback": True,
},
}
monkeypatch.setattr(
lifecycle_service,
"get_telegram_gateway",
lambda: Gateway(),
)
request = Agent99TelegramLifecycleRequest.model_validate(
{
**payload(),
"reconcile_receipt": {
"schema_version": "agent99_telegram_lifecycle_reconcile_v1",
"delivery_id": payload()["delivery_id"],
"incident_id": payload()["incident_id"],
"state_key": payload()["state_key"],
"provider_message_id": "8124",
"destination_binding": destination_binding,
},
}
)
receipt = await lifecycle_service.reconcile_agent99_telegram_lifecycle(
request
)
assert receipt["ok"] is True
assert receipt["delivery_status"] == "sent_reused"
assert receipt["provider_send_performed"] is False
assert receipt["destination_binding_verified"] is True
assert calls == [
{
"delivery_id": payload()["delivery_id"],
"incident_id": payload()["incident_id"],
"state_key": payload()["state_key"],
"project_id": "awoooi",
"expected_provider_message_id": "8124",
"expected_destination_binding": destination_binding,
}
]
@pytest.mark.asyncio
async def test_lifecycle_service_uses_durable_canonical_sender(monkeypatch) -> None:
calls: list[dict] = []
@@ -343,6 +615,7 @@ async def test_lifecycle_reconciles_pending_send_without_duplicate_provider_mess
"_awooop_visual_delivery_verified": True,
"_awooop_delivery_context": {
"destination_binding_verified": True,
"destination_binding": "a" * 64,
},
}
reconciled_response = {
@@ -395,6 +668,7 @@ async def test_lifecycle_reconciles_pending_send_without_duplicate_provider_mess
"state_key": payload()["state_key"],
"project_id": "awoooi",
"expected_provider_message_id": "9126",
"expected_destination_binding": "a" * 64,
}
@@ -449,6 +723,7 @@ async def test_lifecycle_follower_only_reads_inflight_durable_delivery(
assert len(send_calls) == 1
assert len(reconcile_calls) == 1
assert reconcile_calls[0]["expected_provider_message_id"] is None
assert reconcile_calls[0]["expected_destination_binding"] is None
@pytest.mark.asyncio
@@ -470,6 +745,7 @@ async def test_lifecycle_reconciliation_fails_closed_after_bounded_readbacks(
"_awooop_provider_send_performed": True,
"_awooop_delivery_context": {
"destination_binding_verified": True,
"destination_binding": "a" * 64,
},
}
@@ -511,6 +787,10 @@ async def test_lifecycle_reconciliation_fails_closed_after_bounded_readbacks(
call["expected_provider_message_id"] == "9127"
for call in reconcile_calls
)
assert all(
call["expected_destination_binding"] == "a" * 64
for call in reconcile_calls
)
@pytest.mark.asyncio