Commit Graph
3 Commits
Author SHA1 Message Date
SergioandClaude Opus 5 1c237f9da2 mudanza: decidir SIN teclas unitarias, /mnt/vvv entra al censo, y 25 rutas de secretos más
Tres cosas que salieron de usar la herramienta de verdad.

1. `--decidir <fichero>`: decidir EN LOTE desde `<ruta-o-nombre> <decision>` por línea.

   El usuario: «no sé cómo activar o desactivar cosas aquí desde shuma llimphi remoto, que las
   opciones son con teclas unitarias». El modo interactivo lee una tecla por entrada, y hay
   terminales donde eso no se puede usar — una herramienta cuya única forma de decidir exige un
   tipo de terminal no es una herramienta, es una herramienta PARA ESA TERMINAL. El fichero anda en
   cualquiera, se revisa antes de aplicarlo, se versiona y se vuelve a correr.

   Una clave que no empareja con nada, o que empareja con varias, es ERROR RUIDOSO y no se escribe
   NADA: un lote a medias deja decidido lo que nadie revisó.

2. `/mnt/vvv` entra a las raíces del censo. No estaba, y ahí vive el trabajo: los repos de la
   persona, el monorepo, el store, work/sources. El agujero se vio preguntando por `humanoid`: el
   censo sólo conocía `/home/sergio/humanoid` —200 M de `build/` de junio— mientras el proyecto de
   verdad, con su `.git`, estaba en `/mnt/vvv/humanoid`, fuera de toda raíz censada. `repos_git` SÍ
   lo miraba: una parte del censo conocía el árbol y la otra no.

3. 25 rutas más en `rutas-fuera-de-git.txt`, del barrido que hizo el frente tawasuyu sobre su home:
   `~/.wawa/seeds` (sin él ninguna app nueva del génesis nace), `~/.tejido` (la identidad de esta
   máquina en la flota), `~/.local/share/agora`, `~/.config/{wawa,minga,thasnuna,shuma,mirada,hcloud}`,
   `~/keys` y `~/fdroid` (⚠ firma de apps Android), `~/.gnupg`, `~/.pgpass`, `/etc/wireguard`,
   `/etc/{shuma,sandokan,tawasuyu/agente,local.d}`. Son identidades y semillas: no se «vuelven a
   generar», porque generar otras significa ser OTRA máquina para el resto de la flota.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 18:01:16 +00:00
SergioandClaude Opus 5 de7c3faa9c gitea arranca: su [[service]], probado con el entorno de verdad — y dos fallos que sólo salen ahí
La receta ya declara su servicio (SDD 30) y `perfil.servidor` lo habilita. El ArtifactHash NO se
mueve (`b3:391a613e…` antes y después): `[[service]]` está fuera de `hash_inputs`.

⚠ Primero, una corrección del commit anterior: declaraba `gitea` en `perfil.servidor` con SEIS
LÍNEAS DE COMENTARIO y sin la línea `"gitea",`. El perfil cargó igual, el grafo no dijo nada y el
paquete simplemente no estaba. Lo cazó `targets.py --services` al resolver el label: «lo declara
gitea, que NO pertenece al perfil». Un comentario que explica una entrada que no existe se lee como
la entrada.

La card no encarna el binario directo: **gitea se niega a correr como root** (`[F] Gitea is not
supposed to be run as root`), así que va por `setuidgid`. Y comprueba dos cosas del SITIO antes de
arrancar, saliendo 78 con un mensaje que las nombra: `/etc/gitea/app.ini` y el usuario `gitea`. Un
gitea sin config no falla — arranca y ofrece el asistente de «crear administrador» a quien pase.

Probado en el worker con el argv exacto y `env -i`, que es lo que arje hace de verdad. Tres fallos
que con una shell normal no se ven NUNCA:

· `exec setuidgid …` a secas ⇒ `sh: exec: line 0: setuidgid: not found`. El `sh` de busybox de la
  imagen no trae `FEATURE_SH_STANDALONE`: no despacha sus applets, los busca en `PATH`, y PID 1 no
  garantiza ninguno. Todo con ruta absoluta (`/bin/grep`, `/usr/bin/setuidgid`).
· sin `PATH` en el `envp` ⇒ `git not found: executable file not found in $PATH`. **gitea lanza
  `git` como subproceso**, y el mensaje se lee como «falta git» con git instalado y raíz de `base`.
  Un envp vacío no es «limpio»: es sin PATH.
· sin `cd` ⇒ `fatal: error reading '/root/.git'`. El cwd se hereda y gitea corre `git config` en él.
  `Service` no tiene campo `cwd`, así que va en el argv, a la vista.

Con eso: escucha, `GET /` responde **200** y el proceso corre como `gitea`. Las dos guardas
verificadas por separado (78 y su mensaje cada una). El worker quedó limpio y censado: sin usuario,
sin /etc/gitea, sin /var/lib/gitea, sin symlinks y sin procesos.

Y `/etc/gitea` entra en las rutas de la mudanza: el `app.ini` guarda los SECRETOS generados (gitea
los escribe en el propio fichero, que por eso tiene que ser suyo, `gitea:gitea 0660`).

⚠ Lo que queda abierto y está anotado en la receta: **el usuario `gitea` no existe en el producto**.
`/etc/passwd` de la imagen es la constante `takana_bootstrap::PRODUCT_PASSWD` y sólo trae `root` y
`sshd`. El SDD 30 sacó las Cards de una constante de Rust y las puso en la receta; los USUARIOS
siguen donde estaban las Cards. Hasta que se declaren, el usuario llega con los datos del sitio.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
2026-09-14 15:16:21 +00:00
SergioandClaude Opus 5 76535f8e42 censar: el home de la PERSONA no se miraba nunca — y ahí está la clave privada de release
`fuera_de_git()` era una lista cableada de 10 rutas con `~` adentro, y el censo corre como root:
`~` se expandía a `/root`. La huella quedó en `work/mudanza/censo-gioser.toml`, donde `~/.ssh` y
`/root/.ssh` salen IDÉNTICOS. Lo que nunca se censó por su nombre:

  /home/sergio/.config/takana   ⚠ la clave PRIVADA de release (el .pub está EN el repo)
  /home/sergio/.config/gh          el token con el que se crean los espejos de los 26 repos
  /home/sergio/.ssh/config         el bloque `git.gioser.net` `Port 2345`, sin el cual no se clona
  /home/sergio/.gitconfig          los `insteadOf`, que reescriben remotos y esconden que uno es local
  /home/sergio/.claude      6,8 G  la memoria y los transcripts del proyecto

Ninguna de esas falla el día que se borra la máquina: la clave falla la próxima vez que alguien
firma, y para entonces no hay de dónde sacarla. Hoy sólo viajaban dentro del bloque `/home` (22 G,
`destino = ""`), o sea sin que nadie las hubiera mirado.

Cuatro cambios:

· **La lista sale a `rutas-fuera-de-git.txt`**, un fichero de datos con el motivo de cada ruta. Una
  lista cableada se queda vieja sin que nada falle: la anterior preguntaba por `~/.config/hammer`
  —muerto desde el renombre, existe VACÍO— y no preguntaba por `~/.config/takana`.
· **`homes()` lee `/etc/passwd`** y expande `~/…` por cada home real (root incluido, cuentas de
  servicio con `nologin` fuera). En gioser: 6 homes, 19 entradas contra las 9 de antes.
· **Tres estados, no dos.** Un `ls` sin permiso se lee igual que un directorio ausente: `ausente` se
  descarta, `sin_permiso` se REPORTA («2 rutas EXISTEN y no pude leerlas») para que nadie decida
  sobre una lista incompleta creyéndola completa. Probado corriendo el censo como no-root.
· **Una sola llamada** en vez de una por ruta: N rutas × M homes por SSH era el censo tardando más
  que el trabajo que describe. Y cada entrada lleva dueño, tamaño y por qué importa.

Y el paso que faltaba en `planear.py`: `fuera_de_git` no lo consumía NADIE, así que el censo lo
listaba y el plan no proponía copiarlo — se veía y no se actuaba. Ahora es el paso 0 bis, pegado al
del código, con revisión humana para decidir y, por cada ruta `muda`, su `rsync -aHAX --numeric-ids`
(permisos: una llave con el modo cambiado no falla al copiarse, falla al usarse) verificado POR
CONTENIDO: el digest de los digests, que no revela nada y caza lo que contar ficheros no caza — una
llave truncada cuenta como un fichero igual que la entera. Probado en los dos sentidos: idéntico ⇒
0, un byte distinto ⇒ 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
2026-09-14 14:38:56 +00:00