"""Independent frozen archive and packaged-server checks; never runs Cargo or GUI.""" from pathlib import Path, PurePosixPath import hashlib import json import os import re import socket import stat import struct import subprocess import sys import tarfile import time import tomllib import traceback import urllib.request import uuid import zipfile OUT = Path(__file__).resolve().parent ROOT = OUT.parents[1] PREP = ROOT / '.local/authoring-prerelease-20260911' NAME = 'ArcadiaStudio-0.2.0-preview.authoring.20260911-x86_64-pc-windows-gnullvm' ZIP = PREP / 'packages' / (NAME + '.zip') EXTRACT = OUT / 'extracted' PACKAGE = EXTRACT / NAME SOURCE = PREP / 'source' SOURCE_COMMIT = '234e01e27d6935d213097b345d91d369f808af82' BASE_COMMIT = '2ec72d4241fa8971fa6fe9f626937de9dfd7c7eb' EXPECTED_ZIP = '664f30b6217689aca1492eb263b3d15777067d732fa890eeb028f435209dadfa' BINARIES = { 'arcadia-studio.exe': 'd4d9c2bd937e301ff1009d7cb93a34ee5aa6dfc837ff7e87d468c85371b20c31', 'arcadia-server.exe': 'efeeb89c0d2e0f93df4472cb3e9f48b2b722a37ae1043c90a5a56f2e845fe665', 'libunwind.dll': 'f45604a12e8bcd839fd86f667c1be1cc7c4f9da2b3c69ff381ac708f0e1ae7d4', } RESULT = {'checks': [], 'scope': sys.argv[1], 'started_utc': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())} def check(condition, label): if not condition: raise AssertionError(label) RESULT['checks'].append(label) def sha(data): return hashlib.sha256(data).hexdigest() def read_json(path): return json.loads(path.read_text(encoding='utf-8-sig')) def write_json(path, value): with path.open('x', encoding='utf-8', newline='\n') as f: json.dump(value, f, indent=2, ensure_ascii=False) f.write('\n') def file_map(directory): result = {} for p in directory.rglob('*'): check(not p.is_symlink() and not (getattr(p.lstat(), 'st_file_attributes', 0) & 0x400), 'ordinary path: ' + p.relative_to(directory).as_posix()) if p.is_file(): result[p.relative_to(directory).as_posix()] = sha(p.read_bytes()) return result def safe_name(name): p = PurePosixPath(name) return not p.is_absolute() and p.as_posix() == name and '\\' not in name and ':' not in name and all(c not in ('', '.', '..') and not c.endswith(('.', ' ')) and not re.match(r'(?i)^(con|nul|prn|aux|com[1-9]|lpt[1-9])(\.|$)', c) for c in p.parts) def git_blobs(ref, paths): raw = subprocess.run(['git', 'cat-file', '--batch'], input=''.join(ref + ':' + p + '\n' for p in paths).encode(), cwd=ROOT, capture_output=True, check=True).stdout result, cursor = {}, 0 for p in paths: end = raw.index(b'\n', cursor) header = raw[cursor:end].split() check(len(header) == 3 and header[1] == b'blob', 'Git blob exists: ' + ref[:7] + ':' + p) size = int(header[2]) result[p] = raw[end + 1:end + 1 + size] cursor = end + 2 + size check(cursor == len(raw), 'Git batch framing complete: ' + ref[:7]) return result def artifact(): check(not EXTRACT.exists(), 'clean extraction destination absent') check(ZIP.stat().st_size == 32618262 and sha(ZIP.read_bytes()) == EXPECTED_ZIP, 'frozen ZIP size and SHA256') with zipfile.ZipFile(ZIP) as archive: infos = archive.infolist() names = [i.filename for i in infos] check(len(infos) == 559, '559 ZIP members') check(len({n.casefold() for n in names}) == len(names), 'no duplicate or case-colliding ZIP names') check(all(safe_name(n) and n.startswith(NAME + '/') for n in names), 'one safe ZIP root without traversal or Windows special paths') check(all(not i.is_dir() and stat.S_IFMT(i.external_attr >> 16) in (0, stat.S_IFREG) for i in infos), 'ordinary file-only ZIP entries') check(all(i.date_time == (2000, 1, 1, 0, 0, 0) and i.flag_bits & 1 == 0 for i in infos), 'fixed timestamps and no encrypted entries') check(archive.testzip() is None, 'all ZIP CRCs') EXTRACT.mkdir() archive.extractall(EXTRACT) archive_hashes = {i.filename[len(NAME) + 1:]: sha(archive.read(i)) for i in infos} actual = file_map(PACKAGE) check(actual == archive_hashes, 'complete extracted file set and bytes equal ZIP') sums = {} for line in (PACKAGE / 'SHA256SUMS.txt').read_text().splitlines(): match = re.fullmatch(r'([0-9a-f]{64}) (.+)', line) check(match is not None and safe_name(match[2]) and match[2] not in sums, 'well-formed unique checksum row') sums[match[2]] = match[1] check(sums == {p: h for p, h in actual.items() if p != 'SHA256SUMS.txt'}, 'checksum inventory covers every other file exactly') package = read_json(PACKAGE / 'package.json') inputs = package['input_sha256'] generated = {'SHA256SUMS.txt', 'START-HERE.txt', 'THIRD-PARTY-NOTICES.txt', 'dependency-notices.json', 'documentation-check.json', 'package.json'} check(set(actual) - set(inputs) == generated and all(actual[p] == h.lower() for p, h in inputs.items()), '553 package input hashes plus exactly six generated files') check(package['version'] == '0.2.0-preview.authoring.20260911' and package['target'] == 'x86_64-pc-windows-gnullvm', 'version and target') check(all(actual[p] == h for p, h in BINARIES.items()), 'exact GUI, server and runtime hashes') for p in BINARIES: data = (PACKAGE / p).read_bytes() offset = struct.unpack_from(' 0, 'package has notice text: ' + p['name']) refs(p['notices']) for f in p['embedded_fonts']: check(len(f['notices']) > 0, 'embedded font notice present: ' + p['name'] + '/' + f['path']) refs(f['notices']) fonts.append({'package': p['name'], 'path': f['path'], 'sha256': f['sha256'], 'license': f['license']}) if p['source'] is None: directory = SOURCE / 'crates' / p['name'] files = {f.relative_to(directory).as_posix(): sha(f.read_bytes()) for f in directory.rglob('*') if f.is_file() and 'target' not in f.relative_to(directory).parts and f.name != '.cargo-ok'} check(files == p['local_source_sha256'], 'complete ordinary local-crate inventory: ' + p['name']) refs(notice['rust']['notices']) refs(notice['runtime']['notices']) check(notice['runtime']['sha256'] == BINARIES['libunwind.dll'], 'runtime notice is bound to shipped DLL') library_dir = ROOT / '.local/toolchain/rustup/toolchains/stable-x86_64-pc-windows-gnullvm/lib/rustlib/x86_64-pc-windows-gnullvm/lib' check(len(notice['rust']['target_libraries_sha256']) == 58, '58 compiler target libraries recorded') for name, h in notice['rust']['target_libraries_sha256'].items(): check(sha((library_dir / name).read_bytes()) == h, 'retained compiler target-library bytes: ' + name) RESULT['notices'] = {'packages': len(notice['packages']), 'roots': notice['root_packages'], 'lock_sha256': notice['cargo_lock_sha256'], 'notice_reference_files': len(referenced), 'additional_license_files': sorted({p for p in actual if p.startswith('licenses/')} - referenced), 'embedded_fonts': fonts, 'rust_version': notice['rust']['version'], 'runtime_provenance': notice['runtime']['provenance'], 'scope': notice['scope']} def server(): prior = read_json(OUT / 'artifact-result.json') check(prior['status'] == 'PASS' and file_map(PACKAGE) == prior['archive']['files'], 'previously verified extracted package is unchanged') runtime = OUT / 'server-run' runtime.mkdir() data_dir = runtime / 'data' temp = runtime / 'temp' temp.mkdir() windows = Path(os.environ['SystemRoot']) env = {'SystemRoot': str(windows), 'WINDIR': str(windows), 'PATH': str(windows / 'System32') + ';' + str(windows), 'TEMP': str(temp), 'TMP': str(temp)} exe = PACKAGE / 'arcadia-server.exe' RESULT['environment'] = env RESULT['processes'] = [] for arg in ('--version', '--help'): output = subprocess.run([str(exe), arg], cwd=PACKAGE, env=env, capture_output=True, timeout=15, creationflags=subprocess.CREATE_NO_WINDOW) (runtime / (arg[2:] + '.stdout')).write_bytes(output.stdout) (runtime / (arg[2:] + '.stderr')).write_bytes(output.stderr) check(output.returncode == 0 and not output.stderr, arg + ' succeeds under clean runtime PATH') if arg == '--version': check(output.stdout.decode().strip() == 'arcadia-server 0.2.0', 'server reports underlying application version 0.2.0') check(not data_dir.exists(), 'help/version do not create explicit test data directory') opener = urllib.request.build_opener(urllib.request.ProxyHandler({})) request_number = 0 def request(port, method, path, payload=None): nonlocal request_number request_number += 1 body = None if payload is None else json.dumps(payload, ensure_ascii=False).encode() req = urllib.request.Request(f'http://127.0.0.1:{port}' + path, data=body, method=method, headers={} if body is None else {'Content-Type': 'application/json'}) with opener.open(req, timeout=10) as response: raw = response.read() meta = {'method': method, 'path': path, 'status': response.status, 'headers': dict(response.headers), 'body_sha256': sha(raw)} prefix = runtime / f'http-{request_number:02d}' prefix.with_suffix('.body').write_bytes(raw) write_json(prefix.with_suffix('.json'), meta) return meta, raw def start(index): with socket.socket() as s: s.bind(('127.0.0.1', 0)) port = s.getsockname()[1] out = (runtime / f'server-{index}.stdout').open('xb') err = (runtime / f'server-{index}.stderr').open('xb') args = [str(exe), '--bind', f'127.0.0.1:{port}', '--data-dir', str(data_dir)] process = subprocess.Popen(args, cwd=PACKAGE, env=env, stdout=out, stderr=err, creationflags=subprocess.CREATE_NO_WINDOW) out.close() err.close() RESULT['processes'].append({'pid': process.pid, 'port': port, 'arguments': args}) deadline = time.monotonic() + 15 while True: if process.poll() is not None: raise AssertionError('packaged server exited before listening') try: with socket.create_connection(('127.0.0.1', port), timeout=.2): break except OSError: if time.monotonic() > deadline: process.terminate() process.wait(timeout=5) raise AssertionError('packaged server did not listen within 15s') time.sleep(.05) return process, port def stop(process): process.terminate() code = process.wait(timeout=10) RESULT['processes'][-1]['exit_after_explicit_terminate'] = code process = None try: process, port = start(1) for path in ('/health', '/health/ready'): meta, raw = request(port, 'GET', path) check(meta['status'] == 200 and json.loads(raw) == {'status': 'ok'}, path + ' contract') meta, raw = request(port, 'GET', '/api/v1/openapi.json') check(meta['status'] == 200 and raw == (PACKAGE / 'docs/openapi.json').read_bytes(), 'served OpenAPI equals complete packaged source bytes') name = 'Independent package persistence — 救助 20260911' meta, raw = request(port, 'POST', '/api/v1/projects', {'name': name}) created = json.loads(raw) check(meta['status'] == 201, 'one create returns 201') resource = str(uuid.UUID(created['resource_id'])) model_id = str(uuid.UUID(created['model_id'])) expected_summary = {'resource_id': resource, 'revision': 1, 'model_id': model_id, 'schema_version': 7, 'name': name, 'elements': 0, 'relations': 0, 'migration': None} check(created == expected_summary and resource != model_id, 'complete create summary with distinct fresh resource/model IDs') etag = f'"p-{resource}-r1"' headers = {k.lower(): v for k, v in meta['headers'].items()} path = '/api/v1/projects/' + resource check(headers.get('etag') == etag and headers.get('location') == path, 'create ETag and resource Location') meta, raw = request(port, 'GET', path) stored = json.loads(raw) model = {'schema_version': 7, 'id': model_id, 'alias': 'mission', 'name': name, 'description': '', 'elements': {}, 'relations': {}, 'diagrams': {}, 'artifact_links': {}, 'traces': {}} source = f'arcadia 7;\nproject mission {json.dumps(name, ensure_ascii=False)} id "{model_id}" {{\n description "";\n}}\n' expected = {'resource_id': resource, 'revision': 1, 'model': model, 'source_project': {'entry': 'project.arcadia', 'files': {'project.arcadia': source}}} check(meta['status'] == 200 and stored == expected, 'GET equals independently predicted complete Project and SourceBundle') check({k.lower(): v for k, v in meta['headers'].items()}.get('etag') == etag, 'GET ETag equals created revision') disk = data_dir / (resource + '.json') disk_bytes = disk.read_bytes() check(json.loads(disk_bytes) == expected, 'durable disk envelope equals complete expected GET') check({p.name for p in data_dir.iterdir()} == {'.arcadia.lock', disk.name}, 'private store contains only one project and lock') stop(process) process = None process, port = start(2) meta, raw = request(port, 'GET', '/health/ready') check(meta['status'] == 200 and json.loads(raw) == {'status': 'ok'}, 'restarted packaged server ready') meta, raw = request(port, 'GET', path) check(meta['status'] == 200 and json.loads(raw) == expected, 'restart retains exact complete Project and SourceBundle') check({k.lower(): v for k, v in meta['headers'].items()}.get('etag') == etag and disk.read_bytes() == disk_bytes, 'restart retains revision, ETag and every durable envelope byte') RESULT['persistence'] = {'resource_id': resource, 'model_id': model_id, 'revision': 1, 'etag': etag, 'disk_sha256': sha(disk_bytes), 'expected': expected, 'stop_kind': 'explicit process termination after acknowledged durable create; not a graceful-drain claim'} finally: if process is not None and process.poll() is None: stop(process) check(file_map(PACKAGE) == prior['archive']['files'], 'server execution leaves complete extracted package unchanged') check(sha(ZIP.read_bytes()) == EXPECTED_ZIP, 'frozen ZIP unchanged after independent runtime checks') if __name__ == '__main__': result_path = OUT / (sys.argv[1] + '-result.json') if result_path.exists(): raise SystemExit('Refusing to overwrite prior evidence: ' + str(result_path)) try: {'artifact': artifact, 'server': server}[sys.argv[1]]() RESULT['status'] = 'PASS' except Exception as error: RESULT['status'] = 'FAIL' RESULT['error'] = repr(error) RESULT['traceback'] = traceback.format_exc() RESULT['finished_utc'] = time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()) RESULT['script_sha256'] = sha(Path(__file__).read_bytes()) write_json(result_path, RESULT) print(json.dumps({k: RESULT[k] for k in ('scope', 'status', 'started_utc', 'finished_utc')}, indent=2)) print('checks:', len(RESULT['checks'])) if RESULT['status'] == 'FAIL': print(RESULT['traceback']) sys.exit(1)