Files
sergioandClaude Opus 4.8 d99ed58850 harkaq: revertir busybox (era runtime base, rompía builds) + coordinar el §3 con Fable 5
DOS ERRORES MÍOS, uno de dirección y otro técnico, los dos en la cosecha automática:

1. DIRECCIÓN: declaró `busybox` como dep en 29 recetas — cuando la Etapa C lo está
   ELIMINANDO (USERLAND_COMPONENTS=[uutils,findutils,…], ya cerrada; joyas-reusables
   §5 lo confirma: "uutils… Ubuntu 25.10 los envía como default"). Estaba cimentando
   la deuda que el roadmap borra.
2. TÉCNICO: busybox YA está en el runtime base de harkaq (`ro /bin/busybox`, `ro
   /bin/sh` — el sandbox corre `sh -c` y /bin/sh→/bin/busybox). Es CONTRATO, no dep.
   Declararlo apila el busybox de hammer sobre el de Alpine y ROMPE el build:
   binutils daba "cannot run C compiled programs" en las DOS máquinas. Verificado:
   sin busybox declarado, binutils construye (b3:f4507dcd…). Y la cadena se explica:
   binutils roto ⇒ zlib (que lo declara) tampoco construía.

Auditoría de la cosecha (diff real, no la línea completa del +): añadió sólo 5 deps
distintas — make ×73, busybox ×29, perl ×8, pkgconf ×5, binutils ×1. Sólo busybox
estaba mal; las otras 4 son deps reales medidas. busybox revertido de 30 recetas
(queda sólo en busybox.toml, pre-existente).

Es el mismo error que ya me habían señalado con otro disfraz: MEDIR BIEN Y ACCIONAR
MAL. harkaq midió correcto (el build toca /bin/busybox: es el shell); la acción
correcta no era declararlo sino reconocerlo como contrato.

+ COORDINACIÓN del §3 con Fable 5 (mismo diseño, tareas repartidas):
  - Su lección casper queda CONFIRMADA y REFORZADA: la clausura de build no sólo le
    FALTAN las clases del mundo (offline) — también le SOBRA casi todo (headers, gcc).
    Medido: htop (estático, 0 NEEDED) no toca NADA al correr ⇒ política = su binario.
  - Su "la clase viaja como campo de la ConcesionCapacidad, sin formato nuevo" se
    cumple LITERALMENTE: lo firmado es format::Permisos = u32 bitmask en 36 bytes
    canónicos (Ring 0) ⇒ las clases SON los bits. La cripto no se toca.
  - Diseño unificado: frontera (clases, u32, declaradas) + detalle (paths, Landlock,
    medidos). D3 rige en ambos.
  - Reparto: clases→Fable 5; medición/harness→Opus. CONTACTO: runtime-policy.sh ahora
    emite la CLASE detectada (/etc/resolv.conf→dns, /etc/ssl/certs→tls-certs, …), no
    sólo el path: la medición alimenta la tabla, la tabla decide el bit.
  - Consumidor esperando: plan-jaula-juegos F1 (Steam que no puede leer ~/.ssh).

+ juez.sh (§10): nombre único por corrida (con uno fijo pega en caché ⇒ falso
  "sin evidencia"). Fue el juez quien destapó todo esto en su primera corrida real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 23:14:19 -04:00

83 lines
4.1 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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