Files
kefu/deploy/recognition-audit-20260916/run_protocol_audit.py
T
2026-09-21 10:34:06 +08:00

74 lines
3.1 KiB
Python

"""Isolated protocol regression runner; never contact/send to a live client."""
import contextlib
import json
import os
from pathlib import Path
import socket
import sys
import tempfile
import threading
import time
import unittest
from unittest import mock
TARGET = Path(sys.argv[1])
OUT = Path(__file__).resolve().parent
MODULES = sys.argv[2:] or [
'test_native_protocol_pipeline', 'test_protocol_features',
'test_protocol_cross_machine', 'test_wecom_native_protocol',
'test_protocol_knowledge_integration',
]
os.environ['QT_QPA_PLATFORM'] = 'offscreen'
sys.path.insert(0, str(TARGET))
def blocked(*args, **kwargs):
raise AssertionError('Audit disallows real network and native process access')
internal = threading.local()
original_pair = socket.socketpair
original_connect = socket.socket.connect
def socketpair(*args, **kwargs):
# Windows asyncio needs a private socket pair only for its wakeup pipe.
internal.wakeup = True
try:
return original_pair(*args, **kwargs)
finally:
internal.wakeup = False
def connect(sock, address):
if getattr(internal, 'wakeup', False):
return original_connect(sock, address)
return blocked()
with tempfile.TemporaryDirectory(prefix='protocol-audit-') as folder, contextlib.ExitStack() as stack:
import runtime_paths
stack.enter_context(mock.patch.object(runtime_paths, 'application_data_dir', return_value=Path(folder)))
stack.enter_context(mock.patch.object(socket, 'socketpair', new=socketpair))
stack.enter_context(mock.patch.object(socket.socket, 'connect', new=connect))
stack.enter_context(mock.patch.object(socket.socket, 'connect_ex', side_effect=blocked))
if (TARGET/'wecom_native_sender.py').is_file():
import wecom_native_sender
stack.enter_context(mock.patch.object(wecom_native_sender, 'kernel', side_effect=blocked))
import send_lock
send_lock._MUTEX_NAME = 'Local\\ProtocolAudit_' + str(os.getpid())
import test_support
test_support.local_state_redirect.start()
stack.callback(test_support.local_state_redirect.stop)
test_support.queue_log_redirect.start()
stack.callback(test_support.queue_log_redirect.stop)
suite = unittest.defaultTestLoader.loadTestsFromNames(MODULES)
started = time.monotonic()
suffix = os.environ.get('AUDIT_OUTPUT_TAG') or ('boundary' if 'test_protocol_audit_boundaries' in MODULES else 'baseline')
with (OUT / f'protocol-{suffix}.log').open('w', encoding='utf-8') as log:
result = unittest.TextTestRunner(stream=log, verbosity=2).run(suite)
summary = {'target': str(TARGET), 'modules': MODULES, 'tests': result.testsRun,
'failures': len(result.failures), 'errors': len(result.errors),
'skipped': len(result.skipped), 'seconds': round(time.monotonic()-started, 3),
'success': result.wasSuccessful()}
(OUT / f'protocol-{suffix}.json').write_text(json.dumps(summary, indent=2, ensure_ascii=False), encoding='utf-8')
print(json.dumps(summary, ensure_ascii=False))
for _, details in result.failures + result.errors:
print(details)
raise SystemExit(0 if result.wasSuccessful() else 1)