import base64 import hmac import json import os import sys import threading from http.server import BaseHTTPRequestHandler, HTTPServer # Embedded Python uses an isolated ._pth and does not add the script directory. # Resolve sibling modules from this service's source, not an old runtime copy. sys.path.insert(0,os.path.dirname(os.path.abspath(__file__))) sys.dont_write_bytecode=True from windows_containment import contain_inspector # Apply limits before loading parsers, OCR libraries or native model workers. # An unavailable Windows boundary fails startup rather than silently weakening it. CONTAINMENT=contain_inspector() if __name__=="__main__" else {"active":False,"kind":"not-service-entrypoint"} # Broker imports no parser, OCR or model library. All untrusted document work # runs under a capability-free Windows AppContainer, with no network permission. MAX_BYTES = 20 * 1024 * 1024 SANDBOX = None SANDBOX_ENV = {} if __name__ == "__main__": if sys.platform != 'win32': raise SystemExit('Production parser isolation requires Windows') from pathlib import Path from windows_appcontainer import AppContainer source = Path(__file__).resolve().parent python_root = Path(sys.executable).resolve().parent # Development and packaged roots are derived from our own installation; # externally configured model paths must already be copied into that tree. installation = source.parent.parent if source.name == 'inspector' and source.parent.name == 'apps' else source.parent semantic_root = installation / ('.runtime/windows/semantic' if source.parent.name == 'apps' else 'semantic') expected_python = installation / ('.runtime/windows/python' if source.parent.name == 'apps' else 'python') if python_root != expected_python.resolve(): raise SystemExit('Parser runtime must reside in the private installed runtime') roots = [source, python_root] if semantic_root.is_dir(): roots.append(semantic_root) for key in ['EMBEDDING_MODEL_DIR', 'EMBEDDING_WORKER_PATH']: value = os.environ.get(key) if value: resolved = Path(value).resolve() if not resolved.is_relative_to(semantic_root.resolve()): raise SystemExit('Model artifacts must reside in the private installed runtime') SANDBOX_ENV[key] = str(resolved) SANDBOX_ENV.update({'SEARCHI_FORCE_CPU':'1', 'GGML_CPU_ONLY':'1', 'GGML_DISABLE_VULKAN':'1'}) SANDBOX = AppContainer(roots) CONTAINMENT['parserIsolation'] = {'active':True, 'kind':'windows-appcontainer-v1', 'networkCapabilities':0, 'privatePipes':True, 'readOnlyRuntime':True} def dispatch(route, request): if SANDBOX is None: raise RuntimeError('Isolated parser unavailable') payload = json.dumps({'route':route, 'data':request['data'], 'policy':request.get('policy',{})}, allow_nan=False).encode('utf-8') code, output = SANDBOX.run(sys.executable, [str(Path(__file__).with_name('sandbox_worker.py'))], payload, environment=SANDBOX_ENV, timeout=29, max_output=8*1024*1024) if code: raise RuntimeError('Isolated parser failed') result = json.loads(output) if not isinstance(result, dict): raise RuntimeError('Isolated parser response invalid') if route in ['/inspect','/scan-download']: if result.get('decision') not in ['allow','block'] or not isinstance(result.get('coverage',{}).get('complete'),bool): raise RuntimeError('Isolated parser decision invalid') if result['decision']=='allow' and not result['coverage']['complete']: raise RuntimeError('Incomplete parser coverage cannot release content') from stage_timings import enabled, validated diagnostic = result.pop('_diagnosticStages', None) if enabled(request.get('policy', {})): diagnostic = validated(diagnostic) if diagnostic is not None: result['_diagnosticStages'] = diagnostic return result TOKEN=os.environ.get("INSPECTOR_TOKEN", "") if len(TOKEN)<32: raise SystemExit("INSPECTOR_TOKEN must contain at least 32 characters") LOCK=threading.Lock() def watch_parent(): parent=os.environ.get('INSPECTOR_PARENT_PID') if not parent or sys.platform!='win32': return import ctypes kernel=ctypes.WinDLL('kernel32',use_last_error=True) kernel.OpenProcess.argtypes=[ctypes.c_uint32,ctypes.c_int,ctypes.c_uint32] kernel.OpenProcess.restype=ctypes.c_void_p kernel.WaitForSingleObject.argtypes=[ctypes.c_void_p,ctypes.c_uint32] handle=kernel.OpenProcess(0x00100000,False,int(parent)) if not handle: os._exit(0) while kernel.WaitForSingleObject(handle,1000)==258: pass os._exit(0) class Handler(BaseHTTPRequestHandler): def log_message(self, *_args): pass def do_POST(self): if not hmac.compare_digest(self.headers.get("Authorization", ""), "Bearer "+TOKEN): return self.reply(401,{"error":"Inspector authentication required"}) request=None;data=None try: length=int(self.headers.get("Content-Length", "0")) if length<=0 or length>MAX_BYTES*2: return self.reply(413,{"error":"Inspection request too large"}) self.connection.settimeout(30) request=json.loads(self.rfile.read(length)) data=base64.b64decode(request["data"],validate=True) if len(data)>MAX_BYTES: return self.reply(413,{"error":"Content too large"}) with LOCK: if self.path not in ['/inspect','/scan-download','/reference-document','/embed']: return self.reply(404,{"error":"Not found"}) result=dispatch(self.path,request) return self.reply(200,result) except Exception: return self.reply(422,{"error":"Content inspection failed"}) finally: if isinstance(request,dict): request.clear() data=None def reply(self,status,data): body=json.dumps(data,allow_nan=False).encode();self.send_response(status);self.send_header("Content-Type","application/json");self.send_header("Content-Length",str(len(body)));self.send_header("Cache-Control","no-store");self.end_headers();self.wfile.write(body) if __name__=="__main__": threading.Thread(target=watch_parent,daemon=True).start() server=HTTPServer(("127.0.0.1",int(os.environ.get("INSPECTOR_PORT","4311"))),Handler) server.timeout=30 print(json.dumps({"port":server.server_address[1],"containment":CONTAINMENT}),flush=True) server.serve_forever()