#!/bin/sh
# harkaq-farm-setup.sh <ip> — deja un worker de la granja listo para barrer con harkaq.
#
# La granja es el compilador continuo (SDD 16 §4.8), así que esto tiene que ser reproducible y
# no un copy-paste. Idempotente: re-correrlo sobre un worker ya provisto no rompe nada.
#
# Precondición dura: la golden 408909310 (kernel 6.17 ⇒ Landlock ABI 7). Con la vieja (6.8, ABI 4)
# el barrido correría y daría `SinEvidencia` en TODO — que es lo que D7 manda y lo que no sirve
# para medir. Por eso lo primero que hace es verificar el ABI y abortar si no llega.
set -eu

IP="${1:?uso: harkaq-farm-setup.sh <ip>}"
KEY="${SSH_KEY:-$HOME/.ssh/github5}"
REMOTE="${REMOTE:-/opt/hammer}"
SSH="ssh -i $KEY -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes"
HERE="$(cd "$(dirname "$0")" && pwd)"

echo "== 1/4 verificando el ABI (gate: >=7 o no hay evidencia)"
abi=$($SSH "root@$IP" 'python3 -c "
import ctypes; libc=ctypes.CDLL(\"libc.so.6\",use_errno=True)
print(libc.syscall(444,None,0,1))"' 2>/dev/null | tr -d '\r')
echo "   kernel: $($SSH "root@$IP" uname -r 2>/dev/null)  →  Landlock ABI = $abi"
if [ "${abi:-0}" -lt 7 ]; then
    echo "   ABORTO: ABI $abi < 7 ⇒ el kernel no audita denegaciones. Todos los veredictos"
    echo "           saldrían SinEvidencia. ¿El worker salió de la golden 408909310?"
    exit 4
fi

echo "== 2/4 copiando y compilando las piezas"
$SSH "root@$IP" "mkdir -p /root/.cache/harkaq $REMOTE/scripts/harkaq"
scp -q -i "$KEY" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
    "$HERE"/harkaq-uapi.h "$HERE"/harkaq-audit.c "$HERE"/harkaq-exec.c \
    "$HERE"/harkaq-policy.sh "$HERE"/harkaq-verdict.py "$HERE"/harkaq-suggest.py \
    "$HERE"/harkaq-base-closure.py "$HERE"/fase2-barrido.sh \
    "root@$IP:$REMOTE/scripts/harkaq/"
# harkaq-uapi.h no es una comodidad: el worker tiene headers 6.8 sobre kernel 6.17 y NO define
# ni AUDIT_LANDLOCK_ACCESS. Sin él el lector filtraría por un número que no conoce y vería cero
# denegaciones — el falso `Hermetico` de D9, por headers viejos (§4.8).
$SSH "root@$IP" "cd $REMOTE/scripts/harkaq && chmod +x *.sh *.py &&
    gcc -O1 -Wall -o /root/.cache/harkaq/harkaq-audit harkaq-audit.c &&
    gcc -O1 -Wall -static -o /root/.cache/harkaq/harkaq-exec harkaq-exec.c &&
    echo '   compiladas ✓'"

echo "== 3/4 derivando el runtime base DEL ROOTFS DEL WORKER"
# El runtime base es POR ROOTFS (§4.3) — derivarlo del rootfs del worker, no copiar el del
# laptop: los sonames de las libs (libz.so.1.3.2, …) dependen de la versión de Alpine que tenga.
$SSH "root@$IP" "cd $REMOTE &&
    python3 scripts/harkaq/harkaq-base-closure.py .dev-fs/alpine \
        /bin/sh /bin/busybox /bin/bash /bin/coreutils /usr/bin/env 2>/dev/null \
        > /root/.cache/harkaq/base.policy
    printf 'ro /usr/lib/os-release\n' >> /root/.cache/harkaq/base.policy
    # Sondas de compilador de Alpine: se DENIEGAN y se clasifican (D3). Concederlas dejaría a
    # zig/configure usar el gcc de Alpine por detrás — justo lo que la campaña matar-gcc caza.
    for p in /usr/bin/gcc /usr/bin/ldd /usr/bin/c89 /usr/bin/c99 /usr/bin/cpp /usr/bin/getent; do
        printf '# expect %s\n' \"\$p\" >> /root/.cache/harkaq/base.policy
    done
    echo \"   runtime base: \$(grep -c '^ro ' /root/.cache/harkaq/base.policy) reglas + \$(grep -c '^# expect' /root/.cache/harkaq/base.policy) esperadas\""

echo "== 4/4 comprobando la cadena de evidencia de punta a punta"
$SSH "root@$IP" "cd $REMOTE && cargo build -q -p hammer-cli 2>/dev/null || true; ls target/debug/hammer >/dev/null 2>&1 && echo '   hammer-cli listo ✓' || echo '   OJO: falta target/debug/hammer (cargo build -p hammer-cli)'"

cat <<EOF

listo. En el worker:
  cd $REMOTE
  export HARKAQ_BIN=/root/.cache/harkaq HARKAQ_BASE=/root/.cache/harkaq/base.policy
  scripts/harkaq/fase2-barrido.sh recipes/zlib.toml recipes/bzip2.toml ...
EOF
