CAMPAÑA CERRADA: 1166/1166 recetas declaran `license`. Ninguna adivinada — cada una sale del
fichero de licencia de su fuente PINEADA (tarball del sha256 de la receta, o el commit exacto en
la forja), y la cita queda como comentario en la propia receta.
⚠ Y EL GUARDIÁN ESTABA MAL, que es el hallazgo que vale más que las 26. `licencias-rootfs.sh`
resolvía la receta por NOMBRE DE FICHERO (`ls recipes/$pkg.toml`), y el paquete se llama por su
campo `name`, que en 34 recetas NO coincide: nu.toml→`nushell`, dust.toml→`du-dust`,
incoming-kde/qtbase.toml→`qt6-qtbase`… Medido: **14 paquetes que SÍ declaran licencia salían como
«licencia desconocida»** y el guardián vetaba una imagen perfectamente publicable.
El falso veto se nota; el hermano silencioso NO: si existe un `<pkg>.toml` que pertenece a OTRO
paquete, la versión vieja reportaba la licencia EQUIVOCADA sin decir nada. Hoy no pasa —medido,
0 casos, y de los 34 nombres duplicados CERO declaran licencias distintas—, pero ahora es
imposible en vez de improbable.
El arreglo tuvo que ser por LOS DOS lados, y el primer intento rompió el otro: el grafo de estado
nombra sus nodos por el fichero (`dust`) y el artefacto del store por `name` (`du-dust`), así que
resolver sólo por `name` dejaba a `dust` sin licencia. Ahora busca por `name` y cae al fichero.
Medido en los dos sentidos: corpus entero 1128/1128, perfil base+cli 81/81, cero sin licencia.
Y probado CON ROTURA A PROPÓSITO además del control, que es lo único que distingue a un guardián
que sirve de uno que nunca salta:
paquete inexistente en la lista → exit 1 y «ESTA IMAGEN NO SE PUEDE PUBLICAR»
control (zlib nushell qt6-qtbase lsof tzdata) → exit 0, y escribe los textos
(⚠ ojo al medir: `script | tail` devuelve el exit de `tail`. La primera corrida dijo exit=0 sobre
la rotura y no era el guardián, era el pipe.)
SE LEVANTA EL VETO QUE SDD 20 DEJÓ ESCRITO. Decía que `base` y `cli` iban con 2 paquetes cada una
con binarios y licencia desconocida: `lsof` y `tzdata`, «que necesitan la vía LicenseRef- y siguen
vetando a propósito». Hechos los dos, con su texto real en licenses/:
lsof → LicenseRef-lsof (licencia propia de Purdue, sin identificador SPDX)
tzdata → LicenseRef-tz-public-domain (su LICENSE: «all files in the tz code and data … are in
the public domain»; los tres ficheros BSD-3-Clause que menciona NO se instalan — la
receta sólo compila zic y deja /usr/share/zoneinfo)
⚠ DOS QUE NO SE PUEDEN REDISTRIBUIR, y ahora el veto los ve:
duplicacy NO ES LIBRE. Su LICENSE.md: «Free for personal use or commercial trial; non-trial
commercial use requires per-computer CLI licenses … $50 per year»
waybackurls NO DECLARA LICENCIA: en el commit pineado la raíz es .gitignore, README.mkd,
go.mod, main.go y script/ — sin LICENSE ni COPYING, y el README no la menciona. Sin
concesión expresa, el defecto es «todos los derechos reservados»
Los dos con LicenseRef y un texto en licenses/ que explica qué hay, en vez de dejar el campo vacío,
que se lee como «todavía no lo poblamos». Ninguno está hoy en un perfil de imagen; si alguien los
mete, el guardián corta.
De paso queda escrito el texto de `LicenseRef-qorpa-ajena-no-enumerable`, que ya se usaba en
steam-runtime-sniper y no tenía fichero; y `licencias-textos.sh` bajó los canónicos nuevos
(BSL-1.0 para boost, GCC-exception-3.1 que ya hacía falta).
Hueco conocido y anotado en la receta: `XFree86-1.0` (rama del OR de hwdata) se queda sin texto —
SPDX no publica ese identificador, sólo XFree86-1.1, que es otra licencia, y el tarball lo nombra
sin incluirlo. El guardián avisa y no veta, que es correcto: la otra rama del OR es la GPL y su
texto sí está.
NADA SE RE-HASHEA: `license` está fuera de `hash_inputs`. Verificado, no supuesto — `hammer hash`
sobre pigz, lsof y boost después de editarlas devuelve el hash cuyo artefacto YA está en el store.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LCt3ettR4Z7b6wPCBmbvEV
80 lines
5.6 KiB
TOML
80 lines
5.6 KiB
TOML
# OpenSSH 10.3p1 — servidor/cliente SSH desde fuente (Etapa C, LA excepción C del userland Rust).
|
|
#
|
|
# El recorrido de la Etapa C reemplaza busybox pieza por pieza con reimplementaciones Rust maduras
|
|
# (coreutils/findutils/diffutils/ripgrep/netup). OpenSSH es la EXCEPCIÓN deliberada: NO hay servidor
|
|
# SSH en Rust con la madurez/auditoría de OpenSSH (russh/thrussh son librerías cliente, no un sshd de
|
|
# producción), así que la red de servicios se apoya en el OpenSSH portable canónico, construido desde
|
|
# fuente con hammer (no `apk add openssh`). Provee sshd + ssh + ssh-keygen + scp/sftp.
|
|
#
|
|
# DE-ALPINIZADO: build vainilla del tarball portable upstream (cdn.openbsd.org), sin los parches de
|
|
# Alpine (que son para PAM/login.conf/utmp, que aquí NO se usan). Es un SERVICIO del producto, no un
|
|
# input del 4/4 (of_tree) ni una herramienta del toolchain ⇒ no necesita casar byte-a-byte con nada;
|
|
# el criterio es "construye y corre".
|
|
#
|
|
# DEPS (deps.build → materialize como capas overlay en /usr del sandbox):
|
|
# - openssl (recipes/openssl.toml): libcrypto.a estática + headers. sshd enlaza la cripto.
|
|
# - zlib (recipes/zlib.toml): libz.a estática. compresión opcional del transporte.
|
|
# Ambas son no-shared (sólo .a) ⇒ el enlace de OpenSSH es estático por construcción contra ellas; se
|
|
# fuerza LDFLAGS=-static para un sshd/ssh completamente estáticos musl (sin .so que resolver, robusto
|
|
# para un daemon de arranque temprano). getpwnam/getservbyname en musl estático funcionan sin NSS.
|
|
#
|
|
# COMPILADOR: zig cc con zig 0.13.0 (NO 0.16). Igual que openssl/binutils/python3: zig 0.14+ MISCOMPILA
|
|
# binarios musl (regresión 0.14, bisect con flex) y 0.13.0 la esquiva. Coherente además con que
|
|
# libcrypto.a se compiló con el mismo zig 0.13.0.
|
|
#
|
|
# RUNTIME (NO build — se cablea en la card de arje / init, ver Etapa C "servicios"):
|
|
# - usuario de privsep `sshd` en /etc/passwd y el dir /var/empty (root:root, 0711). La privsep es
|
|
# OBLIGATORIA en OpenSSH 10.x.
|
|
# - host keys: generarlas con `ssh-keygen -A` en el primer arranque (por eso el install es
|
|
# `install-nokeys`: NO generamos claves en build-time — serían no-reproducibles y secretas).
|
|
#
|
|
# GOTCHA install: `make install` normal corre host-key + check-config (invoca ssh-keygen/sshd y haría
|
|
# chown a un usuario inexistente fuera de root) ⇒ se usa `install-nokeys`. STRIP_OPT="" desactiva el
|
|
# stripping en la instalación (no dependemos de un `strip` concreto en el sandbox; el binario zig ya
|
|
# sale razonable, y de-strippear es cosmético para un servicio).
|
|
|
|
name = "openssh"
|
|
version = "10.3p1"
|
|
# licencia: LICENCE del tarball pineado. Es una MEZCLA que el propio fichero enumera —BSD-2/3-Clause, ISC, MIT y dominio público— con el resumen «all components are under a BSD licence, or a licence more free than that». Se entrega el fichero entero en vez de una expresión compuesta: la enumeración de upstream no necesita interpretación nuestra
|
|
license = "LicenseRef-openssh"
|
|
|
|
[source]
|
|
tarball = "https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-10.3p1.tar.gz"
|
|
sha256 = "56682a36bb92dcf4b4f016fd8ec8e74059b79a8de25c15d670d731e7d18e45f4"
|
|
|
|
[build]
|
|
compiler = "zig-cc"
|
|
target = "x86_64-linux-musl"
|
|
link = "static"
|
|
zig_version = "0.13.0"
|
|
|
|
[deps]
|
|
build = ["zlib", "openssl", "perl"]
|
|
|
|
[build.phases]
|
|
# --sysconfdir=/etc/ssh: sshd_config/ssh_config viven en /etc/ssh. --with-ssl-dir/--with-zlib=/usr:
|
|
# donde las deps overlayean sus .a + headers. --without-pam/--without-selinux: musl sin PAM, sin SELinux.
|
|
# --with-privsep-path=/var/empty: jaula de privsep. LDFLAGS=-static: binarios musl ESTÁTICOS completos
|
|
# (el target sólo trae el loader musl, no .so de zlib/openssl). --without-hardening: OBLIGATORIO con
|
|
# -static. OpenSSH activa PIE (-fPIE/-pie) por defecto vía "toolchain hardening"; `-pie` GANA sobre
|
|
# `-static` en zig cc/lld ⇒ sin esto el binario sale dinámico (PIE). configure desactiva el PIE
|
|
# automático justo cuando el hardening está off (configure ~L16057: "Turn off automatic PIE when
|
|
# toolchain hardening is off"). Se sacrifica stack-protector/RELRO del servicio — re-endurecer luego.
|
|
#
|
|
# GOTCHA ZIG -static + .so del devfs: el devfs Alpine trae `libz.so` en /usr/lib (zlib runtime base),
|
|
# y `zig cc -static -lz`, con .a y .so presentes, PREFIERE el .so y enlaza DINÁMICO igual (NEEDED
|
|
# libz.so.1) — verificado: `-l:libz.a` da estático puro, `-lz` no. libcrypto se libra sólo porque el
|
|
# devfs no trae libcrypto.so. Para robustez explícita forzamos AMBOS al archivo estático exacto vía
|
|
# `sed` sobre `CHANNELLIBS` del Makefile (único sitio con `-lcrypto`/`-lz`): los .a vienen de las deps
|
|
# overlay en /usr/lib.
|
|
#
|
|
# GOTCHA ZIG -static + libc NATIVO: el sandbox exporta CC="zig cc -mcpu=baseline" SIN `-target`, o sea
|
|
# zig nativo (Alpine musl). En modo nativo `zig cc -static` enlaza el `libc.so` del SISTEMA igual
|
|
# (NEEDED libc.so) en vez del musl embebido de zig — todo lo demás queda estático pero libc no.
|
|
# Override del CC con `-target x86_64-linux-musl`: fuerza el musl bundle de zig en modo estático ⇒
|
|
# binario 100% estático (sin interpreter, sin NEEDED). Mismo triple ABI ⇒ enlaza con las .a nativas
|
|
# (libcrypto.a/libz.a). Se fija en configure (autotools sustituye CC en el Makefile ⇒ compile+link).
|
|
configure = "./configure --prefix=/usr --sysconfdir=/etc/ssh --with-ssl-dir=/usr --with-zlib=/usr --with-privsep-path=/var/empty --without-pam --without-selinux --without-hardening CC='zig cc -mcpu=baseline -target x86_64-linux-musl' LDFLAGS=-static && sed -i '/^CHANNELLIBS=/{s/-lcrypto/-l:libcrypto.a/g;s/-lz/-l:libz.a/g}' Makefile"
|
|
compile = "make -j\"$(nproc)\""
|
|
install = "make install-nokeys DESTDIR=/out STRIP_OPT="
|