Inspect static PDF and OOXML content with bounded local coverage
This commit is contained in:
1 parent
69d820e315
commit
9e7cb57093
14 files changed
+758
-51
No files matched your search
@@ -1,5 +1,6 @@
|
||||
"""Build a pinned private Windows x64 inspector runtime; no machine-wide install."""
|
||||
import hashlib
|
||||
import argparse
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -9,6 +10,9 @@ import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
if sys.platform!='win32': raise SystemExit('Windows runtime provisioning runs on Windows only')
|
||||
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()
|
||||
VERSION='3.13.16'
|
||||
CHECKSUM='97dae5274cc54867065e8d5a3226e48c35017ed332a0fdb0e27d5b5821961297'
|
||||
root=Path.cwd().resolve()
|
||||
@@ -16,11 +20,26 @@ directory=root/'.runtime'/'windows'/'python'
|
||||
directory.mkdir(parents=True,exist_ok=True)
|
||||
requirements=root/'apps'/'inspector'/'requirements.lock.txt'
|
||||
macro_requirements=root/'apps'/'inspector'/'requirements-macros.lock.txt'
|
||||
requirements_hash=hashlib.sha256(requirements.read_bytes()+macro_requirements.read_bytes()).hexdigest()
|
||||
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()
|
||||
manifest=directory/'safetynet-runtime.json'
|
||||
expected={'python':VERSION,'architecture':'amd64','sha256':CHECKSUM,'requirementsHash':requirements_hash}
|
||||
previous=json.loads(manifest.read_text()) if manifest.exists() else {}
|
||||
if previous!=expected:
|
||||
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:
|
||||
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:
|
||||
@@ -42,10 +61,15 @@ if previous!=expected:
|
||||
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)
|
||||
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)
|
||||
manifest.write_text(json.dumps(expected,indent=2))
|
||||
inspector=directory.parent/'inspector'
|
||||
inspector.mkdir(exist_ok=True)
|
||||
for name in ['stage_timings.py','office_macros.py','engine.py','server.py','semantic.py','windows_containment.py','windows_appcontainer.py','sandbox_worker.py','provision_runtime_acl.py']:
|
||||
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']:
|
||||
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)
|
||||
if arguments.verify_existing:
|
||||
manifest.write_text(json.dumps(expected,indent=2))
|
||||
@@ -0,0 +1,65 @@
|
||||
"""Read-only verification of this exact private runtime's pinned distributions.
|
||||
|
||||
Installed RECORD checks detect inconsistent installation; only the PDFium wheel
|
||||
comparison below supplies independent pinned artifact provenance. Neither is an
|
||||
independent attestation of all base package wheels beyond prior provisioning.
|
||||
"""
|
||||
import base64
|
||||
import hashlib
|
||||
import importlib.metadata
|
||||
import re
|
||||
import sys
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
|
||||
root = Path(__file__).resolve().parent.parent
|
||||
runtime = root / '.runtime/windows/python'
|
||||
site = runtime / 'Lib/site-packages'
|
||||
if Path(sys.executable).resolve().parent != runtime.resolve():
|
||||
raise SystemExit('Use the exact private Windows Python runtime')
|
||||
|
||||
names = []
|
||||
checked = 0
|
||||
def file_hash(path):
|
||||
digest = hashlib.sha256()
|
||||
with path.open('rb') as file:
|
||||
for chunk in iter(lambda: file.read(1048576), b''): digest.update(chunk)
|
||||
return digest.digest()
|
||||
|
||||
for filename in ('requirements.lock.txt', 'requirements-macros.lock.txt', 'requirements-pdf.lock.txt'):
|
||||
for line in (root / 'apps/inspector' / filename).read_text(encoding='utf-8').splitlines():
|
||||
if not line or line.startswith('#'): continue
|
||||
match = re.match(r'^([A-Za-z0-9_.-]+)==([^\s]+)\s+--hash=sha256:', line)
|
||||
if not match: raise SystemExit('Runtime dependency lock rejected')
|
||||
name, version = match.groups()
|
||||
distribution = importlib.metadata.distribution(name)
|
||||
if distribution.version != version: raise SystemExit('Runtime dependency version mismatch')
|
||||
names.append(name)
|
||||
for entry in distribution.files or []:
|
||||
if entry.hash is None: continue
|
||||
path = distribution.locate_file(entry).resolve()
|
||||
if not path.is_relative_to(runtime.resolve()) or not path.is_file(): raise SystemExit('Runtime dependency file missing')
|
||||
if entry.hash.mode != 'sha256': raise SystemExit('Runtime dependency hash algorithm rejected')
|
||||
actual = base64.urlsafe_b64encode(file_hash(path)).decode().rstrip('=')
|
||||
if actual != entry.hash.value: raise SystemExit('Runtime dependency file integrity mismatch')
|
||||
checked += 1
|
||||
|
||||
wheel = root / '.runtime/windows/pypdfium2-5.14.0-py3-none-win_amd64.whl'
|
||||
expected = '149fd5c6397b8df8bf7911a93506eff0be874f877afe7ac936cf5d37d21a6a06'
|
||||
if not wheel.is_file() or hashlib.sha256(wheel.read_bytes()).hexdigest() != expected:
|
||||
raise SystemExit('Pinned PDFium wheel verification failed')
|
||||
pdf_files = 0
|
||||
with zipfile.ZipFile(wheel) as archive:
|
||||
for entry in archive.infolist():
|
||||
if entry.is_dir() or entry.filename.endswith('.dist-info/RECORD'): continue
|
||||
target = (site / entry.filename).resolve()
|
||||
if not target.is_relative_to(site.resolve()) or not target.is_file() or target.read_bytes() != archive.read(entry):
|
||||
raise SystemExit('Installed PDFium differs from pinned wheel')
|
||||
pdf_files += 1
|
||||
import pypdfium2
|
||||
if pypdfium2.PYPDFIUM_INFO.api_tag != (5, 14, 0) or pypdfium2.PDFIUM_INFO.flags:
|
||||
raise SystemExit('PDFium feature manifest rejected')
|
||||
licenses = site / 'pypdfium2-5.14.0.dist-info/licenses'
|
||||
if not (licenses / 'LICENSES/Apache-2.0.txt').is_file() or not (licenses / 'LICENSES/BSD-3-Clause.txt').is_file() or not any((licenses / 'data/windows_x64/BUILD_LICENSES').glob('*')):
|
||||
raise SystemExit('PDFium license notices missing')
|
||||
print(f'Private runtime verified: {len(names)} pinned distributions, {checked} RECORD hashes, {pdf_files} pinned PDFium wheel files; license notices retained.')
|
||||
Reference in new issue
Block a user