fix(telegram): fail closed on unverified delivery
This commit is contained in:
@@ -20,6 +20,31 @@ from src.services.telegram_gateway import TelegramGateway
|
||||
|
||||
_CHAT_ID = "verified-chat"
|
||||
_MESSAGE_ID = 77
|
||||
_DESTINATION_BINDING = gateway_module._telegram_destination_binding(_CHAT_ID)
|
||||
_SENT_RECEIPT = {
|
||||
"ok": True,
|
||||
"_awooop_delivery_status": "sent",
|
||||
"_awooop_provider_send_performed": True,
|
||||
"result": {"message_id": _MESSAGE_ID, "chat": {"id": _CHAT_ID}},
|
||||
"_awoooi_canonical_route_receipt": {
|
||||
"schema_version": "telegram_canonical_egress_receipt_v1",
|
||||
"decision": "allowed",
|
||||
"destination_alias": "inbound_interaction_reply_target",
|
||||
"destination_binding": _DESTINATION_BINDING,
|
||||
"sender_bot_alias": "tsenyang_bot",
|
||||
"provider_send_performed": True,
|
||||
},
|
||||
gateway_module._DELIVERY_CONTEXT_KEY: {
|
||||
"schema_version": "telegram_delivery_context_v1",
|
||||
"method": "sendMessage",
|
||||
"sender_bot_alias": "tsenyang_bot",
|
||||
"destination_alias": "inbound_interaction_reply_target",
|
||||
"destination_binding": _DESTINATION_BINDING,
|
||||
"payload_destination_binding": _DESTINATION_BINDING,
|
||||
"provider_destination_binding": _DESTINATION_BINDING,
|
||||
"destination_binding_verified": True,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _assert_verified_callback_payload(payload: dict) -> None:
|
||||
@@ -174,13 +199,15 @@ async def test_llm_and_category_results_keep_verified_callback_context(
|
||||
|
||||
class _Redis:
|
||||
async def get(self, _key: str) -> str:
|
||||
return json.dumps({
|
||||
"name": "inspect",
|
||||
"provider": "internal",
|
||||
"tool": "status",
|
||||
"risk": "low",
|
||||
"incident_id": "INC-1",
|
||||
})
|
||||
return json.dumps(
|
||||
{
|
||||
"name": "inspect",
|
||||
"provider": "internal",
|
||||
"tool": "status",
|
||||
"risk": "low",
|
||||
"incident_id": "INC-1",
|
||||
}
|
||||
)
|
||||
|
||||
monkeypatch.setattr(gateway_module, "get_redis", lambda: _Redis())
|
||||
monkeypatch.setattr(
|
||||
@@ -213,13 +240,15 @@ async def test_llm_and_category_results_keep_verified_callback_context(
|
||||
monkeypatch.setattr(
|
||||
callback_dispatcher,
|
||||
"dispatch_action",
|
||||
AsyncMock(return_value=DispatchResult(
|
||||
success=True,
|
||||
action="inspect",
|
||||
incident_id="INC-1",
|
||||
user_id=42,
|
||||
result_text="result",
|
||||
)),
|
||||
AsyncMock(
|
||||
return_value=DispatchResult(
|
||||
success=True,
|
||||
action="inspect",
|
||||
incident_id="INC-1",
|
||||
user_id=42,
|
||||
result_text="result",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
class _IncidentRepo:
|
||||
@@ -264,7 +293,9 @@ async def test_write_category_callback_keeps_verified_context(
|
||||
"verify_callback",
|
||||
AsyncMock(return_value={"id": 42}),
|
||||
)
|
||||
monkeypatch.setattr(gateway, "_check_incident_state_guard", AsyncMock(return_value=None))
|
||||
monkeypatch.setattr(
|
||||
gateway, "_check_incident_state_guard", AsyncMock(return_value=None)
|
||||
)
|
||||
monkeypatch.setattr(gateway, "_answer_callback", AsyncMock())
|
||||
spec = SimpleNamespace(
|
||||
requires_multi_sig=False,
|
||||
@@ -278,13 +309,15 @@ async def test_write_category_callback_keeps_verified_context(
|
||||
monkeypatch.setattr(
|
||||
callback_dispatcher,
|
||||
"dispatch_action",
|
||||
AsyncMock(return_value=DispatchResult(
|
||||
success=True,
|
||||
action="restart_safe",
|
||||
incident_id="INC-1",
|
||||
user_id=42,
|
||||
result_text="done",
|
||||
)),
|
||||
AsyncMock(
|
||||
return_value=DispatchResult(
|
||||
success=True,
|
||||
action="restart_safe",
|
||||
incident_id="INC-1",
|
||||
user_id=42,
|
||||
result_text="done",
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
class _IncidentRepo:
|
||||
@@ -335,9 +368,7 @@ async def test_approval_replies_keep_verified_callback_context(
|
||||
_assert_verified_callback_payload(status_payload)
|
||||
source_extra = status_payload[gateway_module._AWOOOP_SOURCE_ENVELOPE_EXTRA_KEY]
|
||||
merged = gateway_module._merge_outbound_source_envelope_extra({}, source_extra)
|
||||
assert merged["callback_reply"]["parent_provider_message_id"] == str(
|
||||
_MESSAGE_ID
|
||||
)
|
||||
assert merged["callback_reply"]["parent_provider_message_id"] == str(_MESSAGE_ID)
|
||||
|
||||
send_request.reset_mock()
|
||||
approval_id = UUID("44444444-4444-4444-4444-444444444444")
|
||||
@@ -367,8 +398,9 @@ async def test_approval_replies_keep_verified_callback_context(
|
||||
@pytest.mark.parametrize(
|
||||
("result", "expected"),
|
||||
[
|
||||
({"ok": True}, True),
|
||||
({"ok": True, "_awooop_delivery_status": "sent_reused"}, True),
|
||||
(_SENT_RECEIPT, True),
|
||||
({"ok": True}, False),
|
||||
({"ok": True, "_awooop_delivery_status": "sent_reused"}, False),
|
||||
({"ok": False}, False),
|
||||
(
|
||||
{"ok": True, "_awooop_delivery_status": "blocked_no_egress"},
|
||||
@@ -414,7 +446,7 @@ async def test_approval_structured_no_send_retries_plain_on_exact_parent(
|
||||
) -> None:
|
||||
gateway = TelegramGateway()
|
||||
attempts: list[tuple[str, dict]] = []
|
||||
send_results = iter([primary_failure, {"ok": True}])
|
||||
send_results = iter([primary_failure, dict(_SENT_RECEIPT)])
|
||||
|
||||
async def structured_primary_failure(method: str, payload: dict) -> dict:
|
||||
attempts.append((method, payload))
|
||||
@@ -423,7 +455,7 @@ async def test_approval_structured_no_send_retries_plain_on_exact_parent(
|
||||
return {"ok": True}
|
||||
|
||||
record_failure = AsyncMock(return_value=None)
|
||||
shared_fallback = AsyncMock(return_value={"ok": True})
|
||||
shared_fallback = AsyncMock(return_value=dict(_SENT_RECEIPT))
|
||||
monkeypatch.setattr(gateway, "_send_request", structured_primary_failure)
|
||||
monkeypatch.setattr(gateway, "_record_callback_reply_failure", record_failure)
|
||||
monkeypatch.setattr(gateway, "send_alert_notification", shared_fallback)
|
||||
@@ -454,10 +486,12 @@ async def test_approval_structured_double_no_send_records_durable_failure(
|
||||
) -> None:
|
||||
gateway = TelegramGateway()
|
||||
attempts: list[tuple[str, dict]] = []
|
||||
send_results = iter([
|
||||
{"ok": True, "_awooop_delivery_status": "blocked_no_egress"},
|
||||
{"ok": True, "_awooop_provider_send_performed": False},
|
||||
])
|
||||
send_results = iter(
|
||||
[
|
||||
{"ok": True, "_awooop_delivery_status": "blocked_no_egress"},
|
||||
{"ok": True, "_awooop_provider_send_performed": False},
|
||||
]
|
||||
)
|
||||
|
||||
async def structured_no_send(method: str, payload: dict) -> dict:
|
||||
attempts.append((method, payload))
|
||||
@@ -501,7 +535,7 @@ async def test_callback_card_edits_use_only_verified_inbound_identity(
|
||||
action: str,
|
||||
) -> None:
|
||||
gateway = TelegramGateway()
|
||||
send_request = AsyncMock(return_value={"ok": True})
|
||||
send_request = AsyncMock(return_value=dict(_SENT_RECEIPT))
|
||||
monkeypatch.setattr(gateway, "_send_request", send_request)
|
||||
|
||||
await gateway._update_message_after_action(
|
||||
@@ -658,17 +692,20 @@ async def test_autonomous_lifecycle_threads_use_canonical_route_and_parent_recei
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
gateway = TelegramGateway()
|
||||
send_request = AsyncMock(return_value={"ok": True})
|
||||
send_request = AsyncMock(return_value=dict(_SENT_RECEIPT))
|
||||
monkeypatch.setattr(gateway, "_send_request", send_request)
|
||||
monkeypatch.setattr(gateway_module, "get_redis", lambda: _LifecycleRedis())
|
||||
|
||||
assert await gateway.mark_auto_repaired("INC-1", "playbook", 10) is True
|
||||
assert await gateway.append_incident_update("INC-2", "healthy") is True
|
||||
assert await gateway.append_grouped_alert_digest(
|
||||
incident_id="INC-3",
|
||||
group_key="group-1",
|
||||
digest_text="digest",
|
||||
) is True
|
||||
assert (
|
||||
await gateway.append_grouped_alert_digest(
|
||||
incident_id="INC-3",
|
||||
group_key="group-1",
|
||||
digest_text="digest",
|
||||
)
|
||||
is True
|
||||
)
|
||||
|
||||
send_payloads = [
|
||||
call.args[1]
|
||||
|
||||
Reference in New Issue
Block a user