from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer import json from pathlib import Path import sys import threading import unittest sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'scripts')) from alert_audit import AuditTransport class AuditTransportTests(unittest.TestCase): def test_real_http_headers_and_redirect_refusal(self): calls = [] class Handler(BaseHTTPRequestHandler): def log_message(self, *args): pass def do_POST(self): calls.append((self.path, self.headers['Authorization'], self.headers['Idempotency-Key'])) body = json.loads(self.rfile.read(int(self.headers['Content-Length']))) if body['id'] == 'redirect': self.send_response(302) self.send_header('Location', '/credential-leak') self.end_headers() return self.send_response(202) self.end_headers() self.wfile.write(json.dumps({'status': 'accepted', 'reference': 'audit:' + body['id']}).encode()) server = ThreadingHTTPServer(('127.0.0.1', 0), Handler) thread = threading.Thread(target=server.serve_forever) thread.start() try: transport = AuditTransport(f'http://127.0.0.1:{server.server_port}', lambda: 'fixture-credential', allow_internal_http=True) self.assertEqual(transport({'id': 'test'}), (202, {'status': 'accepted', 'reference': 'audit:test'})) self.assertEqual(transport({'id': 'redirect'}), (302, {})) self.assertEqual(calls, [('/v1/events', 'Bearer fixture-credential', 'test'), ('/v1/events', 'Bearer fixture-credential', 'redirect')]) finally: server.shutdown() thread.join() server.server_close() def test_public_cleartext_and_credentialed_origin_refused(self): for origin in ('http://audit.example', 'https://user:password@audit.example', 'https://audit.example/other', 'https://audit.example?next=elsewhere'): with self.assertRaises(ValueError): AuditTransport(origin, lambda: 'fixture', allow_internal_http=True)