railiance-platform/tests/test_email_connect_smtp_delivery.py
codex 1524c54570 Prepare guarded email-connect platform SMTP reader admission
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a18e2d-f513-7742-b8e7-12af0b744ff3
2026-10-31 11:54:53 +01:00

254 lines
12 KiB
Python

"""Fixed SMTP admission with a synthetic Bao/SMTP boundary; no native credentials."""
import copy
import importlib.util
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest
from unittest.mock import patch
import yaml
ROOT = Path(__file__).resolve().parents[1]
spec = importlib.util.spec_from_file_location('email_connect_delivery', ROOT / 'scripts/email_connect_smtp_delivery.py')
delivery = importlib.util.module_from_spec(spec)
spec.loader.exec_module(delivery)
class FakeOwner:
def __init__(self, lane):
self.lane = lane
self.writes = []
self.revoked = []
self.authenticated = False
self.mailbox = {'data': dict(lane.FIELDS, SMTP_PASSWORD='fixture-only'),
'metadata': {'version': 2}}
boundary = '\n'.join('path "'+p+'" { capabilities = ["deny"] }' for p in (
lane.LANE['kv_path'], lane.LANE['kv_path'].replace('/data/', '/metadata/', 1)))
self.values = {p: {'policy': 'existing-consumer'} if '/policies/' in p else {'unchanged': True}
for p in delivery.PROTECTED}
self.values[delivery.PROTECTED[0]] = {'policy': boundary}
self.changed_consumer = False
self.changed_mailbox = False
self.sealed = False
self.cluster_id = delivery.OPENBAO_CLUSTER_ID
self.auth_policies = ['platform-admin']
def bao(self, args, *, payload=None, allow_failure=False):
if args[0] == 'status':
value = {'cluster_id': self.cluster_id, 'initialized': True, 'sealed': self.sealed}
elif args[:2] == ['token', 'lookup']:
value = {'data': {'policies': self.auth_policies}}
elif args[:2] == ['token', 'create']:
value = {'auth': {'client_token': 'fixture-negative-token'}}
elif args[0] == 'read':
path = args[-1]
if path == self.lane.LANE['kv_path']:
v = copy.deepcopy(self.mailbox)
if self.writes and self.changed_mailbox:
v['metadata']['version'] += 1
value = {'data': v}
elif path in self.values:
v = copy.deepcopy(self.values[path])
if self.writes and self.changed_consumer and path == delivery.PROTECTED[1]:
v['policy'] = 'changed'
value = {'data': v}
else:
assert allow_failure
return subprocess.CompletedProcess([], 2, b'', b'No value found')
elif args[0] == 'write':
path = args[1]
assert path in ('sys/policies/acl/'+self.lane.LANE['policy'],
'auth/kubernetes/role/'+self.lane.LANE['role'])
self.writes.append(path)
v = copy.deepcopy(payload)
for key in ('token_ttl', 'token_max_ttl', 'token_explicit_max_ttl'):
if key in v:
v[key] = 900
self.values[path] = v
value = {}
else:
raise AssertionError(args)
return subprocess.CompletedProcess([], 0, json.dumps(value).encode(), b'')
def smtp(self, host, port, timeout):
owner = self
assert (host, port) == ('smtp.ionos.de', 587)
class SMTP:
def __enter__(self): return self
def __exit__(self, *args): pass
def ehlo(self): pass
def starttls(self, context): assert context.check_hostname
def login(self, user, password):
assert user == 'platform@coulomb.social' and password == 'fixture-only'
owner.authenticated = True
return SMTP()
def run(self):
records = []
receipt = {}
with patch.object(delivery, 'lane_module', return_value=self.lane), \
patch.object(self.lane, 'bao', side_effect=self.bao), \
patch.object(self.lane, 'capabilities', side_effect=lambda token, paths: {p: ['deny'] for p in paths}), \
patch.object(self.lane, 'revoke', side_effect=self.revoked.append), \
patch.object(self.lane.smtplib, 'SMTP', side_effect=self.smtp):
delivery.admit(receipt, lambda r: records.append(copy.deepcopy(r)))
return receipt, records
class AdmissionTests(unittest.TestCase):
def setUp(self):
self.lane = delivery.lane_module()
self.owner = FakeOwner(self.lane)
def test_default_preview_has_no_owner_calls_and_exact_role(self):
with patch.object(delivery, 'lane_module', return_value=self.lane), \
patch.object(self.lane, 'bao', side_effect=AssertionError('no owner call')):
ccr, proposal, digest = delivery.prepare()
self.assertEqual(ccr['status'], 'proposed')
self.assertFalse(ccr['openbao']['auth']['bound_claims_confirmed'])
role = proposal['role']
self.assertEqual(role['bound_service_account_namespaces'], ['email-connect'])
self.assertEqual(role['bound_service_account_names'], ['email-connect-platform-smtp-eso'])
self.assertEqual(role['token_explicit_max_ttl'], '15m')
self.assertTrue(role['token_no_default_policy'])
self.assertNotIn('*', proposal['policy'])
self.assertTrue(digest.startswith('sha256:'))
def test_approval_and_native_binding_do_not_change_reviewed_scope_digest(self):
ccr, _, initial = delivery.prepare()
ccr['status'] = 'approved'; ccr['openbao']['auth']['bound_claims_confirmed'] = True
ccr['review']['comments'] = [{'reviewer': 'fixture', 'decision': 'approved'}]
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / 'ccr.yaml'; path.write_text(yaml.safe_dump(ccr))
with patch.object(delivery, 'CCR', path):
self.assertEqual(delivery.prepare()[2], initial)
ccr['openbao']['auth']['bound_claims']['service_account_namespaces'] = ['other']
path.write_text(yaml.safe_dump(ccr))
with self.assertRaises(delivery.Refused): delivery.prepare()
def test_all_three_execution_gates(self):
ccr, _, digest = delivery.prepare()
with self.assertRaises(delivery.Refused): delivery.execution_guard(ccr, 'wrong', digest)
with self.assertRaises(delivery.Refused): delivery.execution_guard(ccr, digest, digest)
ccr['status'] = 'approved'
with self.assertRaises(delivery.Refused): delivery.execution_guard(ccr, digest, digest)
ccr['openbao']['auth']['bound_claims_confirmed'] = True
delivery.execution_guard(ccr, digest, digest)
def test_new_reader_only_and_existing_consumers_preserved(self):
receipt, records = self.owner.run()
self.assertEqual(receipt['status'], 'reader_admitted_verified')
self.assertTrue(receipt['existing_consumers_preserved'])
self.assertTrue(receipt['mailbox_unchanged'])
self.assertFalse(receipt['native_consumer_auth_verified'])
self.assertFalse(receipt['email_sent'])
self.assertFalse(receipt['application_sender_changed'])
self.assertTrue(self.owner.authenticated)
self.assertEqual(len(self.owner.writes), 2)
self.assertEqual(self.owner.revoked, ['fixture-negative-token'])
self.assertEqual(records[0]['mutation_outcome'], 'unconfirmed')
def test_instance_sealed_and_admin_guards_precede_writes(self):
for kind, value in [('cluster_id', 'wrong'), ('sealed', True), ('auth_policies', ['root'])]:
with self.subTest(kind=kind):
owner = FakeOwner(self.lane); setattr(owner, kind, value)
with self.assertRaises(delivery.Refused): owner.run()
self.assertFalse(owner.writes)
self.assertFalse(owner.authenticated)
def test_missing_agent_boundary_cannot_be_added_implicitly(self):
self.owner.values[delivery.PROTECTED[0]] = {'policy': ''}
with self.assertRaises(delivery.Refused): self.owner.run()
self.assertEqual(self.owner.writes, [])
def test_different_existing_role_prevents_even_policy_creation(self):
self.owner.values['auth/kubernetes/role/'+delivery.LANE['role']] = {'different': True}
with self.assertRaises(self.lane.LaneError): self.owner.run()
self.assertFalse(self.owner.authenticated)
self.assertEqual(self.owner.writes, [])
def test_different_existing_policy_is_not_replaced(self):
self.owner.values['sys/policies/acl/'+delivery.LANE['policy']] = {'policy': 'different'}
with self.assertRaises(delivery.Refused): self.owner.run()
self.assertEqual(self.owner.writes, [])
def test_existing_exact_reader_is_idempotent_without_metadata_writes(self):
self.owner.run(); self.owner.writes.clear()
receipt, _ = self.owner.run()
self.assertEqual(receipt['status'], 'reader_admitted_verified')
self.assertEqual(self.owner.writes, [])
def test_existing_consumer_or_mailbox_change_refuses_success(self):
for field in ['changed_consumer', 'changed_mailbox']:
with self.subTest(field=field):
owner = FakeOwner(self.lane); setattr(owner, field, True)
with self.assertRaises(delivery.Refused): owner.run()
self.assertEqual(len(owner.writes), 2)
def approved(self):
ccr, proposal, digest = delivery.prepare()
ccr['status'] = 'approved'; ccr['openbao']['auth']['bound_claims_confirmed'] = True
return ccr, proposal, digest
def test_failed_attempt_is_private_append_only_and_redacted(self):
ccr, proposal, digest = self.approved()
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / 'receipt.jsonl'
def fail(receipt, checkpoint):
receipt.update(phase='admitting', mutation_outcome='unconfirmed')
checkpoint(receipt)
raise RuntimeError('synthetic private provider text must not leave')
self.assertEqual(delivery.execute(ccr, proposal, digest, digest, path, fail), 1)
rows = [json.loads(line) for line in path.read_text().splitlines()]
self.assertEqual(len(rows), 3)
self.assertEqual(rows[0]['mutation_outcome'], 'not_started')
self.assertEqual(rows[1]['mutation_outcome'], 'unconfirmed')
self.assertEqual(rows[-1]['reason'], 'contained_admission_failure')
self.assertNotIn('private provider', path.read_text())
self.assertEqual(path.stat().st_mode & 0o777, 0o600)
before = path.read_bytes()
with self.assertRaises(FileExistsError): delivery.execute(ccr, proposal, digest, digest, path, fail)
self.assertEqual(path.read_bytes(), before)
def test_interrupted_attempt_never_records_verified(self):
ccr, proposal, digest = self.approved()
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp) / 'receipt.jsonl'
def stop(receipt, checkpoint):
receipt.update(phase='admitting', mutation_outcome='unconfirmed')
checkpoint(receipt); raise SystemExit(7)
with self.assertRaises(SystemExit): delivery.execute(ccr, proposal, digest, digest, path, stop)
rows = [json.loads(line) for line in path.read_text().splitlines()]
self.assertTrue(all(r['status'] == 'started' for r in rows))
self.assertEqual(rows[-1]['mutation_outcome'], 'unconfirmed')
self.assertNotIn('completed_at', rows[-1])
self.assertIn('interrupted_at', rows[-1])
def test_public_receipt_parent_refused(self):
ccr, proposal, digest = self.approved()
with tempfile.TemporaryDirectory() as tmp:
os.chmod(tmp, 0o755)
with self.assertRaises(delivery.Refused):
delivery.execute(ccr, proposal, digest, digest, Path(tmp)/'r', lambda *_: None)
self.assertEqual(list(Path(tmp).iterdir()), [])
def test_execute_refusal_is_silent_and_does_not_create_receipt(self):
with tempfile.TemporaryDirectory() as tmp:
path = Path(tmp)/'receipt.jsonl'
r = subprocess.run([sys.executable, str(ROOT/'scripts/email_connect_smtp_delivery.py'),
'--execute', '--expect-digest', 'wrong', '--receipt', str(path)],
capture_output=True, timeout=10)
self.assertNotEqual(r.returncode, 0)
self.assertEqual((r.stdout, r.stderr), (b'', b''))
self.assertFalse(path.exists())
def test_telemetry_module_is_not_rebound(self):
import telemetry_smtp_delivery
self.assertEqual(telemetry_smtp_delivery.LANE['namespace'], 'telemetry')
if __name__ == '__main__': unittest.main()