#!/bin/sh # harkaq-campana.sh — bucle AUTÓNOMO del worker para la campaña harkaq. Hermano de # farm-worker-loop.sh: muele sin esperar a nadie, 24/7, y no pregunta NADA. # # scripts/farm/harkaq-campana.sh [lista-de-recetas.txt] # # Mide, no decide: por cada receta la construye bajo la jaula y guarda los veredictos crudos en # work/harkaq-campana/.verdicts. La clasificación y la edición de recetas las hace el HUB # (harvest-harkaq.sh, por cron), porque el store del worker es parcial y marcaría como irreducible # lo que sí es declarable. El worker MIDE, el hub CLASIFICA. # # Idempotente: lo ya medido se saltea; re-correrlo sólo mide lo nuevo. Cuando no queda nada, # duerme y re-escanea — igual que farm-worker-loop.sh. # # Diseñado para la NOCHE: nunca bloquea esperando una decisión. Un build que falla NO detiene la # cola; su veredicto se guarda igual (un build que falla es justo cuando más interesa saber qué # tocó fuera de su clausura) y se sigue. Ocho horas de idle por una pregunta es el fallo que este # script existe para no tener. set -u HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}" cd "$HAMMER_DIR" LISTA="${1:-work/harkaq-cola.txt}" OUT="work/harkaq-campana" BIN="${HARKAQ_BIN:-/root/.cache/harkaq}" IDLE_SLEEP="${IDLE_SLEEP:-300}" POR_RECETA="${POR_RECETA:-900}" mkdir -p "$OUT" export HARKAQ=1 HARKAQ_BIN="$BIN" HARKAQ_BASE="${HARKAQ_BASE:-$BIN/base.policy}" export HARKAQ_TIMEOUT="${HARKAQ_TIMEOUT:-300}" # Gate 1: sin ABI>=7 el kernel no audita y TODOS los veredictos saldrían SinEvidencia. Moler la # noche entera para producir "no sabemos" es peor que no moler. abi=$(python3 -c 'import ctypes;print(ctypes.CDLL("libc.so.6").syscall(444,None,0,1))' 2>/dev/null) if [ "${abi:-0}" -lt 7 ]; then echo "ABORTO: Landlock ABI ${abi:-?} < 7 ⇒ sin audit de denegaciones. ¿La golden es la 6.17?" exit 4 fi # Gate 2: ¿el binario TIENE harkaq dentro? La golden hornea un `target/release/takana` viejo y el # rsync excluye /target ⇒ si el `cargo build` del provisioning no corrió, el worker construye # alegremente SIN LA JAULA y produce cero veredictos. Pasó: la primera corrida molió 2 recetas con # un binario del 29/06 (0 ocurrencias de "harkaq") y las marcó "sin veredicto" como si fuera culpa # de las recetas. Ocho horas así son la noche entera perdida — y el log diría "salteada", nunca # "estoy ciego". Es el falso `Hermetico` de D9 mudado al orquestador: la ausencia como respuesta # tranquilizadora. if ! strings ./target/release/takana 2>/dev/null | grep -q harkaq; then echo "ABORTO: ./target/release/takana NO tiene harkaq compilado (¿corrió el cargo build?)." echo " Sin esto la campaña muele sin jaula y produce 0 veredictos, en silencio." exit 4 fi echo "$(date -u +%FT%TZ) campaña harkaq: ABI $abi, binario con jaula ✓, cola $LISTA" while :; do hechas=0; nuevas=0 while IFS= read -r n; do [ -n "$n" ] || continue [ -f "recipes/$n.toml" ] || continue if [ -s "$OUT/$n.verdicts" ]; then hechas=$((hechas + 1)); continue; fi # Forzar build real: `hammer build` pega en la caché si el artefacto ya está sellado y no # correría nada (veredicto vacío que NO es un fallo). La copia va AL LADO del original o se # rompe la resolución de deps.build, que son relativas al dir de la receta. tmp="recipes/.hk-$n.toml" sed "s/^name *= *\"$n\"/name = \"$n-hkm\"/" "recipes/$n.toml" > "$tmp" timeout "$POR_RECETA" ./target/release/takana build "$tmp" --store "$PWD/store" \ > "$OUT/$n.log" 2>&1 rm -f "$tmp" grep '^\[harkaq\] {' "$OUT/$n.log" | sed 's/^\[harkaq\] //' > "$OUT/$n.verdicts" if [ -s "$OUT/$n.verdicts" ]; then nuevas=$((nuevas + 1)) echo "$(date -u +%FT%TZ) ++ $n ($(wc -l < "$OUT/$n.verdicts") fase/s medidas)" else # Sin veredicto: el build ni arrancó (fetch, dep rota…). Se marca para no reintentar # en bucle y se SIGUE — la cola no se detiene por una receta. echo "sin-veredicto" > "$OUT/$n.skip" rm -f "$OUT/$n.verdicts" echo "$(date -u +%FT%TZ) ?? $n — sin veredicto, salteada (ver $OUT/$n.log)" fi done < "$LISTA" echo "$(date -u +%FT%TZ) ciclo: $nuevas nuevas, $hechas ya medidas. durmiendo ${IDLE_SLEEP}s" sleep "$IDLE_SLEEP" done