"""Synthetic tests for the NK-WP-0035-T04 receiver readback helper; no network, no tokens.""" import importlib.util import json import os from pathlib import Path import pytest SOURCE = Path(__file__).parents[1] / 'receiver_readback.py' spec = importlib.util.spec_from_file_location('receiver_readback', SOURCE) rb = importlib.util.module_from_spec(spec) spec.loader.exec_module(rb) CAPTURE = Path(__file__).parents[3] / 'docs/evidence/2026-10-15-cadence-adoption/hourly-observation-capture' def fake_receiver(counts, present, source='qonto-assistant', tenant='tenant:friendly:binky', recon_status=200, basis='independent_reader'): calls = [] def get(path): calls.append(path) if path.startswith('/v1/reconciliation?'): if recon_status != 200: return recon_status, {'error': 'source_not_allowed'} return 200, {'counts': [{'class': k, 'count': v} for k, v in counts.items()], 'basis': basis} event_id = path.rsplit('/', 1)[1] if event_id in present: return 200, {'source': source, 'tenant': tenant, 'id': event_id} return 404, {'error': 'not_found'} return get, calls def test_retained_capture_loads(): request, captured = rb.load_capture(CAPTURE) assert len(request['event_ids']) == 3 assert sum(captured.values()) == 3 def test_agreement(): request, captured = rb.load_capture(CAPTURE) get, calls = fake_receiver(dict(captured), set(request['event_ids'])) receipt = rb.readback(request, captured, get) assert receipt['verdict'] == 'agree' and receipt['findings'] == [] assert 'stream_instance_id=' in calls[0] and len(calls) == 4 assert receipt['token_retained'] is False and receipt['payloads_retained'] is False @pytest.mark.parametrize('case', ['missing_event', 'count_differs', 'extra_class', 'forbidden', 'wrong_tenant']) def test_divergence(case): request, captured = rb.load_capture(CAPTURE) counts, present = dict(captured), set(request['event_ids']) kwargs = {} if case == 'missing_event': present.discard(request['event_ids'][0]) elif case == 'count_differs': cls = next(iter(counts)) counts[cls] += 1 elif case == 'extra_class': counts['audit.allow'] = 1 elif case == 'forbidden': kwargs['recon_status'] = 403 else: kwargs['tenant'] = 'tenant:other' get, _ = fake_receiver(counts, present, **kwargs) receipt = rb.readback(request, captured, get) assert receipt['verdict'] == 'diverge' and receipt['findings'] def test_token_file_must_be_private(tmp_path): token = tmp_path / 'token' token.write_text('abc.def.ghi\n') os.chmod(token, 0o644) with pytest.raises(ValueError): rb.read_token(token) os.chmod(token, 0o600) assert rb.read_token(token) == 'abc.def.ghi' token.write_text('two tokens\n') with pytest.raises(ValueError): rb.read_token(token) def test_receipt_never_contains_token(tmp_path, monkeypatch): token = tmp_path / 'token' token.write_text('SENTINEL-TOKEN-VALUE') os.chmod(token, 0o600) request, captured = rb.load_capture(CAPTURE) get, _ = fake_receiver(dict(captured), set(request['event_ids'])) monkeypatch.setattr(rb, 'http_get', lambda base, tok: get) out = tmp_path / 'receipt.json' assert rb.main(['--capture-dir', str(CAPTURE), '--token-file', str(token), '--output', str(out)]) == 0 assert 'SENTINEL' not in out.read_text() assert json.loads(out.read_text())['verdict'] == 'agree' def test_missing_independent_basis_diverges(): request, captured = rb.load_capture(CAPTURE) get, _ = fake_receiver(captured, set(request['event_ids']), basis=None) receipt = rb.readback(request, captured, get) assert receipt['verdict'] == 'diverge' assert receipt['receiver_basis'] is None assert any('basis' in f for f in receipt['findings'])