#!/bin/sh set -eu umask 022 gate_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) root=$(CDPATH= cd -- "$gate_dir/../../../.." && pwd -P) input=$gate_dir/P15-027-input.json freebsd_src=${FREEBSD_SRC:-/work/build/freebsd-src} base= output= deadline=120 while test "$#" -gt 0; do case "$1" in --base) test "$#" -ge 2 || { printf '%s\n' '--base requires a commit' >&2; exit 20; } base=$2 shift 2 ;; --freebsd-src) test "$#" -ge 2 || { printf '%s\n' '--freebsd-src requires a directory' >&2; exit 20; } freebsd_src=$2 shift 2 ;; --output) test "$#" -ge 2 || { printf '%s\n' '--output requires a directory' >&2; exit 20; } output=$2 shift 2 ;; *) printf 'unknown argument: %s\n' "$1" >&2 exit 20 ;; esac done test -n "$base" || { printf '%s\n' '--base is required' >&2; exit 20; } test -n "$output" || { printf '%s\n' '--output is required' >&2; exit 20; } test -f "$input" || { printf 'missing input: %s\n' "$input" >&2; exit 20; } for tool in date git mktemp patch python3 sha256sum timeout; do command -v "$tool" >/dev/null 2>&1 || { printf 'missing required host tool: %s\n' "$tool" >&2 exit 21 } done case "$output" in /*) ;; *) output=$PWD/$output ;; esac case "$freebsd_src" in /*) ;; *) freebsd_src=$PWD/$freebsd_src ;; esac test ! -e "$output" || { printf 'refusing existing output: %s\n' "$output" >&2; exit 20; } mkdir -p "$output" work=$(mktemp -d "${TMPDIR:-/tmp}/P15-027.XXXXXX") cleanup_trap() { rm -rf -- "$work" } trap cleanup_trap EXIT HUP INT TERM python3 -B - "$output/command-argv.json" "$0" --base "$base" \ --freebsd-src "$freebsd_src" --output "$output" <<'PY' import json from pathlib import Path import sys Path(sys.argv[1]).write_text( json.dumps(sys.argv[2:], ensure_ascii=True, separators=(",", ":")) + "\n", encoding="ascii", ) PY python3 -B - "$output/ownership.json" "$work" "$output" <<'PY' import json from pathlib import Path import sys Path(sys.argv[1]).write_text( json.dumps( { "owned_temporary_paths": [sys.argv[2]], "persistent_output": sys.argv[3], "owned_processes": [], "owned_ports": [], "qemu": "NOT_RUN", "protected_resources_addressed": False, }, ensure_ascii=True, indent=2, sort_keys=True, ) + "\n", encoding="ascii", ) PY set +e timeout -k 5 "$deadline" python3 -B - \ "$root" "$input" "$base" "$freebsd_src" "$output" "$work" "$deadline" <<'PY' \ >"$output/stdout.log" 2>"$output/stderr.log" from __future__ import annotations import hashlib import json import os from pathlib import Path import platform import re import shutil import subprocess import sys import tarfile from typing import Any ROOT = Path(sys.argv[1]) INPUT = Path(sys.argv[2]) REQUESTED_BASE = sys.argv[3] FREEBSD_SRC = Path(sys.argv[4]) OUTPUT = Path(sys.argv[5]) WORK = Path(sys.argv[6]) DEADLINE = int(sys.argv[7]) SPEC = json.loads(INPUT.read_text(encoding="utf-8")) class GateFailure(RuntimeError): def __init__(self, status: str, reason: str): super().__init__(reason) self.status = status self.reason = reason def sha256_bytes(data: bytes) -> str: return hashlib.sha256(data).hexdigest() def sha256_path(path: Path) -> str: return sha256_bytes(path.read_bytes()) def write_json(path: Path, value: Any) -> None: path.write_text( json.dumps(value, ensure_ascii=True, indent=2, sort_keys=True) + "\n", encoding="ascii", ) def run( argv: list[str], *, cwd: Path | None = None, input_bytes: bytes | None = None, allowed: set[int] | None = None, timeout_seconds: int = 30, ) -> subprocess.CompletedProcess[bytes]: try: completed = subprocess.run( argv, cwd=cwd, check=False, input=input_bytes, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout_seconds, ) except subprocess.TimeoutExpired as error: raise GateFailure( "INFRA_BLOCKED", f"command timed out: {' '.join(argv)}" ) from error accepted = {0} if allowed is None else allowed if completed.returncode not in accepted: detail = completed.stderr.decode("utf-8", errors="replace").strip() raise GateFailure( "RUNNER_FAIL", f"command failed ({completed.returncode}): {' '.join(argv)}: {detail}", ) return completed def git_text(repository: Path, *args: str) -> str: return run(["git", "-C", str(repository), *args]).stdout.decode( "utf-8", errors="strict" ).strip() def source_at(commit: str, relative: str) -> bytes: return run( ["git", "-C", str(ROOT), "show", f"{commit}:{relative}"] ).stdout def safe_relative_path(value: str) -> Path: path = Path(value) if path.is_absolute() or ".." in path.parts: raise GateFailure("RUNNER_FAIL", f"unsafe declared path: {value}") if path.name == "introduction.md": raise GateFailure("RUNNER_FAIL", "prohibited path declaration") return path def validate_hash(value: Any, label: str) -> str: if not isinstance(value, str) or re.fullmatch(r"[0-9a-f]{64}", value) is None: raise GateFailure("RUNNER_FAIL", f"invalid SHA-256 for {label}") return value def validate_runtime_item(item: Any, item_id: str) -> None: if not isinstance(item, dict): raise GateFailure("RUNNER_FAIL", f"runtime item is not an object: {item_id}") expected = { "status": "PASS", "exit_code": 0, "target_marker": "reached", "cleanup": "PASS", } for key, value in expected.items(): if item.get(key) != value: raise GateFailure("RUNNER_FAIL", f"runtime item {item_id} has invalid {key}") argv = item.get("command_argv") if not isinstance(argv, list) or not argv or not all(isinstance(v, str) for v in argv): raise GateFailure("RUNNER_FAIL", f"runtime item {item_id} lacks exact argv") if not isinstance(item.get("deadline_seconds"), int) or item["deadline_seconds"] <= 0: raise GateFailure("RUNNER_FAIL", f"runtime item {item_id} lacks deadline") for stream in ("stdout", "stderr"): relative = safe_relative_path(item.get(stream, "")) evidence_path = OUTPUT / relative if not evidence_path.is_file(): raise GateFailure("RUNNER_FAIL", f"runtime item {item_id} lacks {stream}") expected_hash = validate_hash(item.get(f"{stream}_sha256"), f"{item_id} {stream}") if sha256_path(evidence_path) != expected_hash: raise GateFailure("RUNNER_FAIL", f"runtime item {item_id} {stream} hash mismatch") def validate_runtime_record( path: Path, architecture: dict[str, Any], modules: dict[str, dict[str, Any]], resolved_base: str, patch_sha256: str, ) -> dict[str, Any]: record = json.loads(path.read_text(encoding="utf-8")) expected_identity = { "schema": 1, "architecture": architecture["id"], "uname_s": "FreeBSD", "uname_m": architecture["expected_uname_m"], "uname_p": architecture["expected_uname_p"], "dut_base": resolved_base, "temporary_patch_sha256": patch_sha256, "freebsd_source_head": SPEC["freebsd_source"]["head"], } for key, value in expected_identity.items(): if record.get(key) != value: raise GateFailure("RUNNER_FAIL", f"native record identity mismatch: {key}") if record.get("status") not in {"PASS", "DUT_FAIL"}: raise GateFailure("RUNNER_FAIL", "native record status is not authoritative") if record.get("cleanup") != "PASS" or record.get("target_marker") != "reached": raise GateFailure("RUNNER_FAIL", "native record did not reach target with cleanup") if record.get("module_sha256") != { name: value["sha256"] for name, value in modules.items() }: raise GateFailure("RUNNER_FAIL", "native module hashes differ from cross artifacts") fixtures = record.get("fixture_sha256") if not isinstance(fixtures, list) or len(fixtures) < 4: raise GateFailure("RUNNER_FAIL", "native record lacks four fixture hashes") for index, value in enumerate(fixtures): validate_hash(value, f"native fixture {index}") capability = record.get("kernel_zstdio") validate_runtime_item(capability, "kernel-zstdio-capability") if capability.get("options_zstdio") is not True: raise GateFailure("RUNNER_FAIL", "native ZSTDIO capability is not enabled") operations = record.get("operations") if not isinstance(operations, dict): raise GateFailure("RUNNER_FAIL", "native operations are absent") required = SPEC["native_runtime_contract"]["required_operations"] if set(operations) != set(required): raise GateFailure("RUNNER_FAIL", "native operation set is not exact") for item_id in required: validate_runtime_item(operations[item_id], item_id) disabled = operations["zstdio0-zstd-read"] if disabled.get("errno") != "EOPNOTSUPP": raise GateFailure("RUNNER_FAIL", "disabled native Zstd errno is not EOPNOTSUPP") return record def extract_repo_source(resolved_base: str, destination: Path) -> None: archive = run( [ "git", "-C", str(ROOT), "archive", "--format=tar", resolved_base, "repo-pre-15/src", "repo-pre-15/tests/pre15/probes/ondisk_layout.c", ], timeout_seconds=60, ).stdout destination.mkdir(parents=True) archive_path = WORK / "repo-source.tar" archive_path.write_bytes(archive) with tarfile.open(archive_path, mode="r:") as tar: tar.extractall(destination, filter="data") def compile_architecture( architecture: dict[str, Any], resolved_base: str, patch_bytes: bytes, compiler: Path, ) -> dict[str, Any]: arch_id = architecture["id"] arch_root = WORK / "cross" / arch_id source_root = arch_root / "source" extract_repo_source(resolved_base, source_root) run(["patch", "-p1"], cwd=source_root, input_bytes=patch_bytes) src = source_root / "repo-pre-15/src" sys_root = FREEBSD_SRC / "sys" resource_include = Path( run([str(compiler), "-print-resource-dir"]).stdout.decode("ascii").strip() ) / "include" common_flags = [ "-O2", "-pipe", "-fno-common", "-fno-strict-aliasing", "-D_KERNEL", "-DKLD_MODULE", "-nostdinc", "-ffreestanding", "-fwrapv", "-fno-asynchronous-unwind-tables", "-fno-omit-frame-pointer", "-fstack-protector", "-Wall", "-Wstrict-prototypes", "-Wmissing-prototypes", "-Wpointer-arith", "-Wcast-qual", "-Wundef", "-Wno-pointer-sign", "-Wmissing-include-dirs", "-Wno-unknown-pragmas", "-Wno-address-of-packed-member", "-Wno-format-zero-length", "-std=gnu17", "-D__printf__=__freebsd_kprintf__", f"--target={architecture['target_triple']}", *architecture["kernel_cflags"], ] modules: dict[str, dict[str, Any]] = {} for zstdio in (0, 1): build = arch_root / f"zstdio{zstdio}" build.mkdir(parents=True) (build / "opt_global.h").write_bytes(b"") (build / "machine").symlink_to(sys_root / architecture["machine_header_dir"] / "include") for alias, relative in architecture["header_aliases"].items(): (build / alias).symlink_to(sys_root / relative) for mode in ("-p", "-q", "-h"): generated = run( ["awk", "-f", str(sys_root / "tools/vnode_if.awk"), str(sys_root / "kern/vnode_if.src"), mode], cwd=build, ).stdout suffix = {"-p": "vnode_if_newproto.h", "-q": "vnode_if_typedef.h", "-h": "vnode_if.h"}[mode] (build / suffix).write_bytes(generated) include_flags = [ "-include", str(build / "opt_global.h"), "-I", str(build), "-I", str(sys_root), "-I", str(sys_root / "contrib/ck/include"), ] objects = [] stdout_parts = [] stderr_parts = [] for source_name in SPEC["cross_build_contract"]["module_sources"]: obj = build / f"{Path(source_name).stem}.o" argv = [str(compiler), *common_flags, *include_flags] if source_name == "decompressor_zstd.c": argv.extend(["-I", str(sys_root / "contrib/zstd/lib/freebsd")]) if zstdio == 1: argv.append("-DZSTDIO") argv.extend(["-c", str(src / source_name), "-o", str(obj)]) completed = run(argv, cwd=build, timeout_seconds=60) stdout_parts.append(completed.stdout) stderr_parts.append(completed.stderr) objects.append(obj) module = build / "erofs.ko" linked = run( [str(compiler), f"--target={architecture['target_triple']}", "-r", "-nostdlib", *map(str, objects), "-o", str(module)], cwd=build, timeout_seconds=60, ) stdout_parts.append(linked.stdout) stderr_parts.append(linked.stderr) nm_output = run(["nm", "-u", str(module)]).stdout (build / "build.stdout").write_bytes(b"".join(stdout_parts)) (build / "build.stderr").write_bytes(b"".join(stderr_parts)) (build / "nm-u.txt").write_bytes(nm_output) modules[f"zstdio{zstdio}"] = { "path": str(module), "sha256": sha256_path(module), "size_bytes": module.stat().st_size, "nm_u_sha256": sha256_bytes(nm_output), } probe_root = arch_root / "probes" probe_root.mkdir() include_root = probe_root / "include" include_root.mkdir() (include_root / "machine").symlink_to( sys_root / architecture["machine_header_dir"] / "include" ) for alias, relative in architecture["header_aliases"].items(): (include_root / alias).symlink_to(sys_root / relative) probe_flags = [ f"--target={architecture['target_triple']}", "-std=gnu17", "-nostdinc", "-isystem", str(resource_include), "-isystem", str(FREEBSD_SRC / "include"), "-isystem", str(include_root), "-isystem", str(sys_root), ] layout = source_root / "repo-pre-15/tests/pre15/probes/ondisk_layout.c" layout_result = run( [str(compiler), *probe_flags, "-Wall", "-Wextra", "-Werror", "-fsyntax-only", "-Xclang", "-fdump-record-layouts", str(layout)], timeout_seconds=60, ) (probe_root / "layout.stdout").write_bytes(layout_result.stdout) (probe_root / "layout.stderr").write_bytes(layout_result.stderr) unaligned = probe_root / "unaligned-endian.c" unaligned.write_text( SPEC["cross_build_contract"]["unaligned_endian_probe_source"], encoding="ascii", ) assembly = probe_root / "unaligned-endian.s" endian_result = run( [str(compiler), *probe_flags, *architecture["kernel_cflags"], "-O2", "-S", str(unaligned), "-o", str(assembly)], timeout_seconds=60, ) (probe_root / "unaligned-endian.stdout").write_bytes(endian_result.stdout) (probe_root / "unaligned-endian.stderr").write_bytes(endian_result.stderr) if assembly.stat().st_size == 0: raise GateFailure("RUNNER_FAIL", f"empty unaligned/endian probe for {arch_id}") return { "status": "PASS", "temporary_source": str(source_root), "modules": modules, "layout_probe_sha256": sha256_path(layout), "layout_output_sha256": sha256_bytes(layout_result.stdout), "unaligned_endian_probe_sha256": sha256_path(unaligned), "unaligned_endian_assembly_sha256": sha256_path(assembly), } def render_argv(values: list[str], substitutions: dict[str, str]) -> list[str]: rendered = [] for value in values: for key, replacement in substitutions.items(): value = value.replace("{" + key + "}", replacement) rendered.append(value) return rendered def run_native( architecture: dict[str, Any], declaration: dict[str, Any], modules: dict[str, dict[str, Any]], resolved_base: str, patch_sha256: str, ) -> dict[str, Any]: runner_relative = safe_relative_path(declaration.get("runner_path", "")) runner = ROOT / runner_relative if not runner.is_file(): raise GateFailure("INFRA_BLOCKED", f"declared native runner is absent: {runner_relative}") if sha256_path(runner) != validate_hash( declaration.get("runner_sha256"), f"{architecture['id']} runner" ): raise GateFailure("INFRA_BLOCKED", "declared native runner identity changed") native_output = OUTPUT / "native" / architecture["id"] native_output.mkdir(parents=True) substitutions = { "runner": str(runner), "architecture": architecture["id"], "module_zstdio0": modules["zstdio0"]["path"], "module_zstdio1": modules["zstdio1"]["path"], "output": str(native_output), } preflight_argv = render_argv(declaration["preflight_argv"], substitutions) preflight = run( preflight_argv, cwd=ROOT, timeout_seconds=declaration["preflight_deadline_seconds"], ) (native_output / "preflight.runner.stdout").write_bytes(preflight.stdout) (native_output / "preflight.runner.stderr").write_bytes(preflight.stderr) preflight_record = json.loads( (native_output / "preflight.json").read_text(encoding="utf-8") ) for key, value in { "status": "PASS", "exit_code": 0, "target_marker": "reached", "cleanup": "PASS", "uname_s": "FreeBSD", "uname_m": architecture["expected_uname_m"], "uname_p": architecture["expected_uname_p"], }.items(): if preflight_record.get(key) != value: raise GateFailure("INFRA_BLOCKED", f"native preflight mismatch: {key}") runtime_argv = render_argv(declaration["runtime_argv"], substitutions) runtime = run( runtime_argv, cwd=ROOT, allowed={0, 10}, timeout_seconds=declaration["runtime_deadline_seconds"], ) (native_output / "runner.stdout").write_bytes(runtime.stdout) (native_output / "runner.stderr").write_bytes(runtime.stderr) return validate_runtime_record( native_output / "runtime-result.json", architecture, modules, resolved_base, patch_sha256, ) def main() -> int: if SPEC.get("schema") != 1 or SPEC.get("candidate") != "P15-027": raise GateFailure("RUNNER_FAIL", "invalid P15-027 input identity") if SPEC.get("gate") != "G07" or SPEC.get("batch") != "B36": raise GateFailure("RUNNER_FAIL", "invalid G07/B36 input identity") if SPEC.get("prohibited_paths") != ["introduction.md"]: raise GateFailure("RUNNER_FAIL", "prohibited-path contract changed") resolved = git_text(ROOT, "rev-parse", f"{REQUESTED_BASE}^{{commit}}") if resolved != SPEC["required_base"]: raise GateFailure( "INFRA_BLOCKED", f"P15-027 must replay {SPEC['required_base']}, got {resolved}" ) source_tree = git_text(ROOT, "rev-parse", f"{resolved}:repo-pre-15/src") if source_tree != SPEC["repo_source_tree_oid"]: raise GateFailure("INFRA_BLOCKED", "frozen EROFS source tree changed") source_hashes = { path: sha256_bytes(source_at(resolved, path)) for path in SPEC["source_sha256"] } if source_hashes != SPEC["source_sha256"]: raise GateFailure("INFRA_BLOCKED", "frozen gate source identity changed") write_json(OUTPUT / "source-sha256.json", source_hashes) addendum_paths = ( "repo-pre-15/tests/pre15/gates/P15-027.sh", "repo-pre-15/tests/pre15/gates/P15-027-input.json", "repo-pre-15/docs/pre15-stage0/P15-027.md", ) addendum_hashes = { path: sha256_path(ROOT / path) for path in addendum_paths } write_json(OUTPUT / "gate-addendum-sha256.json", addendum_hashes) if sha256_path(ROOT / "repo-pre-15/src/Makefile") != SPEC["source_sha256"]["repo-pre-15/src/Makefile"]: raise GateFailure("RUNNER_FAIL", "production Makefile differs from frozen BASE") patch_spec = SPEC["temporary_makefile_relaxation"] patch_bytes = patch_spec["unified_diff"].encode("ascii") if sha256_bytes(patch_bytes) != patch_spec["sha256"]: raise GateFailure("RUNNER_FAIL", "input-recorded temporary patch hash mismatch") patch_check = WORK / "patch-check" makefile_copy = patch_check / "repo-pre-15/src/Makefile" makefile_copy.parent.mkdir(parents=True) makefile_copy.write_bytes(source_at(resolved, patch_spec["path"])) patch_result = run(["patch", "-p1"], cwd=patch_check, input_bytes=patch_bytes) (OUTPUT / "makefile-relaxation.patch").write_bytes(patch_bytes) (OUTPUT / "patch.stdout").write_bytes(patch_result.stdout) (OUTPUT / "patch.stderr").write_bytes(patch_result.stderr) if sha256_path(makefile_copy) != patch_spec["patched_makefile_sha256"]: raise GateFailure("RUNNER_FAIL", "temporary Makefile relaxation result changed") patch_record = { "path": patch_spec["path"], "sha256": patch_spec["sha256"], "patched_makefile_sha256": sha256_path(makefile_copy), "production_makefile_changed": False, "temporary_apply": "PASS", } write_json(OUTPUT / "temporary-patch.json", patch_record) if not FREEBSD_SRC.is_dir(): raise GateFailure("INFRA_BLOCKED", f"FreeBSD source is absent: {FREEBSD_SRC}") freebsd = SPEC["freebsd_source"] freebsd_head = git_text(FREEBSD_SRC, "rev-parse", "HEAD") freebsd_prefix = git_text(FREEBSD_SRC, "rev-parse", "--show-prefix") if freebsd_head != freebsd["head"] or freebsd_prefix != freebsd["git_prefix"]: raise GateFailure("INFRA_BLOCKED", "FreeBSD source identity changed") git_root = Path(git_text(FREEBSD_SRC, "rev-parse", "--show-toplevel")) freebsd_source_tree = git_text( git_root, "rev-parse", f"{freebsd_head}:{freebsd['git_tree_path']}" ) freebsd_sys_tree = git_text( git_root, "rev-parse", f"{freebsd_head}:{freebsd['git_tree_path']}/sys" ) if freebsd_source_tree != freebsd["source_tree_oid"] or freebsd_sys_tree != freebsd["sys_tree_oid"]: raise GateFailure("INFRA_BLOCKED", "FreeBSD source tree object changed") freebsd_hashes = { path: sha256_path(FREEBSD_SRC / path) for path in freebsd["sha256"] } if freebsd_hashes != freebsd["sha256"]: raise GateFailure("INFRA_BLOCKED", "selected FreeBSD source hashes changed") compiler_path = Path(shutil.which("clang") or "").resolve() if not compiler_path.is_file(): raise GateFailure("INFRA_BLOCKED", "clang is unavailable") compiler = SPEC["toolchain"]["compiler"] compiler_version = run([str(compiler_path), "--version"]).stdout.decode( "utf-8", errors="strict" ).splitlines()[0] if ( str(compiler_path) != compiler["realpath"] or sha256_path(compiler_path) != compiler["sha256"] or compiler_version != compiler["version"] ): raise GateFailure("INFRA_BLOCKED", "cross compiler identity changed") compiler_targets = run([str(compiler_path), "--print-targets"]).stdout.decode( "utf-8", errors="strict" ) architectures = SPEC["architectures"] if [item.get("id") for item in architectures] != ["arm64", "riscv64", "i386"]: raise GateFailure("RUNNER_FAIL", "architecture audit set is not exact") if sum(item.get("pointer_bits") == 32 for item in architectures) < 1: raise GateFailure("RUNNER_FAIL", "architecture audit lacks a 32-bit target") source_support = {} for architecture in architectures: arch_id = architecture["id"] header = FREEBSD_SRC / "sys" / architecture["machine_header_dir"] / "include/param.h" if not header.is_file(): raise GateFailure("INFRA_BLOCKED", f"FreeBSD source lacks {arch_id}") if sha256_path(header) != architecture["param_h_sha256"]: raise GateFailure("INFRA_BLOCKED", f"FreeBSD {arch_id} source identity changed") target_pattern = rf"^\s*{re.escape(architecture['compiler_backend'])}\s+-" if re.search(target_pattern, compiler_targets, re.MULTILINE) is None: raise GateFailure("INFRA_BLOCKED", f"clang lacks {arch_id} backend") source_support[arch_id] = { "status": "PASS", "freebsd_machine_headers": str(header), "param_h_sha256": sha256_path(header), "compiler_backend": architecture["compiler_backend"], "target_triple": architecture["target_triple"], "pointer_bits": architecture["pointer_bits"], } probe_source = SPEC["cross_build_contract"]["unaligned_endian_probe_source"].encode("ascii") if sha256_bytes(probe_source) != SPEC["cross_build_contract"]["unaligned_endian_probe_sha256"]: raise GateFailure("RUNNER_FAIL", "input-recorded unaligned/endian probe changed") inventory = { "schema": 1, "host": {"system": platform.system(), "machine": platform.machine()}, "local_host_is_qualifying_native_freebsd": False, "local_host_reason": "host is not FreeBSD and is not any candidate architecture", "declared_native_environments": { item["id"]: item["native_environment"] is not None for item in architectures }, "emulator_tools": { item["id"]: shutil.which(item["emulator_tool"]) for item in architectures }, "emulator_binary_is_native_runtime_evidence": False, "source_toolchain_support": source_support, "protected_resources_addressed": False, "inventory_rule": "only an explicit, validated same-architecture FreeBSD runner declaration can start cross work", } write_json(OUTPUT / "runtime-environment-inventory.json", inventory) write_json( OUTPUT / "freebsd-source-identity.json", { "path": str(FREEBSD_SRC), "git_root": str(git_root), "git_prefix": freebsd_prefix, "git_tree_path": freebsd["git_tree_path"], "head": freebsd_head, "source_tree_oid": freebsd_source_tree, "sys_tree_oid": freebsd_sys_tree, "sha256": freebsd_hashes, }, ) write_json( OUTPUT / "toolchain-identity.json", { "compiler_realpath": str(compiler_path), "compiler_sha256": sha256_path(compiler_path), "compiler_version": compiler_version, "print_targets_sha256": sha256_bytes(compiler_targets.encode("utf-8")), }, ) results = [] go_architectures = [] for architecture in architectures: declaration = architecture["native_environment"] record: dict[str, Any] = { "architecture": architecture["id"], "machine_arch": architecture["machine_arch"], "pointer_bits": architecture["pointer_bits"], "source_toolchain": source_support[architecture["id"]], } if declaration is None: record.update( { "native_environment": { "status": "STOP", "reason": "no declared same-architecture FreeBSD runtime environment", }, "cross_build_and_probes": { "status": "NOT_RUN", "reason": "cross-only evidence cannot authorize allowlisting", }, "native_runtime": { "status": "NOT_RUN", "reason": "same-architecture FreeBSD runtime is absent", }, "decision": "STOP", } ) results.append(record) continue for key in ( "runner_path", "runner_sha256", "preflight_argv", "runtime_argv", "preflight_deadline_seconds", "runtime_deadline_seconds", ): if key not in declaration: raise GateFailure("RUNNER_FAIL", f"incomplete native declaration: {key}") cross = compile_architecture( architecture, resolved, patch_bytes, compiler_path ) native = run_native( architecture, declaration, cross["modules"], resolved, patch_spec["sha256"], ) native_pass = native["status"] == "PASS" record.update( { "native_environment": {"status": "PASS", "declaration": declaration}, "cross_build_and_probes": cross, "native_runtime": native, "decision": "GO" if native_pass else "STOP", } ) if native_pass: go_architectures.append(architecture["id"]) results.append(record) overall_status = "GO" if go_architectures else "STOP" result = { "schema": 1, "gate": "G07", "candidate": "P15-027", "batch": "B36", "status": overall_status, "reason": ( "at least one architecture completed its own cross and native requirements" if go_architectures else "no architecture has a declared same-architecture FreeBSD runtime" ), "requested_base": REQUESTED_BASE, "resolved_base": resolved, "repo_source_tree_oid": source_tree, "deadline_seconds": DEADLINE, "expected_exit_code": 0 if go_architectures else 22, "architectures": results, "go_architectures": go_architectures, "allowlist_authorization": go_architectures, "false_go_guard": "each authorized architecture must independently have cross_build_and_probes=PASS and native_runtime=PASS", "b36": "AUTHORIZED" if go_architectures else "STOP-NO-SOURCE", "production_makefile_guard_preserved": True, "production_source_changed": False, "qemu": "NOT_RUN" if not go_architectures else "runner-defined", "full_feature_suite": "NOT_RUN", "smoke_suite": "NOT_RUN", "protected_resources_addressed": False, } write_json(OUTPUT / "result.json", result) print(json.dumps(result, ensure_ascii=True, sort_keys=True)) return 0 if go_architectures else 22 try: raise SystemExit(main()) except GateFailure as error: failure = { "schema": 1, "gate": "G07", "candidate": "P15-027", "status": error.status, "reason": error.reason, "requested_base": REQUESTED_BASE, "deadline_seconds": DEADLINE, "b36": "NOT_RUN", "target_marker": "not_reached", "production_source_changed": False, "protected_resources_addressed": False, } write_json(OUTPUT / "result.json", failure) print(json.dumps(failure, ensure_ascii=True, sort_keys=True)) raise SystemExit({"RUNNER_FAIL": 20, "INFRA_BLOCKED": 21}.get(error.status, 20)) PY gate_rc=$? set -e cleanup_status=PASS if ! rm -rf -- "$work"; then cleanup_status=FAIL gate_rc=20 fi trap - EXIT HUP INT TERM printf 'owned temporary path removed: %s\ncleanup=%s\n' \ "$work" "$cleanup_status" >"$output/cleanup.log" python3 -B - "$output" "$gate_rc" "$cleanup_status" <<'PY' from __future__ import annotations import hashlib import json from pathlib import Path import sys output = Path(sys.argv[1]) exit_code = int(sys.argv[2]) cleanup = sys.argv[3] if cleanup != "PASS": status = "RUNNER_FAIL" origin = "runner" elif exit_code == 0: status = "PASS" origin = "gate" elif exit_code == 22: status = "STOP" origin = "gate" elif exit_code in (124, 137): status = "INFRA_BLOCKED" origin = "infrastructure" else: status = "RUNNER_FAIL" origin = "runner" (output / "attempt.json").write_text( json.dumps( { "schema": 1, "exit_code": exit_code, "status": status, "failure_origin": origin, "cleanup": cleanup, "target_marker": "reached" if status in {"PASS", "STOP"} else "not_reached", }, ensure_ascii=True, indent=2, sort_keys=True, ) + "\n", encoding="ascii", ) lines = [] for path in sorted(output.iterdir(), key=lambda item: item.name): if path.is_file() and path.name != "SHA256SUMS": digest = hashlib.sha256(path.read_bytes()).hexdigest() lines.append(f"{digest} {path.name}") (output / "SHA256SUMS").write_text("\n".join(lines) + "\n", encoding="ascii") PY printf 'P15-027 gate exit=%s cleanup=%s output=%s\n' \ "$gate_rc" "$cleanup_status" "$output" exit "$gate_rc"