#!/bin/sh
# runtime-policy.sh <binario> [args…] — política de RUNTIME derivada por medición (SDD 17 §3).
#
# La clausura que harkaq mide en BUILD **no** es la política de runtime: un build lee `zlib.h`,
# `make`, el compilador; el binario resultante no lee nada de eso. Son dos clausuras de dos
# sujetos distintos. Lo que sí sirve es la TÉCNICA: correr el binario bajo la jaula con política
# mínima y dejar que las denegaciones digan qué necesita. Eso ES su política de runtime, derivada
# por evidencia y no escrita a mano.
#
#   scripts/harkaq/runtime-policy.sh store/<hash>-htop/usr/bin/htop --version
#
# BASELINE: el `sh` que lanza al binario también deniega cosas (locale, ld.so.cache). Se mide
# primero un `true` para conocer ese ruido y RESTARLO — si no, la política del binario se lleva
# la basura del lanzador.
#
# Cómo encaja con la concesión firmada de arje/wawa (PLAN-ATESTACION):
#   - `ConcesionCapacidad` firma `(blake3(binario), u32)` en 36 bytes canónicos, zero-alloc, Ring 0
#     ⇒ es la FRONTERA gruesa. NO se toca: meterle paths rompería todas las firmas y contradice
#     "capacidad = frontera física, no tabla".
#   - Esta política es el DETALLE granular (fs, paths), vive en userspace y se aplica con Landlock.
#   Los dos coexisten: el kernel verifica la frontera; Landlock aplica el detalle.
set -eu

BIN="${1:?uso: runtime-policy.sh <binario> [args…]}"
shift || true
HUB="$(cd "$(dirname "$0")/../.." && pwd)"
cd "$HUB"
BIN="$(cd "$(dirname "$BIN")" && pwd)/$(basename "$BIN")"   # absoluto
POL="$(mktemp)"; BASE="$(mktemp)"; MED="$(mktemp)"
trap 'rm -f "$POL" "$BASE" "$MED"' EXIT

# Política mínima DERIVADA (no a mano: escribirla a mano se olvida de libc.musl y el sh ni
# arranca). El sandbox de harkaq-run monta el HOST ⇒ el cierre es el del sh DEL HOST.
scripts/harkaq/harkaq-base-closure.py / /bin/sh 2>/dev/null > "$POL"
echo "ro $BIN" >> "$POL"

denegados() {  # corre $1 bajo la jaula y lista los paths denegados
    HARKAQ_TIMEOUT=10 scripts/harkaq/harkaq-run.sh "$POL" "$1" 2>/dev/null \
        | grep '^{' | head -1 \
        | python3 -c 'import json,sys
try:
    v=json.load(sys.stdin)
    if v["estado"]=="SinEvidencia": print("SIN-EVIDENCIA:"+v.get("motivo","")[:60]); raise SystemExit
    for d in v["denials"]: print(d["path"])
except Exception: pass'
}

echo "══ baseline: el ruido del lanzador (sh)"
denegados "true" | sort -u > "$BASE"
grep -q 'SIN-EVIDENCIA' "$BASE" && { echo "   $(cat "$BASE")"; echo "   ⇒ sin evidencia fiable: no se afirma ninguna política"; exit 3; }
sed 's/^/   − /' "$BASE"

echo "══ medición: $(basename "$BIN") $*"
denegados "$BIN $*" | sort -u > "$MED"
grep -q 'SIN-EVIDENCIA' "$MED" && { echo "   $(cat "$MED")"; exit 3; }

echo
echo "══ POLÍTICA DE RUNTIME de $(basename "$BIN") (medida − baseline):"
propios=$(comm -23 "$MED" "$BASE")
if [ -z "$propios" ]; then
    echo "   (ninguna) — el binario no tocó NADA fuera de sí mismo."
    echo "   ⇒ política Landlock: sólo \`ro $BIN\`. Es el caso de un estático que no abre ficheros."
else
    echo "$propios" | sed 's/^/   ro /'
    # CONTACTO con el §3 (clases de servicio, diseño de Fable 5): la medición no sólo lista
    # paths — propone la CLASE. El path va a Landlock (detalle, userspace); la clase va al bit
    # del u32 firmado (frontera, Ring 0). La medición ALIMENTA la tabla; la tabla decide el bit.
    # Ninguno ensancha por su cuenta (D3).
    clases=""
    echo "$propios" | grep -qE '/etc/(resolv\.conf|hosts)'    && clases="$clases dns"
    echo "$propios" | grep -qE '/etc/ssl/certs'                && clases="$clases tls-certs"
    echo "$propios" | grep -qE '/usr/share/zoneinfo|/etc/TZ'   && clases="$clases tz"
    echo "$propios" | grep -qE '/dev/log'                      && clases="$clases syslog"
    if [ -n "$clases" ]; then
        echo
        echo "   ── clases de servicio detectadas (§3: van al u32 firmado, NO a Landlock):"
        for c in $clases; do echo "      $c"; done
        echo "      ⇒ declarar por nombre en la ConcesionCapacidad; el resto de arriba es Landlock."
    fi
    echo
    echo "   ⇒ los `ro` van a la política Landlock del binario instalado."
fi
