66db5484e98fc67ce06b8b096c3411e61215c26c
8
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
390fdf2dcb |
ensayo con los DATOS REALES de gioser: su gitea corriendo en takana — y el git de la distro no clona por HTTP
Sin tocar gioser (todo lectura) y en la VM desechable. Dentro de la VM: `<title>GioSer Gitea: Git with a cup of tea</title>`, 200, `/explore/repos` listando los repos de verdad (sergio/takana, tawasuyu/agora, card, chasqui, cosmos, khipu, llimphi…) y el clon de uno de ellos con 478 commits y HEAD correcto. El snapshot de la DB se saca EN CALIENTE y sale consistente: `sqlite3 gitea.db ".backup …"` con el servidor vivo, 1,5 s para 314 M, `integrity_check` ok, 44 filas en `repository`. Copiar el fichero a pelo mientras el servidor escribe es justo lo que no hay que hacer. Tres detalles que sólo aparecen con los datos puestos: · **El uid del origen no es el del destino.** Los ficheros llegan con su uid NUMÉRICO y el gitea de gioser es 969, no el 916 que declaraba la receta. O se chownean 2 G —lento, y hay que acordarse— o gitea no puede leer sus datos, y eso no falla al copiar: falla al arrancar. La receta pasa a 969, alineada con el origen. El ArtifactHash no se mueve (`[[user]]` está fuera de hash_inputs). · El `app.ini` de gioser escucha en `127.0.0.1:3002` porque allá caddy hace de proxy: la caja sirve, pero sólo desde dentro. `HTTP_ADDR`/`ROOT_URL` son adaptación, no copiado. · 🧨 **El `git` de la distro no puede clonar por HTTP**: `git: 'remote-http' is not a git command`. Medido sobre el artefacto sellado: `git-core/` trae `git-remote-ext`, `git-remote-fd` y `git-http-backend` (el lado SERVIDOR) y no `git-remote-http`; `strings` da 0 referencias a libcurl pese a que `curl` está en `[deps] build`. No se había notado porque en el hub se usa el git de Artix, no el sellado. Un hub nuevo no podría clonar el repo por HTTPS. Re-sellar `git` es raíz de `perfil.base` ⇒ unidad propia. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn |
||
|
|
467a87cdb8 |
la imagen del servidor, armada y booteada — tres fallos que sólo aparecen ahí
Se armó la imagen del perfil `servidor` con gitea y se arrancó en QEMU. Los tres hallazgos, en el orden en que aparecieron, son los que justifican probar la imagen en vez de dar por buena la receta. 1) ⚠⚠ ESCRIBIR EN EL ROOTFS HIDRATADO ES ESCRIBIR DENTRO DEL STORE `takana users --merge` hacía `fs::write` sobre `<rootfs>/etc/passwd`. Un rootfs hidratado se arma con HARDLINKS contra el store: medido, ese fichero y el del artefacto `product-rootfs` eran **el mismo inode (1225824, 2 links, modo 444)**. Un `write` habría modificado el artefacto SELLADO, y todas las imágenes futuras habrían salido con la cuenta metida dentro del producto. Acá se salvó porque el store es de sólo lectura y salió `Permission denied` — confiar en eso es confiar en un permiso. Ahora `escribir_rompiendo_hardlink()`: temporal + `rename`. Con su control, que afirma lo que importa: tras escribir, el fichero del store **conserva su contenido**, baja a 1 link y el del rootfs tiene otro inode. Verificado también sobre la imagen real. 2) LA IMAGEN TRAÍA EL BINARIO, LA CUENTA… Y NADIE LO ARRANCABA Primera imagen: `gitea` instalado, `gitea:x:916` en `/etc/passwd`, y en el `genesis` de la seed sólo `sshd`, `console-getty`, `hammerd`, `hammer-product`. `servidor-image.sh` no inyectaba las Cards — eso sólo estaba en el camino de las imágenes de escritorio. Y ninguna métrica lo dice: `--services` responde que el perfil lo habilita, y lo habilita; lo que faltaba era el paso que lleva esa declaración a la imagen. Ahora llama a `service-cards` + `inyectar-cards.py` (idempotente por label). 3) ⚡ EL BINARIO MORÍA CON `trap invalid opcode` — Y EL BUG ESTABA EN EL BUILDER Con la card en el genesis y la config puesta, gitea arrancaba y moría al instante: traps: gitea[91] trap invalid opcode ip:79ea992 ... in gitea[...] El sandbox exporta `CC` apuntando a un wrapper que pone `-mcpu=baseline` (`sandbox.rs` ya avisaba: «de paso cierra el SIGILL de AVX en qemu64»), y la fase Go del propio builder lo PISABA con `CC="zig cc"` a secas — que por defecto es `-mcpu=native` y hornea la ISA del que compila. El binario corría perfecto en el worker y moría en QEMU-TCG. No falla al compilar ni al sellar: falla al EJECUTAR en otra CPU. Y el `ArtifactHash` no lo puede cazar, porque la CPU del builder no entra en `hash_inputs` — dos workers distintos sellan bytes distintos bajo la misma dirección. Arreglado en el builder y en la receta; re-hashea las CINCO recetas `cgo = true` (gitea, usql, sq, gocryptfs, naabu), que es correcto: lo que había sellado no es portable. gitea: `b3:391a613e…` → `b3:5edf9c16…`. Lo verificado en la VM: PID 1 = arje-zero · la cuenta de `[[user]]` en `/etc/passwd` y `/etc/group` de la imagen · la card de gitea en el `genesis` · y arje encarnándola, con la guarda saliendo 78 y `/var/log/arje/ente-gitea.log` diciendo exactamente «falta /etc/gitea/app.ini — es config del SITIO». Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn |
||
|
|
d611f8577d |
[[user]] en la receta: la otra mitad del SDD 30 — un demonio que no corre como root necesita cuenta
El SDD 30 sacó las Cards de una constante de Rust y las puso en la receta. Los USUARIOS se quedaron
donde estaban las Cards: `/etc/passwd` de la imagen es `takana_bootstrap::PRODUCT_PASSWD`, un literal
con `root` y `sshd`, y añadir un tercero era editar Rust y recompilar takana.
No es simetría por elegancia, es un servicio que no arranca: `gitea` se niega a correr como root, su
Card hace `setuidgid gitea`, y sin la cuenta arranca, muere y reintenta para siempre con un log que
dice `unknown user` — no «a la imagen le falta una cuenta».
[[user]]
name = "gitea"
uid = 916
home = "/var/lib/gitea"
**El uid se declara, no se asigna**, por la misma razón que el ULID de la Card: un «primero libre a
partir de 1000» hace que dos imágenes del mismo perfil salgan con dueños distintos y el rootfs deje
de reproducir SIN QUE NADA FALLE — los ficheros se ven iguales y `ls -l` dice otro número. Fuera de
`hash_inputs`, medido: el hash de gitea no se movió (`b3:391a613e…` antes y después).
`takana users <recetas…> [--merge <rootfs>]` es el gemelo de `service-cards`, y fusiona **por clave,
no por línea entera** — componer dos veces no duplica, y `grep -q` de la línea completa no serviría
porque la misma cuenta con otro GECOS se leería como nueva. Tres decisiones con su control:
· Una cuenta ya presente con OTRA línea es CONFLICTO y no se pisa: sale ≠0. Pisarla es cambiarle el
uid a ficheros que ya son de alguien, y eso se descubre dentro de la VM.
· Se planea todo y sólo entonces se escribe. Fichero a fichero, un conflicto en `passwd` dejaba el
`group` ya escrito: media cuenta es peor que ninguna, porque parece que está. Comprobado con el
caso exacto — `group` sin la cuenta, `passwd` con otro uid — y los DOS ficheros quedan intactos.
· Un `passwd` ausente es un error, no un fichero a crear: crearlo dejaría una imagen SIN `root`.
La validación rechaza lo que rompe tarde: `root`/`sshd`/`nobody` y sus uids, uid fuera de
100..=65533, `home` relativo y un `:` en cualquier campo — que partiría la línea y fallaría lejos.
Y `--user-paths` NO es `--service-paths` con otro nombre: aquél lista los servicios HABILITADOS,
éste los paquetes INSTALADOS que declaran cuentas. `postgres` instalado y sin levantar necesita su
usuario igual, porque los ficheros de la imagen ya son suyos.
`scripts/servidor-image.sh` lo aplica entre hidratar el perfil y sellar la imagen, y aborta si hay
conflicto: un rootfs con el uid equivocado produce ficheros de un dueño que no existe.
Verde: 6 tests del módulo, core 234, cli 88, bootstrap 42, `targets.py --selftest` 7/7.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
|
||
|
|
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 |
||
|
|
74151a2b0c |
gitea 1.27.0 con sqlite y bindata: el binario sellado no podía abrir la base de datos
La mudanza de gioser pasa por levantar su gitea del otro lado — 28 repos, 26 sin copia fuera. El
corpus ya tenía `gitea` sellado (1.26.4, `b3:35bb4f04…`) y NO sirve, medido contra el artefacto:
$ gitea --config app.ini migrate
Error: sqlite3 requires: -tags sqlite,sqlite_unlock_notify
this Gitea binary was not built with SQLite3 support
Construía, reproducía y no podía abrir la sqlite en la que gioser guarda TODO (`DB_TYPE = sqlite3`).
Y `gitea --version` decía `version development`. Es subcomando-sin-driver un piso más abajo.
Tres cambios, y el tercero es el que no se ve venir:
· Pin 1.27.0 (gioser corre 1.27.0). No es cosmético: gitea migra el esquema hacia adelante y se
planta si la DB trae migraciones más nuevas que el binario, así que el pin va por delante del
origen, nunca por detrás.
· Tags `sqlite,sqlite_unlock_notify` (⇒ `cgo = true`, el driver de mattn es C) y `bindata`, que
embebe `public/` y `templates/`: sin él la receta publica sólo el ejecutable y el servidor
arrancaría sin UI.
· La fuente pasa de `repo`+`commit` al TARBALL DE RELEASE. El clon no alcanza: la UI se compila
con Node y las deps Go no están vendoreadas en git. El `gitea-src-1.27.0.tar.gz` trae las dos
cosas hechas — medido: `public/assets/` 764, `vendor/` 11246, `templates/` 663 — así que
construye con el lab tal cual, sin Node y sin red. La URL es locator (ADR 0013); ancla el sha256.
Nuevo hash: `b3:391a613e…`. Declarado en `perfil.servidor` como paquete y NO en `servicios`:
arrancarlo necesita el [[service]] del SDD 30 con su app.ini, y declarar un arranque que no existe
sería la mentira que ese campo existe para no tener.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Tf9T4vGzsMoT7eS8YzMFn
|
||
|
|
e852f48491 |
takana etapa 5a: los comentarios de las 741 recetas
Barrido de TEXTO puro: 1427 líneas de comentario TOML. Cero ArtifactHash movidos, y eso está MEDIDO, no deducido: hasheé las 741 antes y después y los ficheros de hashes son idénticos byte a byte (723 con hash real + 18 que ya no hasheaban de antes). El guardián valió la pena: el primer barrido, filtrando por 'la línea empieza con #', movió el hash de helix, lsof y steam-runtime-sniper. La causa es que una fase se escribe como compile = <triple> ... <triple> y sus comentarios de SHELL también empiezan con #, pero viven dentro del VALOR — y las fases sí entran en hash_inputs. El barrido ahora calcula los rangos de las cadenas multilínea de TOML y no entra ahí. Quedan intactos a propósito: .hammer-zig-cc y .hammer-cargo-vendor (literales dentro de fases), hammerd, hammer-recover y toda ruta que empiece por / |
||
|
|
a6a9d59e4f |
licencias: 936 de 1141 (82%) — detección por evidencia, con sus dos imprecisiones declaradas
Esta mañana eran 0. Tras la tabla curada (228) y este paso, 936. Ninguna receta se
re-hasheó: verificado en 30 de las 708 tocadas, 30 hashes idénticos, 0 cambiados.
DE DÓNDE SALE EL DATO, Y POR QUÉ NO ES ADIVINAR. `scripts/licencias-detectar.sh` consulta
la API /repos/{o}/{r}/license de GitHub para las 673 recetas cuya fuente vive allí. Eso
devuelve el resultado de DETECTAR el fichero LICENSE que el repo tiene de verdad
(licensee), no una etiqueta escrita a mano en una web: es la misma evidencia que veríamos
abriendo el tarball, obtenida sin bajar 673 tarballs por un enlace de 8 Mbps. 610 con SPDX
definido; las 63 que GitHub marca NOASSERTION/other se DESCARTAN — un «no sé» de la fuente
se propaga como hueco, no se redondea a una licencia plausible.
Las familias no-GitHub van curadas por la URL DE FUENTE, que es la evidencia que el nombre
no da. Y ahí cometí el error simétrico al que este mismo fichero advertía: había puesto
`knighttime` entre las «herramientas Go» POR SU NOMBRE, y su tarball sale de
download.kde.org — es un Framework de KDE, LGPL. Descartar por nombre falla igual que
aceptar por nombre. Corregido en la cabecera.
LAS DOS IMPRECISIONES, contables con `licencias.sh --revisar` en vez de escondidas:
1. SPDX OBSOLETOS Y AMBIGUOS (71 recetas). GitHub devuelve `GPL-3.0`, `LGPL-2.1`,
`AGPL-3.0`… identificadores que SPDX declaró obsoletos PRECISAMENTE porque no
distinguen `-only` de `-or-later`, y esa diferencia decide con qué se puede combinar el
paquete. NO se normalizan a ciegas: mapear GPL-3.0 → GPL-3.0-or-later sería inventar el
dato que falta. Quedan marcadas para resolver mirando el fuente.
2. LICENCIAS DOBLES COLAPSADAS. La API devuelve UNA sola licencia y muchos proyectos Rust
son «MIT OR Apache-2.0» (p.ej. `fd` quedó como Apache-2.0). No es falso —cumplir una de
las opciones concedidas basta— pero es incompleto. Lo resuelve el cierre estructural:
leer el campo `license` del Cargo.toml en la fase de fetch.
Y un fallo que habría escrito basura en silencio: `licencias-detectadas.tsv` tiene TRES
columnas (añade el owner/repo consultado, para poder auditar) y el sembrador leía dos, así
que la licencia se habría llevado pegado el slug — `license = "MIT<TAB>owner/repo"`, sin
que nada lo validara. Arreglado antes de sembrar.
Quedan 205 sin licencia y 71 por desambiguar.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
ce126dd5ee | Etapa G: cosecha go-8 (13, repo 444->457) — k8s grandes (cilium-cli/istioctl/gitea) |