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…

Rust 45TOML 36Markdown 26Shell 7878 Sutichaykuna

⎇ ba1fb2d3a8ada748984dceeb0f58e6b3e67772b8 recipes/atuq.toml TOML · 120 siq'ikuna · 8.5 KB Ñawpa willay ch'uya

atuq ABRE: el app_id estaba compilado en el binario, y el árbol copiado llegaba de sólo lectura 5d06a3b83 · Sergio ·

1# atuq 0.1.0 — el navegador de la distro, como ARTEFACTO DERIVADO de firefox.
2#
3# ══ POR QUÉ DERIVADO Y NO UN FORK DE FUENTE ════════════════════════════════════════════════════
4# Zen —el fork de Firefox al que esto reemplaza en nuestro catálogo— parchea el árbol de Gecko y
5# recompila. Nosotros no distribuimos un binario: sellamos artefactos. Entonces atuq puede DEPENDER
6# de `firefox` y poner su capa encima, y eso cambia el precio de todo:
7#   · una iteración de chrome cuesta SEGUNDOS, no las cuatro horas de un build de Gecko;
8#   · no mueve el `ArtifactHash` de `firefox` ⇒ el corpus no se invalida;
9#   · las CVE se heredan gratis: cuando sube `firefox`, atuq se reconstruye solo.
10# El razonamiento completo, con lo que se promete y lo que NO (spoiler: no habrá «modo Tor»), está
11# en `docs/26-atuq-envoltorio-gecko.md`.
12#
13# ══ SU FUENTE ES ESTE REPO ═════════════════════════════════════════════════════════════════════
14# `source.dir` es el modo de fuente que se agregó para esto (hammer-core/src/recipe.rs): el árbol
15# vive en `recipes/atuq/` y se hashea por CONTENIDO con `ArtifactHash::of_tree`, igual que ya se
16# hacía con los `patches`. No hay commit que pinear y no hay fetch: editar un CSS mueve el hash.
17#
18# ══ v0.2: EL BRANDING VIVE DENTRO DEL ZIP ══════════════════════════════════════════════════════
19# La v0.1 dejó el branding fuera porque había que mirar el árbol real antes de adivinar. Ya se miró,
20# y lo que se encontró decide la forma de esta versión:
21#
22#   · `application.ini` del appdir arranca con el comentario «This file is not used». Es HERENCIA
23#     del árbol de desarrollo: en un build empaquetado el launcher SÍ lo lee. `rebrand.py` no le
24#     cree al comentario, comprueba que las claves estén y falla si no.
25#   · Las cadenas que la gente VE están dentro de `browser/omni.ja` (`brand.ftl`), así que sin
26#     re-empacar el zip no hay branding posible. Y el original dice **Nightly**, no «Firefox»,
27#     porque construimos con `--with-branding=browser/branding/unofficial`.
28#   · Los ICONOS, en cambio, están FUERA del zip (`browser/chrome/icons/default/`) ⇒ se reemplazan
29#     sin tocarlo.
30#   · `browser/omni.ja` son 56 MB con TODAS sus entradas sin comprimir y con `date_time` ya
31#     normalizado a 2010-01-01: Mozilla también persigue reproducibilidad. El re-empaque preserva
32#     orden, método y fecha — el orden porque es el que Gecko lee al arrancar, y es lo que el
33#     `jarlog` del PGO refinará cuando exista.
34name    = "atuq"
35version = "0.2.0"
36# El artefacto CONTIENE Firefox, así que hereda su licencia. El overlay de `recipes/atuq/` es
37# nuestro, pero eso no cambia lo que se distribuye.
38license = "MPL-2.0"
39
40[source]
41dir = "atuq"
42
43[build]
44# No se compila nada: esta receta copia y edita ficheros. `compiler` y `link` entran igual en el
45# hash, así que se dejan en el default del corpus para no inventar una identidad que no significa
46# nada.
47target = "x86_64-linux-musl"
48
49[build.phases]
50configure = "echo 'atuq: nada que configurar — es un artefacto derivado'"
51compile   = "echo 'atuq: nada que compilar — el motor lo pone la dep firefox'"
52install = '''
53set -e
54SRC=/usr/lib/firefox
55DST=/out/usr/lib/atuq
56
57# ── LAS ASERCIONES VAN PRIMERO, Y FALLAN RUIDOSAS ─────────────────────────────────────────────
58# Un derivado que no encuentra su base no debe producir un artefacto flaco: produciría un
59# directorio con cuatro ficheros de configuración, `Store::has` lo daría por presente y el fallo
60# aparecería el día que alguien intente abrir el navegador. Un ausente falla fuerte; un vacío llega
61# hasta el final diciendo que todo fue bien (regla 3 del CLAUDE.md).
62[ -d "$SRC" ] || { echo "atuq: no está el árbol de firefox en $SRC — ¿la dep se materializó?" >&2; exit 1; }
63[ -x "$SRC/firefox" ] || { echo "atuq: $SRC/firefox no existe o no es ejecutable" >&2; exit 1; }
64[ -f "$SRC/browser/omni.ja" ] || { echo "atuq: falta $SRC/browser/omni.ja" >&2; exit 1; }
65
66mkdir -p "$DST"
67cp -a "$SRC"/. "$DST"/
68# ── EL ÁRBOL COPIADO LLEGA DE SÓLO LECTURA ────────────────────────────────────────────────────
69# `cp -a` preserva los modos, y los ficheros del store están sellados sin permiso de escritura. Todo
70# lo que viene después —el `.ini`, el `omni.ja`, los iconos, el parche del app_id— los MODIFICA.
71# En el worker esto pasaba inadvertido porque corre como root, que ignora los bits de permiso; el
72# primer build fuera de root murió con `PermissionError: /out/usr/lib/atuq/application.ini`.
73# Es la clase de bug que sólo aparece en la máquina de otro, así que se arregla acá y no en el
74# entorno: un artefacto no debe depender de con qué uid lo construiste.
75chmod -R u+w "$DST"
76
77# ── LA CAPA DE CONFIGURACIÓN ──────────────────────────────────────────────────────────────────
78# `defaults/pref/` es el único sitio desde el que se puede pedir el autoconfig ANTES de que exista
79# un perfil; el resto cuelga de ahí.
80mkdir -p "$DST/defaults/pref" "$DST/chrome" "$DST/distribution"
81cp /src/prefs/autoconfig.js        "$DST/defaults/pref/autoconfig.js"
82cp /src/atuq.cfg                   "$DST/atuq.cfg"
83cp /src/chrome/atuq.css            "$DST/chrome/atuq.css"
84cp /src/distribution/policies.json "$DST/distribution/policies.json"
85
86# ── EL BRANDING ───────────────────────────────────────────────────────────────────────────────
87# Todo lo que exige entrar al zip, editar el .ini o dibujar un PNG está en una herramienta aparte:
88# el shell no tiene `zip` en este lab, y `zipfile` además deja fijar orden, fecha y permisos, que
89# es de lo que depende que el artefacto reproduzca. La herramienta VERIFICA cada cambio y falla si
90# la entrada que iba a reemplazar no estaba.
91python3 /src/tools/rebrand.py "$DST" /src /out
92
93# ── INTEGRACIÓN CON EL ESCRITORIO ─────────────────────────────────────────────────────────────
94mkdir -p /out/usr/bin /out/usr/share/applications
95cp /src/atuq.desktop /out/usr/share/applications/atuq.desktop
96# El lanzador es un script y no un symlink: ni el binario ni sus `.so` traen RPATH (comprobado con
97# `readelf -d`), así que sin `LD_LIBRARY_PATH` el motor no encuentra su propio libnspr4 y muere en
98# XPCOMGlueLoad antes de pintar nada. El porqué completo está en el propio fichero.
99cp /src/bin/atuq /out/usr/bin/atuq
100chmod 0755 /out/usr/bin/atuq
101
102# ── INVENTARIO ────────────────────────────────────────────────────────────────────────────────
103# Lo que distingue este artefacto de su base, listado con tamaños, para que el log del build
104# responda solo la primera pregunta del diagnóstico cuando «atuq se ve como Firefox».
105echo "atuq: capa aplicada —"
106for f in defaults/pref/autoconfig.js atuq.cfg chrome/atuq.css distribution/policies.json; do
107  [ -s "$DST/$f" ] || { echo "atuq: $f quedó VACÍO o ausente" >&2; exit 1; }
108  echo "  $f ($(wc -c < "$DST/$f") bytes)"
109done
110[ -x "$DST/atuq" ] || { echo "atuq: el binario renombrado no quedó ejecutable" >&2; exit 1; }
111[ -x /out/usr/bin/atuq ] || { echo "atuq: el lanzador no quedó ejecutable" >&2; exit 1; }
112grep -q '^Name=atuq' "$DST/application.ini" || { echo "atuq: application.ini no quedó rebrandeado" >&2; exit 1; }
113'''
114
115[deps]
116# `firefox` como dep de BUILD y no de runtime: su árbol se materializa en el sandbox, se copia
117# dentro del artefacto de atuq y a partir de ahí atuq no lo necesita más. El precio es que el
118# artefacto pesa lo que pesa Firefox otra vez; la salida barata (una granja de symlinks) rompe la
119# resolución del appdir por /proc/self/exe, así que la v0.1 paga el disco y lo dice.
120build = ["firefox", "python3"]