#!/usr/bin/env bash # Credential-safe, closed S12 evidence harness. Self-test uses temporary fakes only. set -euo pipefail umask 077 readonly EXIT_USAGE=64 readonly EXIT_VALIDATION=69 readonly SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" readonly REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" readonly SELF="$SCRIPT_DIR/e2e-single-request-claude.sh" readonly DEFAULT_SCHEMA="$SCRIPT_DIR/fixtures/single-request-claude-smoke-manifest.schema.json" readonly EXPECTED_RESULT='IOP single-request Claude smoke verified.' readonly PROMPT='Create smoke-result.txt containing exactly one line: IOP single-request Claude smoke verified. The file must end with a terminating newline. Verify the exact file bytes before finishing.' readonly MAX_CAPTURE_BYTES=8388608 readonly MAX_FRESH_OBSERVATION_BYTES=16777216 readonly CHILD_SUPERVISOR_GRACE_SECONDS=2 readonly CHILD_SUPERVISOR_WAIT_TICKS=60 RUN_TMP_ROOT='' RUN_TMP='' PUBLISH_TMP='' PUBLISH_PARENT='' PUBLISH_PREFIX='' CHILD_PID='' CLEANING=0 log() { printf '[single-request-claude-smoke] %s\n' "$*" >&2 } fail() { log "validation failed: $*" exit "$EXIT_VALIDATION" } usage() { printf '%s\n' 'usage: e2e-single-request-claude.sh --self-test | --validate-manifest PATH [--schema PATH] | --preflight-only|--run --claude PATH --runtime-evidence PATH --base-url URL --model ID --edge-bin PATH --node-bin PATH --edge-config PATH --observation-file PATH --metrics-url URL --workspace PATH --output PATH --secret-env NAME [--schema PATH]' >&2 } sha_string() { python3 - "$1" <<'PY' import hashlib, sys print("sha256:" + hashlib.sha256(sys.argv[1].encode()).hexdigest()) PY } sha_file() { python3 - "$1" <<'PY' import hashlib, sys h = hashlib.sha256() with open(sys.argv[1], "rb") as stream: for block in iter(lambda: stream.read(1024 * 1024), b""): h.update(block) print("sha256:" + h.hexdigest()) PY } canonical_existing() { python3 - "$1" <<'PY' import os, sys path = os.path.realpath(sys.argv[1]) if not os.path.exists(path): raise SystemExit(1) print(path) PY } file_identity() { python3 - "$1" <<'PY' import os, stat, sys st = os.lstat(sys.argv[1]) if not stat.S_ISREG(st.st_mode): raise SystemExit(1) print(st.st_dev, st.st_ino, st.st_size) PY } file_size() { python3 - "$1" <<'PY' import os, sys print(os.lstat(sys.argv[1]).st_size) PY } prefix_digest() { python3 - "$1" "$2" <<'PY' import hashlib, sys path, raw_size = sys.argv[1:] remaining = int(raw_size) h = hashlib.sha256() with open(path, "rb") as stream: while remaining: block = stream.read(min(1024 * 1024, remaining)) if not block: raise SystemExit(1) h.update(block) remaining -= len(block) print("sha256:" + h.hexdigest()) PY } tree_digest() { python3 - "$1" <<'PY' import hashlib, os, stat, sys root = os.path.realpath(sys.argv[1]) records = [] for current, dirs, files in os.walk(root, topdown=True, followlinks=False): dirs.sort() files.sort() for name in dirs + files: path = os.path.join(current, name) rel = os.path.relpath(path, root).replace(os.sep, "/") st = os.lstat(path) if stat.S_ISREG(st.st_mode): body = hashlib.sha256() with open(path, "rb") as stream: for block in iter(lambda: stream.read(1024 * 1024), b""): body.update(block) kind, value = "file", body.hexdigest() elif stat.S_ISDIR(st.st_mode): kind, value = "dir", "" elif stat.S_ISLNK(st.st_mode): kind = "link" value = hashlib.sha256(os.readlink(path).encode()).hexdigest() else: kind, value = "special", str(stat.S_IFMT(st.st_mode)) records.append((rel, kind, value)) h = hashlib.sha256() for record in sorted(records): h.update("\0".join(record).encode() + b"\0") print("sha256:" + h.hexdigest()) PY } worktree_digest() { python3 - "$REPO_ROOT" <<'PY' import hashlib, os, sys root = os.path.realpath(sys.argv[1]) inputs = [ "apps/edge/internal/openai", "apps/edge/internal/service", "apps/node/internal/bootstrap", "apps/node/internal/workspace", "packages/go/config", "scripts/e2e-single-request-claude.sh", "scripts/fixtures/single-request-claude-smoke-manifest.schema.json", "Makefile", ] files = [] for rel in inputs: path = os.path.join(root, rel) if os.path.isdir(path): for current, dirs, names in os.walk(path): dirs.sort() for name in sorted(names): candidate = os.path.join(current, name) if os.path.isfile(candidate) and not os.path.islink(candidate): files.append(candidate) elif os.path.isfile(path) and not os.path.islink(path): files.append(path) h = hashlib.sha256() for path in sorted(files): rel = os.path.relpath(path, root).replace(os.sep, "/") body = hashlib.sha256() with open(path, "rb") as stream: for block in iter(lambda: stream.read(1024 * 1024), b""): body.update(block) h.update(rel.encode() + b"\0" + body.hexdigest().encode() + b"\0") print("sha256:" + h.hexdigest()) PY } observed_worktree_digest() { if [ "${IOP_SMOKE_SELF_TEST-}" = '1' ] && [[ "${IOP_SMOKE_TEST_WORKTREE_DIGEST-}" =~ ^sha256:[0-9a-f]{64}$ ]]; then printf '%s\n' "$IOP_SMOKE_TEST_WORKTREE_DIGEST" return fi worktree_digest } current_branch_digest() { local branch branch="$(git -C "$REPO_ROOT" rev-parse --abbrev-ref HEAD 2>/dev/null)" || fail 'source branch unavailable' sha_string "$branch" } runner_os() { python3 - <<'PY' import platform print(platform.system().lower()) PY } runner_arch() { python3 - <<'PY' import platform print(platform.machine().lower()) PY } parse_args() { MODE='' SCHEMA="$DEFAULT_SCHEMA" MANIFEST='' CLAUDE_BIN='' RUNTIME_EVIDENCE='' BASE_URL='' MODEL='' EDGE_BIN='' NODE_BIN='' EDGE_CONFIG='' OBSERVATION_FILE='' METRICS_URL='' WORKSPACE='' OUTPUT='' SECRET_ENV='' while (($#)); do case "$1" in --self-test|--preflight-only|--run) [ -z "$MODE" ] || { usage; exit "$EXIT_USAGE"; } MODE="${1#--}" ;; --validate-manifest) [ -z "$MODE" ] || { usage; exit "$EXIT_USAGE"; } MODE='validate-manifest' shift (($#)) || { usage; exit "$EXIT_USAGE"; } MANIFEST="$1" ;; --schema|--claude|--runtime-evidence|--base-url|--model|--edge-bin|--node-bin|--edge-config|--observation-file|--metrics-url|--workspace|--output|--secret-env) local key="$1" shift (($#)) || { usage; exit "$EXIT_USAGE"; } case "$key" in --schema) SCHEMA="$1" ;; --claude) CLAUDE_BIN="$1" ;; --runtime-evidence) RUNTIME_EVIDENCE="$1" ;; --base-url) BASE_URL="$1" ;; --model) MODEL="$1" ;; --edge-bin) EDGE_BIN="$1" ;; --node-bin) NODE_BIN="$1" ;; --edge-config) EDGE_CONFIG="$1" ;; --observation-file) OBSERVATION_FILE="$1" ;; --metrics-url) METRICS_URL="$1" ;; --workspace) WORKSPACE="$1" ;; --output) OUTPUT="$1" ;; --secret-env) SECRET_ENV="$1" ;; esac ;; *) usage exit "$EXIT_USAGE" ;; esac shift done [ -n "$MODE" ] || { usage; exit "$EXIT_USAGE"; } } validate_schema_contract() { python3 - "$1" <<'PY' import json, sys try: schema = json.load(open(sys.argv[1])) except Exception: raise SystemExit(1) def closed(value): if isinstance(value, dict): if value.get("type") == "object" and value.get("additionalProperties") is not False: return False return all(closed(item) for item in value.values()) if isinstance(value, list): return all(closed(item) for item in value) return True root = ["schema_version", "source", "runtime", "ingress", "stages", "terminal", "workspace", "verification", "redaction"] runtime = [ "runner_os", "runner_arch", "workspace_os", "workspace_arch", "workspace_root_digest", "workspace_owner_digest", "claude_digest", "claude_version_digest", "claude_help_digest", "edge_digest", "edge_version_digest", "node_digest", "node_version_digest", "config_digest", "config_check_digest", "schema_digest", "base_url_digest", "public_model_digest", "stage_engines", "stage_binding_digest", ] defs = schema.get("$defs", {}) if not closed(schema): raise SystemExit(1) if schema.get("type") != "object" or schema.get("additionalProperties") is not False: raise SystemExit(1) if schema.get("required") != root: raise SystemExit(1) if defs.get("runtime", {}).get("required") != runtime: raise SystemExit(1) if defs.get("workspace", {}).get("required") != ["before_digest", "after_digest", "changed"]: raise SystemExit(1) if defs.get("verification", {}).get("required") != ["command_digest", "result_file_digest", "exit_code"]: raise SystemExit(1) PY } validate_manifest() { python3 - "$1" "$2" <<'PY' import hashlib, json, re, sys try: manifest = json.load(open(sys.argv[1])) schema = json.load(open(sys.argv[2])) except Exception: raise SystemExit(1) def closed(value): if isinstance(value, dict): if value.get("type") == "object" and value.get("additionalProperties") is not False: return False return all(closed(item) for item in value.values()) if isinstance(value, list): return all(closed(item) for item in value) return True def exact(value, keys): return isinstance(value, dict) and set(value) == set(keys) digest_pattern = re.compile(r"^sha256:[0-9a-f]{64}$") head_pattern = re.compile(r"^[0-9a-f]{40}$") platform_pattern = re.compile(r"^[a-z0-9_+-]{1,32}$") bad_key = re.compile(r"prompt|output|token|key|auth|credential|secret|password|api_key|apikey|endpoint|bearer|cookie|session", re.I) bad_raw = re.compile(r"SECRET_SENTINEL|RAW_|https?://|Bearer\s|sk-ant-", re.I) def digest(value): return isinstance(value, str) and bool(digest_pattern.fullmatch(value)) def safe(value): if isinstance(value, dict): return all((key == "forbidden_key_count" or not bad_key.search(key)) and safe(item) for key, item in value.items()) if isinstance(value, list): return all(safe(item) for item in value) return not (isinstance(value, str) and bad_raw.search(value)) root_keys = ["schema_version", "source", "runtime", "ingress", "stages", "terminal", "workspace", "verification", "redaction"] source_keys = ["head", "branch_digest", "worktree_digest"] runtime_keys = [ "runner_os", "runner_arch", "workspace_os", "workspace_arch", "workspace_root_digest", "workspace_owner_digest", "claude_digest", "claude_version_digest", "claude_help_digest", "edge_digest", "edge_version_digest", "node_digest", "node_version_digest", "config_digest", "config_check_digest", "schema_digest", "base_url_digest", "public_model_digest", "stage_engines", "stage_binding_digest", ] if not closed(schema) or not exact(manifest, root_keys) or manifest.get("schema_version") != "1" or not safe(manifest): raise SystemExit(1) source = manifest["source"] runtime = manifest["runtime"] if not exact(source, source_keys) or not head_pattern.fullmatch(source["head"]): raise SystemExit(1) if not all(digest(source[key]) for key in ["branch_digest", "worktree_digest"]): raise SystemExit(1) if not exact(runtime, runtime_keys): raise SystemExit(1) if not platform_pattern.fullmatch(runtime["runner_os"]) or not platform_pattern.fullmatch(runtime["runner_arch"]): raise SystemExit(1) if runtime["workspace_os"] not in {"darwin", "linux"} or runtime["workspace_os"] != runtime["runner_os"] or not platform_pattern.fullmatch(runtime["workspace_arch"]): raise SystemExit(1) runtime_digests = [key for key in runtime_keys if key.endswith("_digest")] if not all(digest(runtime[key]) for key in runtime_digests): raise SystemExit(1) engines = runtime["stage_engines"] if engines != ["gemini", "ornith-fast", "gemini"]: raise SystemExit(1) owner_material = "|".join([ runtime["workspace_os"], runtime["workspace_arch"], runtime["workspace_root_digest"], runtime["config_digest"], runtime["node_digest"], runtime["node_version_digest"], ]) owner_digest = "sha256:" + hashlib.sha256(owner_material.encode()).hexdigest() binding_material = "|".join([runtime["config_digest"], runtime["config_check_digest"], runtime["base_url_digest"], runtime["public_model_digest"], *engines]) binding_digest = "sha256:" + hashlib.sha256(binding_material.encode()).hexdigest() if runtime["workspace_owner_digest"] != owner_digest or runtime["stage_binding_digest"] != binding_digest: raise SystemExit(1) ingress = manifest["ingress"] if not exact(ingress, ["delta"]) or isinstance(ingress["delta"], bool) or not isinstance(ingress["delta"], int) or ingress["delta"] != 1: raise SystemExit(1) stages = manifest["stages"] if not isinstance(stages, list) or len(stages) != 3: raise SystemExit(1) for item, stage, engine in zip(stages, ["plan", "work", "review"], engines): if not exact(item, ["stage", "engine_family", "duration_ms", "binding_digest"]): raise SystemExit(1) if item["stage"] != stage or item["engine_family"] != engine or item["binding_digest"] != binding_digest: raise SystemExit(1) if isinstance(item["duration_ms"], bool) or not isinstance(item["duration_ms"], int) or item["duration_ms"] < 0: raise SystemExit(1) terminal = manifest["terminal"] if not exact(terminal, ["count", "stop_reason", "duration_ms"]) or isinstance(terminal["count"], bool) or not isinstance(terminal["count"], int) or terminal["count"] != 1 or terminal["stop_reason"] != "end_turn": raise SystemExit(1) if isinstance(terminal["duration_ms"], bool) or not isinstance(terminal["duration_ms"], int) or terminal["duration_ms"] < 0: raise SystemExit(1) workspace = manifest["workspace"] if not exact(workspace, ["before_digest", "after_digest", "changed"]): raise SystemExit(1) if not digest(workspace["before_digest"]) or not digest(workspace["after_digest"]) or workspace["before_digest"] == workspace["after_digest"] or workspace["changed"] is not True: raise SystemExit(1) verification = manifest["verification"] if not exact(verification, ["command_digest", "result_file_digest", "exit_code"]): raise SystemExit(1) if not digest(verification["command_digest"]) or not digest(verification["result_file_digest"]): raise SystemExit(1) if isinstance(verification["exit_code"], bool) or not isinstance(verification["exit_code"], int) or verification["exit_code"] != 0: raise SystemExit(1) redaction = manifest["redaction"] if not exact(redaction, ["forbidden_match_count", "forbidden_key_count"]): raise SystemExit(1) if any(isinstance(redaction[key], bool) or not isinstance(redaction[key], int) or redaction[key] != 0 for key in redaction): raise SystemExit(1) PY } validate_url() { python3 - "$1" <<'PY' import sys, urllib.parse try: parsed = urllib.parse.urlsplit(sys.argv[1]) except Exception: raise SystemExit(1) if parsed.scheme not in {"http", "https"} or not parsed.hostname: raise SystemExit(1) if parsed.username is not None or parsed.password is not None or parsed.query or parsed.fragment: raise SystemExit(1) if any(ord(char) < 32 or ord(char) == 127 for char in sys.argv[1]): raise SystemExit(1) PY } validate_claude_base() { python3 - "$1" <<'PY' import sys, urllib.parse try: parsed = urllib.parse.urlsplit(sys.argv[1]) except Exception: raise SystemExit(1) if parsed.scheme not in {"http", "https"} or not parsed.hostname: raise SystemExit(1) if parsed.username is not None or parsed.password is not None or parsed.query or parsed.fragment: raise SystemExit(1) if parsed.path not in {"", "/"}: raise SystemExit(1) if any(ord(char) < 32 or ord(char) == 127 for char in sys.argv[1]): raise SystemExit(1) PY } validate_model() { python3 - "$1" <<'PY' import sys value = sys.argv[1] if not value or len(value.encode()) > 256 or any(ord(char) < 32 or ord(char) == 127 for char in value): raise SystemExit(1) PY } validate_observation_source() { python3 - "$1" <<'PY' import json, os, sys path = sys.argv[1] allowed_messages = { "bootstrap artifact server listening", "connected to control plane", "edge listening for nodes", "edge_anthropic_pre_ingress_rejection", "edge_single_request_observation", "edge_single_request_terminal_rejection", "node connection established", "node ready", "node registration accepted, awaiting dispatch-ready", "node unregistered", "openai-compatible server listening", } limit = 1024 * 1024 size = os.path.getsize(path) with open(path, "rb") as stream: if size > limit: stream.seek(size - limit) stream.readline() body = stream.read(limit) for raw in body.splitlines(): try: item = json.loads(raw) except Exception: continue if not isinstance(item, dict): continue level, timestamp, message = item.get("level"), item.get("ts"), item.get("msg") if ( isinstance(level, str) and isinstance(timestamp, (int, float)) and not isinstance(timestamp, bool) and isinstance(message, str) and message in allowed_messages ): raise SystemExit(0) raise SystemExit(1) PY } validate_support_tools() { local tool if [ "${IOP_SMOKE_SELF_TEST-}" = '1' ] && [ "${IOP_SMOKE_TEST_FAIL_CHECK-}" = 'support-tool' ]; then fail 'required support executable unavailable' fi for tool in python3 curl git cmp mktemp grep sed rm chmod basename dirname printenv env sleep; do command -v "$tool" >/dev/null 2>&1 || fail 'required support executable unavailable' done } stop_child_supervisor() { local pid="$1" tick kill -TERM "$pid" >/dev/null 2>&1 || true for ((tick = 0; tick < CHILD_SUPERVISOR_WAIT_TICKS; tick++)); do kill -0 "$pid" >/dev/null 2>&1 || break sleep 0.05 done if kill -0 "$pid" >/dev/null 2>&1; then kill -KILL "$pid" >/dev/null 2>&1 || true fi wait "$pid" >/dev/null 2>&1 || true } cleanup_run_artifacts() { [ "$CLEANING" -eq 0 ] || return 0 CLEANING=1 if [ -n "$CHILD_PID" ]; then stop_child_supervisor "$CHILD_PID" CHILD_PID='' fi if [ -n "$PUBLISH_TMP" ] && [ -n "$PUBLISH_PARENT" ] && [ -n "$PUBLISH_PREFIX" ]; then local publish_parent publish_name publish_parent="$(canonical_existing "$(dirname "$PUBLISH_TMP")" 2>/dev/null || true)" publish_name="$(basename "$PUBLISH_TMP")" if [ "$publish_parent" = "$PUBLISH_PARENT" ] && [[ "$publish_name" == "$PUBLISH_PREFIX"* ]]; then rm -f -- "$PUBLISH_TMP" fi PUBLISH_TMP='' fi if [ -n "$RUN_TMP" ] && [ -n "$RUN_TMP_ROOT" ]; then local run_parent run_name run_parent="$(canonical_existing "$(dirname "$RUN_TMP")" 2>/dev/null || true)" run_name="$(basename "$RUN_TMP")" if [ "$run_parent" = "$RUN_TMP_ROOT" ] && [[ "$run_name" == single-request-claude.* ]]; then rm -rf -- "$RUN_TMP" fi RUN_TMP='' fi CLEANING=0 } handle_signal() { local status="$1" cleanup_run_artifacts trap - EXIT HUP INT TERM exit "$status" } create_run_context() { local requested_root requested_root="${IOP_SMOKE_TMP_ROOT:-${TMPDIR:-/tmp}}" RUN_TMP_ROOT="$(canonical_existing "$requested_root" 2>/dev/null)" || fail 'temporary root unavailable' [ -d "$RUN_TMP_ROOT" ] && [ -w "$RUN_TMP_ROOT" ] || fail 'temporary root unavailable' RUN_TMP="$(mktemp -d "$RUN_TMP_ROOT/single-request-claude.XXXXXX")" || fail 'temporary run directory unavailable' chmod 700 "$RUN_TMP" trap cleanup_run_artifacts EXIT trap 'handle_signal 129' HUP trap 'handle_signal 130' INT trap 'handle_signal 143' TERM } finish_run_context() { cleanup_run_artifacts trap - EXIT HUP INT TERM } prepare_output_target() { [[ "$OUTPUT" == /* ]] || fail 'output target unsafe' local parent name parent="$(canonical_existing "$(dirname "$OUTPUT")" 2>/dev/null)" || fail 'output parent unavailable' name="$(basename "$OUTPUT")" [ -d "$parent" ] && [ -w "$parent" ] || fail 'output parent unavailable' [ "$OUTPUT" = "$parent/$name" ] || fail 'output target unsafe' [ "$name" != '.' ] && [ "$name" != '..' ] && [ -n "$name" ] || fail 'output target unsafe' [ ! -e "$OUTPUT" ] && [ ! -L "$OUTPUT" ] || fail 'output target already exists' PUBLISH_PARENT="$parent" PUBLISH_PREFIX=".$name.tmp." PUBLISH_TMP="$(mktemp "$PUBLISH_PARENT/$PUBLISH_PREFIX"'XXXXXX')" || fail 'publication temporary unavailable' } capture_command() { local target="$1" shift python3 - "$target" "$@" <<'PY' import os, signal, subprocess, sys target, *command = sys.argv[1:] try: with open(target, "wb") as output: process = subprocess.Popen(command, stdout=output, stderr=subprocess.STDOUT, start_new_session=True) try: status = process.wait(timeout=8) except subprocess.TimeoutExpired: os.killpg(process.pid, signal.SIGKILL) process.wait() raise SystemExit(1) if status != 0 or os.path.getsize(target) == 0 or os.path.getsize(target) > 65536: raise SystemExit(1) except Exception: raise SystemExit(1) PY } load_runtime() { local facts facts="$(python3 - "$RUNTIME_EVIDENCE" <<'PY' import hashlib, json, re, sys try: data = json.load(open(sys.argv[1])) source = data["source"] runtime = data["runtime"] digest = re.compile(r"^sha256:[0-9a-f]{64}$") platform = re.compile(r"^[a-z0-9_+-]{1,32}$") source_keys = {"head", "branch_digest", "worktree_digest"} runtime_keys = { "runner_os", "runner_arch", "workspace_os", "workspace_arch", "workspace_root_digest", "workspace_owner_digest", "claude_digest", "claude_version_digest", "claude_help_digest", "edge_digest", "edge_version_digest", "node_digest", "node_version_digest", "config_digest", "config_check_digest", "schema_digest", "base_url_digest", "public_model_digest", "stage_engines", "stage_binding_digest", } assert set(data) == {"schema_version", "source", "runtime"} and data["schema_version"] == "1" assert set(source) == source_keys and set(runtime) == runtime_keys assert re.fullmatch(r"[0-9a-f]{40}", source["head"]) assert all(digest.fullmatch(source[key]) for key in ["branch_digest", "worktree_digest"]) assert platform.fullmatch(runtime["runner_os"]) and platform.fullmatch(runtime["runner_arch"]) assert runtime["workspace_os"] in {"darwin", "linux"} assert runtime["workspace_os"] == runtime["runner_os"] and platform.fullmatch(runtime["workspace_arch"]) assert all(digest.fullmatch(runtime[key]) for key in runtime_keys if key.endswith("_digest")) assert runtime["stage_engines"] == ["gemini", "ornith-fast", "gemini"] owner_material = "|".join([ runtime["workspace_os"], runtime["workspace_arch"], runtime["workspace_root_digest"], runtime["config_digest"], runtime["node_digest"], runtime["node_version_digest"], ]) owner = "sha256:" + hashlib.sha256(owner_material.encode()).hexdigest() binding_material = "|".join([runtime["config_digest"], runtime["config_check_digest"], runtime["base_url_digest"], runtime["public_model_digest"], *runtime["stage_engines"]]) binding = "sha256:" + hashlib.sha256(binding_material.encode()).hexdigest() assert runtime["workspace_owner_digest"] == owner and runtime["stage_binding_digest"] == binding values = [ source["head"], source["branch_digest"], source["worktree_digest"], runtime["runner_os"], runtime["runner_arch"], runtime["workspace_os"], runtime["workspace_arch"], runtime["workspace_root_digest"], runtime["workspace_owner_digest"], runtime["claude_digest"], runtime["claude_version_digest"], runtime["claude_help_digest"], runtime["edge_digest"], runtime["edge_version_digest"], runtime["node_digest"], runtime["node_version_digest"], runtime["config_digest"], runtime["config_check_digest"], runtime["schema_digest"], runtime["base_url_digest"], runtime["public_model_digest"], *runtime["stage_engines"], runtime["stage_binding_digest"], ] print("\t".join(values)) except Exception: raise SystemExit(1) PY )" 2>/dev/null || fail 'runtime evidence invalid' IFS=$'\t' read -r RHEAD RBRANCH RTREE RRUNNER_OS RRUNNER_ARCH RWORKSPACE_OS RWORKSPACE_ARCH RWORKSPACE_ROOT RWORKSPACE_OWNER RCLAUDE RCLAUDE_VERSION RCLAUDE_HELP REDGE REDGE_VERSION RNODE RNODE_VERSION RCONFIG RCONFIG_CHECK RSCHEMA RBASE RPUBLIC_MODEL RPLAN_ENGINE RWORK_ENGINE RREVIEW_ENGINE RBIND <<<"$facts" [ -n "$RBIND" ] || fail 'runtime evidence invalid' } validate_runtime_snapshot() { local phase="$1" local workspace_root claude_version claude_help edge_version node_version config_check [ "$RHEAD" = "$(git -C "$REPO_ROOT" rev-parse HEAD 2>/dev/null)" ] || fail 'source head mismatch' [ "$RBRANCH" = "$(current_branch_digest)" ] || fail 'source branch mismatch' [ "$RTREE" = "$(observed_worktree_digest)" ] || fail 'source worktree mismatch' [ "$RRUNNER_OS" = "$(runner_os)" ] || fail 'runner operating system mismatch' [ "$RRUNNER_ARCH" = "$(runner_arch)" ] || fail 'runner architecture mismatch' workspace_root="$(canonical_existing "$WORKSPACE" 2>/dev/null)" || fail 'workspace unavailable' [ "$WORKSPACE" = "$workspace_root" ] || fail 'workspace target unsafe' [ "$RWORKSPACE_ROOT" = "$(sha_string "$workspace_root")" ] || fail 'workspace identity mismatch' [ "$RCLAUDE" = "$(sha_file "$CLAUDE_BIN")" ] || fail 'Claude identity mismatch' [ "$REDGE" = "$(sha_file "$EDGE_BIN")" ] || fail 'Edge identity mismatch' [ "$RNODE" = "$(sha_file "$NODE_BIN")" ] || fail 'Node identity mismatch' [ "$RCONFIG" = "$(sha_file "$EDGE_CONFIG")" ] || fail 'config identity mismatch' [ "$RSCHEMA" = "$(sha_file "$SCHEMA")" ] || fail 'schema identity mismatch' [ "$RBASE" = "$(sha_string "$BASE_URL")" ] || fail 'base URL identity mismatch' [ "$RPUBLIC_MODEL" = "$(sha_string "$MODEL")" ] || fail 'public model identity mismatch' claude_version="$RUN_TMP/$phase-claude-version" claude_help="$RUN_TMP/$phase-claude-help" edge_version="$RUN_TMP/$phase-edge-version" node_version="$RUN_TMP/$phase-node-version" config_check="$RUN_TMP/$phase-config-check" capture_command "$claude_version" "$CLAUDE_BIN" --version 2>/dev/null || fail 'Claude version check failed' capture_command "$claude_help" "$CLAUDE_BIN" --help 2>/dev/null || fail 'Claude help check failed' local flag for flag in --print --output-format --verbose --no-session-persistence --bare; do grep -Fq -- "$flag" "$claude_help" || fail 'Claude required flag unavailable' done capture_command "$edge_version" "$EDGE_BIN" version 2>/dev/null || fail 'Edge version check failed' capture_command "$node_version" "$NODE_BIN" version 2>/dev/null || fail 'Node version check failed' capture_command "$config_check" "$EDGE_BIN" config check --config "$EDGE_CONFIG" 2>/dev/null || fail 'Edge config check failed' [ "$RCLAUDE_VERSION" = "$(sha_file "$claude_version")" ] || fail 'Claude version identity mismatch' [ "$RCLAUDE_HELP" = "$(sha_file "$claude_help")" ] || fail 'Claude help identity mismatch' [ "$REDGE_VERSION" = "$(sha_file "$edge_version")" ] || fail 'Edge version identity mismatch' [ "$RNODE_VERSION" = "$(sha_file "$node_version")" ] || fail 'Node version identity mismatch' [ "$RCONFIG_CHECK" = "$(sha_file "$config_check")" ] || fail 'config check identity mismatch' } probe_urls() { python3 - "$BASE_URL" <<'PY' import sys, urllib.parse parsed = urllib.parse.urlsplit(sys.argv[1]) origin = urllib.parse.urlunsplit((parsed.scheme, parsed.netloc, "", "", "")) print(origin + "/healthz") print(origin + "/v1/messages") print(origin + "/anthropic/v1/models") PY } probe_health_listener() { local health_url health_url="$(probe_urls | sed -n '1p')" || fail 'base URL probe derivation failed' [ -n "$health_url" ] || fail 'base URL probe derivation failed' curl -fsS --max-time 5 --max-filesize 8192 "$health_url" >"$RUN_TMP/health-body" 2>"$RUN_TMP/health-error" || fail 'health listener unavailable' } probe_messages_listener() { local code messages_url messages_url="$(probe_urls | sed -n '2p')" || fail 'base URL probe derivation failed' [ -n "$messages_url" ] || fail 'base URL probe derivation failed' code="$(curl -sS --max-time 5 --max-filesize 8192 -o "$RUN_TMP/messages-body" -w '%{http_code}' -X OPTIONS "$messages_url" 2>"$RUN_TMP/messages-error")" || fail 'Messages listener unavailable' case "$code" in 401|405) ;; *) fail 'Messages listener unavailable' ;; esac } probe_authenticated_model() { local catalog_url catalog_body catalog_url="$(probe_urls | sed -n '3p')" || fail 'authenticated model probe derivation failed' [ -n "$catalog_url" ] || fail 'authenticated model probe derivation failed' catalog_body="$RUN_TMP/authenticated-model-body" IOP_SMOKE_AUTH_SECRET="$SECRET_VALUE" \ python3 - <<'PY' | \ curl --config - -fsS --max-time 5 --max-filesize 8192 \ -o "$catalog_body" "$catalog_url" \ 2>"$RUN_TMP/authenticated-model-error" || fail 'authenticated model probe rejected' import os secret = os.environ.pop("IOP_SMOKE_AUTH_SECRET") if not secret or "\n" in secret or "\r" in secret: raise SystemExit(1) escaped = secret.replace("\\", "\\\\").replace('"', '\\"') print('header = "x-api-key: ' + escaped + '"') print('header = "anthropic-version: 2023-06-01"') PY python3 - "$catalog_body" "$MODEL" <<'PY' || fail 'authenticated model probe rejected' import json, sys try: path, model = sys.argv[1:] assert model body = open(path, "rb").read(8193) assert len(body) <= 8192 data = json.loads(body) assert set(data) == {"data", "has_more", "first_id", "last_id"} assert data["has_more"] is False and isinstance(data["data"], list) ids = [] for item in data["data"]: assert set(item) == {"id", "created_at", "display_name", "type"} assert all(isinstance(item[key], str) for key in item) assert item["id"] and item["type"] == "model" ids.append(item["id"]) assert ids.count(model) == 1 except Exception: raise SystemExit(1) PY } ingress_value() { local label="$1" local target="$RUN_TMP/metrics-$label" curl -fsS --max-time 5 --max-filesize 1048576 "$METRICS_URL" >"$target" 2>"$RUN_TMP/metrics-$label-error" || fail 'metrics endpoint unavailable' python3 - "$target" <<'PY' import decimal, re, sys values = [] pattern = re.compile(r"^iop_anthropic_single_request_ingress_total\s+([^\s]+)\s*$") for line in open(sys.argv[1]): match = pattern.match(line) if match: try: value = decimal.Decimal(match.group(1)) except decimal.InvalidOperation: raise SystemExit(1) if value < 0 or not value.is_finite(): raise SystemExit(1) values.append(value) if len(values) != 1: raise SystemExit(1) print(values[0]) PY } metric_delta() { python3 - "$1" "$2" <<'PY' import decimal, sys before, after = map(decimal.Decimal, sys.argv[1:]) delta = after - before if delta != 1: raise SystemExit(1) print(delta) PY } capture_observation_snapshot() { read -r OBS_DEVICE OBS_INODE OBS_SIZE <<<"$(file_identity "$OBSERVATION_FILE" 2>/dev/null)" || fail 'observation log unavailable' OBS_PREFIX="$(prefix_digest "$OBSERVATION_FILE" "$OBS_SIZE" 2>/dev/null)" || fail 'observation log unavailable' } capture_runtime_identity() { read -r RUNTIME_DEVICE RUNTIME_INODE RUNTIME_SIZE <<<"$(file_identity "$RUNTIME_EVIDENCE" 2>/dev/null)" || fail 'runtime evidence unavailable' RUNTIME_DIGEST="$(sha_file "$RUNTIME_EVIDENCE")" } validate_runtime_identity_unchanged() { local device inode size read -r device inode size <<<"$(file_identity "$RUNTIME_EVIDENCE" 2>/dev/null)" || fail 'runtime evidence changed' [ "$device" = "$RUNTIME_DEVICE" ] && [ "$inode" = "$RUNTIME_INODE" ] && [ "$size" = "$RUNTIME_SIZE" ] || fail 'runtime evidence changed' [ "$(sha_file "$RUNTIME_EVIDENCE")" = "$RUNTIME_DIGEST" ] || fail 'runtime evidence changed' } preflight() { local ingress_before_auth ingress_after_auth validate_support_tools [ -n "$CLAUDE_BIN" ] && [ -n "$RUNTIME_EVIDENCE" ] && [ -n "$BASE_URL" ] && [ -n "$MODEL" ] || fail 'caller input absent' [ -n "$EDGE_BIN" ] && [ -n "$NODE_BIN" ] && [ -n "$EDGE_CONFIG" ] && [ -n "$OBSERVATION_FILE" ] && [ -n "$METRICS_URL" ] || fail 'caller input absent' [ -n "$WORKSPACE" ] && [ -n "$OUTPUT" ] && [ -n "$SECRET_ENV" ] || fail 'caller input absent' [ -f "$CLAUDE_BIN" ] && [ -x "$CLAUDE_BIN" ] && [ ! -L "$CLAUDE_BIN" ] || fail 'Claude executable unavailable' [ -f "$EDGE_BIN" ] && [ -x "$EDGE_BIN" ] && [ ! -L "$EDGE_BIN" ] || fail 'Edge executable unavailable' [ -f "$NODE_BIN" ] && [ -x "$NODE_BIN" ] && [ ! -L "$NODE_BIN" ] || fail 'Node executable unavailable' [ -f "$RUNTIME_EVIDENCE" ] && [ -r "$RUNTIME_EVIDENCE" ] && [ ! -L "$RUNTIME_EVIDENCE" ] || fail 'runtime evidence unavailable' [ -f "$EDGE_CONFIG" ] && [ -r "$EDGE_CONFIG" ] && [ ! -L "$EDGE_CONFIG" ] || fail 'Edge config unavailable' [ -f "$OBSERVATION_FILE" ] && [ -r "$OBSERVATION_FILE" ] && [ ! -L "$OBSERVATION_FILE" ] || fail 'observation log unavailable' [ -f "$SCHEMA" ] && [ -r "$SCHEMA" ] && [ ! -L "$SCHEMA" ] || fail 'manifest schema unavailable' [ -d "$WORKSPACE" ] && [ -w "$WORKSPACE" ] && [ ! -L "$WORKSPACE" ] || fail 'workspace not writable' [ ! -e "$WORKSPACE/smoke-result.txt" ] && [ ! -L "$WORKSPACE/smoke-result.txt" ] || fail 'workspace result already exists' validate_claude_base "$BASE_URL" 2>/dev/null || fail 'base URL invalid' validate_url "$METRICS_URL" 2>/dev/null || fail 'metrics URL invalid' validate_model "$MODEL" 2>/dev/null || fail 'public model invalid' validate_observation_source "$OBSERVATION_FILE" 2>/dev/null || fail 'observation log incompatible' [[ "$SECRET_ENV" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]] || fail 'secret variable name invalid' SECRET_VALUE="$(printenv "$SECRET_ENV" 2>/dev/null || true)" [ -n "$SECRET_VALUE" ] || fail 'secret variable absent' validate_schema_contract "$SCHEMA" 2>/dev/null || fail 'manifest schema invalid' prepare_output_target load_runtime capture_runtime_identity validate_runtime_snapshot preflight probe_health_listener probe_messages_listener ingress_before_auth="$(ingress_value preflight-before-auth)" || fail 'metrics counter unavailable' probe_authenticated_model ingress_after_auth="$(ingress_value preflight-after-auth)" || fail 'metrics counter unavailable' [ "$ingress_before_auth" = "$ingress_after_auth" ] || fail 'authenticated model probe changed ingress' capture_observation_snapshot } classify_claude_failure() { python3 - "$1" "$2" <<'PY' import sys try: body = b"".join(open(path, "rb").read() for path in sys.argv[1:]).lower() except Exception: print("unknown") raise SystemExit(0) rules = [ ("cli-validation", "cli-usage", [b"requires --verbose", b"unknown option", b"invalid input format", b"input must be provided"]), ("authentication-rejected", "http-401", [b"status 401", b"api error: 401", b"api error 401", b'"status":401', b'"status": 401']), ("authentication-rejected", "authentication", [b"authentication", b"unauthorized", b"invalid api key", b"invalid x-api-key"]), ("transport-failure", "connection-refused", [b"econnrefused", b"connection refused"]), ("transport-failure", "network-timeout", [b"timed out", b"network timeout"]), ("transport-failure", "dns-failure", [b"enotfound"]), ("transport-failure", "fetch-failed", [b"fetch failed"]), ("transport-failure", "tls-certificate", [b"certificate has expired", b"unable to verify the first certificate", b"self signed certificate", b"certificate verify failed", b"unable to get local issuer certificate"]), ("transport-failure", "connection-error", [b"connection error"]), ("api-rejected", "unsupported-beta", [b"unsupported anthropic-beta"]), ("api-rejected", "unknown-field", [b"json: unknown field"]), ("api-rejected", "invalid-thinking", [b"thinking.display", b"adaptive thinking", b"thinking must be enabled"]), ("api-rejected", "invalid-output-config", [b"output_config.effort", b"output_config.format"]), ("api-rejected", "http-400", [b"status 400", b"api error: 400", b"api error 400", b'"status":400', b'"status": 400', b"bad request"]), ("api-rejected", "http-403", [b"status 403", b"api error: 403", b"api error 403", b'"status":403', b'"status": 403', b"forbidden"]), ("api-rejected", "http-404", [b"status 404", b"api error: 404", b"api error 404", b'"status":404', b'"status": 404']), ("api-rejected", "http-429", [b"status 429", b"api error: 429", b"api error 429", b'"status":429', b'"status": 429', b"rate limit"]), ("api-rejected", "api-error", [b"api error"]), ] for failure_class, reason, patterns in rules: if any(pattern in body for pattern in patterns): print(failure_class + "|" + reason) break else: print("unknown|unclassified") PY } run_claude_child() { local status classification failure_class failure_reason CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1 \ CLAUDE_CODE_DISABLE_TERMINAL_TITLE=1 \ CLAUDE_CODE_MAX_RETRIES=0 \ ANTHROPIC_BASE_URL="$BASE_URL" \ ANTHROPIC_MODEL="$MODEL" \ ANTHROPIC_API_KEY="$SECRET_VALUE" \ IOP_CLAUDE_SUPERVISOR_BIN="$CLAUDE_BIN" \ IOP_CLAUDE_SUPERVISOR_WORKSPACE="$WORKSPACE" \ IOP_CLAUDE_SUPERVISOR_OUT="$RUN_TMP/claude-out" \ IOP_CLAUDE_SUPERVISOR_ERR="$RUN_TMP/claude-err" \ IOP_CLAUDE_SUPERVISOR_PROMPT="$PROMPT" \ IOP_CLAUDE_SUPERVISOR_GRACE_SECONDS="$CHILD_SUPERVISOR_GRACE_SECONDS" \ python3 -c ' import os import signal import subprocess import sys import time grace = float(os.environ["IOP_CLAUDE_SUPERVISOR_GRACE_SECONDS"]) command = [ os.environ["IOP_CLAUDE_SUPERVISOR_BIN"], "--print", "--output-format", "stream-json", "--verbose", "--no-session-persistence", "--bare", os.environ["IOP_CLAUDE_SUPERVISOR_PROMPT"], ] child = None pending_signal = None termination_signal = None settling = False settled = False test_early_signal = ( os.environ.get("IOP_SMOKE_SELF_TEST") == "1" and os.environ.get("IOP_CLAUDE_SUPERVISOR_TEST_EARLY_SIGNAL") == "1" ) def group_exists(): if child is None: return False try: os.killpg(child.pid, 0) except ProcessLookupError: return False except PermissionError: return True return True def wait_for_group_empty(deadline): while group_exists() and time.monotonic() < deadline: time.sleep(0.05) return not group_exists() def settle_group(): global settled, settling if child is None or settled or settling: return settling = True try: if group_exists(): try: os.killpg(child.pid, signal.SIGTERM) except ProcessLookupError: pass wait_for_group_empty(time.monotonic() + grace) if group_exists(): try: os.killpg(child.pid, signal.SIGKILL) except ProcessLookupError: pass wait_for_group_empty(time.monotonic() + grace) if group_exists(): raise RuntimeError("Claude process group did not terminate") settled = True finally: settling = False def child_preexec(): import resource resource.setrlimit(resource.RLIMIT_FSIZE, (16384 * 512, 16384 * 512)) if test_early_signal: os.kill(os.getppid(), signal.SIGTERM) def terminate(signum, _frame): global pending_signal, termination_signal if child is None: if pending_signal is None: pending_signal = signum return if settling: return if termination_signal is None: termination_signal = signum settle_group() try: child.wait(timeout=grace) except subprocess.TimeoutExpired: raise RuntimeError("Claude child did not terminate") raise SystemExit(128 + termination_signal) signal.signal(signal.SIGHUP, terminate) signal.signal(signal.SIGINT, terminate) signal.signal(signal.SIGTERM, terminate) with open(os.environ["IOP_CLAUDE_SUPERVISOR_OUT"], "wb") as stdout, open(os.environ["IOP_CLAUDE_SUPERVISOR_ERR"], "wb") as stderr: child = subprocess.Popen( command, cwd=os.environ["IOP_CLAUDE_SUPERVISOR_WORKSPACE"], stdout=stdout, stderr=stderr, start_new_session=True, env=os.environ.copy(), preexec_fn=child_preexec, ) if pending_signal is not None: terminate(pending_signal, None) status = child.wait() settle_group() raise SystemExit(status) ' & CHILD_PID=$! if wait "$CHILD_PID"; then status=0 else status=$? fi CHILD_PID='' [ "$(file_size "$RUN_TMP/claude-out")" -le "$MAX_CAPTURE_BYTES" ] || fail 'Claude stdout exceeded capture bound' [ "$(file_size "$RUN_TMP/claude-err")" -le "$MAX_CAPTURE_BYTES" ] || fail 'Claude stderr exceeded capture bound' if [ "$status" -ne 0 ]; then classification="$(classify_claude_failure "$RUN_TMP/claude-out" "$RUN_TMP/claude-err" 2>/dev/null || true)" failure_class="${classification%%|*}" failure_reason="${classification#*|}" case "$failure_class" in cli-validation|authentication-rejected|transport-failure|api-rejected|unknown) ;; *) failure_class=unknown ;; esac case "$failure_reason" in cli-usage|http-401|authentication|connection-refused|network-timeout|dns-failure|fetch-failed|tls-certificate|connection-error|unsupported-beta|unknown-field|invalid-thinking|invalid-output-config|http-400|http-403|http-404|http-429|api-error|unclassified) ;; *) failure_reason=unclassified ;; esac fail "Claude invocation failed (status $status class $failure_class reason $failure_reason)" fi } extract_fresh_observation() { local target="$1" local length="$2" python3 - "$OBSERVATION_FILE" "$OBS_SIZE" "$length" "$target" <<'PY' import sys source, raw_offset, raw_length, target = sys.argv[1:] offset, length = int(raw_offset), int(raw_length) with open(source, "rb") as stream: stream.seek(offset) body = stream.read(length) if len(body) != length: raise SystemExit(1) with open(target, "wb") as output: output.write(body) PY } build_manifest() { local fresh="$1" local target="$2" local before="$3" local after="$4" local result_digest="$5" local verifier_digest="$6" local verifier_status="$7" local delta="$8" python3 - "$fresh" "$target" "$before" "$after" "$result_digest" "$verifier_digest" "$verifier_status" "$delta" \ "$RHEAD" "$RBRANCH" "$RTREE" "$RRUNNER_OS" "$RRUNNER_ARCH" "$RWORKSPACE_OS" "$RWORKSPACE_ARCH" \ "$RWORKSPACE_ROOT" "$RWORKSPACE_OWNER" "$RCLAUDE" "$RCLAUDE_VERSION" "$RCLAUDE_HELP" "$REDGE" "$REDGE_VERSION" \ "$RNODE" "$RNODE_VERSION" "$RCONFIG" "$RCONFIG_CHECK" "$RSCHEMA" "$RBASE" "$RPUBLIC_MODEL" \ "$RPLAN_ENGINE" "$RWORK_ENGINE" "$RREVIEW_ENGINE" "$RBIND" <<'PY' import collections, json, re, sys ( fresh, target, before, after, result_digest, verifier_digest, raw_verifier_status, raw_delta, head, branch, tree, runner_os, runner_arch, workspace_os, workspace_arch, workspace_root, workspace_owner, claude, claude_version, claude_help, edge, edge_version, node, node_version, config, config_check, schema, base, public_model, plan_engine, work_engine, review_engine, binding, ) = sys.argv[1:] try: verifier_status = int(raw_verifier_status) assert verifier_status == 0 and float(raw_delta) == 1 allowed = { "level", "ts", "time", "caller", "logger", "msg", "message", "correlation", "event_class", "stage", "operation", "outcome", "error_class", "duration_ms", "tool_count", "has_result", } observations = [] with open(fresh) as stream: for line in stream: try: item = json.loads(line) except Exception: continue if item.get("msg", item.get("message")) != "edge_single_request_observation": continue assert set(item).issubset(allowed) correlation = item.get("correlation") assert isinstance(correlation, str) and re.fullmatch(r"sr-[a-z0-9-]{1,64}", correlation) observations.append(item) groups = collections.defaultdict(list) for item in observations: groups[item["correlation"]].append(item) candidates = [] for records in groups.values(): request = [item for item in records if item.get("event_class") == "request" and item.get("operation") == "total"] stages = [item for item in records if item.get("event_class") == "stage"] terminals = [item for item in records if item.get("event_class") == "terminal"] if len(request) == 1 and len(stages) == 3 and len(terminals) == 1: candidates.append((request[0], stages, terminals[0])) assert len(candidates) == 1 request, stages, terminal = candidates[0] engines = [plan_engine, work_engine, review_engine] packed = [] for item, stage, engine in zip(stages, ["plan", "work", "review"], engines): assert item.get("stage") == stage and item.get("operation") == stage and item.get("outcome") == "success" assert item.get("error_class") in (None, "", "none") duration = item.get("duration_ms") assert isinstance(duration, int) and not isinstance(duration, bool) and duration >= 0 packed.append({"stage": stage, "engine_family": engine, "duration_ms": duration, "binding_digest": binding}) assert request.get("outcome") == "success" and request.get("error_class") in (None, "", "none") request_duration = request.get("duration_ms") assert request_duration == 0 assert terminal.get("operation") == "terminal" and terminal.get("outcome") == "success" assert terminal.get("error_class") in (None, "", "none") assert terminal.get("has_result") is True total_duration = terminal.get("duration_ms") assert isinstance(total_duration, int) and not isinstance(total_duration, bool) and total_duration >= 0 manifest = { "schema_version": "1", "source": {"head": head, "branch_digest": branch, "worktree_digest": tree}, "runtime": { "runner_os": runner_os, "runner_arch": runner_arch, "workspace_os": workspace_os, "workspace_arch": workspace_arch, "workspace_root_digest": workspace_root, "workspace_owner_digest": workspace_owner, "claude_digest": claude, "claude_version_digest": claude_version, "claude_help_digest": claude_help, "edge_digest": edge, "edge_version_digest": edge_version, "node_digest": node, "node_version_digest": node_version, "config_digest": config, "config_check_digest": config_check, "schema_digest": schema, "base_url_digest": base, "public_model_digest": public_model, "stage_engines": engines, "stage_binding_digest": binding, }, "ingress": {"delta": 1}, "stages": packed, "terminal": {"count": 1, "stop_reason": "end_turn", "duration_ms": total_duration}, "workspace": {"before_digest": before, "after_digest": after, "changed": True}, "verification": {"command_digest": verifier_digest, "result_file_digest": result_digest, "exit_code": verifier_status}, "redaction": {"forbidden_match_count": 0, "forbidden_key_count": 0}, } with open(target, "w") as output: json.dump(manifest, output, sort_keys=True, separators=(",", ":")) output.write("\n") except Exception: raise SystemExit(1) PY } validate_raw_redaction() { python3 - "$PUBLISH_TMP" "$SECRET_VALUE" "$BASE_URL" "$MODEL" "$WORKSPACE" "$OUTPUT" "$EXPECTED_RESULT" <<'PY' import sys body = open(sys.argv[1], "rb").read() for value in sys.argv[2:]: encoded = value.encode() if len(encoded) >= 4 and encoded in body: raise SystemExit(1) PY } atomic_publish_no_replace() { python3 - "$1" "$2" <<'PY' import ctypes, os, platform, sys source, target = map(os.fsencode, sys.argv[1:]) with open(sys.argv[1], "rb") as stream: os.fsync(stream.fileno()) libc = ctypes.CDLL(None, use_errno=True) system = platform.system().lower() if system == "linux" and hasattr(libc, "renameat2"): operation = libc.renameat2 operation.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint] operation.restype = ctypes.c_int status = operation(-100, source, -100, target, 1) elif system == "darwin" and hasattr(libc, "renamex_np"): operation = libc.renamex_np operation.argtypes = [ctypes.c_char_p, ctypes.c_char_p, ctypes.c_uint] operation.restype = ctypes.c_int status = operation(source, target, 0x00000004) else: raise SystemExit(1) if status != 0: raise SystemExit(1) try: descriptor = os.open(os.path.dirname(sys.argv[2]), os.O_RDONLY) try: os.fsync(descriptor) finally: os.close(descriptor) except OSError: pass PY } run_once() { create_run_context preflight local before_metric before_workspace after_metric after_workspace delta local current_device current_inode current_size fresh_size result_digest verifier_digest verifier_status before_metric="$(ingress_value before)" || fail 'metrics counter unavailable' before_workspace="$(tree_digest "$WORKSPACE")" run_claude_child validate_runtime_identity_unchanged validate_runtime_snapshot post read -r current_device current_inode current_size <<<"$(file_identity "$OBSERVATION_FILE" 2>/dev/null)" || fail 'observation log unavailable' [ "$current_device" = "$OBS_DEVICE" ] && [ "$current_inode" = "$OBS_INODE" ] && [ "$current_size" -ge "$OBS_SIZE" ] || fail 'observation log rotated or truncated' [ "$(prefix_digest "$OBSERVATION_FILE" "$OBS_SIZE")" = "$OBS_PREFIX" ] || fail 'observation log rotated or truncated' fresh_size=$((current_size - OBS_SIZE)) [ "$fresh_size" -le "$MAX_FRESH_OBSERVATION_BYTES" ] || fail 'fresh observation exceeded capture bound' extract_fresh_observation "$RUN_TMP/fresh-observation" "$fresh_size" || fail 'fresh observation extraction failed' after_metric="$(ingress_value after)" || fail 'metrics counter unavailable' delta="$(metric_delta "$before_metric" "$after_metric" 2>/dev/null)" || fail 'ingress delta mismatch' after_workspace="$(tree_digest "$WORKSPACE")" [ "$before_workspace" != "$after_workspace" ] || fail 'workspace did not change' [ -f "$WORKSPACE/smoke-result.txt" ] && [ -r "$WORKSPACE/smoke-result.txt" ] && [ ! -L "$WORKSPACE/smoke-result.txt" ] || fail 'workspace verification file absent' printf '%s\n' "$EXPECTED_RESULT" >"$RUN_TMP/expected-result" if cmp -s -- "$RUN_TMP/expected-result" "$WORKSPACE/smoke-result.txt"; then verifier_status=0 else verifier_status=$? fi if [ "${IOP_SMOKE_SELF_TEST-}" = '1' ] && [ "${IOP_SMOKE_TEST_FORCE_VERIFIER_FAILURE-}" = '1' ]; then verifier_status=1 fi [ "$verifier_status" -eq 0 ] || fail 'workspace verification failed' result_digest="$(sha_file "$WORKSPACE/smoke-result.txt")" verifier_digest="$(sha_string "cmp-v1|$(sha_file "$RUN_TMP/expected-result")")" build_manifest "$RUN_TMP/fresh-observation" "$PUBLISH_TMP" "$before_workspace" "$after_workspace" "$result_digest" "$verifier_digest" "$verifier_status" "$delta" || fail 'fresh evidence does not satisfy S12 harness contract' validate_manifest "$PUBLISH_TMP" "$SCHEMA" || fail 'generated manifest invalid' validate_raw_redaction || fail 'generated manifest contains forbidden raw evidence' [ ! -e "$OUTPUT" ] && [ ! -L "$OUTPUT" ] || fail 'output target changed during run' atomic_publish_no_replace "$PUBLISH_TMP" "$OUTPUT" || fail 'manifest publication failed' PUBLISH_TMP='' finish_run_context log 'run manifest validated and written (redacted evidence only)' } preflight_only() { create_run_context preflight finish_run_context log 'preflight passed without a Claude invocation' } self_test() { mkdir -p "$REPO_ROOT/build" python3 - "$SELF" "$REPO_ROOT" "$DEFAULT_SCHEMA" "$EXPECTED_RESULT" "$PROMPT" <<'PY' import copy import hashlib import http.server import json import os import pathlib import platform import shutil import signal import socketserver import subprocess import sys import tempfile import threading import time import urllib.error import urllib.request SELF, REPO_ROOT, SCHEMA, EXPECTED_RESULT, PROMPT = sys.argv[1:] REPO_ROOT = pathlib.Path(REPO_ROOT).resolve() SCHEMA = pathlib.Path(SCHEMA).resolve() class TestFailure(Exception): pass def check(condition, message): if not condition: raise TestFailure(message) def sha_text(value): return "sha256:" + hashlib.sha256(value.encode()).hexdigest() def sha_file(path): return "sha256:" + hashlib.sha256(pathlib.Path(path).read_bytes()).hexdigest() def recompute(runtime): values = runtime["runtime"] owner_material = "|".join([ values["workspace_os"], values["workspace_arch"], values["workspace_root_digest"], values["config_digest"], values["node_digest"], values["node_version_digest"], ]) values["workspace_owner_digest"] = sha_text(owner_material) binding_material = "|".join([values["config_digest"], values["config_check_digest"], values["base_url_digest"], values["public_model_digest"], *values["stage_engines"]]) values["stage_binding_digest"] = sha_text(binding_material) CLAUDE_VERSION = "Claude fake 1\n" CLAUDE_HELP = "--print\n--output-format\n--verbose\n--no-session-persistence\n--bare\n" EDGE_VERSION = "IOP Edge fake 1\n" NODE_VERSION = "IOP Node fake 1\n" CONFIG_CHECK = "configuration valid\n" SELF_TEST_WORKTREE = sha_text("credential-free-self-test-worktree-v1") CLAUDE_FAKE = r'''#!/usr/bin/env bash set -euo pipefail hash_text(){ if command -v sha256sum >/dev/null 2>&1;then printf %s "$1"|sha256sum|awk '{print "sha256:"$1}';else printf %s "$1"|shasum -a 256|awk '{print "sha256:"$1}';fi; } if [ "${1-}" = '--version' ];then [ "${IOP_SMOKE_FAKE_CLAUDE_VERSION-}" != 'fail' ] || exit 20 printf 'Claude fake 1\n' exit 0 fi if [ "${1-}" = '--help' ];then [ "${IOP_SMOKE_FAKE_CLAUDE_HELP-}" != 'fail' ] || exit 21 if [ "${IOP_SMOKE_FAKE_CLAUDE_HELP-}" = 'missing' ];then printf '%s\n' '--print' '--output-format';else printf '%s\n' '--print' '--output-format' '--verbose' '--no-session-persistence' '--bare';fi exit 0 fi verbose_count=0 last_arg='' for arg in "$@";do last_arg="$arg" if [ "$arg" = '--verbose' ];then verbose_count=$((verbose_count+1));fi done [ "$verbose_count" -eq 1 ] || exit 26 [ "$(hash_text "$last_arg")" = "$IOP_SMOKE_FAKE_EXPECT_PROMPT_DIGEST" ] || exit 32 printf '1\n' >>"$IOP_SMOKE_FAKE_MARKER" [ "$(hash_text "${ANTHROPIC_MODEL-}")" = "$IOP_SMOKE_FAKE_EXPECT_MODEL_DIGEST" ] || exit 22 [ "$(hash_text "${ANTHROPIC_BASE_URL-}")" = "$IOP_SMOKE_FAKE_EXPECT_BASE_DIGEST" ] || exit 23 [ -n "${ANTHROPIC_API_KEY-}" ] || exit 24 [ "${CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS-}" = '1' ] || exit 27 [ "${CLAUDE_CODE_DISABLE_TERMINAL_TITLE-}" = '1' ] || exit 29 [ "${CLAUDE_CODE_MAX_RETRIES-}" = '0' ] || exit 28 behavior="${IOP_SMOKE_FAKE_BEHAVIOR-success}" case "$behavior" in claude-failure-cli) printf '%s\n' 'Error: stream-json requires --verbose' >&2; exit 25 ;; claude-failure-auth) printf '%s\n' 'Error: authentication rejected' >&2; exit 25 ;; claude-failure-transport) printf '%s\n' 'Error: connection refused' >&2; exit 25 ;; claude-failure-connection) printf '%s\n' 'Error: API Error: Connection error. SECRET_CONNECTION_MARKER' >&2; exit 25 ;; claude-failure-tls) printf '%s\n' 'Error: API Error: Connection error. certificate has expired SECRET_CERT_MARKER' >&2; exit 25 ;; claude-failure-api) printf '%s\n' 'Error: status 429' >&2; exit 25 ;; claude-failure-api-400) printf '%s\n' 'Error: API Error: 400 rejected-field-marker' >&2; exit 25 ;; claude-failure-api-400-beta) printf '%s\n' 'Error: API Error: 400 unsupported anthropic-beta "SECRET_REJECTED_BETA"' >&2; exit 25 ;; claude-failure-api-400-field) printf '%s\n' 'Error: API Error: 400 decode Messages request: json: unknown field "SECRET_FIELD_MARKER"' >&2; exit 25 ;; claude-failure-api-400-thinking) printf '%s\n' 'Error: API Error: 400 thinking.display SECRET_THINKING_MARKER' >&2; exit 25 ;; claude-failure-api-400-output) printf '%s\n' 'Error: API Error: 400 output_config.effort SECRET_OUTPUT_MARKER' >&2; exit 25 ;; claude-failure-unknown) printf '%s\n' 'opaque failure' >&2; exit 25 ;; esac if [ "$behavior" = 'leader-exit' ];then ( trap '' TERM INT HUP; while :; do sleep 1; done ) & printf '%s\n' "$!" >"$IOP_SMOKE_FAKE_DESCENDANT" exit 0 fi if [ "$behavior" = 'term-resistant' ] || [ "$behavior" = 'early-signal' ];then ( trap '' TERM INT HUP; while :; do sleep 1; done ) & printf '%s\n' "$!" >"$IOP_SMOKE_FAKE_DESCENDANT" trap '' TERM INT HUP while :; do sleep 1; done fi emit(){ request_duration=0 terminal_duration=11 terminal_result=',"has_result":true' case "$behavior" in timing-swapped) request_duration=11; terminal_duration=0 ;; terminal-no-result) terminal_result='' ;; terminal-false-result) terminal_result=',"has_result":false' ;; esac for line in \ "{\"msg\":\"edge_single_request_observation\",\"correlation\":\"sr-selftest\",\"event_class\":\"request\",\"stage\":\"none\",\"operation\":\"total\",\"outcome\":\"success\",\"error_class\":\"none\",\"duration_ms\":$request_duration}" \ '{"msg":"edge_single_request_observation","correlation":"sr-selftest","event_class":"stage","stage":"plan","operation":"plan","outcome":"success","error_class":"none","duration_ms":3}' \ '{"msg":"edge_single_request_observation","correlation":"sr-selftest","event_class":"stage","stage":"work","operation":"work","outcome":"success","error_class":"none","duration_ms":5}' \ '{"msg":"edge_single_request_observation","correlation":"sr-selftest","event_class":"stage","stage":"review","operation":"review","outcome":"success","error_class":"none","duration_ms":2}' \ "{\"msg\":\"edge_single_request_observation\",\"correlation\":\"sr-selftest\",\"event_class\":\"terminal\",\"stage\":\"none\",\"operation\":\"terminal\",\"outcome\":\"success\",\"error_class\":\"none\",\"duration_ms\":$terminal_duration$terminal_result}" do printf '%s\n' "$line" >>"$IOP_SMOKE_FAKE_OBSERVATION";done } if [ "$behavior" = 'rotated' ];then : >"$IOP_SMOKE_FAKE_OBSERVATION";fi if [ "$behavior" != 'stale' ];then emit;fi printf 'iop_anthropic_single_request_ingress_total 1\n' >"$IOP_SMOKE_FAKE_METRICS" case "$behavior" in no-change) ;; wrong-content) printf 'wrong\n' >smoke-result.txt ;; *) printf 'IOP single-request Claude smoke verified.\n' >smoke-result.txt ;; esac if [ "$behavior" = 'config-after' ];then printf 'changed\n' >>"$IOP_SMOKE_FAKE_CONFIG";fi if [ "$behavior" = 'node-after' ];then printf '# changed\n' >>"$IOP_SMOKE_FAKE_NODE";fi if [ "$behavior" = 'runtime-after' ];then printf '\n' >>"$IOP_SMOKE_FAKE_RUNTIME";fi if [ "$behavior" = 'output-race' ];then printf 'concurrent owner\n' >"$IOP_SMOKE_FAKE_OUTPUT";fi ''' EDGE_FAKE = r'''#!/usr/bin/env bash set -euo pipefail if [ "${1-}" = 'version' ];then [ "${IOP_SMOKE_FAKE_EDGE_VERSION-}" != 'fail' ] || exit 30;printf 'IOP Edge fake 1\n';exit 0;fi if [ "${1-}" = 'config' ] && [ "${2-}" = 'check' ] && [ "${3-}" = '--config' ] && [ -f "${4-}" ];then [ "${IOP_SMOKE_FAKE_CONFIG_CHECK-}" != 'fail' ] || exit 31;printf 'configuration valid\n';exit 0;fi exit 32 ''' NODE_FAKE = r'''#!/usr/bin/env bash set -euo pipefail if [ "${1-}" = 'version' ];then [ "${IOP_SMOKE_FAKE_NODE_VERSION-}" != 'fail' ] || exit 40;printf 'IOP Node fake 1\n';exit 0;fi exit 41 ''' class Listener(http.server.BaseHTTPRequestHandler): metrics_path = None model = "MODEL_SENTINEL" secret = "SECRET_SENTINEL_VALUE" mode = "ok" def do_GET(self): if self.path == "/healthz": if Listener.mode == "health-fail": self.send_response(503) self.end_headers() return self.send_response(200) self.end_headers() self.wfile.write(b"ok\n") return if self.path == "/metrics": if Listener.mode == "metrics-fail": self.send_response(503) self.end_headers() return self.send_response(200) self.end_headers() self.wfile.write(pathlib.Path(Listener.metrics_path).read_bytes()) return if self.path == "/anthropic/v1/models": if Listener.mode == "catalog-auth-reject" or self.headers.get("x-api-key") != Listener.secret: self.send_response(401) self.end_headers() return if self.headers.get("anthropic-version") != "2023-06-01": self.send_response(400) self.end_headers() return if Listener.mode == "catalog-malformed": body = b"not-json\n" else: model = "OTHER_MODEL" if Listener.mode == "catalog-model-missing" else Listener.model body = json.dumps({ "data": [{"id": model, "created_at": "2024-01-01T00:00:00Z", "display_name": model, "type": "model"}], "has_more": False, "first_id": model, "last_id": model, }).encode() if Listener.mode == "catalog-ingress-change": pathlib.Path(Listener.metrics_path).write_text("iop_anthropic_single_request_ingress_total 1\n") self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(body))) self.end_headers() self.wfile.write(body) return self.send_response(404) self.end_headers() def do_OPTIONS(self): if self.path == "/v1/messages": status = { "messages-auth": 401, "messages-fail": 503, "messages-missing": 404, }.get(Listener.mode, 405) self.send_response(status) self.end_headers() return self.send_response(404) self.end_headers() def log_message(self, *_): return class Server(socketserver.ThreadingMixIn, http.server.HTTPServer): daemon_threads = True def mutate_json(path, function, reconcile=False): data = json.loads(path.read_text()) function(data) if reconcile: recompute(data) path.write_text(json.dumps(data, sort_keys=True)) def create_fixture(suite, name, base_url): root = suite / name workspace = root / "workspace-PATH_SENTINEL" output_dir = root / "output" raw_root = root / "raw" workspace.mkdir(parents=True) output_dir.mkdir() raw_root.mkdir() marker = root / "marker" marker.write_text("") descendant = root / "descendant" descendant.write_text("") observation = root / "observation" observation.write_text('{"level":"info","ts":1,"msg":"node ready"}\n') metrics = root / "metrics" metrics.write_text("iop_anthropic_single_request_ingress_total 0\n") claude = root / "claude" claude.write_text(CLAUDE_FAKE) claude.chmod(0o700) edge = root / "edge" edge.write_text(EDGE_FAKE) edge.chmod(0o700) node = root / "node" node.write_text(NODE_FAKE) node.chmod(0o700) config = root / "edge-config" config.write_text("fixed config\n") runtime_path = root / "runtime-evidence" model = "MODEL_SENTINEL" output = output_dir / "manifest.json" head = subprocess.check_output(["git", "-C", str(REPO_ROOT), "rev-parse", "HEAD"], text=True).strip() branch = subprocess.check_output(["git", "-C", str(REPO_ROOT), "rev-parse", "--abbrev-ref", "HEAD"], text=True).strip() values = { "runner_os": platform.system().lower(), "runner_arch": platform.machine().lower(), "workspace_os": platform.system().lower(), "workspace_arch": platform.machine().lower(), "workspace_root_digest": sha_text(str(workspace.resolve())), "workspace_owner_digest": "", "claude_digest": sha_file(claude), "claude_version_digest": "sha256:" + hashlib.sha256(CLAUDE_VERSION.encode()).hexdigest(), "claude_help_digest": "sha256:" + hashlib.sha256(CLAUDE_HELP.encode()).hexdigest(), "edge_digest": sha_file(edge), "edge_version_digest": "sha256:" + hashlib.sha256(EDGE_VERSION.encode()).hexdigest(), "node_digest": sha_file(node), "node_version_digest": "sha256:" + hashlib.sha256(NODE_VERSION.encode()).hexdigest(), "config_digest": sha_file(config), "config_check_digest": "sha256:" + hashlib.sha256(CONFIG_CHECK.encode()).hexdigest(), "schema_digest": sha_file(SCHEMA), "base_url_digest": sha_text(base_url), "public_model_digest": sha_text(model), "stage_engines": ["gemini", "ornith-fast", "gemini"], "stage_binding_digest": "", } runtime = { "schema_version": "1", "source": {"head": head, "branch_digest": sha_text(branch), "worktree_digest": SELF_TEST_WORKTREE}, "runtime": values, } recompute(runtime) runtime_path.write_text(json.dumps(runtime, sort_keys=True)) return { "root": root, "workspace": workspace, "output_dir": output_dir, "raw_root": raw_root, "descendant": descendant, "marker": marker, "observation": observation, "metrics": metrics, "claude": claude, "edge": edge, "node": node, "config": config, "runtime": runtime_path, "model": model, "base_url": base_url, "metrics_url": base_url + "/metrics", "output": output, } def command_for(fixture, mode="--preflight-only", schema=SCHEMA, overrides=None): values = { "--claude": fixture["claude"], "--runtime-evidence": fixture["runtime"], "--base-url": fixture["base_url"], "--model": fixture["model"], "--edge-bin": fixture["edge"], "--node-bin": fixture["node"], "--edge-config": fixture["config"], "--observation-file": fixture["observation"], "--metrics-url": fixture["metrics_url"], "--workspace": fixture["workspace"], "--output": fixture["output"], "--secret-env": "IOP_SMOKE_TEST_SECRET", "--schema": schema, } if overrides: values.update(overrides) command = [SELF, mode] for key, value in values.items(): command.extend([key, str(value)]) return command def environment_for(fixture, extra=None): environment = os.environ.copy() environment.update({ "IOP_SMOKE_SELF_TEST": "1", "IOP_SMOKE_TEST_WORKTREE_DIGEST": SELF_TEST_WORKTREE, "IOP_SMOKE_TMP_ROOT": str(fixture["raw_root"]), "IOP_SMOKE_TEST_SECRET": "SECRET_SENTINEL_VALUE", "IOP_SMOKE_FAKE_MARKER": str(fixture["marker"]), "IOP_SMOKE_FAKE_OBSERVATION": str(fixture["observation"]), "IOP_SMOKE_FAKE_METRICS": str(fixture["metrics"]), "IOP_SMOKE_FAKE_CONFIG": str(fixture["config"]), "IOP_SMOKE_FAKE_NODE": str(fixture["node"]), "IOP_SMOKE_FAKE_RUNTIME": str(fixture["runtime"]), "IOP_SMOKE_FAKE_OUTPUT": str(fixture["output"]), "IOP_SMOKE_FAKE_EXPECT_MODEL_DIGEST": sha_text(fixture["model"]), "IOP_SMOKE_FAKE_EXPECT_BASE_DIGEST": sha_text(fixture["base_url"]), "IOP_SMOKE_FAKE_EXPECT_PROMPT_DIGEST": sha_text(PROMPT), "IOP_SMOKE_FAKE_DESCENDANT": str(fixture["descendant"]), "CLAUDE_CODE_MAX_RETRIES": "9", "CLAUDE_CODE_DISABLE_TERMINAL_TITLE": "0", }) if extra: environment.update(extra) return environment def assert_redacted(fixture, result, case): combined = result.stdout + result.stderr forbidden = [ "SECRET_SENTINEL_VALUE", fixture["model"], fixture["base_url"], str(fixture["workspace"]), str(fixture["output"]), ] check(all(value not in combined for value in forbidden), case + ": raw value leaked") def assert_cleanup(fixture, case): check(list(fixture["raw_root"].iterdir()) == [], case + ": raw temporary capture remained") def closed_failure_reason(result): reason = "no closed reason" prefix = "[single-request-claude-smoke] validation failed: " for line in result.stderr.splitlines(): if line.startswith(prefix): candidate = line[len(prefix):] if candidate and all(character.isalnum() or character in " ()-" for character in candidate): reason = candidate return reason def run_case(fixture, case, mode="--preflight-only", expect_success=False, expect_child=0, expect_output=False, env=None, overrides=None, schema=SCHEMA): Listener.metrics_path = fixture["metrics"] Listener.model = fixture["model"] result = subprocess.run( command_for(fixture, mode=mode, schema=schema, overrides=overrides), env=environment_for(fixture, env), capture_output=True, text=True, timeout=25, ) assert_redacted(fixture, result, case) if (result.returncode == 0) != expect_success: raise TestFailure(case + ": unexpected exit status (" + closed_failure_reason(result) + ")") marker_count = len([line for line in fixture["marker"].read_text().splitlines() if line]) if expect_child is not None and marker_count != expect_child: raise TestFailure(case + ": unexpected child count " + str(marker_count) + " (" + closed_failure_reason(result) + ")") assert_cleanup(fixture, case) check(fixture["output"].exists() == expect_output, case + ": unexpected final output state") partials = [path for path in fixture["output_dir"].iterdir() if path != fixture["output"]] check(not partials, case + ": partial publication remained") return result def require_descendant_pid(fixture, case): deadline = time.monotonic() + 10 descendant = fixture["descendant"] while time.monotonic() < deadline: if descendant.exists(): value = descendant.read_text().strip() if value: try: return int(value) except ValueError: raise TestFailure(case + ": descendant PID was invalid") time.sleep(0.05) raise TestFailure(case + ": descendant did not start") def assert_process_gone(pid, case): deadline = time.monotonic() + 5 while time.monotonic() < deadline: try: os.kill(pid, 0) except ProcessLookupError: return time.sleep(0.05) raise TestFailure(case + ": descendant remained") def apply_preflight_mutation(name, fixture): environment = {} overrides = {} schema = SCHEMA Listener.mode = "ok" if name == "support-tool": environment["IOP_SMOKE_TEST_FAIL_CHECK"] = "support-tool" elif name == "claude-executable": fixture["claude"].chmod(0o600) elif name == "edge-executable": fixture["edge"].chmod(0o600) elif name == "node-file": overrides["--node-bin"] = fixture["root"] / "absent-node" elif name == "node-executable": fixture["node"].chmod(0o600) elif name == "claude-version": environment["IOP_SMOKE_FAKE_CLAUDE_VERSION"] = "fail" elif name == "claude-help": environment["IOP_SMOKE_FAKE_CLAUDE_HELP"] = "missing" elif name == "edge-version": environment["IOP_SMOKE_FAKE_EDGE_VERSION"] = "fail" elif name == "node-version": environment["IOP_SMOKE_FAKE_NODE_VERSION"] = "fail" elif name == "config-check": environment["IOP_SMOKE_FAKE_CONFIG_CHECK"] = "fail" elif name == "runtime-file": overrides["--runtime-evidence"] = fixture["root"] / "absent-runtime" elif name == "source-head": mutate_json(fixture["runtime"], lambda data: data["source"].__setitem__("head", "0" * 40)) elif name == "source-branch": mutate_json(fixture["runtime"], lambda data: data["source"].__setitem__("branch_digest", sha_text("wrong"))) elif name == "source-worktree": mutate_json(fixture["runtime"], lambda data: data["source"].__setitem__("worktree_digest", sha_text("wrong"))) elif name == "runner-os": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("runner_os", "wrong")) elif name == "runner-arch": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("runner_arch", "wrong")) elif name == "workspace-owner-os": mutate_json( fixture["runtime"], lambda data: data["runtime"].__setitem__( "workspace_os", "linux" if data["runtime"]["workspace_os"] == "darwin" else "darwin" ), reconcile=True, ) elif name == "workspace-owner-os-unsupported": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("workspace_os", "windows"), reconcile=True) elif name == "workspace-root": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("workspace_root_digest", sha_text("wrong")), reconcile=True) elif name == "claude-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("claude_digest", sha_text("wrong"))) elif name == "claude-version-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("claude_version_digest", sha_text("wrong"))) elif name == "claude-help-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("claude_help_digest", sha_text("wrong"))) elif name == "edge-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("edge_digest", sha_text("wrong"))) elif name == "edge-version-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("edge_version_digest", sha_text("wrong"))) elif name == "node-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("node_digest", sha_text("wrong")), reconcile=True) elif name == "node-version-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("node_version_digest", sha_text("wrong")), reconcile=True) elif name == "config-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("config_digest", sha_text("wrong")), reconcile=True) elif name == "config-check-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("config_check_digest", sha_text("wrong")), reconcile=True) elif name == "schema-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("schema_digest", sha_text("wrong"))) elif name == "base-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("base_url_digest", sha_text("wrong")), reconcile=True) elif name == "model-digest": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("public_model_digest", sha_text("wrong")), reconcile=True) elif name == "stage-engines": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("stage_engines", ["gemini", "gemini", "ornith-fast"]), reconcile=True) elif name == "stage-binding": mutate_json(fixture["runtime"], lambda data: data["runtime"].__setitem__("stage_binding_digest", sha_text("wrong"))) elif name == "health-listener": Listener.mode = "health-fail" elif name == "messages-listener": Listener.mode = "messages-fail" elif name == "messages-missing": Listener.mode = "messages-missing" elif name == "catalog-auth": Listener.mode = "catalog-auth-reject" elif name == "catalog-model": Listener.mode = "catalog-model-missing" elif name == "catalog-body": Listener.mode = "catalog-malformed" elif name == "catalog-ingress": Listener.mode = "catalog-ingress-change" elif name == "metrics-listener": Listener.mode = "metrics-fail" elif name == "metrics-counter": fixture["metrics"].write_text("unrelated 1\n") elif name == "observation-log": fixture["observation"].unlink() fixture["observation"].mkdir() elif name == "observation-plain": fixture["observation"].write_text("process stdout without structured Edge events\n") elif name == "workspace": overrides["--workspace"] = fixture["root"] / "absent-workspace" elif name == "secret-name": overrides["--secret-env"] = "bad-name" elif name == "secret-value": overrides["--secret-env"] = "IOP_SMOKE_ABSENT_SECRET" elif name == "output-existing": fixture["output"].write_text("occupied\n") elif name == "result-existing": (fixture["workspace"] / "smoke-result.txt").write_text(EXPECTED_RESULT + "\n") elif name == "schema-contract": bad_schema = fixture["root"] / "bad-schema" data = json.loads(SCHEMA.read_text()) data["$defs"]["workspace"].pop("additionalProperties") bad_schema.write_text(json.dumps(data)) schema = bad_schema else: raise TestFailure(name + ": unknown preflight mutation") return environment, overrides, schema try: with tempfile.TemporaryDirectory(prefix="single-request-claude-self-test.", dir=REPO_ROOT / "build") as suite_raw: suite = pathlib.Path(suite_raw) server = Server(("127.0.0.1", 0), Listener) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() base_url = "http://127.0.0.1:" + str(server.server_address[1]) try: double_messages_request = urllib.request.Request(base_url + "/v1/v1/messages", method="OPTIONS") try: urllib.request.urlopen(double_messages_request, timeout=5) raise TestFailure("exact-route: double-v1 Messages path was accepted") except urllib.error.HTTPError as error: check(error.code == 404, "exact-route: double-v1 Messages path did not return 404") positive_preflight = create_fixture(suite, "positive-preflight", base_url) Listener.mode = "ok" run_case(positive_preflight, "positive-preflight", expect_success=True) authenticated_preflight = create_fixture(suite, "authenticated-preflight", base_url) Listener.mode = "messages-auth" run_case(authenticated_preflight, "authenticated-preflight", expect_success=True) Listener.mode = "ok" terminal_v1_preflight = create_fixture(suite, "terminal-v1-preflight", base_url + "/v1") run_case(terminal_v1_preflight, "terminal-v1-preflight") preflight_cases = [ "support-tool", "claude-executable", "edge-executable", "node-file", "node-executable", "claude-version", "claude-help", "edge-version", "node-version", "config-check", "runtime-file", "source-head", "source-branch", "source-worktree", "runner-os", "runner-arch", "workspace-owner-os", "workspace-owner-os-unsupported", "workspace-root", "claude-digest", "claude-version-digest", "claude-help-digest", "edge-digest", "edge-version-digest", "node-digest", "node-version-digest", "config-digest", "config-check-digest", "schema-digest", "base-digest", "model-digest", "stage-engines", "stage-binding", "health-listener", "messages-listener", "messages-missing", "metrics-listener", "catalog-auth", "catalog-model", "catalog-body", "catalog-ingress", "metrics-counter", "observation-log", "observation-plain", "workspace", "secret-name", "secret-value", "output-existing", "result-existing", "schema-contract", ] for name in preflight_cases: fixture = create_fixture(suite, "preflight-" + name, base_url) environment, overrides, selected_schema = apply_preflight_mutation(name, fixture) run_case( fixture, "preflight-" + name, env=environment, overrides=overrides, schema=selected_schema, expect_output=name == "output-existing", ) Listener.mode = "ok" valid = create_fixture(suite, "run-valid", base_url) Listener.mode = "ok" run_case(valid, "run-valid", mode="--run", expect_success=True, expect_child=1, expect_output=True) subprocess.run([SELF, "--validate-manifest", str(valid["output"]), "--schema", str(SCHEMA)], check=True, capture_output=True, text=True, timeout=10) manifest = json.loads(valid["output"].read_text()) check(manifest["workspace"]["changed"] is True, "run-valid: workspace change missing") check(manifest["verification"]["exit_code"] == 0, "run-valid: verifier result missing") check(manifest["runtime"]["public_model_digest"] == sha_text(valid["model"]), "run-valid: model binding missing") check(manifest["runtime"]["node_digest"] == sha_file(valid["node"]), "run-valid: Node binding missing") check(manifest["runtime"]["node_version_digest"] == sha_text(NODE_VERSION), "run-valid: Node version binding missing") check(manifest["terminal"]["duration_ms"] == 11, "run-valid: terminal total missing") mutations = { "extra-key": lambda data: data.__setitem__("prompt", "SECRET_SENTINEL"), "source": lambda data: data["source"].__setitem__("branch_digest", "bad"), "base": lambda data: data["runtime"].__setitem__("base_url_digest", sha_text("changed")), "model": lambda data: data["runtime"].__setitem__("public_model_digest", sha_text("changed")), "config": lambda data: data["runtime"].__setitem__("config_digest", sha_text("changed")), "node": lambda data: data["runtime"].__setitem__("node_digest", sha_text("changed")), "node-version": lambda data: data["runtime"].__setitem__("node_version_digest", sha_text("changed")), "binding": lambda data: data["runtime"].__setitem__("stage_binding_digest", sha_text("changed")), "engine": lambda data: data["stages"][1].__setitem__("engine_family", "gemini"), "stage": lambda data: data["stages"][0].__setitem__("stage", "work"), "terminal": lambda data: data["terminal"].__setitem__("count", 2), "ingress-boolean": lambda data: data["ingress"].__setitem__("delta", True), "terminal-boolean": lambda data: data["terminal"].__setitem__("count", True), "workspace-change": lambda data: data["workspace"].__setitem__("changed", False), "workspace-digest": lambda data: data["workspace"].__setitem__("after_digest", data["workspace"]["before_digest"]), "verifier": lambda data: data["verification"].__setitem__("exit_code", 1), "verifier-boolean": lambda data: data["verification"].__setitem__("exit_code", False), "redaction-boolean": lambda data: data["redaction"].__setitem__("forbidden_match_count", False), } for name, mutation in mutations.items(): candidate = copy.deepcopy(manifest) mutation(candidate) path = valid["root"] / ("manifest-" + name) path.write_text(json.dumps(candidate)) result = subprocess.run([SELF, "--validate-manifest", str(path), "--schema", str(SCHEMA)], capture_output=True, text=True, timeout=10) check(result.returncode != 0, "manifest mutation accepted: " + name) classified_failures = [ ("cli", "claude-failure-cli", "cli-validation", "cli-usage"), ("auth", "claude-failure-auth", "authentication-rejected", "authentication"), ("transport", "claude-failure-transport", "transport-failure", "connection-refused"), ("connection", "claude-failure-connection", "transport-failure", "connection-error"), ("tls", "claude-failure-tls", "transport-failure", "tls-certificate"), ("api", "claude-failure-api", "api-rejected", "http-429"), ("api-400", "claude-failure-api-400", "api-rejected", "http-400"), ("api-400-beta", "claude-failure-api-400-beta", "api-rejected", "unsupported-beta"), ("api-400-field", "claude-failure-api-400-field", "api-rejected", "unknown-field"), ("api-400-thinking", "claude-failure-api-400-thinking", "api-rejected", "invalid-thinking"), ("api-400-output", "claude-failure-api-400-output", "api-rejected", "invalid-output-config"), ("unknown", "claude-failure-unknown", "unknown", "unclassified"), ] for name, behavior, failure_class, failure_reason in classified_failures: fixture = create_fixture(suite, "run-classified-" + name, base_url) result = run_case( fixture, "run-classified-" + name, mode="--run", expect_child=1, env={"IOP_SMOKE_FAKE_BEHAVIOR": behavior}, ) check("class " + failure_class + " reason " + failure_reason + ")" in result.stderr, "run-classified-" + name + ": closed diagnostic missing") for marker in ["rejected-field-marker", "secret_rejected_beta", "secret_field_marker", "secret_thinking_marker", "secret_output_marker", "secret_connection_marker", "secret_cert_marker"]: check(marker not in result.stderr.lower(), "run-classified-" + name + ": raw diagnostic text leaked") run_failures = [ ("stale", "stale", {}, False), ("rotated", "rotated", {}, False), ("no-change", "no-change", {}, False), ("wrong-content", "wrong-content", {}, False), ("verifier-failure", "success", {"IOP_SMOKE_TEST_FORCE_VERIFIER_FAILURE": "1"}, False), ("config-after", "config-after", {}, False), ("node-after", "node-after", {}, False), ("runtime-after", "runtime-after", {}, False), ("timing-swapped", "timing-swapped", {}, False), ("terminal-no-result", "terminal-no-result", {}, False), ("terminal-false-result", "terminal-false-result", {}, False), ("output-race", "output-race", {}, True), ] for name, behavior, extra, expect_output in run_failures: fixture = create_fixture(suite, "run-" + name, base_url) environment = {"IOP_SMOKE_FAKE_BEHAVIOR": behavior, **extra} run_case(fixture, "run-" + name, mode="--run", expect_child=1, expect_output=expect_output, env=environment) if name == "output-race": check(fixture["output"].read_text() == "concurrent owner\n", "run-output-race: existing target was overwritten") leader_exit_fixture = create_fixture(suite, "run-leader-exit", base_url) started = time.monotonic() run_case( leader_exit_fixture, "run-leader-exit", mode="--run", expect_child=1, env={"IOP_SMOKE_FAKE_BEHAVIOR": "leader-exit"}, ) check(time.monotonic() - started < 6, "run-leader-exit: supervisor cleanup was not bounded") assert_process_gone(require_descendant_pid(leader_exit_fixture, "run-leader-exit"), "run-leader-exit") early_signal_fixture = create_fixture(suite, "run-early-signal", base_url) started = time.monotonic() run_case( early_signal_fixture, "run-early-signal", mode="--run", expect_child=None, env={ "IOP_SMOKE_FAKE_BEHAVIOR": "early-signal", "IOP_CLAUDE_SUPERVISOR_TEST_EARLY_SIGNAL": "1", }, ) check(time.monotonic() - started < 6, "run-early-signal: supervisor cleanup was not bounded") early_descendant = early_signal_fixture["descendant"] if early_descendant.exists() and early_descendant.read_text().strip(): assert_process_gone(require_descendant_pid(early_signal_fixture, "run-early-signal"), "run-early-signal") signal_fixture = create_fixture(suite, "run-term-resistant", base_url) Listener.metrics_path = signal_fixture["metrics"] process = subprocess.Popen( command_for(signal_fixture, mode="--run"), env=environment_for(signal_fixture, {"IOP_SMOKE_FAKE_BEHAVIOR": "term-resistant"}), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, ) deadline = time.monotonic() + 10 while time.monotonic() < deadline and not signal_fixture["marker"].read_text().strip(): time.sleep(0.05) check(bool(signal_fixture["marker"].read_text().strip()), "run-signal: child did not start") descendant_pid = require_descendant_pid(signal_fixture, "run-term-resistant") process.terminate() started = time.monotonic() stdout, stderr = process.communicate(timeout=10) check(time.monotonic() - started < 6, "run-term-resistant: supervisor cleanup was not bounded") check(process.returncode != 0, "run-term-resistant: interruption succeeded unexpectedly") class Result: pass result = Result() result.stdout, result.stderr = stdout, stderr assert_redacted(signal_fixture, result, "run-term-resistant") assert_cleanup(signal_fixture, "run-term-resistant") check(not signal_fixture["output"].exists(), "run-term-resistant: final output remained") check(list(signal_fixture["output_dir"].iterdir()) == [], "run-term-resistant: partial publication remained") assert_process_gone(descendant_pid, "run-term-resistant") finally: server.shutdown() server.server_close() thread.join(timeout=5) except TestFailure as error: print("[single-request-claude-self-test] " + str(error), file=sys.stderr) raise SystemExit(1) except Exception: print("[single-request-claude-self-test] unexpected self-test failure", file=sys.stderr) raise SystemExit(1) PY log 'self-test passed: exact Claude base-route coverage, structured observation admission, child-only zero retry, authenticated model admission, closed failure classification, model/Edge/Node/runtime binding, zero-child preflight, derived verification, redaction, cleanup, signal handling, and atomic publication' } main() { parse_args "$@" case "$MODE" in self-test) self_test ;; validate-manifest) [ -f "$MANIFEST" ] && [ -f "$SCHEMA" ] || fail 'manifest or schema unavailable' validate_schema_contract "$SCHEMA" 2>/dev/null || fail 'manifest schema invalid' validate_manifest "$MANIFEST" "$SCHEMA" || fail 'manifest validation failed' log 'manifest is valid' ;; preflight-only) preflight_only ;; run) run_once ;; *) usage exit "$EXIT_USAGE" ;; esac } main "$@"