459 lines
29 KiB
Python
459 lines
29 KiB
Python
"""Prepare/check a same-source native stage; launch only on explicit launch command.
|
|
|
|
No compiler or application is run by check/stage. Config contains pins to actual
|
|
receipts, never configurable success predicates. Parent reviews the final config.
|
|
"""
|
|
from pathlib import Path
|
|
from datetime import datetime, timezone
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import os
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
|
|
ROOT = Path(__file__).resolve().parent.parent
|
|
TRIAL = ROOT / '.local/native-qa/navigation-palette-20260913-01'
|
|
RUNTIME = 'aa282fa47bb2c4e210cea5e470cdbdca58568f0be0bc73e404d86ab9cd95ef6a'
|
|
SCOPES = ['Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml', '.cargo', 'build',
|
|
'crates', 'assets', 'docs', 'examples', 'harness/fixtures']
|
|
PREFIX = ['cargo', 'test', '--locked', '-p', 'oa-desktop', '--bin', 'arcadia-studio']
|
|
|
|
|
|
def require(condition, message):
|
|
if not condition:
|
|
raise ValueError(message)
|
|
|
|
|
|
def now():
|
|
return datetime.now(timezone.utc).isoformat()
|
|
|
|
|
|
def identity(raw):
|
|
return {'bytes': len(raw), 'sha256': hashlib.sha256(raw).hexdigest()}
|
|
|
|
|
|
def rooted(name):
|
|
require(isinstance(name, str) and name, 'Pending/missing path')
|
|
path = Path(name)
|
|
if not path.is_absolute():
|
|
path = ROOT / path
|
|
resolved = path.resolve()
|
|
require(resolved.is_relative_to(ROOT), 'Evidence/output must stay in this checkout: ' + name)
|
|
current = path.absolute()
|
|
while current != ROOT and current.is_relative_to(ROOT):
|
|
require(not current.is_symlink() and not current.is_junction(), 'Reparse evidence path: ' + str(current))
|
|
current = current.parent
|
|
return resolved
|
|
|
|
|
|
def write_new(path, raw):
|
|
with path.open('xb') as stream:
|
|
stream.write(raw)
|
|
|
|
|
|
def save(path, value):
|
|
write_new(path, (json.dumps(value, indent=2) + '\n').encode('utf-8'))
|
|
|
|
|
|
def command(record):
|
|
result = list(record['command'])
|
|
require(result, 'Empty recorded command')
|
|
result[0] = Path(result[0]).name.casefold().removesuffix('.exe')
|
|
return result
|
|
|
|
|
|
def preflight(config_path, source):
|
|
require(re.fullmatch('[0-9a-f]{40}', source), 'Exact final source SHA required')
|
|
config_path = rooted(str(config_path))
|
|
config_raw = config_path.read_bytes()
|
|
cfg = json.loads(config_raw)
|
|
require(cfg['schema'] == 1 and cfg['source'] == source, 'Pending or different configured source')
|
|
stage = rooted(cfg['stage'])
|
|
require(stage.is_relative_to(ROOT / '.local/native-qa') and not stage.is_relative_to(TRIAL)
|
|
and not TRIAL.is_relative_to(stage), 'Use a separate new stage under .local/native-qa')
|
|
pins = {}
|
|
|
|
def pin(item):
|
|
require(isinstance(item, dict) and isinstance(item.get('bytes'), int)
|
|
and re.fullmatch('[0-9a-f]{64}', item.get('sha256') or ''), 'Pending/invalid evidence pin')
|
|
path = rooted(item['path'])
|
|
raw = path.read_bytes()
|
|
require(identity(raw) == {key: item[key] for key in ('bytes', 'sha256')}, 'Changed evidence: ' + str(path))
|
|
pins[str(path)] = identity(raw)
|
|
return raw
|
|
|
|
def document(item):
|
|
return json.loads(pin(item))
|
|
|
|
# Require exact complete raw committed build/gate membership, not clean status alone.
|
|
manifests = []
|
|
gates = {}
|
|
for mode in ('listing', 'focused', 'scroll', 'full', 'strict'):
|
|
spec = cfg['gates'][mode]
|
|
record = document(spec['result'])
|
|
inputs = document(spec['inputs'])
|
|
log = pin(spec['log']).decode('utf-8', errors='strict')
|
|
require(record['source'] == record['head_after'] == inputs['source'] == source
|
|
and record['exit'] == 0 and record['changed_inputs'] == [], 'Gate did not pass unchanged at final source: ' + mode)
|
|
require(rooted(spec['inputs']['path']) == rooted(spec['result']['path']).parent / record['inputs'], 'Gate input-manifest path mismatch')
|
|
manifests.append((inputs['inputs'], SCOPES))
|
|
wanted = {
|
|
'listing': PREFIX + ['--', '--list'],
|
|
'focused': PREFIX + ['navigation_union', '--', '--test-threads=1'],
|
|
'scroll': PREFIX + ['preview_scroll_tests', '--', '--test-threads=1'],
|
|
'full': PREFIX + ['--', '--test-threads=1'],
|
|
'strict': ['cargo', 'clippy', '--locked', '-p', 'oa-desktop', '--all-targets', '--', '-D', 'warnings'],
|
|
}[mode]
|
|
require(command(record) == wanted, 'Unexpected actual gate command: ' + mode)
|
|
if mode != 'strict':
|
|
require(len(record['artifacts']) == 1, 'Gate requires its actual test executable')
|
|
pin(record['artifacts'][0])
|
|
gates[mode] = (spec, record, log)
|
|
listing = gates['listing'][1]
|
|
names = re.findall(r'^([^\r\n]+): test\r?$', gates['listing'][2], re.M)
|
|
require(names and len(names) == len(set(names)) and names == listing['listing_members']
|
|
and len(names) == listing['listing_count'], 'Exact actual listing mismatch')
|
|
require(re.findall(r'^(\d+) tests, (\d+) benchmarks\s*$', gates['listing'][2], re.M)
|
|
== [(str(len(names)), '0')], 'Listing summary mismatch')
|
|
required = document(cfg['required_names'])['groups']
|
|
for key, count in [('navigation_union', 17), ('preview_scroll_tests', 4)]:
|
|
selected = {name for name in names if key in name}
|
|
require(len(selected) == count and selected == set(required[key])
|
|
and len(required[key]) == count, 'Required exact membership mismatch: ' + key)
|
|
required_all = set()
|
|
for key, members in required.items():
|
|
require(len(members) == len(set(members)) and set(members).issubset(names), 'Unlisted/duplicate required tests: ' + key)
|
|
required_all.update(members)
|
|
for mode in ('listing', 'focused', 'scroll'):
|
|
spec, record, log = gates[mode]
|
|
admitted = document(spec['admission'])
|
|
require(admitted['source'] == source and admitted['mode'] == ('list' if mode == 'listing' else 'focused')
|
|
and admitted['result_sha256'] == spec['result']['sha256']
|
|
and admitted['log_sha256'] == spec['log']['sha256']
|
|
and admitted['inputs_sha256'] == spec['inputs']['sha256']
|
|
and admitted['required_names_sha256'] == cfg['required_names']['sha256']
|
|
and admitted['artifact'] == record['artifacts'][0] == listing['artifacts'][0], 'Admission does not bind actual gate: ' + mode)
|
|
if mode != 'listing':
|
|
selector = 'navigation_union' if mode == 'focused' else 'preview_scroll_tests'
|
|
actual = re.findall(r'^test ([^\r\n]+) \.\.\. ok\s*$', log, re.M)
|
|
require(len(actual) == len(set(actual)) and set(actual) == set(required[selector]), 'Focused executed membership differs')
|
|
require(re.findall(r'test result: ok\. (\d+) passed; (\d+) failed; (\d+) ignored;', log)
|
|
== [(str(len(actual)), '0', '0')], 'Focused summary differs')
|
|
full = gates['full']
|
|
require(full[1]['artifacts'][0] == listing['artifacts'][0], 'Full/list test executable differs')
|
|
full_cases = re.findall(r'^test ([^\r\n]+) \.\.\. (ok|ignored)(?:, [^\r\n]*)?\s*$', full[2], re.M)
|
|
require(len(full_cases) == len(names) and len({name for name, _ in full_cases}) == len(names)
|
|
and {name for name, _ in full_cases} == set(names), 'Full executed membership differs from listing')
|
|
ignored = {name for name, status in full_cases if status == 'ignored'}
|
|
require(isinstance(cfg['approved_full_ignored'], list) and ignored == set(cfg['approved_full_ignored'])
|
|
and not (ignored & required_all), 'Unapproved ignored/full required test')
|
|
require(re.findall(r'test result: ok\. (\d+) passed; (\d+) failed; (\d+) ignored;', full[2])
|
|
== [(str(len(names) - len(ignored)), '0', str(len(ignored)))], 'Full summary differs')
|
|
|
|
build_cfg = cfg['build']
|
|
build = document(build_cfg['result'])
|
|
build_inputs = document(build_cfg['inputs'])
|
|
environment = document(build_cfg['environment'])
|
|
cargo_raw = pin(build_cfg['stdout'])
|
|
pin(build_cfg['stderr'])
|
|
require(build['source'] == build['head_after'] == build_inputs['source'] == source
|
|
and build['outcome'] == 'passed' and build['exit'] == 0 and build['failure'] is None
|
|
and build['changed_inputs'] == [] and build['status_after'] == '', 'Both-artifact build not completed unchanged')
|
|
require(command(build) == ['cargo', 'build', '--locked', '--offline', '-p', 'oa-desktop', '-p', 'oa-server', '--bins', '--message-format=json-render-diagnostics'], 'Wrong artifact build command')
|
|
for key in ('inputs', 'environment', 'stdout', 'stderr'):
|
|
require(build[key] == {field: build_cfg[key][field] for field in ('bytes', 'sha256')}, 'Build receipt/log binding differs: ' + key)
|
|
require('host: x86_64-pc-windows-gnullvm' in environment['tools']['rustc']['version'], 'Wrong recorded Rust host')
|
|
manifests.append((build_inputs['inputs'], SCOPES + ['scripts']))
|
|
messages = [json.loads(line) for line in cargo_raw.splitlines()]
|
|
require([m for m in messages if m.get('reason') == 'build-finished'] == [{'reason': 'build-finished', 'success': True}], 'Actual Cargo finish not unique/successful')
|
|
selected = [m for m in messages if m.get('reason') == 'compiler-artifact' and m.get('executable')
|
|
and m.get('target', {}).get('name') in ('arcadia-studio', 'arcadia-server') and m['target']['kind'] == ['bin']]
|
|
require(len(selected) == len(build['artifacts']) == 2, 'Two actual preserved binary records required')
|
|
payloads = {}
|
|
for artifact in build['artifacts']:
|
|
name = artifact['name']
|
|
require(name in ('arcadia-studio', 'arcadia-server') and name + '.exe' not in payloads, 'Duplicate/wrong artifact')
|
|
require(artifact['cargo_artifact'] in selected, 'Preserved artifact not emitted by Cargo')
|
|
profile = artifact['cargo_artifact']['profile']
|
|
require(profile['opt_level'] == '0' and profile['debug_assertions'] and not profile['test'], 'Expected actual development profile')
|
|
require(rooted(artifact['cargo_artifact']['executable']) == rooted(artifact['origin']), 'Cargo artifact origin mismatch')
|
|
item = {'path': artifact['preserved'], **{key: artifact[key] for key in ('bytes', 'sha256')}}
|
|
raw = pin(item)
|
|
require(raw[:2] == b'MZ' and len(raw) >= 64, 'Not PE executable')
|
|
pe = int.from_bytes(raw[60:64], 'little')
|
|
require(raw[pe:pe+4] == b'PE\0\0' and int.from_bytes(raw[pe+4:pe+6], 'little') == 0x8664, 'Not Windows x64 PE')
|
|
payloads[name + '.exe'] = item
|
|
require(cfg['runtime']['sha256'] == RUNTIME, 'Only the reviewed September runtime is admitted')
|
|
pin(cfg['runtime'])
|
|
payloads['libunwind.dll'] = cfg['runtime']
|
|
|
|
all_inputs = {}
|
|
for rows, scopes in manifests:
|
|
expected = subprocess.check_output(['git', 'ls-tree', '-r', '--name-only', source, *scopes], cwd=ROOT).decode().splitlines()
|
|
require(len(rows) == len(expected) and {row['path'] for row in rows} == set(expected), 'Incomplete committed input membership')
|
|
for row in rows:
|
|
if row['path'] in all_inputs:
|
|
require(all_inputs[row['path']] == row, 'Gate/build input identity differs')
|
|
all_inputs[row['path']] = row
|
|
ordered = sorted(all_inputs)
|
|
blobs = subprocess.check_output(['git', 'cat-file', '--batch'], cwd=ROOT,
|
|
input=''.join(source + ':' + path + '\n' for path in ordered).encode())
|
|
offset = 0
|
|
for path in ordered:
|
|
end = blobs.index(b'\n', offset)
|
|
_, kind, size = blobs[offset:end].split()
|
|
require(kind == b'blob', 'Missing committed blob')
|
|
size = int(size)
|
|
raw = blobs[end+1:end+1+size]
|
|
require(blobs[end+1+size:end+2+size] == b'\n', 'Bad Git blob framing')
|
|
offset = end+2+size
|
|
require(identity(raw) == {key: all_inputs[path][key] for key in ('bytes', 'sha256')}, 'Raw Git input mismatch: ' + path)
|
|
require(pin(all_inputs[path]) == raw, 'Current input differs: ' + path)
|
|
if path.startswith(('docs/', 'examples/')):
|
|
payloads[path] = all_inputs[path]
|
|
require(offset == len(blobs), 'Extra Git response')
|
|
|
|
oracle = cfg['oracle']
|
|
oracle_build = document(oracle['build'])
|
|
oracle_source = oracle['build_source']
|
|
require(re.fullmatch('[0-9a-f]{40}', oracle_source or '')
|
|
and oracle_build['source'] == oracle_build['head_after'] == oracle_source
|
|
and oracle_build['exit'] == 0 and oracle_build['outcome'] == 'passed'
|
|
and oracle_build['failure'] is None and oracle_build['changed_inputs'] == []
|
|
and oracle_build['status_after'] == '', 'Oracle build did not pass unchanged at its declared source')
|
|
build_dir = rooted(oracle['build']['path']).parent
|
|
for name in ('stdout', 'stderr'):
|
|
pin({'path': str(build_dir / (name + '.log')), **oracle_build[name]})
|
|
captured = {rooted(path): item for path, item in oracle_build['inputs_before'].items()}
|
|
require(len(captured) == len(oracle_build['inputs_before']), 'Duplicate captured oracle input')
|
|
build_launcher = rooted(oracle['build_launcher']['path'])
|
|
pin(oracle['build_launcher'])
|
|
require(captured[build_launcher] == oracle_build['launcher']
|
|
== {key: oracle['build_launcher'][key] for key in ('bytes', 'sha256')}, 'Oracle build launcher differs')
|
|
pin(oracle['source'])
|
|
require(str(rooted(oracle['source']['path'])) in oracle_build['command']
|
|
and captured[rooted(oracle['source']['path'])]
|
|
== {key: oracle['source'][key] for key in ('bytes', 'sha256')}, 'Reviewed oracle source not build-bound')
|
|
require(oracle_build['source_inputs'], 'Missing preserved oracle compilation inputs')
|
|
for item in oracle_build['source_inputs']:
|
|
require(captured[rooted(item['path'])] == {key: item[key] for key in ('bytes', 'sha256')}, 'Preserved source identity differs')
|
|
pin({'path': item['preserved'], **captured[rooted(item['path'])]})
|
|
binary = rooted(oracle['binary']['path'])
|
|
pin(oracle['binary'])
|
|
require(rooted(oracle_build['binary']['path']) == binary and oracle_build['binary']['sha256'] == oracle['binary']['sha256']
|
|
and oracle_build['binary']['bytes'] == oracle['binary']['bytes'], 'Oracle executable not build-bound')
|
|
require(oracle_build['command'][-2:] == ['-o', str(binary)], 'Oracle build output differs')
|
|
# Compare the FINAL test anchor with captured dependency identities. The old
|
|
# desktop test executable/anchor may have been overwritten by a desktop fix.
|
|
anchor = document(oracle['final_anchor'])
|
|
test_exe = rooted(listing['artifacts'][0]['path'])
|
|
suffix = test_exe.stem.removeprefix('arcadia_studio-').removeprefix('arcadia-studio-')
|
|
require(rooted(oracle['final_anchor']['path']) == test_exe.parent.parent / '.fingerprint' / ('oa-desktop-' + suffix) / 'test-bin-arcadia-studio.json', 'Final oracle anchor not admitted test executable fingerprint')
|
|
require(set(oracle['dependencies']) == {'oa_core', 'serde_json'}, 'Exact oracle dependency pair required')
|
|
for name, binding in oracle['dependencies'].items():
|
|
rlib = rooted(binding['rlib']['path'])
|
|
fingerprint_path = rooted(binding['fingerprint']['path'])
|
|
require(fingerprint_path.name == 'lib-' + name and fingerprint_path.parent.parent == test_exe.parent.parent / '.fingerprint'
|
|
and rlib == test_exe.parent / ('lib' + name + '-' + fingerprint_path.parent.name.rsplit('-', 1)[1] + '.rlib'), 'Fingerprint/rlib paths do not correspond')
|
|
fingerprint = pin(binding['fingerprint']).decode().strip()
|
|
pin(binding['rlib'])
|
|
fingerprint_json = rooted(binding['fingerprint_json']['path'])
|
|
require(fingerprint_json == fingerprint_path.with_name(fingerprint_path.name + '.json'), 'Dependency fingerprint JSON path differs')
|
|
pin(binding['fingerprint_json'])
|
|
expected = [row[3] for row in anchor['deps'] if row[1] == name]
|
|
require(expected == [int.from_bytes(bytes.fromhex(fingerprint), 'little')], 'Dependency does not match admitted core fingerprint: ' + name)
|
|
linked = [arg.split('=', 1)[1] for index, arg in enumerate(oracle_build['command'])
|
|
if index and oracle_build['command'][index - 1] == '--extern' and arg.startswith(name + '=')]
|
|
require(len(linked) == 1, 'Oracle command dependency not unique: ' + name)
|
|
old_rlib = rooted(linked[0])
|
|
old_suffix = old_rlib.stem.rsplit('-', 1)[1]
|
|
old_fingerprints = [path for path in captured if path.name == 'lib-' + name and path.parent.name.endswith('-' + old_suffix)]
|
|
require(len(old_fingerprints) == 1, 'Captured dependency fingerprint not unique: ' + name)
|
|
old_fp = old_fingerprints[0]
|
|
for item, old_path in ((binding['rlib'], old_rlib), (binding['fingerprint'], old_fp),
|
|
(binding['fingerprint_json'], old_fp.with_name(old_fp.name + '.json'))):
|
|
require(captured[old_path] == {key: item[key] for key in ('bytes', 'sha256')}, 'Final dependency differs from captured oracle bytes: ' + name)
|
|
|
|
captured_manifests = [path for path in captured if path.name.endswith('.inputs.json')]
|
|
require(len(captured_manifests) == 1, 'Captured oracle listing-input manifest not unique')
|
|
captured_manifest = captured_manifests[0]
|
|
old_inputs = document({'path': str(captured_manifest), **captured[captured_manifest]})
|
|
require(old_inputs['source'] == oracle_source, 'Captured listing source differs from oracle build source')
|
|
|
|
def core_scope(path):
|
|
return path.startswith(('crates/oa-core/', '.cargo/')) or path in ('Cargo.toml', 'Cargo.lock', 'rust-toolchain.toml')
|
|
|
|
scoped_rows = [row for row in old_inputs['inputs'] if core_scope(row['path'])]
|
|
captured_core = {row['path']: {key: row[key] for key in ('bytes', 'sha256')} for row in scoped_rows}
|
|
final_core = {path: {key: row[key] for key in ('bytes', 'sha256')} for path, row in all_inputs.items() if core_scope(path)}
|
|
require(len(captured_core) == len(scoped_rows) and captured_core == final_core,
|
|
'Final complete core/config raw inputs differ from captured oracle scope')
|
|
runtime_launcher = rooted(oracle['run_launcher']['path'])
|
|
pin(oracle['run_launcher'])
|
|
|
|
def oracle_run(spec, arguments):
|
|
run = document(spec['receipt'])
|
|
run_dir = rooted(spec['receipt']['path']).parent
|
|
require(run['source'] == oracle_source and run['exit'] == 0 and run['outcome'] == 'passed'
|
|
and run['failure'] is None and run['changed_inputs'] == [] and run['inputs_unchanged'] is True
|
|
and run['oracle_sha256'] == oracle['binary']['sha256']
|
|
and run['command'] == [str(binary), *arguments], 'Actual oracle run failed/differs')
|
|
require(rooted(run['build']['path']) == rooted(oracle['build']['path'])
|
|
and {key: run['build'][key] for key in ('bytes', 'sha256')}
|
|
== {key: oracle['build'][key] for key in ('bytes', 'sha256')}, 'Run does not bind selected oracle build')
|
|
require(run['launcher'] == {key: oracle['run_launcher'][key] for key in ('bytes', 'sha256')}, 'Run launcher differs')
|
|
for name in ('stdout', 'stderr'):
|
|
require(rooted(run[name]['path']) == run_dir / (name + '.log'), 'Run log location differs')
|
|
pin(run[name])
|
|
verified = document(spec['verified_core_inputs'])
|
|
require(rooted(spec['verified_core_inputs']['path']) == run_dir / 'verified-core-inputs.json'
|
|
and verified == scoped_rows and run['verified_core_inputs'] == len(scoped_rows), 'Run core-input evidence differs')
|
|
watched = {rooted(path): item for path, item in run['inputs_before'].items()}
|
|
expected_paths = {binary, rooted(oracle['build']['path']), captured_manifest}
|
|
runtimes = [path for path in watched if path.name == 'libunwind.dll']
|
|
require(len(runtimes) == 1 and watched[runtimes[0]] == {key: cfg['runtime'][key] for key in ('bytes', 'sha256')}, 'Run runtime differs')
|
|
expected_paths.add(runtimes[0])
|
|
expected_folders = [] if arguments == ['self-check'] else [rooted(arg).parent for arg in arguments[1:3]]
|
|
require([rooted(tree['folder']) for tree in run['input_trees']] == expected_folders, 'Run fixture tree roots differ')
|
|
for tree in run['input_trees']:
|
|
folder = rooted(tree['folder'])
|
|
actual = {path.resolve() for path in folder.rglob('*') if path.is_file()}
|
|
require(len(tree['paths']) == len(actual) and {rooted(path) for path in tree['paths']} == actual, 'Run fixture tree membership changed')
|
|
expected_paths.update(actual)
|
|
require(len(watched) == len(run['inputs_before']) and set(watched) == expected_paths, 'Run watched input membership differs')
|
|
for path, item in watched.items():
|
|
pin({'path': str(path), **item})
|
|
|
|
oracle_run(oracle['self_check'], ['self-check'])
|
|
preparation = document(cfg['fixture_preparation'])
|
|
require(rooted(cfg['fixture_preparation']['path']) == TRIAL / 'preparation.json', 'Original trial preparation required')
|
|
provenance = rooted(preparation['provenance_manifest']['path'])
|
|
provenance_raw = provenance.read_bytes()
|
|
require(identity(provenance_raw)['sha256'] == preparation['provenance_manifest']['sha256'], 'Original fixture archive provenance changed')
|
|
pins[str(provenance)] = identity(provenance_raw)
|
|
prepared_paths = set()
|
|
for row in preparation['files']:
|
|
item = {**row, 'path': str(TRIAL / row['path'])}
|
|
require(pin(item) == rooted(row['source']).read_bytes(), 'Prepared original fixture differs')
|
|
prepared_paths.add(rooted(item['path']))
|
|
migration = document(cfg['migration']['result'])
|
|
intent = document(cfg['migration']['intent'])
|
|
require(migration['status'] == 'PASS' and (migration['from_schema'], migration['to_schema']) == (3, 7)
|
|
and migration['independent_full_project_equal'] is True and migration['current_readmission_exact'] is True
|
|
and migration['originals_preserved'] is True and migration['alias_tokens'] == 6 and migration['alias_files'] == 2,
|
|
'Actual separate fixture migration not admitted')
|
|
require((intent['from_schema'], intent['to_schema']) == (3, 7) and intent['execution_complete'] is False,
|
|
'Preserve the original pending migration intent, not a rewritten success claim')
|
|
require(cfg['fixture_evidence'], 'Pending fixture/migration evidence')
|
|
for item in cfg['fixture_evidence']:
|
|
pin(item)
|
|
require(len(cfg['fixture_pairs']) >= 3, 'Prepared fixture admissions missing')
|
|
covered, pairs = set(), set()
|
|
for pair in cfg['fixture_pairs']:
|
|
require(pair['files'], 'Empty fixture pair inventory')
|
|
inventory_paths = set()
|
|
for item in pair['files']:
|
|
path = rooted(item['path'])
|
|
require(path.is_relative_to(TRIAL), 'Fixture outside trial')
|
|
pin(item)
|
|
inventory_paths.add(path)
|
|
baseline, work = rooted(pair['baseline_entry']), rooted(pair['work_entry'])
|
|
require(baseline in inventory_paths and work in inventory_paths and baseline != work, 'Pair entries not distinct inventoried fixtures')
|
|
# Require complete directory membership, not just a declared subset.
|
|
actual_paths = {p.resolve() for directory in (baseline.parent, work.parent) for p in directory.rglob('*') if p.is_file()}
|
|
require(actual_paths == inventory_paths, 'Fixture pair has unlisted/missing files')
|
|
require((baseline, work) not in pairs, 'Duplicate fixture admission')
|
|
pairs.add((baseline, work))
|
|
covered.update(inventory_paths)
|
|
oracle_run(pair['admission'], ['same', str(baseline), str(work)])
|
|
require(prepared_paths.issubset(covered), 'An original prepared fixture has no current-core admission')
|
|
migrated_base = rooted(cfg['migration']['baseline_entry'])
|
|
require(any(base == migrated_base for base, _ in pairs), 'Migrated source-project baseline lacks current-core admission')
|
|
return cfg, stage, payloads, {'source': source, 'config_path': str(config_path), 'config': identity(config_raw),
|
|
'helper': identity(Path(__file__).read_bytes()), 'evidence': pins,
|
|
'oracle_source': oracle_source, 'oracle_binary': oracle['binary'], 'oracle_core_inputs': len(captured_core),
|
|
'listing_count': len(names), 'full_passed': len(names) - len(ignored), 'full_ignored': sorted(ignored),
|
|
'profile': 'unoptimized development', 'scope': 'Identified native stage admission only; native acceptance pending'}
|
|
|
|
|
|
def stage_map(stage):
|
|
result = {}
|
|
for path in stage.rglob('*'):
|
|
require(not path.is_symlink() and not path.is_junction(), 'Reparse stage input')
|
|
if path.is_file() and path != stage / 'manifest.json':
|
|
result[path.relative_to(stage).as_posix()] = identity(path.read_bytes())
|
|
return result
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument('mode', choices=('check', 'stage', 'launch'))
|
|
parser.add_argument('config', type=Path)
|
|
parser.add_argument('source')
|
|
args = parser.parse_args()
|
|
cfg, stage, payloads, attestation = preflight(args.config.resolve(), args.source)
|
|
if args.mode == 'check':
|
|
print(json.dumps({'evidence_admitted': True, 'ready_for_stage': not stage.exists(), **attestation}, indent=2))
|
|
return
|
|
if args.mode == 'stage':
|
|
stage.mkdir(exist_ok=False)
|
|
for name, item in payloads.items():
|
|
path = stage / name
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
raw = rooted(item['path']).read_bytes()
|
|
require(identity(raw) == {key: item[key] for key in ('bytes', 'sha256')}, 'Input changed during staging')
|
|
write_new(path, raw)
|
|
copied = stage_map(stage)
|
|
require(copied == {name: {key: item[key] for key in ('bytes', 'sha256')} for name, item in payloads.items()}, 'Staged copies differ from selected inputs')
|
|
manifest = {**attestation, 'created': now(), 'payloads': copied}
|
|
save(stage / 'manifest.json', manifest)
|
|
print(json.dumps({'stage': str(stage), 'manifest': identity((stage / 'manifest.json').read_bytes())}))
|
|
return
|
|
manifest_raw = (stage / 'manifest.json').read_bytes()
|
|
manifest = json.loads(manifest_raw)
|
|
require(all(manifest[key] == attestation[key] for key in attestation), 'Stage admission/config no longer matches')
|
|
require(stage_map(stage) == manifest['payloads'], 'Stage membership/bytes changed')
|
|
for name in ('launch-request.json', 'launch.json', 'closure.json', 'stdout.log', 'stderr.log', 'supervisor-error.json', 'profile', 'temp', 'working-directory'):
|
|
require(not (TRIAL / name).exists(), 'Trial launch already attempted: ' + name)
|
|
profile, temporary, cwd = TRIAL / 'profile', TRIAL / 'temp', TRIAL / 'working-directory'
|
|
profile.mkdir(); temporary.mkdir(); cwd.mkdir()
|
|
for path in (profile / 'AppData/Local', profile / 'AppData/Roaming'):
|
|
path.mkdir(parents=True)
|
|
windows = Path(os.environ['SystemRoot'])
|
|
env = {key: os.environ[key] for key in ('SystemRoot', 'WINDIR', 'SystemDrive', 'ProgramData', 'ALLUSERSPROFILE', 'PUBLIC', 'COMSPEC', 'PATHEXT', 'NUMBER_OF_PROCESSORS', 'PROCESSOR_ARCHITECTURE', 'OS') if key in os.environ}
|
|
env.update(PATH=os.pathsep.join(map(str, (stage, windows / 'System32', windows))),
|
|
USERPROFILE=str(profile), HOMEDRIVE=profile.drive, HOMEPATH=str(profile)[len(profile.drive):],
|
|
LOCALAPPDATA=str(profile / 'AppData/Local'), APPDATA=str(profile / 'AppData/Roaming'), TEMP=str(temporary), TMP=str(temporary))
|
|
invocation = [str(stage / 'arcadia-studio.exe')]
|
|
request = {'utc': now(), 'source': args.source, 'command': invocation, 'cwd': str(cwd), 'environment': env,
|
|
'stage_manifest': identity(manifest_raw), 'config': attestation['config'], 'helper': attestation['helper']}
|
|
save(TRIAL / 'launch-request.json', request)
|
|
process = None
|
|
try:
|
|
with (TRIAL / 'stdout.log').open('xb') as stdout, (TRIAL / 'stderr.log').open('xb') as stderr:
|
|
process = subprocess.Popen(invocation, cwd=cwd, env=env, stdin=subprocess.DEVNULL,
|
|
stdout=stdout, stderr=stderr, creationflags=subprocess.CREATE_NO_WINDOW)
|
|
launch = {**request, 'pid': process.pid, 'spawned_utc': now(), 'gui': manifest['payloads']['arcadia-studio.exe'], 'runtime': manifest['payloads']['libunwind.dll']}
|
|
save(TRIAL / 'launch.json', launch)
|
|
print(json.dumps(launch), flush=True)
|
|
code = process.wait()
|
|
unchanged = stage_map(stage) == manifest['payloads'] and (stage / 'manifest.json').read_bytes() == manifest_raw
|
|
closure = {'utc': now(), 'source': args.source, 'pid': process.pid, 'exit': code,
|
|
'stage_unchanged': unchanged, 'stdout': identity((TRIAL / 'stdout.log').read_bytes()),
|
|
'stderr': identity((TRIAL / 'stderr.log').read_bytes()), 'scope': 'Observed owned-process closure; not automatic native acceptance'}
|
|
save(TRIAL / 'closure.json', closure)
|
|
print(json.dumps(closure), flush=True)
|
|
raise SystemExit(code if code else (0 if unchanged else 1))
|
|
except (Exception, KeyboardInterrupt) as error:
|
|
save(TRIAL / 'supervisor-error.json', {'utc': now(), 'error': repr(error),
|
|
'pid': None if process is None else process.pid,
|
|
'observed_exit': None if process is None else process.poll(),
|
|
'scope': 'Supervisor failure; no invented normal closure and no unrelated process cleanup'})
|
|
raise
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|