"""Real owner portal/adapters/receiver with synthetic session, directory and mail sink.""" import html import json import os import socket import subprocess import threading import time from contextlib import contextmanager from pathlib import Path from socketserver import ThreadingMixIn from wsgiref.simple_server import WSGIRequestHandler, WSGIServer, make_server import pytest TENANT = "tenant:communication-test" CLIENT = "coulomb-social-test" TOKEN = "synthetic-user-engine-mail-token" class QuietHandler(WSGIRequestHandler): def log_message(self, *args): pass class FixtureServer(ThreadingMixIn, WSGIServer): daemon_threads = True @contextmanager def server(app, ports): httpd = make_server("127.0.0.1", 0, app, server_class=FixtureServer, handler_class=QuietHandler) ports.add(httpd.server_port) thread = threading.Thread(target=httpd.serve_forever, daemon=True) thread.start() try: yield f"http://127.0.0.1:{httpd.server_port}" finally: httpd.shutdown() httpd.server_close() thread.join(timeout=5) @pytest.mark.browser @pytest.mark.usecase("CSOC-UC-010") @pytest.mark.usecase("CSOC-UC-011") def test_real_owner_registration_and_invitation(tmp_path, monkeypatch): ports = set() connect, resolve = socket.socket.connect, socket.getaddrinfo def guarded_connect(sock, address): if (not isinstance(address, tuple) or address[0] != "127.0.0.1" or address[1] not in ports): raise RuntimeError("Owner harness refuses non-fixture connections") return connect(sock, address) def guarded_resolve(host, port, *args, **kwargs): if host != "127.0.0.1" or int(port) not in ports: raise RuntimeError("Owner harness refuses DNS/non-fixture connections") return resolve(host, port, *args, **kwargs) monkeypatch.setattr(socket.socket, "connect", guarded_connect) monkeypatch.setattr(socket.socket, "connect_ex", guarded_connect) monkeypatch.setattr(socket, "getaddrinfo", guarded_resolve) monkeypatch.setattr(socket, "getfqdn", lambda *args: "localhost") with pytest.raises(RuntimeError), socket.socket() as denied: denied.connect(("203.0.113.1", 443)) with pytest.raises(RuntimeError): socket.getaddrinfo("provider.example.test", 443) import email_connect import user_engine from email_connect.callers import CallerPolicy, ScopedTransactionalApplication from email_connect.transactional import SQLiteDeliveryStore from user_engine.adapters.delivery import HTTPOutboxDeliveryAdapter from user_engine.adapters.local import InMemoryUserEngineStore, LocalAuthorizationCheckPort from user_engine.adapters.registration_verification import HTTPRegistrationVerificationAdapter from user_engine.oidc import BrowserSession, OIDCClient from user_engine.ports import ProvisioningResult from user_engine.service import UserEngineService from user_engine.testing.fixtures import FixtureIdentityClaimsAdapter, human_actor_claims from user_engine.web import PortalApplication snapshot = Path(os.environ["PYTHONPATH"]).resolve() assert all(Path(package.__file__).resolve().is_relative_to(snapshot) for package in (email_connect, user_engine)) messages, provisions, events = [], [], [] store = InMemoryUserEngineStore() store.migrate() service = UserEngineService(store=store, identity_adapter=FixtureIdentityClaimsAdapter(), authorization=LocalAuthorizationCheckPort()) ledger = SQLiteDeliveryStore(str(tmp_path / "mail.db")) class MailSink: def send(self, recipient, subject, body): assert recipient.endswith("@example.test") messages.append({"recipient": recipient, "subject": subject, "body": body}) return "synthetic-provider-reference-" + str(len(messages)) def check(self): pass class Directory: def provision(self, request): provisions.append(request) return ProvisioningResult("synthetic-directory", request.preferred_username, "password_setup_required", password_setup_url="https://directory.example.test/setup") oidc = OIDCClient(issuer="https://issuer.example.test", client_id=CLIENT, redirect_uri="https://portal.example.test/callback", audience=CLIENT) claims = human_actor_claims(tenant=TENANT, subject="synthetic-inviter") claims["roles"] = ["tenant-admin"] service.me(claims) oidc.sessions["synthetic-admin-session"] = BrowserSession( claims=claims, expires_at=time.time() + 3600, csrf_token="synthetic-admin-csrf") operator = service.identity_adapter.normalize(human_actor_claims( tenant="platform:root", subject="synthetic-delivery-operator")) portal = PortalApplication(service, trusted_proxy_secret="synthetic-proxy-secret-long-enough", login_url="https://issuer.example.test/login", oidc_client=oidc, provisioning=Directory(), registration_clients=(CLIENT,), registration_tenants=(TENANT,), registration_oidc_issuer="https://issuer.example.test", registration_password_setup_origins=("https://directory.example.test",)) def response(start, payload, content_type="application/json", status="200 OK"): data = payload.encode() if isinstance(payload, str) else json.dumps(payload).encode() start(status, [("Content-Type", content_type), ("Content-Length", str(len(data)))]) return [data] def fixtures(env, start): path = env["PATH_INFO"] if path == "/mailbox": body = "

Synthetic mailbox

" + "".join( f'
'
                + html.escape(m["body"]) + "
" for m in messages) return response(start, body, "text/html") if path == "/state": return response(start, {"messages": len(messages), "provisions": len(provisions), "events": len(events), "users": service.operability_snapshot().metrics["users"]}) if env["REQUEST_METHOD"] != "POST": return response(start, {}, status="404 Not Found") raw = env["wsgi.input"].read(int(env.get("CONTENT_LENGTH") or 0)) data = json.loads(raw or b"{}") if path == "/events": assert env.get("HTTP_AUTHORIZATION") == "Bearer synthetic-event-token" assert "primary_email" not in data["data"] events.append(data) elif path == "/deliver": service.deliver_outbox(operator, portal.outbox_delivery, worker_id="fixture-worker") elif path == "/expire": with ledger.lock, ledger.db: ledger.db.execute("UPDATE verifications SET expires_at=? WHERE email=?", ("2000-01-01T00:00:00+00:00", data["email"])) elif path == "/suppress": ledger.suppress(data["email"]) else: return response(start, {}, status="404 Not Found") return response(start, {"ok": True}) with server(fixtures, ports) as fixture_url, server(portal, ports) as portal_url: policies = [CallerPolicy( caller_id=name, token=TOKEN if name == "user-engine" else "synthetic-other-caller-token", source="user-engine", bindings=frozenset({(TENANT, CLIENT)}), operations=frozenset({"send", "status", "delivery-status", "verify", "consume", "cancel"}), templates=frozenset({"family_member.invited", "family_invitation.resent"}), rate_per_minute=120, burst=100, max_payload_bytes=32768, ) for name in ("user-engine", "other-caller")] receiver = ScopedTransactionalApplication(ledger, MailSink(), portal_url, policies) with server(receiver, ports) as mail_url: portal.registration_verification = HTTPRegistrationVerificationAdapter( base_url=mail_url, bearer_token=TOKEN) portal.outbox_delivery = HTTPOutboxDeliveryAdapter( event_url=fixture_url + "/events", event_bearer_token="synthetic-event-token", mail_url=mail_url + "/v1/send", mail_bearer_token=TOKEN, mail_client_bindings=json.dumps([[TENANT, CLIENT]])) result = subprocess.run( [os.environ["OWNER_NODE"], os.environ["OWNER_BROWSER_SCRIPT"], portal_url, fixture_url, mail_url, os.environ["OWNER_PLAYWRIGHT_MODULE"]], capture_output=True, text=True, timeout=150) assert result.returncode == 0, result.stdout + result.stderr checks = json.loads(result.stdout) assert len(provisions) == 1 assert provisions[0].preferred_username == "verified.person" assert all(p.primary_email.endswith("@example.test") for p in provisions) with ledger.lock: assert ledger.db.execute("SELECT count(*) FROM verifications WHERE consumed_at IS NOT NULL" ).fetchone()[0] == 1 assert ledger.db.execute("SELECT count(*) FROM verifications WHERE canceled_at IS NOT NULL" ).fetchone()[0] == 1 ledger.db.close() assert checks["passed"] and checks["browser_requests_outside_fixture"] == 0 Path(os.environ["OWNER_CHECKS_RESULT"]).write_text(json.dumps(checks))