gioser

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 815Rust 56Shell 37Markdown 291229 Definitions

la jaula no viajaba en NINGUNA imagen: `bwrap` y `harkaq-exec` entran a `perfil.base`

Mudando `api.sergio.gioser.net` a la caja de produccion, `takana qorpa provision` aborto:

    Error: no encuentro harkaq-exec en /root/.cache/harkaq/harkaq-exec
      construilo:  gcc -O1 -Wall -static -o ... scripts/harkaq/harkaq-exec.c

El mensaje es bueno y la receta que propone es IMPOSIBLE de seguir: en una caja instalada no hay
gcc, ni `scripts/`, ni arbol de desarrollo. El binario solo existia como un `gcc` a mano en la
cache de `$HOME` del hub, o sea que la jaula del ADR 0015 funcionaba unicamente en la maquina
donde alguien la habia compilado.

Y su companero estaba igual, medido en `build-state.json`: `bwrap` sellado desde hace meses con
`"perfiles": []` — CERO perfiles. Lo invocan por PATH tanto `qorpa` como el sandbox de
`takana build` (`takana-build/src/sandbox.rs`), asi que **ninguna imagen de takana podia enjaular
nada, ni construir**. Es [[subcomando-sin-driver]] un piso mas abajo: el CLI que los llama viaja
en todas las imagenes y sus herramientas en ninguna.

Tres piezas:

· `recipes/harkaq-exec.toml` — nueva. Estatico musl, `b3:cd34954f...`, 269 K. El pin va al commit
  que toco la FUENTE (`1d9ddcee`, 2026-09-03) y no a HEAD: el `.c` no se mueve desde entonces y el
  repo commitea cada media hora por el cron de la cosecha — pinear HEAD re-hashearia la receta cada
  media hora sin que su fuente cambiara. La fuente sigue en `scripts/harkaq/` y no en un arbol
  propio porque tres scripts la compilan desde ahi y dos copias divergen en silencio.
· `qorpa.rs` — busca el binario tambien en `/usr/bin`, que es de donde sale en cualquier maquina
  que no sea el hub. El orden es HARKAQ_BIN (lo que el operador declara) → arbol de desarrollo →
  paquete, para que un cambio en la jaula se pruebe sin instalar nada. Y el error ya nombra las
  dos salidas, no solo la del hub.
· `targets.toml` — los dos en `perfil.base`.

Medido en la caja de produccion tras aplicarlos: `bwrap 0.11.0` + harkaq-exec responden, y
`takana qorpa provision sergioh-api` instala python 3.14.7 con pacman DENTRO de la jaula
(`[harkaq] jaula puesta: ABI 9`). El 3.14 no es casualidad: el venv de gioser trae extensiones
`cpython-314-...-gnu.so`, asi que la imagen de Arch pineada da la misma serie.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

dbfb7d492be7e9c30093dc7df7cda54707051999 · by Sergio · (1 month ago) · parent 9bb1308a5 · browse the tree at this commit

Semantic delta · 2

crates/takana-cli/src/qorpa.rs

3 files · +97 −10

diff --git a/crates/takana-cli/src/qorpa.rs b/crates/takana-cli/src/qorpa.rs
index 08da0059..ddbdb9ac 100644
--- a/crates/takana-cli/src/qorpa.rs
+++ b/crates/takana-cli/src/qorpa.rs
@@ -834,15 +834,33 @@ struct Grants {
     seal_image: bool,
 }
 
-/// Dónde vive `harkaq-exec`. Misma convención que el harkaq del build (`HARKAQ_BIN`).
+/// Dónde vive `harkaq-exec`. Misma convención que el harkaq del build (`HARKAQ_BIN`), **más el
+/// binario instalado**, que es el caso de cualquier máquina que no sea el hub de desarrollo.
+///
+/// ⚠ MEDIDO el 2026-09-15 en la caja de producción: sólo se buscaba en `~/.cache/harkaq`, o sea en
+/// la caché de quien lo hubiera compilado a mano. En una caja instalada no hay `gcc`, ni `scripts/`,
+/// ni caché — así que `qorpa` abortaba con una instrucción imposible de seguir y la jaula del ADR
+/// 0015 funcionaba únicamente en la máquina donde alguien la había construido. Ahora
+/// `recipes/harkaq-exec.toml` lo publica en `/usr/bin` y va declarado en `perfil.base`.
+///
+/// El orden es deliberado: lo que el operador declara (`HARKAQ_BIN`) gana, después el árbol de
+/// desarrollo —para que un cambio en la jaula se pruebe sin instalar nada—, y el paquete al final.
+/// Si no está ninguno se devuelve el primer candidato, que es el que nombra el error.
 fn harkaq_exec() -> PathBuf {
-    std::env::var("HARKAQ_BIN")
-        .map(PathBuf::from)
-        .unwrap_or_else(|_| {
-            PathBuf::from(std::env::var("HOME").unwrap_or_else(|_| "/root".into()))
-                .join(".cache/harkaq")
-        })
-        .join("harkaq-exec")
+    if let Ok(dir) = std::env::var("HARKAQ_BIN") {
+        return PathBuf::from(dir).join("harkaq-exec");
+    }
+    let cache = PathBuf::from(std::env::var("HOME").unwrap_or_else(|_| "/root".into()))
+        .join(".cache/harkaq")
+        .join("harkaq-exec");
+    if cache.exists() {
+        return cache;
+    }
+    let instalado = PathBuf::from("/usr/bin/harkaq-exec");
+    if instalado.exists() {
+        return instalado;
+    }
+    cache
 }
 
 /// Las capabilities que hacen que el uid 0 de adentro sea root DE VERDAD.
@@ -1616,8 +1634,11 @@ fn run_instance(
         let exec = harkaq_exec();
         if !exec.exists() {
             bail!(
-                "no encuentro harkaq-exec en {} — la instancia NO va a correr enjaulada y eso no se \
-                 hace en silencio.\n  construilo:  gcc -O1 -Wall -static -o {} scripts/harkaq/harkaq-exec.c\n                   o corré con --no-jail si sabés lo que estás haciendo.",
+                "no encuentro harkaq-exec en {} ni en /usr/bin — la instancia NO va a correr \
+                 enjaulada y eso no se hace en silencio.\n  instalalo:   está en `perfil.base` como \
+                 receta `harkaq-exec`; en una caja instalada, `takana upgrade`.\n  o construilo:  \
+                 gcc -O1 -Wall -static -o {} scripts/harkaq/harkaq-exec.c   (sólo en el árbol de \
+                 desarrollo)\n                   o corré con --no-jail si sabés lo que estás haciendo.",
                 exec.display(), exec.display()
             );
         }
diff --git a/docs/state/targets.toml b/docs/state/targets.toml
index 8c720b97..e6087034 100644
--- a/docs/state/targets.toml
+++ b/docs/state/targets.toml
@@ -42,6 +42,15 @@ paquetes = [
   # Estaba sellado desde hace meses y en UN solo perfil (`escritorio-kde`) — la lección de `foot`
   # otra vez: el paquete existe, y no viaja en la imagen que lo necesita.
   "tar",
+  # `bwrap` + `harkaq-exec` (2026-09-15): LA JAULA. Los invoca `takana qorpa` —para correr una imagen
+  # ajena— y también el sandbox de `takana build` (`takana-build/src/sandbox.rs` llama a `bwrap` por
+  # PATH). Estaban en **CERO perfiles**: `bwrap` sellado desde hace meses con `"perfiles": []`, y
+  # `harkaq-exec` sin receta siquiera, sólo como un `gcc` a mano en `~/.cache/harkaq` del hub. O sea
+  # que ninguna imagen de takana podía enjaular nada, ni construir. Se descubrió mudando
+  # `api.sergio.gioser.net` a la caja de producción: `qorpa provision` abortó pidiendo un binario que
+  # sólo existía en la máquina donde alguien lo había compilado. Van en `base` porque el CLI que los
+  # llama viaja en TODAS las imágenes — [[subcomando-sin-driver]] visto un piso más abajo.
+  "bwrap", "harkaq-exec",
   # `bash-completion` (2026-09-09): el tabulador de las herramientas del sistema. Entra como raíz
   # porque NADIE lo alcanza por deps de build — los paquetes que instalan completados sólo preguntan
   # por su `.pc` y, si no está, se saltan la instalación en silencio. Es un hueco de RUNTIME puro,
diff --git a/recipes/harkaq-exec.toml b/recipes/harkaq-exec.toml
new file mode 100644
index 00000000..f02b0bf9
--- /dev/null
+++ b/recipes/harkaq-exec.toml
@@ -0,0 +1,57 @@
+# harkaq-exec — el último eslabón de la jaula, empaquetado como receta.
+#
+# POR QUÉ EXISTE (descubierto el 2026-09-15, mudando `api.sergio.gioser.net` a la caja nueva).
+# `takana qorpa provision` murió en la caja de producción con:
+#
+#     Error: no encuentro harkaq-exec en /root/.cache/harkaq/harkaq-exec — la instancia NO va a
+#            correr enjaulada y eso no se hace en silencio.
+#       construilo:  gcc -O1 -Wall -static -o … scripts/harkaq/harkaq-exec.c
+#
+# El mensaje es bueno y la receta que propone es imposible: **en una caja instalada no hay gcc, ni
+# árbol de desarrollo, ni `scripts/`**. El binario sólo existía como un `gcc` a mano en el hub, en
+# una caché de `$HOME` — o sea que la jaula del ADR 0015 funcionaba únicamente en la máquina donde
+# alguien la había compilado. Es [[subcomando-sin-driver]] otra vez, un piso más abajo: `takana
+# qorpa` viaja en TODAS las imágenes y su herramienta en NINGUNA.
+#
+# ⚠ Y su compañero `bwrap` estaba igual: sellado desde hace meses, declarado en CERO perfiles
+# (`"perfiles": []` en `build-state.json`) — y lo invocan por PATH tanto `qorpa` como el sandbox de
+# `takana build` (`takana-build/src/sandbox.rs`). Los dos entran a `perfil.base` en la misma unidad
+# de trabajo: una imagen de takana que no puede enjaular no puede ni construir.
+#
+# ── EL PIN VA AL COMMIT QUE TOCÓ LA FUENTE, no a HEAD ─────────────────────────────────────────────
+# `scripts/harkaq/harkaq-exec.c` no cambia desde el 2026-09-03; el repo, cada media hora (el cron de
+# la cosecha commitea el estado del grafo). Pinear HEAD re-hashearía esta receta cada media hora sin
+# que su fuente se moviera. El commit de abajo es el último que tocó el `.c` y su `.h`.
+#
+# La fuente vive en `scripts/` y no en un árbol propio de la receta a propósito: `harkaq-run.sh`,
+# `harkaq-farm-setup.sh` y `q2-runtime-base.sh` la compilan desde ahí, y dos copias del mismo `.c`
+# divergen en silencio. El precio es subir el `commit` cuando la jaula cambie — el mismo que paga
+# `recipes/takana.toml`.
+
+name    = "harkaq-exec"
+version = "0.0.1"
+license = "MIT"
+
+[source]
+# El repo del propio takana; la URL es sólo locator y no entra en `hash_inputs` (ADR 0013 §1).
+repo   = "https://git.gioser.net/sergio/takana.git"
+commit = "1d9ddcee373fa58f3a311cf5444b2d30040046ab"
+
+[build]
+compiler = "zig-cc"
+target   = "x86_64-linux-musl"
+# Estático **obligatorio**, no por costumbre: harkaq-exec corre DENTRO del rootfs del sandbox, donde
+# no hay cargador dinámico que valga (lo dice el encabezado del propio `.c`).
+link     = "static"
+
+[build.phases]
+# El árbol es el repo entero, sin sistema de build que detectar: las tres fases van a mano.
+configure = "true"
+# `-mcpu=baseline` por reproducibilidad independiente de la CPU del builder, como el resto del lab
+# (y ver [[cgo-sin-baseline-sigill]]: hornear la ISA del que compila es un SIGILL en otra caja).
+# Los headers de seccomp/landlock salen del rootfs del lab; `harkaq-uapi.h` está al lado del `.c`.
+compile   = "zig cc -mcpu=baseline -static -O1 -Wall -o harkaq-exec scripts/harkaq/harkaq-exec.c"
+install   = "mkdir -p /out/usr/bin && cp harkaq-exec /out/usr/bin/harkaq-exec"
+
+[deps]
+build = ["binutils"]