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 1534Shell 199Rust 109Markdown 993713 Definitions

lo que el agente arregló DENTRO de la jaula, escrito afuera para que sobreviva al recreate

El agente que trabaja enjaulado encontró y arregló tres defectos a mano, pero viven en el `upper`,
que por el D3 del ADR 0015 es caché descartable: al primer `recreate` se pierden. Esto es esa mano,
escrita.

1. No hay entrada en /etc/passwd para el uid de adentro: ssh y git mueren con «No user exists for uid
   1001» y ni intentan conectar. Pasa porque la instancia de persona va con root = false —si no, el
   CLI se ve uid 0 y rechaza --dangerously-skip-permissions— y ese uid no existe en la imagen Arch.
2. /etc/ssh/ssh_config.d es de la capa inferior y su dueño cae fuera del mapa (nobody), así que ssh
   ABORTA con «Bad owner or permissions»; no degrada, aborta. El directorio no se puede mover (EXDEV
   en overlay), así que se redirige el Include a una copia propia.
3. known_hosts se siembra desde el anfitrión, que es lo que evita el StrictHostKeyChecking contra el
   worker la primera vez —y el ~/.ssh de adentro ya pasó a rw en el manifiesto, para que ssh pueda
   escribirlo cuando aparezca un host nuevo—.

Escribe en el upper como la PERSONA, no como root: si no, le dejaría ficheros que ella no puede tocar.

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

e5e723b670c3f504fce90a8be9d3ada239d85cc5 · by Sergio · (1 month ago) · parent c4d8b6869 · browse the tree at this commit

Semantic delta

No definition changed: this change is text, documentation or data.

1 files · +64 −0

diff --git a/scripts/servidor/jaula-preparar.sh b/scripts/servidor/jaula-preparar.sh
new file mode 100755
index 00000000..8aca0b4b
--- /dev/null
+++ b/scripts/servidor/jaula-preparar.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+# Repone en la jaula de una persona lo que NO cabe en el manifiesto y por eso vive en el `upper`
+# —que por el D3 del ADR 0015 es **caché descartable**—. Se corre EN LA CAJA, como root, DESPUÉS de
+# cada `takana qorpa recreate`.
+#
+# ── POR QUÉ HAY COSAS FUERA DEL MANIFIESTO ──────────────────────────────────────────────────────
+# `instance.toml` declara imagen, paquetes y concesiones. No declara «editá este fichero de la
+# imagen», y tres defectos reales pedían exactamente eso. Los encontró el agente trabajando adentro
+# (2026-09-18) y los arregló a mano; esto es esa mano, escrita, para que sobreviva al recreate.
+#
+#   1. **No hay entrada en `/etc/passwd` para el uid de adentro.** `ssh` y `git` mueren con
+#      `No user exists for uid 1001` — ni lo intentan. Pasa porque la instancia de persona va con
+#      `root = false` (si no, el CLI se ve uid 0 y rechaza `--dangerously-skip-permissions`), y ese
+#      uid no existe en la imagen de Arch.
+#   2. **`/etc/ssh/ssh_config.d` es de la capa inferior y su dueño cae fuera del mapa** (`nobody`),
+#      así que `ssh` ABORTA con `Bad owner or permissions on …/20-systemd-ssh-proxy.conf`. No
+#      degrada: aborta. Y el directorio no se puede mover (EXDEV en overlay), así que se redirige el
+#      `Include` a una copia propia.
+#   3. `known_hosts` se siembra desde el ANFITRIÓN (ver abajo), que es lo que evita el
+#      `StrictHostKeyChecking` contra el worker la primera vez.
+set -eu
+
+U=${1:-sergio}
+INST=${INST:-claude-$U}
+UP=${UP:-/var/lib/hammer/qorpa/instances/$INST/upper}
+UID_DENTRO=$(id -u "$U")
+
+[ -d "$UP" ] || { echo "no existe el upper de $INST en $UP" >&2; exit 1; }
+# El upper es de la persona: escribir como root dejaría ficheros que ella no puede tocar.
+esc() { install -d -o "$U" -g "$U" "$(dirname "$1")"; }
+
+# ── 1. la cuenta, dentro de la imagen ───────────────────────────────────────────────────────────
+esc "$UP/etc/passwd"
+if [ ! -f "$UP/etc/passwd" ]; then cp /var/lib/hammer/qorpa/images/*/rootfs/etc/passwd "$UP/etc/passwd" 2>/dev/null || : ; fi
+grep -q "^$U:" "$UP/etc/passwd" 2>/dev/null || \
+  echo "$U:x:$UID_DENTRO:$UID_DENTRO::/home/$U:/usr/bin/bash" >> "$UP/etc/passwd"
+esc "$UP/etc/group"
+if [ ! -f "$UP/etc/group" ]; then cp /var/lib/hammer/qorpa/images/*/rootfs/etc/group "$UP/etc/group" 2>/dev/null || : ; fi
+grep -q "^$U:" "$UP/etc/group" 2>/dev/null || echo "$U:x:$UID_DENTRO:" >> "$UP/etc/group"
+chown "$U:$U" "$UP/etc/passwd" "$UP/etc/group" 2>/dev/null || true
+echo "  ✓ $U en el passwd/group de la instancia (uid $UID_DENTRO)"
+
+# ── 2. el Include de ssh, a un directorio cuyo dueño SÍ está en el mapa ──────────────────────────
+esc "$UP/etc/ssh/ssh_config"
+if [ ! -f "$UP/etc/ssh/ssh_config" ]; then
+  cp /var/lib/hammer/qorpa/images/*/rootfs/etc/ssh/ssh_config "$UP/etc/ssh/ssh_config" 2>/dev/null || :
+fi
+if [ -f "$UP/etc/ssh/ssh_config" ]; then
+  install -d -o "$U" -g "$U" "$UP/etc/ssh/ssh_config.d.local"
+  sed -i "s|^Include /etc/ssh/ssh_config.d/\*.conf|Include /etc/ssh/ssh_config.d.local/*.conf|" "$UP/etc/ssh/ssh_config"
+  chown "$U:$U" "$UP/etc/ssh/ssh_config"
+  echo "  ✓ Include redirigido a ssh_config.d.local (el original es de la capa inferior, dueño fuera del mapa)"
+fi
+
+# ── 3. known_hosts sembrado desde el anfitrión ──────────────────────────────────────────────────
+K=/home/$U/.ssh/known_hosts
+install -d -o "$U" -g "$U" -m 700 "/home/$U/.ssh"
+for h in dev.gioser.net git.gioser.net; do
+  grep -q "^\[\?$h" "$K" 2>/dev/null || ssh-keyscan -t ed25519 "$h" 2>/dev/null >> "$K" || true
+done
+chown "$U:$U" "$K" 2>/dev/null || true; chmod 600 "$K" 2>/dev/null || true
+echo "  ✓ known_hosts con $(grep -c . "$K" 2>/dev/null || echo 0) entradas"
+
+echo "jaula $INST preparada — lo del manifiesto (paquetes, concesiones) lo pone `takana qorpa provision`"