Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a198ed-70cc-7362-a569-d5dbef39b86a
320 lines
13 KiB
Python
320 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
"""Exercise owner mail sources using temporary ledgers and synthetic mail only.
|
|
|
|
This probe documents present capabilities and missing integration. It is not an
|
|
inbound worker, sender deployment, credential admission or suppression operator.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import hashlib
|
|
import io
|
|
import json
|
|
import sys
|
|
import tempfile
|
|
from datetime import UTC, datetime
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
import mail_return_operation as return_operation
|
|
|
|
|
|
def main():
|
|
if not __debug__:
|
|
raise SystemExit("Assertions must be enabled")
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--owner-repo", type=Path, required=True)
|
|
parser.add_argument("--native-evidence", type=Path, required=True)
|
|
args = parser.parse_args()
|
|
source = args.owner_repo.resolve() / "src"
|
|
native = json.loads(args.native_evidence.read_text())
|
|
module = source / "email_connect/transactional.py"
|
|
assert (
|
|
hashlib.sha256(module.read_bytes()).hexdigest()
|
|
== native["running_process_configuration"]["transactional_source_sha256"]
|
|
)
|
|
|
|
# Fail any attempted Python network connection/bind, even if a future source
|
|
# change accidentally substitutes a real transport for these fixtures.
|
|
def no_network(event, _args):
|
|
if event in {"socket.connect", "socket.bind", "socket.getaddrinfo", "socket.sendto"}:
|
|
raise RuntimeError("Offline rehearsal forbids network access")
|
|
|
|
sys.addaudithook(no_network)
|
|
sys.path.insert(0, str(source))
|
|
from email_connect.callers import CallerPolicy, ScopedTransactionalApplication
|
|
from email_connect.config import (
|
|
AppConfig,
|
|
MailboxConfig,
|
|
ReportsConfig,
|
|
ScanConfig,
|
|
SourceConfig,
|
|
StorageConfig,
|
|
)
|
|
from email_connect.scanner import scan_mailbox
|
|
from email_connect.storage import StateStore
|
|
from email_connect.transactional import SMTPProvider, SQLiteDeliveryStore
|
|
|
|
captured = []
|
|
|
|
class SyntheticSMTP:
|
|
def __init__(self, *args, **kwargs):
|
|
self.tls = False
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, *args):
|
|
pass
|
|
|
|
def starttls(self, context):
|
|
assert context.check_hostname
|
|
self.tls = True
|
|
|
|
def login(self, username, password):
|
|
assert self.tls and username == "fixture" and password == "fixture-only"
|
|
|
|
def send_message(self, message):
|
|
assert message["To"] == "recipient@example.test"
|
|
captured.append(message)
|
|
|
|
def policy(name, operations, tenant="tenant:fixture"):
|
|
return CallerPolicy(
|
|
caller_id=name,
|
|
token="fixture-credential-" + name,
|
|
source=name,
|
|
bindings=frozenset({(tenant, "client:fixture")}),
|
|
operations=frozenset(operations),
|
|
templates=frozenset({"family_member.invited"}),
|
|
rate_per_minute=60,
|
|
burst=30,
|
|
max_payload_bytes=8192,
|
|
)
|
|
|
|
sender = policy("user-engine", {"send", "delivery-status"})
|
|
operator = policy("fixture-operator", {"suppress", "unsuppress"})
|
|
other = policy("fixture-other", {"send"}, "tenant:other")
|
|
|
|
def event(name, caller=sender, tenant="tenant:fixture"):
|
|
return {
|
|
"id": name,
|
|
"source": caller.source,
|
|
"type": "family_member.invited",
|
|
"tenant": tenant,
|
|
"client_id": "client:fixture",
|
|
"data": {"primary_email": "recipient@example.test", "invitation_id": name},
|
|
}
|
|
|
|
def invoke(app, payload, path="/v1/send", caller=sender):
|
|
raw = json.dumps(payload).encode()
|
|
result = {}
|
|
env = {
|
|
"PATH_INFO": path,
|
|
"REQUEST_METHOD": "POST",
|
|
"CONTENT_LENGTH": str(len(raw)),
|
|
"wsgi.input": io.BytesIO(raw),
|
|
"HTTP_AUTHORIZATION": "Bearer " + caller.token,
|
|
"HTTP_IDEMPOTENCY_KEY": payload.get("id", ""),
|
|
}
|
|
body = b"".join(app(env, lambda status, headers: result.update(status=int(status[:3]))))
|
|
return result["status"], json.loads(body)
|
|
|
|
with (
|
|
tempfile.TemporaryDirectory(prefix="csoc-mail-return-") as tmp,
|
|
patch("email_connect.transactional.smtplib.SMTP", SyntheticSMTP),
|
|
):
|
|
root = Path(tmp)
|
|
ledger = SQLiteDeliveryStore(str(root / "transactional.sqlite"))
|
|
provider = SMTPProvider(
|
|
"smtp.example.test", 587, "fixture", "fixture-only", "platform@example.test"
|
|
)
|
|
app = ScopedTransactionalApplication(
|
|
ledger, provider, "https://issuer.example.test", [sender, operator, other]
|
|
)
|
|
assert invoke(app, event("invitation-1"))[0] == 202
|
|
assert len(captured) == 1
|
|
message = captured[0]
|
|
reference = str(message["Message-ID"])
|
|
assert message["From"] == "platform@example.test"
|
|
assert message["Reply-To"] is None and message["Return-Path"] is None
|
|
assert (
|
|
ledger.db.execute(
|
|
"SELECT count(*) FROM deliveries WHERE provider_ref=?", (reference,)
|
|
).fetchone()[0]
|
|
== 1
|
|
)
|
|
fixture = root / "mailbox"
|
|
fixture.mkdir()
|
|
(fixture / "bounce.eml").write_text(
|
|
"From: mailer-daemon@example.test\nTo: platform@example.test\n"
|
|
"Subject: Delivery Status Notification (Failure)\n"
|
|
"Date: Sat, 31 Oct 2026 10:00:00 +0000\n"
|
|
"Message-ID: <fixture-bounce@example.test>\n"
|
|
"Content-Type: text/plain; charset=utf-8\n\n"
|
|
"Delivery failure.\nFinal-Recipient: rfc822; recipient@example.test\n"
|
|
"Action: failed\nStatus: 5.1.1\nDiagnostic-Code: smtp; 550 User unknown\n"
|
|
"Original-Message-ID: " + reference + "\n"
|
|
)
|
|
config = AppConfig(
|
|
mailbox=MailboxConfig(id="fixture-mailbox", protocol="fixture"),
|
|
scan=ScanConfig(),
|
|
storage=StorageConfig(str(root / "scanner.sqlite")),
|
|
reports=ReportsConfig(str(root / "reports")),
|
|
source=SourceConfig(fixture_dir=str(fixture)),
|
|
)
|
|
scan = scan_mailbox(config)
|
|
evidence = StateStore(config.storage.path)
|
|
rows = evidence.evidence_rows()
|
|
assert scan.scan.messages_seen == 1 and len(rows) == 1
|
|
assert rows[0]["original_message_id"] == reference
|
|
assert rows[0]["affected_email_address"] == "recipient@example.test"
|
|
assert rows[0]["assessment_subclass"] == "fail.hard_bounce"
|
|
assert not ledger.is_suppressed("recipient@example.test")
|
|
repeat = scan_mailbox(config)
|
|
assert repeat.scan.messages_new == 0 and repeat.scan.evidence_events_created == 0
|
|
payload = {"recipient": "recipient@example.test", "reason": "hard_bounce"}
|
|
assert invoke(app, payload, "/v1/suppressions")[0] == 403
|
|
assert not ledger.is_suppressed("recipient@example.test")
|
|
assert invoke(app, payload, "/v1/suppressions", operator)[0] == 200
|
|
assert invoke(app, event("invitation-2")) == (400, {"error": "recipient_suppressed"})
|
|
assert invoke(app, event("invitation-3", other, "tenant:other"), caller=other) == (
|
|
400,
|
|
{"error": "recipient_suppressed"},
|
|
)
|
|
assert len(captured) == 1
|
|
ledger.db.close()
|
|
ledger = SQLiteDeliveryStore(str(root / "transactional.sqlite"))
|
|
assert ledger.is_suppressed("recipient@example.test")
|
|
app = ScopedTransactionalApplication(
|
|
ledger, provider, "https://issuer.example.test", [sender, operator, other]
|
|
)
|
|
assert invoke(app, payload, "/v1/suppressions/remove")[0] == 403
|
|
assert invoke(app, payload, "/v1/suppressions/remove", operator)[0] == 200
|
|
assert not ledger.is_suppressed("recipient@example.test")
|
|
assert len(captured) == 1
|
|
# Exercise the actual selected-return operator against the real owner's
|
|
# ledger and scoped send path, without admitting an HTTP operator caller.
|
|
strict_dsn = (
|
|
"MIME-Version: 1.0\r\nContent-Type: multipart/report; "
|
|
'report-type=delivery-status; boundary="dsn"\r\n\r\n'
|
|
"--dsn\r\nContent-Type: text/plain\r\n\r\nFailure.\r\n"
|
|
"--dsn\r\nContent-Type: message/delivery-status\r\n\r\n"
|
|
"Reporting-MTA: dns; fixture.example.test\r\n"
|
|
f"Original-Message-ID: {reference}\r\n\r\n"
|
|
"Final-Recipient: rfc822; recipient@example.test\r\n"
|
|
"Action: failed\r\nStatus: 5.1.1\r\n\r\n--dsn--\r\n"
|
|
).encode()
|
|
document = {
|
|
"schema_version": 1,
|
|
"callers": [
|
|
{
|
|
"caller_id": sender.caller_id,
|
|
"source": sender.source,
|
|
"bindings": [list(v) for v in sender.bindings],
|
|
"templates": sorted(sender.templates),
|
|
}
|
|
],
|
|
}
|
|
audit = root / "selected-return-audit"
|
|
audit.mkdir(mode=0o700)
|
|
plan = return_operation.prepare(
|
|
root / "transactional.sqlite",
|
|
strict_dsn,
|
|
"recipient@example.test",
|
|
document,
|
|
"Synthetic operator verified this controlled return",
|
|
invitation_payload=event("invitation-1"),
|
|
)
|
|
|
|
def table_rows():
|
|
return {
|
|
table: ledger.db.execute('SELECT * FROM "' + table + '" ORDER BY 1').fetchall()
|
|
for (table,) in ledger.db.execute(
|
|
"SELECT name FROM sqlite_master WHERE type='table'"
|
|
)
|
|
}
|
|
|
|
before = table_rows()
|
|
return_operation.apply(
|
|
root / "transactional.sqlite",
|
|
plan,
|
|
strict_dsn,
|
|
document,
|
|
return_operation.digest(plan),
|
|
audit,
|
|
)
|
|
after = table_rows()
|
|
assert {k: v for k, v in before.items() if k != "suppressions"} == {
|
|
k: v for k, v in after.items() if k != "suppressions"
|
|
}
|
|
assert invoke(app, event("operator-blocked")) == (400, {"error": "recipient_suppressed"})
|
|
assert invoke(app, event("operator-other", other, "tenant:other"), caller=other) == (
|
|
400,
|
|
{"error": "recipient_suppressed"},
|
|
)
|
|
release = return_operation.prepare_release(
|
|
root / "transactional.sqlite",
|
|
audit,
|
|
return_operation.digest(plan),
|
|
"Synthetic operator verified the corrected recipient",
|
|
)
|
|
before = table_rows()
|
|
return_operation.apply(
|
|
root / "transactional.sqlite",
|
|
release,
|
|
None,
|
|
None,
|
|
return_operation.digest(release),
|
|
audit,
|
|
)
|
|
after = table_rows()
|
|
assert {k: v for k, v in before.items() if k != "suppressions"} == {
|
|
k: v for k, v in after.items() if k != "suppressions"
|
|
}
|
|
assert not ledger.is_suppressed("recipient@example.test") and len(captured) == 1
|
|
ledger.db.close()
|
|
evidence.close()
|
|
assert not root.exists()
|
|
print(
|
|
json.dumps(
|
|
{
|
|
"schema": "coulomb.mail-return-boundary-rehearsal.v1",
|
|
"completed_at": datetime.now(UTC).isoformat(),
|
|
"source_sha256": {
|
|
str(p.relative_to(args.owner_repo.resolve())): hashlib.sha256(
|
|
p.read_bytes()
|
|
).hexdigest()
|
|
for p in sorted((source / "email_connect").glob("*.py"))
|
|
},
|
|
"probe_sha256": hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
|
|
"transactional_source_matches_native": True,
|
|
"smtp_transport": "in-process synthetic replacement; no SMTP connection",
|
|
"message_id_correlates_with_ledger_and_synthetic_bounce": True,
|
|
"explicit_reply_to_or_return_path_headers": False,
|
|
"scanner_deduplicates_evidence": True,
|
|
"scanner_updates_transactional_suppression": False,
|
|
"ordinary_sender_suppress_and_unsuppress_denied": True,
|
|
"synthetic_operator_suppression_blocks_send_and_survives_restart": True,
|
|
"suppression_scope": "recipient-global across callers and tenants",
|
|
"explicit_synthetic_operator_unsuppression_verified": True,
|
|
"selected_return_operator_source_sha256": hashlib.sha256(
|
|
Path(return_operation.__file__).read_bytes()
|
|
).hexdigest(),
|
|
"selected_operator_correlates_actual_owner_payload_and_accepted_message_id": True,
|
|
"selected_operator_suppresses_across_callers_and_explicitly_releases": True,
|
|
"selected_operator_preserves_all_five_other_ledger_tables": True,
|
|
"native_operator_admission_proved": False,
|
|
"received_mail_authenticity_or_correlation_authority_proved": False,
|
|
"python_network_operations_blocked": True,
|
|
"temporary_ledgers_removed": True,
|
|
"mail_sent": False,
|
|
"production_mailbox_accessed": False,
|
|
},
|
|
indent=2,
|
|
)
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|