#!/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" "$REPRO_DIR" "$PROOF"
cd "$ROOT"

REPOSITORY_URL="https://github.com/cri-o/cri-o.git"
FIXED_COMMIT="f4d95dfe70c4af4afff0c5a96e1a36975c2f65f9"
EXPECTED_VULN_COMMIT="6e902ee2a9f7ce535855c68c92c6838f087f578f"
CACHE_CONTEXT="$ROOT/project_cache_context.json"
FALLBACK_REPO="$ROOT/artifacts/cri-o"
REPO="$FALLBACK_REPO"
if [ -r "$CACHE_CONTEXT" ]; then
  CANDIDATE="$(python3 - "$CACHE_CONTEXT" <<'PY'
import json,sys
try:
    d=json.load(open(sys.argv[1], encoding='utf-8'))
    print(d.get('project_cache_dir','') + '/repo' if d.get('prepared') and d.get('project_cache_dir') else '')
except Exception: print('')
PY
)"
  if [ -n "$CANDIDATE" ]; then REPO="$CANDIDATE"; fi
fi
mkdir -p "$(dirname "$REPO")"

write_failure_manifest() {
  local note="$1"
  python3 - "$REPRO_DIR/runtime_manifest.json" "$note" <<'PY'
import json,sys
out,note=sys.argv[1:]
data={"entrypoint_kind":"endpoint","entrypoint_detail":"CRI RuntimeService CreateContainer endpoint with checkpoint archive image","service_started":False,"healthcheck_passed":False,"target_path_reached":False,"runtime_stack":[],"proof_artifacts":[],"artifact_sha256":{},"notes":note}
with open(out,'w',encoding='utf-8') as f: json.dump(data,f,indent=2,sort_keys=True); f.write('\n')
PY
}
write_failure_manifest "attempt started; no confirmed runtime evidence yet"
trap 'rc=$?; if [ "$rc" -ne 0 ]; then write_failure_manifest "reproduction attempt failed; inspect logs/reproduction_steps.log and logs/repro/"; fi' EXIT
exec > >(tee "$LOGS/reproduction_steps.log") 2>&1

echo "[setup] resolving immutable CRI-O source"
if [ ! -d "$REPO/.git" ]; then git clone "$REPOSITORY_URL" "$REPO"; fi
git -C "$REPO" fetch --force origin "$FIXED_COMMIT" bb54fa0fba793889d815e5943abd6f8afc938c39
VULN_COMMIT="$(git -C "$REPO" rev-parse "$FIXED_COMMIT^")"
FIXED_RESOLVED="$(git -C "$REPO" rev-parse "$FIXED_COMMIT")"
[ "$VULN_COMMIT" = "$EXPECTED_VULN_COMMIT" ]
! git -C "$REPO" show "$VULN_COMMIT:pkg/config/config.go" | grep -q 'CheckpointRestoreConfig'
git -C "$REPO" show "$FIXED_RESOLVED:pkg/config/config.go" | grep -q 'CheckpointRestoreConfig'
printf 'repository=%s\nvulnerable_commit=%s\nfirst_fix_commit=%s\nsecure_default_commit=%s\n' \
  "$REPOSITORY_URL" "$VULN_COMMIT" "$FIXED_RESOLVED" bb54fa0fba793889d815e5943abd6f8afc938c39 > "$PROOF/source-identity.txt"

echo "[setup] checking Docker runtime"
docker info >/dev/null
DRIVER="$REPRO_DIR/crio_checkpoint_driver.sh"
RUNC_PATCH="$REPRO_DIR/runc_rootless_restore.patch"
CRIU_PATCH="$REPRO_DIR/criu_rootless_uts.patch"
[ -r "$CRIU_PATCH" ] || { echo "required patch missing: $CRIU_PATCH" >&2; exit 1; }
[ -r "$RUNC_PATCH" ] || { echo "required patch missing: $RUNC_PATCH" >&2; exit 1; }
[ -x "$DRIVER" ] || { echo "required helper missing or not executable: $DRIVER" >&2; exit 1; }
rm -rf "$PROOF/current"; mkdir -p "$PROOF/current"
set +e
timeout 1800 docker run --rm --cap-add ALL \
  --security-opt apparmor=unconfined --security-opt seccomp=unconfined \
  -v "$REPO:/src/cri-o" -v "$DRIVER:/runner/crio_checkpoint_driver.sh:ro" \
  -v "$RUNC_PATCH:/runner/runc_rootless_restore.patch:ro" \
  -v "$CRIU_PATCH:/runner/criu_rootless_uts.patch:ro" \
  -v "$PROOF/current:/proof" \
  -e VULN_COMMIT="$VULN_COMMIT" -e FIXED_COMMIT="$FIXED_RESOLVED" \
  debian:trixie-slim /bin/bash /runner/crio_checkpoint_driver.sh \
  >"$LOGS/repro/docker-driver.log" 2>&1
DRIVER_RC=$?
set -e
cat "$LOGS/repro/docker-driver.log" || true
[ "$DRIVER_RC" -eq 0 ] || { echo "driver failed: rc=$DRIVER_RC"; exit 1; }

for n in 1 2; do
  grep -q '^service_started=true$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^healthcheck_passed=true$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^target_path_reached=true$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^restore_result=accepted$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^restored_uid=0$' "$PROOF/current/vulnerable-$n.txt"
  SOURCE_CAP="$(awk '/^CapEff:/{print $2}' "$PROOF/current/source-process-status.txt")"
  [ "$SOURCE_CAP" != 0000000000000000 ]
  grep -q "^restored_cap_eff=$SOURCE_CAP$" "$PROOF/current/vulnerable-$n.txt"
  grep -q '^requested_run_as_user=65534$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^requested_no_new_privs=true$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^requested_drop_all=true$' "$PROOF/current/vulnerable-$n.txt"
  grep -q '^service_started=true$' "$PROOF/current/fixed-$n.txt"
  grep -q '^healthcheck_passed=true$' "$PROOF/current/fixed-$n.txt"
  grep -q '^target_path_reached=true$' "$PROOF/current/fixed-$n.txt"
  grep -q '^restore_result=rejected$' "$PROOF/current/fixed-$n.txt"
done

cp "$PROOF/source-identity.txt" "$PROOF/current/source-identity.txt"
TARGET_DIGEST="$(printf 'git:%s@%s' "$REPOSITORY_URL" "$VULN_COMMIT" | sha256sum | awk '{print $1}')"
python3 - "$REPRO_DIR/runtime_manifest.json" "$PROOF/current" "$TARGET_DIGEST" "$VULN_COMMIT" <<'PY'
import hashlib,json,os,platform,sys
out,proof_dir,target_digest,commit=sys.argv[1:]; root=os.environ['PRUVA_ROOT']; rels=[]
for name in sorted(os.listdir(proof_dir)):
 p=os.path.join(proof_dir,name)
 if os.path.isfile(p): rels.append(os.path.relpath(p,root))
hashes={rel:hashlib.sha256(open(os.path.join(root,rel),'rb').read()).hexdigest() for rel in rels}
data={"entrypoint_kind":"endpoint","entrypoint_detail":"CRI RuntimeService CreateContainer endpoint with a local checkpoint archive as ContainerConfig.image","service_started":True,"healthcheck_passed":True,"target_path_reached":True,"runtime_stack":["crictl","CRI gRPC RuntimeService","CRI-O","conmon","runc","CRIU"],"target_identity":{"repository_url":"https://github.com/cri-o/cri-o.git","commit_sha":commit,"target_digest":target_digest,"platform":"linux","architecture":platform.machine()},"proof_artifacts":rels,"artifact_sha256":hashes,"notes":"Two vulnerable API restore attempts retained root/full capabilities despite a restricted destination request; two fixed-default controls rejected restore."}
with open(out,'w',encoding='utf-8') as f: json.dump(data,f,indent=2,sort_keys=True); f.write('\n')
PY

echo "CONFIRMED: vulnerable CRI-O accepted restricted checkpoint restore and retained privileged process state; fixed default rejected restore (2/2 each)."
trap - EXIT
exit 0
