harkaq: revertir busybox (era runtime base, rompía builds) + coordinar el §3 con Fable 5

DOS ERRORES MÍOS, uno de dirección y otro técnico, los dos en la cosecha automática:

1. DIRECCIÓN: declaró `busybox` como dep en 29 recetas — cuando la Etapa C lo está
   ELIMINANDO (USERLAND_COMPONENTS=[uutils,findutils,…], ya cerrada; joyas-reusables
   §5 lo confirma: "uutils… Ubuntu 25.10 los envía como default"). Estaba cimentando
   la deuda que el roadmap borra.
2. TÉCNICO: busybox YA está en el runtime base de harkaq (`ro /bin/busybox`, `ro
   /bin/sh` — el sandbox corre `sh -c` y /bin/sh→/bin/busybox). Es CONTRATO, no dep.
   Declararlo apila el busybox de hammer sobre el de Alpine y ROMPE el build:
   binutils daba "cannot run C compiled programs" en las DOS máquinas. Verificado:
   sin busybox declarado, binutils construye (b3:f4507dcd…). Y la cadena se explica:
   binutils roto ⇒ zlib (que lo declara) tampoco construía.

Auditoría de la cosecha (diff real, no la línea completa del +): añadió sólo 5 deps
distintas — make ×73, busybox ×29, perl ×8, pkgconf ×5, binutils ×1. Sólo busybox
estaba mal; las otras 4 son deps reales medidas. busybox revertido de 30 recetas
(queda sólo en busybox.toml, pre-existente).

Es el mismo error que ya me habían señalado con otro disfraz: MEDIR BIEN Y ACCIONAR
MAL. harkaq midió correcto (el build toca /bin/busybox: es el shell); la acción
correcta no era declararlo sino reconocerlo como contrato.

+ COORDINACIÓN del §3 con Fable 5 (mismo diseño, tareas repartidas):
  - Su lección casper queda CONFIRMADA y REFORZADA: la clausura de build no sólo le
    FALTAN las clases del mundo (offline) — también le SOBRA casi todo (headers, gcc).
    Medido: htop (estático, 0 NEEDED) no toca NADA al correr ⇒ política = su binario.
  - Su "la clase viaja como campo de la ConcesionCapacidad, sin formato nuevo" se
    cumple LITERALMENTE: lo firmado es format::Permisos = u32 bitmask en 36 bytes
    canónicos (Ring 0) ⇒ las clases SON los bits. La cripto no se toca.
  - Diseño unificado: frontera (clases, u32, declaradas) + detalle (paths, Landlock,
    medidos). D3 rige en ambos.
  - Reparto: clases→Fable 5; medición/harness→Opus. CONTACTO: runtime-policy.sh ahora
    emite la CLASE detectada (/etc/resolv.conf→dns, /etc/ssl/certs→tls-certs, …), no
    sólo el path: la medición alimenta la tabla, la tabla decide el bit.
  - Consumidor esperando: plan-jaula-juegos F1 (Steam que no puede leer ~/.ssh).

+ juez.sh (§10): nombre único por corrida (con uno fijo pega en caché ⇒ falso
  "sin evidencia"). Fue el juez quien destapó todo esto en su primera corrida real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-16 23:14:19 -04:00
co-authored by Claude Opus 4.8
parent 2e85dfc8a3
commit d99ed58850
44 changed files with 697 additions and 35 deletions
+45
View File
@@ -84,6 +84,51 @@ dlopen de módulos NSS — la mitad de por qué casper existe no aplica:
La clase viaja como campo de la `ConcesionCapacidad` — sin formato nuevo.
**Medición que confirma y acota lo anterior (Opus 4.8, 2026-07-16).** Se probó el riel de punta
a punta y salieron dos cosas que ajustan el diseño; la lección casper queda **confirmada y
reforzada**:
1. **El sujeto: la clausura de build no puede ser la política de runtime, ni siquiera de base.**
No es sólo que le falten las clases del mundo (casper): también le **sobra** casi todo. Un
build lee `zlib.h`, `make`, `gcc`; el binario resultante no abre ninguno. Medido con `htop`
(musl-estático, **0 `NEEDED`**): bajo la jaula con política mínima **no tocó un solo fichero**
fuera de sí mismo ⇒ su política de runtime es `ro <su binario>` y nada más. Derivarla del
build le habría concedido headers y compilador — permisos de más, firmados.
**la política granular se MIDE corriendo el binario** (`scripts/harkaq/runtime-policy.sh`:
corre bajo la jaula y **resta el baseline del lanzador**, que si no se lleva el ruido del `sh`).
Para un estático la política *no puede* salir de las libs: sólo de correrlo.
2. **La cripto ya es "frontera, no tabla" — y por eso las clases encajan sin tocarla.** Lo que la
`ConcesionCapacidad` firma **no** es `card-core::Permissions` (el struct) sino
`format::Permisos` = **`u32` bitmask**, dentro de `mensaje_capacidad` =
`hash(32) || permisos_le(4)` = **36 bytes canónicos, zero-alloc, con espejo `no_std` en Ring 0**
(`wawa-kernel/src/claves.rs:464`). Meterle una tabla de paths rompería **todas** las firmas y
contradiría el "capacidad = frontera física, no tabla" que este mismo §3 cita.
**las clases de servicio SON los bits del `u32`** (`PERMISO_RED` ya es uno; `dns` sería otro).
"Sin formato nuevo" se cumple literalmente.
**Diseño unificado (los dos niveles coexisten, cada uno donde cabe):**
| nivel | qué | dónde | cómo se obtiene |
|---|---|---|---|
| **frontera** | clases de servicio (`dns`, `tls-certs`, `random`, `locale`, `syslog`) | `u32` firmado, verificado en Ring 0 | **declaradas por nombre** — no se pueden medir: el build es offline (casper) |
| **detalle** | paths concretos (fs) | Landlock, userspace | **medidos** corriendo el binario bajo la jaula |
El kernel verifica la frontera con 36 bytes; Landlock aplica el detalle. D3 rige en ambos: nada
se ensancha en silencio.
**Reparto de tareas (para no pisarnos):**
- **Clases de servicio** (Fable 5): la tabla clase→permiso musl, el bit en el `u32`, y el cableado
con `ConcesionCapacidad`/`arje-absorb --attest-from`.
- **Medición** (Opus 4.8): `runtime-policy.sh`, el harness harkaq (jaula, lector, canario D9) y el
baseline del lanzador.
- **Punto de contacto acordado**: `runtime-policy.sh` emitirá también la **clase** detectada, no
sólo el path — si el binario toca `/etc/resolv.conf` ⇒ propone `dns`; si toca `/etc/ssl/certs/`
`tls-certs`. La medición alimenta la tabla; la tabla decide el bit. Ninguno de los dos
ensancha por su cuenta.
- **Consumidor esperándonos**: `plan-jaula-juegos.md` F1 («la jaula sellada con pressure-vessel +
política harkaq del runtime») — un Steam que no puede leer `~/.ssh` sale de este §3.
### 4. CVE por grafo
`hammer affected CVE-X` exacto (grafo fuente→artefacto→instalado) + frontera mínima de
+47
View File
@@ -0,0 +1,47 @@
# adwaita-hello — app Adwaita mínima de VALIDACIÓN: prueba que libadwaita-1.a es linkeable de verdad.
# AdwApplication + AdwApplicationWindow + AdwToolbarView. Link 100% estático vía pkg-config --static
# libadwaita-1 + las privadas de gdk/gsk/appstream que el .pc no declara. Mismo patrón que gtk4-hello.
name = "adwaita-hello"
version = "1.7.6"
[source]
tarball = "https://download.gnome.org/sources/libadwaita/1.7/libadwaita-1.7.6.tar.xz"
sha256 = "5eacc5550f0bdbba6a1568aebf25a3d88f5ee07d6b558becc6fd9487579c9a29"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
configure = "true"
compile = '''
cat > adw_hello.c <<'CEOF'
#include <adwaita.h>
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *win = adw_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(win), "Adwaita en hammer");
gtk_window_set_default_size(GTK_WINDOW(win), 400, 260);
GtkWidget *toolbar = adw_toolbar_view_new();
adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar), adw_header_bar_new());
GtkWidget *status = adw_status_page_new();
adw_status_page_set_title(ADW_STATUS_PAGE(status), "libadwaita static-musl ✓");
adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar), status);
adw_application_window_set_content(ADW_APPLICATION_WINDOW(win), toolbar);
gtk_window_present(GTK_WINDOW(win));
}
int main(int argc, char **argv) {
AdwApplication *app = adw_application_new("org.hammer.adw", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
CEOF
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
zig cc -mcpu=baseline -static adw_hello.c -o adwaita-hello $(pkg-config --cflags --libs --static libadwaita-1 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
'''
install = "mkdir -p /out/usr/bin && cp adwaita-hello /out/usr/bin/adwaita-hello"
[deps]
build = ["pkgconf", "libadwaita", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
+1 -1
View File
@@ -45,4 +45,4 @@ _abuild_phase
'''
[deps]
build = ["ncurses", "readline", "linux-headers", "busybox", "make"]
build = ["ncurses", "readline", "linux-headers", "make"]
+1 -1
View File
@@ -43,7 +43,7 @@ link = "dynamic"
zig_version = "0.13.0"
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
# --disable-nls: sin gettext (ausente en el toolchain hermético). --disable-werror: binutils promueve
+1 -1
View File
@@ -32,7 +32,7 @@ link = "static"
flags = ["--enable-single-binary", "--disable-nls"]
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
# install por defecto (make install DESTDIR=/out) deja el multicall en /out/usr/bin/coreutils; lo
+1 -1
View File
@@ -43,4 +43,4 @@ _abuild_phase
'''
[deps]
build = ["linux-headers", "busybox", "make"]
build = ["linux-headers", "make"]
+1 -1
View File
@@ -59,4 +59,4 @@ _abuild_phase
'''
[deps]
build = ["linux-headers", "busybox", "pkgconf"]
build = ["linux-headers", "pkgconf"]
-3
View File
@@ -24,9 +24,6 @@ link = "dynamic"
# bueno por-receta ⇒ gcc deja de hacer falta (toolchain 100% zig). No es input del 4/4. SDD 11 §7.2b.
zig_version = "0.13.0"
[deps]
build = ["busybox"]
[build.phases]
configure = "./configure --prefix=/usr --disable-nls --disable-shared"
compile = "make -j\"$(nproc)\""
+1 -1
View File
@@ -15,4 +15,4 @@ install = "make install DESTDIR=/out"
# libpng+zlib: freetype se compila --with-png, así que freetype2.pc trae `Requires: libpng`
# (y libpng.pc → zlib); sin ellos pkg-config no resuelve freetype2 y ./configure aborta.
[deps]
build = ["freetype", "expat", "pkgconf", "gperf", "python3", "libpng", "zlib", "busybox", "make"]
build = ["freetype", "expat", "pkgconf", "gperf", "python3", "libpng", "zlib", "make"]
+1 -1
View File
@@ -18,7 +18,7 @@ link = "static"
flags = []
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
+1 -1
View File
@@ -9,7 +9,7 @@ compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
configure = "CXXFLAGS=\"$CXXFLAGS -std=c++14\" ./configure --prefix=/usr"
+47
View File
@@ -0,0 +1,47 @@
# gtk4-hello — app GTK4 mínima de VALIDACIÓN: prueba que libgtk-4.a (static) es linkeable de verdad.
# Reutiliza el tarball de GTK4 solo como acarreo de [source] (lo ignora); escribe su propio hello.c y
# lo linkea ESTÁTICO contra todo el cierre GTK4 vía `pkg-config --static gtk4`. Si sella, el toolkit
# de GUI del lab es usable por apps, no solo "compila". deps = cierre .pc completo + gtk4.
name = "gtk4-hello"
version = "4.18.6"
[source]
tarball = "https://download.gnome.org/sources/gtk/4.18/gtk-4.18.6.tar.xz"
sha256 = "e1817c650ddc3261f9a8345b3b22a26a5d80af154630dedc03cc7becefffd0fa"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
# no-op: el tarball trae meson.build y el lab inyectaría `meson setup` por defecto si omito configure.
configure = "true"
compile = '''
cat > hammer_hello.c <<'CEOF'
#include <gtk/gtk.h>
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *win = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(win), "Hola desde hammer");
gtk_window_set_default_size(GTK_WINDOW(win), 360, 220);
GtkWidget *label = gtk_label_new("GTK4 static-musl ✓ (zig cc)");
gtk_window_set_child(GTK_WINDOW(win), label);
gtk_window_present(GTK_WINDOW(win));
}
int main(int argc, char **argv) {
GtkApplication *app = gtk_application_new("org.hammer.hola", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
CEOF
# gtk4.pc NO declara Libs.private (asume link dinámico contra libgtk-4.so); para ESTÁTICO hay que sumar
# las privadas que gdk/gsk linkean directo (harfbuzz-subset, epoxy, wayland, xkbcommon, tiff, jpeg).
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
zig cc -mcpu=baseline -static hammer_hello.c -o gtk4-hello $(pkg-config --cflags --libs --static gtk4 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
'''
install = "mkdir -p /out/usr/bin && cp gtk4-hello /out/usr/bin/gtk4-hello"
[deps]
build = ["pkgconf", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
+39
View File
@@ -0,0 +1,39 @@
# gtk4 4.18.6 — el toolkit de GUI. meson static, backend SOLO wayland (sin X11/broadway/win/mac),
# renderer GL vía libepoxy (vulkan disabled), todo lo opcional off (demos/tests/docs/cups/gstreamer/
# introspection). Corona el stack gráfico C del lab: con esto el corpus puede producir apps GTK reales.
# Deps = cierre transitivo .pc completo (pkg-config estático resuelve Requires.private).
name = "gtk4"
version = "4.18.6"
[source]
tarball = "https://download.gnome.org/sources/gtk/4.18/gtk-4.18.6.tar.xz"
sha256 = "e1817c650ddc3261f9a8345b3b22a26a5d80af154630dedc03cc7becefffd0fa"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
# GTK4 construye libgtk.a (static_library 'gtk') Y libgtk-4.so; las tools linkean la .so con libgtk_dep,
# imposible en el lab static-musl. Parche: que las tools usen libgtk_static_dep (la .a). El sed es seguro:
# "libgtk_dep" NO es substring de "libgtk_static_dep" ⇒ no toca las que ya usan el estático.
configure = "sed -i 's/libgtk_dep/libgtk_static_dep/g' tools/meson.build && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dwayland-backend=true -Dx11-backend=false -Dbroadway-backend=false -Dwin32-backend=false -Dmacos-backend=false -Dvulkan=disabled -Dintrospection=disabled -Dbuild-demos=false -Dbuild-testsuite=false -Dbuild-tests=false -Dbuild-examples=false -Dmedia-gstreamer=disabled -Dprint-cups=disabled -Dprint-cpdb=disabled -Dcloudproviders=disabled -Dsysprof=disabled -Dtracker=disabled -Dcolord=disabled -Df16c=disabled -Ddocumentation=false -Dman-pages=false -Dc_args=-Wno-error=date-time"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
# meson instala solo libgtk-4.so y genera convenience-libs THIN (gtk/gdk/gsk por separado, referencian
# los .o por ruta → inútiles fuera del build dir). Fusiono los tres en UN archive GORDO libgtk-4.a (embebe
# todos los .o) para que `-lgtk-4` + `-static` linkee de verdad en el lab static-musl.
install = '''
PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild
rm -f /out/usr/lib/libgtk-4.a
cd output
objs=""
for a in $(find . -name '*.a'); do
d=$(dirname "$a"); b=$(basename "$a")
for o in $(cd "$d" && zig ar t "$b"); do objs="$objs $d/$o"; done
done
zig ar rcs /out/usr/lib/libgtk-4.a $objs
'''
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "glib", "cairo", "pango", "gdk-pixbuf", "graphene", "libepoxy", "wayland", "wayland-protocols", "libxkbcommon", "libdrm", "fontconfig", "harfbuzz", "fribidi", "libpng", "pixman", "freetype", "expat", "libffi", "pcre2", "zlib", "libjpeg-turbo", "libtiff", "mesa"]
+23
View File
@@ -0,0 +1,23 @@
# gtksourceview 5.16.0 — widget de edición de código (resaltado, números de línea…) sobre GTK4.
# Base de editores/IDEs (gnome-text-editor lo usa). meson static. introspection/vapi/docs/tests off.
name = "gtksourceview"
version = "5.16.0"
[source]
tarball = "https://download.gnome.org/sources/gtksourceview/5.16/gtksourceview-5.16.0.tar.xz"
sha256 = "ab35d420102f3e8b055dd3b8642d3a48209f888189e6254d0ffb4b6a7e8c3566"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
# gtksourceview 5.16 no tiene opción tests; los ejecutables de tests/testsuite linkean gtk4 estático y
# fallan por las privadas (tiff/epoxy/cairo-script). La LIB sí construye → elimino esos subdirs con sed.
configure = "sed -i \"/subdir('tests')/d;/subdir('testsuite')/d\" meson.build && PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dintrospection=disabled -Dvapi=false -Ddocumentation=false -Dsysprof=false -Dc_args=-Wno-error=date-time"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "gettext-tiny", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libxml2", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "wayland-protocols", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
+138
View File
@@ -0,0 +1,138 @@
# hammer-edit — editor de código REAL para el distro: Adwaita + GtkSourceView, abrir/guardar/guardar-como
# (GtkFileDialog), resaltado por extensión, números de línea, apertura de archivos desde la CLI. Link 100%
# estático (gtk4+libadwaita+gtksourceview). No es una demo: es una app instalable y usable.
name = "hammer-edit"
version = "1.0.0"
[source]
tarball = "https://download.gnome.org/sources/gtksourceview/5.16/gtksourceview-5.16.0.tar.xz"
sha256 = "ab35d420102f3e8b055dd3b8642d3a48209f888189e6254d0ffb4b6a7e8c3566"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
configure = "true"
compile = '''
cat > hammer_edit.c <<'CEOF'
#include <adwaita.h>
#include <gtksourceview/gtksource.h>
#include <string.h>
typedef struct { GtkWindow *win; GtkSourceBuffer *buf; GFile *file; } App;
static void set_title(App *a) {
char *name = a->file ? g_file_get_basename(a->file) : g_strdup("Sin título");
char *full = g_strdup_printf("%s — hammer-edit", name);
gtk_window_set_title(a->win, full);
g_free(name); g_free(full);
}
static void load_file(App *a, GFile *file) {
char *contents; gsize len;
if (!g_file_load_contents(file, NULL, &contents, &len, NULL, NULL)) return;
gtk_text_buffer_set_text(GTK_TEXT_BUFFER(a->buf), contents, len);
g_free(contents);
g_set_object(&a->file, file);
GtkSourceLanguageManager *lm = gtk_source_language_manager_get_default();
char *base = g_file_get_basename(file);
GtkSourceLanguage *lang = gtk_source_language_manager_guess_language(lm, base, NULL);
gtk_source_buffer_set_language(a->buf, lang);
g_free(base);
set_title(a);
}
static void open_cb(GObject *src, GAsyncResult *res, gpointer ud) {
App *a = ud;
GFile *file = gtk_file_dialog_open_finish(GTK_FILE_DIALOG(src), res, NULL);
if (file) { load_file(a, file); g_object_unref(file); }
}
static void on_open(GtkButton *b, gpointer ud) {
App *a = ud;
GtkFileDialog *d = gtk_file_dialog_new();
gtk_file_dialog_open(d, a->win, NULL, open_cb, a);
g_object_unref(d);
}
static void save_to(App *a, GFile *file) {
GtkTextIter s, e;
gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(a->buf), &s, &e);
char *text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(a->buf), &s, &e, FALSE);
g_file_replace_contents(file, text, strlen(text), NULL, FALSE,
G_FILE_CREATE_NONE, NULL, NULL, NULL);
g_free(text);
g_set_object(&a->file, file);
set_title(a);
}
static void save_cb(GObject *src, GAsyncResult *res, gpointer ud) {
App *a = ud;
GFile *file = gtk_file_dialog_save_finish(GTK_FILE_DIALOG(src), res, NULL);
if (file) { save_to(a, file); g_object_unref(file); }
}
static void on_save(GtkButton *b, gpointer ud) {
App *a = ud;
if (a->file) { save_to(a, a->file); return; }
GtkFileDialog *d = gtk_file_dialog_new();
gtk_file_dialog_save(d, a->win, NULL, save_cb, a);
g_object_unref(d);
}
static App *build_window(GtkApplication *app) {
App *a = g_new0(App, 1);
GtkWidget *win = adw_application_window_new(app);
a->win = GTK_WINDOW(win);
gtk_window_set_default_size(a->win, 820, 580);
GtkWidget *tv = adw_toolbar_view_new();
GtkWidget *hb = adw_header_bar_new();
GtkWidget *ob = gtk_button_new_from_icon_name("document-open-symbolic");
GtkWidget *sb = gtk_button_new_from_icon_name("document-save-symbolic");
gtk_widget_set_tooltip_text(ob, "Abrir");
gtk_widget_set_tooltip_text(sb, "Guardar");
g_signal_connect(ob, "clicked", G_CALLBACK(on_open), a);
g_signal_connect(sb, "clicked", G_CALLBACK(on_save), a);
adw_header_bar_pack_start(ADW_HEADER_BAR(hb), ob);
adw_header_bar_pack_end(ADW_HEADER_BAR(hb), sb);
adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(tv), hb);
a->buf = gtk_source_buffer_new(NULL);
gtk_source_buffer_set_highlight_syntax(a->buf, TRUE);
GtkWidget *view = gtk_source_view_new_with_buffer(a->buf);
gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(view), TRUE);
gtk_source_view_set_highlight_current_line(GTK_SOURCE_VIEW(view), TRUE);
gtk_source_view_set_auto_indent(GTK_SOURCE_VIEW(view), TRUE);
gtk_widget_add_css_class(view, "monospace");
GtkWidget *sc = gtk_scrolled_window_new();
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(sc), view);
adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(tv), sc);
adw_application_window_set_content(ADW_APPLICATION_WINDOW(win), tv);
set_title(a);
return a;
}
static void activate(GApplication *app, gpointer ud) {
App *a = build_window(GTK_APPLICATION(app));
gtk_window_present(a->win);
}
static void open_files(GApplication *app, GFile **files, gint n, const char *hint, gpointer ud) {
App *a = build_window(GTK_APPLICATION(app));
if (n > 0) load_file(a, files[0]);
gtk_window_present(a->win);
}
int main(int argc, char **argv) {
AdwApplication *app = adw_application_new("org.hammer.edit", G_APPLICATION_HANDLES_OPEN);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
g_signal_connect(app, "open", G_CALLBACK(open_files), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
CEOF
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
zig cc -mcpu=baseline -static hammer_edit.c -o hammer-edit $(pkg-config --cflags --libs --static gtksourceview-5 libadwaita-1 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
'''
install = "mkdir -p /out/usr/bin && cp hammer-edit /out/usr/bin/hammer-edit"
[deps]
build = ["pkgconf", "gtksourceview", "libadwaita", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
@@ -0,0 +1,92 @@
This patch links libmandoc dynamically instead of statically, this
causes the package size to be reduced by roughly 50%.
See also: https://inbox.vuxu.org/mandoc-tech/2L1YC2WD8JUE5.3QGU3CQ10EGCD@8pit.net/T/#u
diff --git a/Makefile b/Makefile
index 48c4741..252e11e 100644
--- a/Makefile
+++ b/Makefile
@@ -367,9 +367,13 @@ WWW_INCS = eqn.h.html \
tbl_int.h.html \
tbl_parse.h.html
+LIBMANDOC = libmandoc.so
+MANDOCLIB = -L. -lmandoc
+
# === USER CONFIGURATION ===============================================
include Makefile.local
+CFLAGS += -fPIC
# === DEPENDENCY HANDLING ==============================================
@@ -392,7 +396,7 @@ distclean: clean
rm -f Makefile.local config.h config.h.old config.log config.log.old
clean:
- rm -f libmandoc.a $(LIBMANDOC_OBJS) $(ALL_COBJS)
+ rm -f $(LIBMANDOC) $(LIBMANDOC_OBJS) $(ALL_COBJS)
rm -f mandoc man $(MAIN_OBJS)
rm -f man.cgi $(CGI_OBJS)
rm -f mandocd catman catman.o $(MANDOCD_OBJS)
@@ -432,11 +436,11 @@ base-install: mandoc demandoc soelim
$(INSTALL_MAN) makewhatis.8 \
$(DESTDIR)$(MANDIR)/man8/$(BINM_MAKEWHATIS).8
-lib-install: libmandoc.a
+lib-install: $(LIBMANDOC)
mkdir -p $(DESTDIR)$(LIBDIR)
mkdir -p $(DESTDIR)$(INCLUDEDIR)
mkdir -p $(DESTDIR)$(MANDIR)/man3
- $(INSTALL_LIB) libmandoc.a $(DESTDIR)$(LIBDIR)
+ $(INSTALL_LIB) $(LIBMANDOC) $(DESTDIR)$(LIBDIR)
$(INSTALL_LIB) eqn.h man.h mandoc.h mandoc_aux.h mandoc_parse.h \
mdoc.h roff.h tbl.h $(DESTDIR)$(INCLUDEDIR)
$(INSTALL_MAN) mandoc.3 mandoc_escape.3 mandoc_malloc.3 \
@@ -485,7 +489,7 @@ uninstall:
rm -f $(DESTDIR)$(SBINDIR)/$(BINM_CATMAN)
rm -f $(DESTDIR)$(MANDIR)/man8/mandocd.8
rm -f $(DESTDIR)$(MANDIR)/man8/$(BINM_CATMAN).8
- rm -f $(DESTDIR)$(LIBDIR)/libmandoc.a
+ rm -f $(DESTDIR)$(LIBDIR)/$(LIBMANDOC)
rm -f $(DESTDIR)$(MANDIR)/man3/mandoc.3
rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_escape.3
rm -f $(DESTDIR)$(MANDIR)/man3/mandoc_malloc.3
@@ -515,23 +519,26 @@ Makefile.local config.h: configure $(TESTSRCS)
libmandoc.a: $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
$(AR) rs $@ $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
-mandoc: $(MAIN_OBJS) libmandoc.a
- $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) libmandoc.a $(LDADD)
+libmandoc.so: $(MANDOC_COBJS) $(LIBMANDOC_OBJS)
+ $(CC) $(LDFLAGS) -shared -o $@ $(MANDOC_COBJS) $(LIBMANDOC_OBJS) $(LDADD)
+
+mandoc: $(MAIN_OBJS) $(LIBMANDOC)
+ $(CC) -o $@ $(LDFLAGS) $(MAIN_OBJS) $(MANDOCLIB) $(LDADD)
man: mandoc
$(LN) mandoc man
-man.cgi: $(CGI_OBJS) libmandoc.a
- $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) libmandoc.a $(LDADD)
+man.cgi: $(CGI_OBJS) $(LIBMANDOC)
+ $(CC) $(STATIC) -o $@ $(LDFLAGS) $(CGI_OBJS) $(MANDOCLIB) $(LDADD)
-mandocd: $(MANDOCD_OBJS) libmandoc.a
- $(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) libmandoc.a $(LDADD)
+mandocd: $(MANDOCD_OBJS) $(LIBMANDOC)
+ $(CC) -o $@ $(LDFLAGS) $(MANDOCD_OBJS) $(MANDOCLIB) $(LDADD)
-catman: catman.o libmandoc.a
- $(CC) -o $@ $(LDFLAGS) catman.o libmandoc.a $(LDADD)
+catman: catman.o $(LIBMANDOC)
+ $(CC) -o $@ $(LDFLAGS) catman.o $(MANDOCLIB) $(LDADD)
-demandoc: $(DEMANDOC_OBJS) libmandoc.a
- $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) libmandoc.a $(LDADD)
+demandoc: $(DEMANDOC_OBJS) $(LIBMANDOC)
+ $(CC) -o $@ $(LDFLAGS) $(DEMANDOC_OBJS) $(MANDOCLIB) $(LDADD)
soelim: $(SOELIM_COBJS) soelim.o
$(CC) -o $@ $(LDFLAGS) $(SOELIM_COBJS) soelim.o
+12
View File
@@ -0,0 +1,12 @@
These tests only work with read/write access to /dev/tty0 (or similar)
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -8,7 +8,6 @@
m4_include([unittest.at])
-m4_include([utils.at])
m4_include([libcommon.at])
m4_include([libkeymap.at])
m4_include([libkbdfile.at])
+11
View File
@@ -0,0 +1,11 @@
Ref https://github.com/wismill/kbd/commit/0f410510f586e659fbdba9cfc3846be343b8dd30
--- a/tests/unittest.at
+++ b/tests/unittest.at
@@ -5,5 +5,5 @@
]])
m4_define([UNITTEST_MEMCHECK],[
-AT_CHECK([UNITTEST_RUN_MEMCHECK([$1])],[$2],[$3],[$4],[$5],[$6])
+AT_CHECK([$1],[$2],[$3],[$4],[$5],[$6])
])
+22
View File
@@ -0,0 +1,22 @@
# libadwaita 1.7.6 — los widgets modernos de GNOME sobre GTK4 (Adwaita). meson static.
# Compila sus estilos SCSS con sassc en build. examples/tests/vapi/introspection/docs off.
# deps = gtk4 + su cierre .pc completo + sassc.
name = "libadwaita"
version = "1.7.6"
[source]
tarball = "https://download.gnome.org/sources/libadwaita/1.7/libadwaita-1.7.6.tar.xz"
sha256 = "5eacc5550f0bdbba6a1568aebf25a3d88f5ee07d6b558becc6fd9487579c9a29"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dexamples=false -Dtests=false -Dvapi=false -Dintrospection=disabled -Dgtk_doc=false -Dc_args=-Wno-error=date-time"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "sassc", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "wayland-protocols", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
+1 -1
View File
@@ -25,7 +25,7 @@ target = "x86_64-linux-musl"
link = "static"
[deps]
build = ["busybox", "make", "zlib"]
build = ["make", "zlib"]
[build.phases]
# -fno-sanitize=undefined: mismo motivo que zlib — sin él, zig cc emite llamadas UBSan que el
+1 -1
View File
@@ -23,7 +23,7 @@ link = "static"
[deps]
# libnl 3.11 regenera sus parsers netlink ⇒ flex (lexer) + bison (parser) + m4 (bison lo invoca).
build = ["flex", "bison", "m4", "busybox", "make"]
build = ["flex", "bison", "m4", "make"]
[build.phases]
configure = "./configure --build=$CBUILD --host=$CHOST --prefix=/usr --libdir=/usr/lib --disable-shared --enable-static --disable-cli"
+1 -1
View File
@@ -38,4 +38,4 @@ make DESTDIR="/out" install
'''
[deps]
build = ["linux-headers", "busybox", "make"]
build = ["linux-headers", "make"]
+1 -1
View File
@@ -34,7 +34,7 @@ target = "x86_64-linux-musl"
link = "dynamic"
[deps]
build = ["flex", "bison", "m4", "openssl", "elfutils", "busybox", "make"]
build = ["flex", "bison", "m4", "openssl", "elfutils", "make"]
[build.phases]
configure = """
+1 -1
View File
@@ -72,7 +72,7 @@ target = "x86_64-linux-musl"
link = "dynamic"
[deps]
build = ["flex", "bison", "m4", "openssl", "elfutils", "busybox", "make"]
build = ["flex", "bison", "m4", "openssl", "elfutils", "make"]
[build.phases]
configure = """
+1 -1
View File
@@ -36,7 +36,7 @@
# integrity/dns_resolver, no apagable sin desarmar media config) ⇒ su host-tool certs/extract-cert
# #incluye openssl. Por eso libelf + openssl se proveen como BOOTSTRAP-LIBS apk en bootstrap-devfs.sh
# (status g++/zlib-dev; SEGUROS para el of_tree: hammerd no usa openssl, arje-zero va preseeded).
# deps.build=[flex,bison,m4] son hammer-built; libelf/openssl quedan de-Alpinizables luego con
# deps.build = [] son hammer-built; libelf/openssl quedan de-Alpinizables luego con
# recipes/{elfutils,openssl}.toml.
# - [DEUDA kikin, 2026-07-16] IO_URING + BPF_SYSCALL explícitos (contrato PLAN-KIKIN §4.bis) van
# en linux-metal/linux-generic; ACÁ NO todavía: este of_tree es LOAD-BEARING del selfhost-verify
-3
View File
@@ -26,9 +26,6 @@ target = "x86_64-linux-musl"
link = "static"
zig_version = "0.13.0"
[deps]
build = ["busybox"]
[build.phases]
configure = "./configure --prefix=/usr --without-x CC='zig cc -mcpu=baseline -target x86_64-linux-musl' LDFLAGS=-static"
compile = "make -j\"$(nproc)\""
+1 -1
View File
@@ -17,7 +17,7 @@ link = "static"
flags = []
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
configure = '''
+16
View File
@@ -0,0 +1,16 @@
# pango 1.57.1 — layout/render de texto i18n (base de GTK). meson static.
name = "pango"
version = "1.57.1"
[source]
tarball = "https://download.gnome.org/sources/pango/1.57/pango-1.57.1.tar.xz"
sha256 = "e65d6d117080dc3aeeb7d8b4b3b518f7383aa2e6cfce23117c623cd624764c2f"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
configure = "PKG_CONFIG_PATH=/usr/lib/pkgconfig PYTHONPATH=/usr/lib/python3.12/site-packages meson setup output --prefix=/usr --buildtype=release --wrap-mode=nodownload --prefer-static -Ddefault_library=static -Dc_args=-Wno-error=date-time -Dintrospection=disabled -Dgtk_doc=false -Dbuild-testsuite=false -Dbuild-examples=false"
compile = "PYTHONPATH=/usr/lib/python3.12/site-packages ninja -C output"
install = "PYTHONPATH=/usr/lib/python3.12/site-packages DESTDIR=/out meson install -C output --no-rebuild"
[deps]
build = ["meson", "samurai", "python3", "pkgconf", "cairo", "harfbuzz", "fribidi", "glib", "freetype", "fontconfig", "pixman", "libpng", "expat", "libffi", "pcre2", "zlib"]
+1 -1
View File
@@ -52,4 +52,4 @@ make DESTDIR="/out" install
# lvm2 (device-mapper) ausente y opcional → --disable-device-mapper. libuuid real vía util-linux
# (dep de build); pkgconf resuelve uuid.pc. bash/ncurses/readline innecesarios al binario estático.
[deps]
build = ["util-linux", "linux-headers", "pkgconf", "busybox", "make"]
build = ["util-linux", "linux-headers", "pkgconf", "make"]
+1 -1
View File
@@ -36,7 +36,7 @@ link = "dynamic"
zig_version = "0.13.0"
[deps]
build = ["zlib", "busybox", "pkgconf"]
build = ["zlib", "pkgconf"]
[build.phases]
configure = "./configure --prefix=/usr --without-ensurepip --disable-test-modules --with-ensurepip=no CFLAGS=\"-Wno-error=date-time\""
+1 -1
View File
@@ -13,4 +13,4 @@ configure = "./configure --prefix=/usr --disable-shared --enable-static --with-c
compile = "make"
install = "make install DESTDIR=/out"
[deps]
build = ["ncurses", "busybox", "make"]
build = ["ncurses", "make"]
+1 -1
View File
@@ -54,4 +54,4 @@ make DESTDIR="/out" install
# depends de runtime de Alpine (NO build-deps): python3
[deps]
build = ["zlib", "linux-headers", "busybox"]
build = ["zlib", "linux-headers"]
+1 -1
View File
@@ -47,4 +47,4 @@ _abuild_phase
# perl era build-dep de Alpine sólo para tests/docs; el tarball trae configure + sed.1 pregenerado.
[deps]
build = ["linux-headers", "busybox", "make"]
build = ["linux-headers", "make"]
+1 -1
View File
@@ -74,4 +74,4 @@ install -m644 /dev/null etc/subgid
# deps de Alpine remapeadas al catálogo canónico. AUSENTES quitadas:
# linux-pam, libbsd, setcap. Sin fcaps (setcap falla en el sandbox) ⇒ sin libcap.
[deps]
build = ["linux-headers", "busybox", "make"]
build = ["linux-headers", "make"]
+57
View File
@@ -0,0 +1,57 @@
# sourceview-hello — VALIDACIÓN del editor: ventana Adwaita con un GtkSourceView (resaltado C, números
# de línea) editable. Junta libadwaita + gtksourceview + gtk4, link 100% estático. Es, de hecho, el
# esqueleto de un editor de código real para el distro.
name = "sourceview-hello"
version = "5.16.0"
[source]
tarball = "https://download.gnome.org/sources/gtksourceview/5.16/gtksourceview-5.16.0.tar.xz"
sha256 = "ab35d420102f3e8b055dd3b8642d3a48209f888189e6254d0ffb4b6a7e8c3566"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[build.phases]
configure = "true"
compile = '''
cat > sv_hello.c <<'CEOF'
#include <adwaita.h>
#include <gtksourceview/gtksource.h>
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *win = adw_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(win), "Editor hammer");
gtk_window_set_default_size(GTK_WINDOW(win), 640, 420);
GtkWidget *toolbar = adw_toolbar_view_new();
adw_toolbar_view_add_top_bar(ADW_TOOLBAR_VIEW(toolbar), adw_header_bar_new());
GtkSourceBuffer *buf = gtk_source_buffer_new(NULL);
GtkSourceLanguageManager *lm = gtk_source_language_manager_get_default();
GtkSourceLanguage *lang = gtk_source_language_manager_get_language(lm, "c");
if (lang) gtk_source_buffer_set_language(buf, lang);
gtk_text_buffer_set_text(GTK_TEXT_BUFFER(buf),
"#include <stdio.h>\nint main(void){\n printf(\"hola hammer\\n\");\n return 0;\n}\n", -1);
GtkWidget *view = gtk_source_view_new_with_buffer(buf);
gtk_source_view_set_show_line_numbers(GTK_SOURCE_VIEW(view), TRUE);
gtk_widget_add_css_class(view, "monospace");
GtkWidget *scroll = gtk_scrolled_window_new();
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(scroll), view);
adw_toolbar_view_set_content(ADW_TOOLBAR_VIEW(toolbar), scroll);
adw_application_window_set_content(ADW_APPLICATION_WINDOW(win), toolbar);
gtk_window_present(GTK_WINDOW(win));
}
int main(int argc, char **argv) {
AdwApplication *app = adw_application_new("org.hammer.editor", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
int status = g_application_run(G_APPLICATION(app), argc, argv);
g_object_unref(app);
return status;
}
CEOF
export PKG_CONFIG_PATH=/usr/lib/pkgconfig
zig cc -mcpu=baseline -static sv_hello.c -o sourceview-hello $(pkg-config --cflags --libs --static gtksourceview-5 libadwaita-1 harfbuzz-subset epoxy xkbcommon wayland-client wayland-egl libtiff-4 libjpeg cairo-script-interpreter)
'''
install = "mkdir -p /out/usr/bin && cp sourceview-hello /out/usr/bin/sourceview-hello"
[deps]
build = ["pkgconf", "gtksourceview", "libadwaita", "appstream", "libyaml", "curl", "openssl", "libxmlb", "libxml2", "zstd", "gtk4", "pango", "gdk-pixbuf", "cairo", "graphene", "glib", "harfbuzz", "fribidi", "fontconfig", "freetype", "pixman", "libpng", "expat", "libjpeg-turbo", "libtiff", "libepoxy", "wayland", "libxkbcommon", "libdrm", "pcre2", "libffi", "zlib", "mesa"]
+1 -1
View File
@@ -9,7 +9,7 @@ compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "static"
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
configure = "./configure --prefix=/usr --disable-shared --enable-static"
+1 -1
View File
@@ -18,7 +18,7 @@ link = "static"
flags = []
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
+1 -1
View File
@@ -73,4 +73,4 @@ make DESTDIR="/out" install
# deps de Alpine/nix remapeadas al catálogo canónico. AUSENTES quitadas:
# autoconf/automake/po4a/libxcrypt/sqlite/linux-pam/libcap-ng/systemd-minimal-libs.
[deps]
build = ["linux-headers", "busybox", "make"]
build = ["linux-headers", "make"]
+1 -1
View File
@@ -18,7 +18,7 @@ link = "static"
flags = []
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
# de build() de Alpine (traducido; el lab provee $CBUILD/$CHOST — Etapa G Fase 3; revisá --shared para estático):
+1 -1
View File
@@ -23,7 +23,7 @@ target = "x86_64-linux-musl"
link = "static"
[deps]
build = ["libnl", "busybox", "make"]
build = ["libnl", "make"]
[build.phases]
configure = '''
+1 -1
View File
@@ -43,7 +43,7 @@ link = "static"
zig_version = "0.13.0"
[deps]
build = ["busybox", "make"]
build = ["make"]
[build.phases]
configure = "./configure --prefix=/usr --disable-libreadline --disable-libedit --disable-libacl --disable-xattr --disable-zlib --disable-libbz2 --disable-libcdio CC='zig cc -mcpu=baseline -target x86_64-linux-musl' LDFLAGS=-static"
+1 -1
View File
@@ -25,7 +25,7 @@ target = "x86_64-linux-musl"
link = "static"
[deps]
build = ["make"]
build = ["make", "binutils"]
[build.phases]
# --static: sólo libz.a (sin .so; mrustc/rustc enlazan estático). --prefix=/usr: zlib.h→/usr/include,
+16 -1
View File
@@ -62,6 +62,21 @@ if [ -z "$propios" ]; then
echo " ⇒ política Landlock: sólo \`ro $BIN\`. Es el caso de un estático que no abre ficheros."
else
echo "$propios" | sed 's/^/ ro /'
# CONTACTO con el §3 (clases de servicio, diseño de Fable 5): la medición no sólo lista
# paths — propone la CLASE. El path va a Landlock (detalle, userspace); la clase va al bit
# del u32 firmado (frontera, Ring 0). La medición ALIMENTA la tabla; la tabla decide el bit.
# Ninguno ensancha por su cuenta (D3).
clases=""
echo "$propios" | grep -qE '/etc/(resolv\.conf|hosts)' && clases="$clases dns"
echo "$propios" | grep -qE '/etc/ssl/certs' && clases="$clases tls-certs"
echo "$propios" | grep -qE '/usr/share/zoneinfo|/etc/TZ' && clases="$clases tz"
echo "$propios" | grep -qE '/dev/log' && clases="$clases syslog"
if [ -n "$clases" ]; then
echo
echo " ── clases de servicio detectadas (§3: van al u32 firmado, NO a Landlock):"
for c in $clases; do echo " $c"; done
echo " ⇒ declarar por nombre en la ConcesionCapacidad; el resto de arriba es Landlock."
fi
echo
echo " ⇒ pegar en la política Landlock del binario instalado."
echo " ⇒ los `ro` van a la política Landlock del binario instalado."
fi
+104
View File
@@ -0,0 +1,104 @@
#!/bin/sh
# juez.sh <receta> — JUEZ MECÁNICO del bucle agéntico (SDD 17 §10).
#
# agente propone receta → harkaq veredicto → granja reproduce ×2 → catálogo acepta
#
# Sin humano en el medio para la parte mecánica: el humano decide QUÉ construir; el juez decide
# si lo construido MERECE entrar al catálogo, y lo decide con evidencia, no con opinión.
#
# scripts/juez.sh recipes/zlib.toml
#
# Dos preguntas, dos veredictos, ninguno negociable:
# 1. ¿HERMÉTICO? harkaq (SDD 16): ¿usó algo que no declaró? El kernel responde.
# `denials=[]` no se cree, se GANA (el canario lo demuestra — D9).
# 2. ¿REPRODUCIBLE? consenso (SDD 17 §1): N builders independientes, ¿el mismo hash?
# Si sí, el artefacto es confiable SIN FIRMA.
#
# Si falla, el juez no dice "no" a secas: dice POR QUÉ y qué hacer.
# - Impuro → harkaq-suggest: "declarar dep: make" (arreglo mecánico)
# - Divergente → why-differs: qué fichero, qué causa (codegen/timestamp/build-id)
#
# Es el bucle que el SDD 08 §4 pide ("la IA propone, el sistema reproduce, el humano commitea")
# con la pieza que faltaba: un juez que la IA no puede convencer, sólo satisfacer.
set -eu
RECETA="${1:?uso: juez.sh <receta.toml>}"
HUB="$(cd "$(dirname "$0")/.." && pwd)"
cd "$HUB"
n=$(basename "$RECETA" .toml)
BUILDERS="${BUILDERS:-2}"
echo "══════ JUEZ MECÁNICO — $n"
echo
# ── 1. ¿HERMÉTICO? (harkaq)
echo "── 1/2 ¿usó algo que no declaró? [harkaq, SDD 16]"
if [ ! -x "${HARKAQ_BIN:-$HOME/.cache/harkaq}/harkaq-audit" ]; then
echo " ⊘ harkaq no está compilado ⇒ SIN EVIDENCIA. El juez NO afirma hermeticidad."
echo " (compilar scripts/harkaq/*.c y `setcap cap_audit_read` — ver scripts/harkaq/README.md)"
veredicto_h="sin-evidencia"
else
export HARKAQ=1 HARKAQ_BIN="${HARKAQ_BIN:-$HOME/.cache/harkaq}"
export HARKAQ_BASE="${HARKAQ_BASE:-$HARKAQ_BIN/base.policy}" HARKAQ_TIMEOUT="${HARKAQ_TIMEOUT:-200}"
# Nombre ÚNICO por corrida: con uno fijo, la 2ª vez `hammer build` pega en CACHÉ, no
# construye nada, no hay veredictos y el juez dice "sin evidencia" — un falso negativo que
# parece un problema de la receta. (Gotcha conocido; me mordió al probar el juez.)
uniq="$n-juez-$$"
tmp="$(dirname "$RECETA")/.juez-$n.toml"
sed -E "s/^(name\s*=\s*)\"$n\"/\1\"$uniq\"/" "$RECETA" > "$tmp"
out=$(timeout "${POR:-600}" ./target/debug/hammer build "$tmp" --store "$PWD/store" 2>&1 || true)
rm -f "$tmp"; rm -rf store/*-"$uniq" 2>/dev/null || true
veredictos=$(echo "$out" | grep '^\[harkaq\] {' | sed 's/^\[harkaq\] //')
deuda=""
if [ -z "$veredictos" ]; then
echo " ⊘ sin veredicto (¿caché? ¿el build ni arrancó?) ⇒ SIN EVIDENCIA"
veredicto_h="sin-evidencia"
else
veredicto_h="hermetico"
i=0
echo "$veredictos" | while IFS= read -r v; do :; done
printf '%s\n' "$veredictos" > /tmp/.juez-v
while IFS= read -r v; do
i=$((i + 1)); echo "$v" > /tmp/.juez-1
est=$(scripts/harkaq/harkaq-verdict.py /tmp/.juez-1 "$HARKAQ_BASE" --human 2>/dev/null | head -1 | sed 's/^ *estado: //;s/ .*//')
echo " fase $i: ${est:-?}"
[ "$est" = "Impuro" ] && { veredicto_h="impuro"; \
scripts/harkaq/harkaq-suggest.py /tmp/.juez-1 "$HARKAQ_BASE" "$PWD/store" "$PWD/recipes" "$RECETA" 2>/dev/null | sed 's/^/ /'; }
[ "$est" = "SinEvidencia" ] && veredicto_h="sin-evidencia"
done < /tmp/.juez-v
# el while corre en subshell: recuperar el peor veredicto por marcador
grep -q '"estado":"Impuro"' /tmp/.juez-v && veredicto_h="impuro"
grep -q '"estado":"SinEvidencia"' /tmp/.juez-v && veredicto_h="sin-evidencia"
fi
fi
echo
# ── 2. ¿REPRODUCIBLE? (consenso)
echo "── 2/2 ¿N builders independientes dan el mismo hash? [consenso, SDD 17 §1]"
if consenso=$(BUILDERS="$BUILDERS" timeout "${POR_CONSENSO:-1200}" scripts/consenso.sh "$RECETA" "$BUILDERS" 2>&1); then
echo "$consenso" | grep -E '✅|builder' | sed 's/^/ /'
veredicto_r="consenso"
else
rc=$?
echo "$consenso" | grep -E '⚠️|builder|SIN CONSENSO' | sed 's/^/ /'
[ "$rc" = 1 ] && veredicto_r="divergencia" || veredicto_r="sin-consenso"
if [ "$veredicto_r" = divergencia ]; then
echo " ── why-differs (SDD 17 §2) explicaría la divergencia:"
echo " scripts/why-differs.py <hashA> <hashB> --store ./store"
fi
fi
echo
# ── VEREDICTO
echo "══════ VEREDICTO"
if [ "$veredicto_h" = hermetico ] && [ "$veredicto_r" = consenso ]; then
echo " ✅ ACEPTAR — no usó nada sin declarar Y $BUILDERS builders lo reprodujeron bit a bit."
echo " El catálogo puede confiar en este artefacto sin firma y sin revisión humana del build."
exit 0
fi
echo " ❌ NO ACEPTAR"
[ "$veredicto_h" = impuro ] && echo " · hermeticidad: usa algo sin declarar (ver la sugerencia arriba: es una línea)"
[ "$veredicto_h" = sin-evidencia ] && echo " · hermeticidad: SIN EVIDENCIA — no se afirma nada (D9: un lector ciego y un build limpio son idénticos)"
[ "$veredicto_r" = divergencia ] && echo " · reproducibilidad: los builders NO coinciden ⇒ hay un canal impuro"
[ "$veredicto_r" = sin-consenso ] && echo " · reproducibilidad: no hubo suficientes builders con hash"
exit 1