diff --git a/scripts/consenso.sh b/scripts/consenso.sh new file mode 100755 index 00000000..556e83b6 --- /dev/null +++ b/scripts/consenso.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# consenso.sh [N] — CONSENSO DE RECONSTRUCCIÓN (SDD 17 §1). +# +# N builders INDEPENDIENTES reproducen el mismo hash ⇒ el binario es confiable **sin que nadie +# firme nada**. Convierte la reproducibilidad de QA en primitiva de distribución: cualquiera +# puede ser mirror, nadie puede envenenar el repo. +# +# scripts/consenso.sh recipes/bzip2.toml 2 +# +# Builders: este hub (laptop) + N-1 workers efímeros de la granja, cada uno una máquina física +# distinta con su propio OS. Si coinciden ⇒ CONSENSO. Si divergen ⇒ candidato a `why-differs` +# (SDD 17 §2) — y eso también es información: una divergencia es un canal impuro encontrado. +# +# Por qué esto no lo puede ofrecer nix/debian: su repro es incompleta. hammer ya paga el +# invariante (bit-repro verificada: selfhost, kernel), así que esto cae casi solo del invariante +# — que es la tesis del SDD 17: buscar "qué cae del invariante", no "qué frontera agregar". +# +# NO firma ni publica: sólo produce el veredicto de consenso. El log de transparencia +# (`fork-proof`, hash-encadenado + detección de equivocation) es el paso siguiente y YA está +# escrito en tawasuyu — no hay que construir un rekor. +set -eu + +RECETA="${1:?uso: consenso.sh [N-builders]}" +N="${2:-2}" +HUB="$(cd "$(dirname "$0")/.." && pwd)" +cd "$HUB" +IMAGE="${IMAGE:-408909310}" +TYPE="${TYPE:-ccx23}" +LOCATION="${LOCATION:-hel1}" +SSHKEY="${SSHKEY:-desarrollo@jlsoltech.com}" +SSH_KEY="${SSH_KEY:-$HOME/.ssh/github5}" +SSH="ssh -i $SSH_KEY -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o BatchMode=yes" +n=$(basename "$RECETA" .toml) +OUT="work/consenso"; mkdir -p "$OUT" + +echo "══ CONSENSO DE RECONSTRUCCIÓN — $n, $N builders independientes" + +# Builder 1: el hub. Es un builder legítimo (otra máquina, otro OS que los workers). +echo "── builder 1: hub local ($(uname -s), $(grep -m1 '^NAME=' /etc/os-release 2>/dev/null | cut -d'"' -f2 || echo '?'))" +h1=$(timeout "${POR:-900}" ./target/debug/hammer build "$RECETA" --store "$PWD/store" 2>/dev/null \ + | grep -oE '^b3:[a-f0-9]{64}' | head -1) +echo " → ${h1:-FALLÓ}" +[ -z "$h1" ] && { echo " el hub no puede construir $n ⇒ sin consenso posible desde acá"; exit 3; } +echo "$h1 hub" > "$OUT/$n.hashes" + +# Builders 2..N: workers efímeros, cada uno una máquina física distinta. +i=2 +while [ "$i" -le "$N" ]; do + name="hkc-$i" + echo "── builder $i: worker efímero $name" + hcloud server create --name "$name" --image "$IMAGE" --type "$TYPE" --location "$LOCATION" \ + --ssh-key "$SSHKEY" >/dev/null 2>&1 + ip=$(hcloud server ip "$name") + for _ in $(seq 1 30); do $SSH "root@$ip" true 2>/dev/null && break; sleep 6; done + rsync -az -e "$SSH" --exclude /work --exclude /store --exclude '/store-*' --exclude /target \ + --exclude /dist --exclude /tandas --exclude /.dev-fs --exclude /.git --exclude /.scratch \ + --exclude '*.png' --exclude '/content*' ./ "root@$ip:/opt/hammer/" >/dev/null 2>&1 + hN=$($SSH "root@$ip" "export PATH=\$HOME/.cargo/bin:\$PATH; cd /opt/hammer && \ + cargo build --release -q -p hammer-cli 2>/dev/null; \ + timeout ${POR:-900} ./target/release/hammer build $RECETA --store \$PWD/store 2>/dev/null \ + | grep -oE '^b3:[a-f0-9]{64}' | head -1" 2>/dev/null | tr -d '\r') + echo " → ${hN:-FALLÓ}" + [ -n "$hN" ] && echo "$hN $name" >> "$OUT/$n.hashes" + hcloud server delete "$name" >/dev/null 2>&1 + i=$((i + 1)) +done + +echo +echo "══ VEREDICTO" +cat "$OUT/$n.hashes" | sed 's/^/ /' +distintos=$(awk '{print $1}' "$OUT/$n.hashes" | sort -u | wc -l) +cuantos=$(wc -l < "$OUT/$n.hashes") +if [ "$cuantos" -lt 2 ]; then + echo " SIN CONSENSO: sólo $cuantos builder(s) produjeron hash. No se afirma nada." + exit 3 +elif [ "$distintos" = 1 ]; then + echo " ✅ CONSENSO ($cuantos/$cuantos builders, mismo hash bit a bit)" + echo " ⇒ el artefacto es confiable SIN FIRMA: N máquinas independientes lo reprodujeron." + exit 0 +else + echo " ⚠️ DIVERGENCIA: $distintos hashes distintos entre $cuantos builders." + echo " ⇒ hay un canal impuro. Es trabajo para \`why-differs\` (SDD 17 §2) — y la" + echo " divergencia YA es información: el invariante bit-repro se rompió acá." + exit 1 +fi