2026-10-13 10:33:31 +02:00
"""Build a pinned private Windows x64 inspector runtime; no machine-wide install."""
import hashlib
2026-10-14 10:12:34 +02:00
import argparse
2026-10-13 10:33:31 +02:00
import json
import shutil
import subprocess
import sys
import urllib.request
import zipfile
from pathlib import Path
if sys . platform != 'win32' : raise SystemExit ( 'Windows runtime provisioning runs on Windows only' )
2026-10-14 10:12:34 +02:00
parser = argparse . ArgumentParser ( description = __doc__ )
parser . add_argument ( '--verify-existing' , action = 'store_true' , help = 'Verify exact installed locks/wheel before updating manifest; no dependency reinstall' )
arguments = parser . parse_args ()
2026-10-13 10:33:31 +02:00
VERSION = '3.13.16'
CHECKSUM = '97dae5274cc54867065e8d5a3226e48c35017ed332a0fdb0e27d5b5821961297'
root = Path . cwd () . resolve ()
directory = root / '.runtime' / 'windows' / 'python'
directory . mkdir ( parents = True , exist_ok = True )
requirements = root / 'apps' / 'inspector' / 'requirements.lock.txt'
2026-10-13 16:58:15 +02:00
macro_requirements = root / 'apps' / 'inspector' / 'requirements-macros.lock.txt'
2026-10-14 10:12:34 +02:00
pdf_requirements = root / 'apps' / 'inspector' / 'requirements-pdf.lock.txt'
requirements_hash = hashlib . sha256 ( requirements . read_bytes () + macro_requirements . read_bytes () + pdf_requirements . read_bytes ()) . hexdigest ()
2026-10-13 10:33:31 +02:00
manifest = directory / 'safetynet-runtime.json'
expected = { 'python' : VERSION , 'architecture' : 'amd64' , 'sha256' : CHECKSUM , 'requirementsHash' : requirements_hash }
2026-10-13 16:58:15 +02:00
previous = json . loads ( manifest . read_text ()) if manifest . exists () else {}
2026-10-14 10:12:34 +02:00
pdf_wheel = directory . parent / 'pypdfium2-5.14.0-py3-none-win_amd64.whl'
pdf_checksum = '149fd5c6397b8df8bf7911a93506eff0be874f877afe7ac936cf5d37d21a6a06'
if not arguments . verify_existing and not pdf_wheel . exists ():
# Retain the reviewed wheel for independent verification on fresh builds.
# Verification mode remains offline and never repairs a missing archive.
subprocess . run ([ sys . executable , '-m' , 'pip' , 'download' , '--dest' , str ( directory . parent ),
'--platform' , 'win_amd64' , '--python-version' , '3.13' , '--implementation' , 'cp' , '--abi' , 'cp313' ,
'--only-binary=:all:' , '--no-deps' , '--require-hashes' , '-r' , str ( pdf_requirements )], check = True )
if not pdf_wheel . is_file () or hashlib . sha256 ( pdf_wheel . read_bytes ()) . hexdigest () != pdf_checksum :
raise SystemExit ( 'Retained PDF renderer wheel missing or checksum mismatch' )
if arguments . verify_existing :
if any ( previous . get ( k ) != expected [ k ] for k in ( 'python' , 'architecture' , 'sha256' )):
raise SystemExit ( 'Existing private runtime identity mismatch' )
subprocess . run ([ str ( directory / 'python.exe' ), str ( root / 'scripts/verify-python-dependencies.py' )], check = True )
if previous != expected and not arguments . verify_existing :
2026-10-13 10:33:31 +02:00
archive = directory . parent / f 'python- { VERSION } -embed-amd64.zip'
if not archive . exists () or hashlib . sha256 ( archive . read_bytes ()) . hexdigest () != CHECKSUM :
with urllib . request . urlopen ( f 'https://www.python.org/ftp/python/ { VERSION } /python- { VERSION } -embed-amd64.zip' , timeout = 60 ) as response :
payload = response . read ( 20 * 1024 * 1024 )
if hashlib . sha256 ( payload ) . hexdigest () != CHECKSUM : raise SystemExit ( 'Python runtime checksum mismatch' )
archive . write_bytes ( payload )
2026-10-13 16:58:15 +02:00
if not ( directory / 'python.exe' ) . exists () or any ( previous . get ( k ) != expected [ k ] for k in ( 'python' , 'architecture' , 'sha256' )):
with zipfile . ZipFile ( archive ) as package :
for entry in package . infolist ():
target = ( directory / entry . filename ) . resolve ()
if not target . is_relative_to ( directory ): raise SystemExit ( 'Runtime archive path rejected' )
if not entry . is_dir ():
target . parent . mkdir ( parents = True , exist_ok = True )
target . write_bytes ( package . read ( entry ))
2026-10-13 10:33:31 +02:00
( directory / 'python313._pth' ) . write_text ( 'python313.zip \n . \n Lib/site-packages \n ../inspector \n import site \n ' )
subprocess . run ([ sys . executable , '-m' , 'pip' , 'install' , '--target' , str ( directory / 'Lib' / 'site-packages' ),
'--platform' , 'win_amd64' , '--python-version' , '3.13' , '--implementation' , 'cp' , '--abi' , 'cp313' ,
'--only-binary=:all:' , '--require-hashes' , '--upgrade' , '-r' , str ( requirements )], check = True )
2026-10-13 16:58:15 +02:00
subprocess . run ([ sys . executable , '-m' , 'pip' , 'install' , '--target' , str ( directory / 'Lib' / 'site-packages' ),
'--platform' , 'win_amd64' , '--python-version' , '3.13' , '--implementation' , 'cp' , '--abi' , 'cp313' ,
'--only-binary=:all:' , '--no-deps' , '--require-hashes' , '--upgrade' , '-r' , str ( macro_requirements )], check = True )
2026-10-14 10:12:34 +02:00
subprocess . run ([ sys . executable , '-m' , 'pip' , 'install' , '--target' , str ( directory / 'Lib' / 'site-packages' ),
'--platform' , 'win_amd64' , '--python-version' , '3.13' , '--implementation' , 'cp' , '--abi' , 'cp313' ,
'--only-binary=:all:' , '--no-deps' , '--require-hashes' , '--upgrade' , '-r' , str ( pdf_requirements )], check = True )
2026-10-13 10:33:31 +02:00
manifest . write_text ( json . dumps ( expected , indent = 2 ))
inspector = directory . parent / 'inspector'
inspector . mkdir ( exist_ok = True )
2026-10-14 10:12:34 +02:00
for name in [ 'stage_timings.py' , 'pdf_documents.py' , 'office_content.py' , 'office_macros.py' , 'engine.py' , 'server.py' , 'semantic.py' , 'windows_containment.py' , 'windows_appcontainer.py' , 'sandbox_worker.py' , 'provision_runtime_acl.py' ]:
2026-10-13 10:33:31 +02:00
shutil . copyfile ( root / 'apps' / 'inspector' / name , inspector / name )
subprocess . run ([ str ( directory / 'python.exe' ), '-c' , 'import pypdf, PIL, defusedxml, yara, engine; assert engine.inspect_content(b"public", {"dlp":{"maxBytes":1024,"rules":[],"semantic":{"enabled":False}}})["decision"] == "allow"; assert yara.compile(source="rule test { condition: true }").match(data=b"test"); engine.local_ocr(); print("Bundled Windows inspector, YARA and offline ONNX OCR runtime verified.")' ], check = True )
subprocess . run ([ str ( directory / 'python.exe' ), str ( root / 'apps/inspector/provision_runtime_acl.py' ), '--provision' ], check = True )
2026-10-14 10:12:34 +02:00
if arguments . verify_existing :
manifest . write_text ( json . dumps ( expected , indent = 2 ))