bootstrap_inputs.py (2307B)
1 """Explicit, relocatable bootstrap executables; no previous-store discovery. 2 3 The caller selects/trusts the kit manifest (normally through the repository or 4 release identity). These checks bind its named artifacts to exact bytes; they do 5 not establish a publisher's identity. Host bundle import validates wire/ABI data. 6 """ 7 import hashlib 8 import json 9 from pathlib import Path 10 import re 11 12 from generation_backend import BACKENDS 13 14 SCHEMA = 'tricu.bootstrap-kit.v1' 15 ROLES = {'compiler': 'rebuilt-compiler.arboricx', 'adapter': 'io-adapter.arboricx'} 16 17 18 def load_kit(directory, backend): 19 """Read and verify both artifacts before any generation output is created. 20 21 Return captured bytes, not paths to reopen after verification. Fixed basenames 22 avoid metadata-controlled path traversal; selected kit directories are trusted. 23 """ 24 directory = Path(directory) 25 raw = (directory / 'bootstrap-kit.json').read_bytes() 26 record = json.loads(raw) 27 if not isinstance(record, dict) or record.get('schema') != SCHEMA: 28 raise ValueError('unsupported bootstrap kit schema') 29 if backend not in BACKENDS or record.get('backend') != backend: 30 raise ValueError('bootstrap kit backend mismatch') 31 expected_exports = {'compiler': BACKENDS[backend][0], 'adapter': 'main'} 32 artifacts = record.get('artifacts') 33 if not isinstance(artifacts, dict) or set(artifacts) != set(ROLES): 34 raise ValueError('bootstrap kit requires exactly compiler and adapter artifacts') 35 payloads = {} 36 for role, filename in ROLES.items(): 37 item = artifacts[role] 38 if not isinstance(item, dict) or item.get('file') != filename: 39 raise ValueError('invalid bootstrap kit filename: ' + role) 40 if item.get('export') != expected_exports[role]: 41 raise ValueError('invalid bootstrap kit export: ' + role) 42 pin = item.get('sha256') 43 if not isinstance(pin, str) or not re.fullmatch(r'[0-9a-f]{64}', pin): 44 raise ValueError('invalid bootstrap kit digest: ' + role) 45 payload = (directory / filename).read_bytes() 46 if hashlib.sha256(payload).hexdigest() != pin: 47 raise ValueError('bootstrap kit digest mismatch: ' + role) 48 payloads[role] = payload 49 return raw, payloads, hashlib.sha256(raw).hexdigest()