bootstrap_inputs.py (2840B)
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 SCHEMA_V2 = 'tricu.bootstrap-kit.v2' 16 ROLES = {'compiler': 'rebuilt-compiler.arboricx', 'adapter': 'io-adapter.arboricx'} 17 18 19 def load_kit(directory, backend): 20 """Read and verify both artifacts before any generation output is created. 21 22 Return captured bytes, not paths to reopen after verification. Fixed basenames 23 avoid metadata-controlled path traversal; selected kit directories are trusted. 24 """ 25 directory = Path(directory) 26 raw = (directory / 'bootstrap-kit.json').read_bytes() 27 record = json.loads(raw) 28 if not isinstance(record, dict) or record.get('schema') not in (SCHEMA, SCHEMA_V2): 29 raise ValueError('unsupported bootstrap kit schema') 30 kit_io_version(record) 31 if backend not in BACKENDS or record.get('backend') != backend: 32 raise ValueError('bootstrap kit backend mismatch') 33 expected_exports = {'compiler': BACKENDS[backend][0], 'adapter': 'main'} 34 artifacts = record.get('artifacts') 35 if not isinstance(artifacts, dict) or set(artifacts) != set(ROLES): 36 raise ValueError('bootstrap kit requires exactly compiler and adapter artifacts') 37 payloads = {} 38 for role, filename in ROLES.items(): 39 item = artifacts[role] 40 if not isinstance(item, dict) or item.get('file') != filename: 41 raise ValueError('invalid bootstrap kit filename: ' + role) 42 if item.get('export') != expected_exports[role]: 43 raise ValueError('invalid bootstrap kit export: ' + role) 44 pin = item.get('sha256') 45 if not isinstance(pin, str) or not re.fullmatch(r'[0-9a-f]{64}', pin): 46 raise ValueError('invalid bootstrap kit digest: ' + role) 47 payload = (directory / filename).read_bytes() 48 if hashlib.sha256(payload).hexdigest() != pin: 49 raise ValueError('bootstrap kit digest mismatch: ' + role) 50 payloads[role] = payload 51 return raw, payloads, hashlib.sha256(raw).hexdigest() 52 53 54 def kit_io_version(record): 55 from generation_io import version 56 if record.get('schema') == SCHEMA: 57 if 'io_version' in record and version(record['io_version']) != 1: 58 raise ValueError('v1 bootstrap kits describe IO v1 only') 59 return 1 60 if record.get('schema') != SCHEMA_V2 or 'io_version' not in record: 61 raise ValueError('explicit bootstrap kit IO version required') 62 return version(record['io_version'])