diff --git a/recipes/firefox.toml b/recipes/firefox.toml index a46d7e04..4d16baf5 100644 --- a/recipes/firefox.toml +++ b/recipes/firefox.toml @@ -133,16 +133,16 @@ flags = [] # Entra en `hash_inputs` A PROPÓSITO (cambia el contenido del artefacto), y usa `zig objcopy`, que # siempre está en el sandbox ⇒ no agrega una dep de build. strip_debug = true -# ⚠ DEUDA MEDIDA EL 2026-09-05: ESTE ARTEFACTO NO REPRODUCE BIT A BIT ═══════════════════════════ -# `application.ini` del artefacto sellado trae `BuildID=20260905035306`: la FECHA Y HORA del build. -# Dos construcciones de esta misma receta, con el mismo hash, producen bytes distintos — que es -# exactamente el agujero que el invariante de reproducibilidad existe para cerrar, y no se ve en -# `build-state.json` porque el ArtifactHash es input-addressed y no se mueve. -# El arreglo es el que ya usa Alpine: exportar `MOZ_BUILD_DATE` con un valor determinista en las -# fases (su APKBUILD lo deriva de `SOURCE_DATE_EPOCH`; acá el candidato natural es un valor fijo, -# que al vivir en el texto de la fase entra en `hash_inputs` y queda declarado). -# NO se aplica de paso: cambiar una fase re-hashea la receta y cuesta otro build de cuatro horas -# más el re-sellado de `atuq`, que cuelga de ella. Es su propia unidad de trabajo. +# ══ `MOZ_BUILD_DATE`: SIN ESTO EL ARTEFACTO NO REPRODUCE ══════════════════════════════════════ +# El `BuildID` de `application.ini` es, por defecto, la FECHA Y HORA del build. Medido en el +# artefacto sellado del 2026-09-05: `BuildID=20260905035306`. Dos construcciones de esta misma +# receta, con el mismo ArtifactHash, producían bytes distintos — justo el agujero que el invariante +# de reproducibilidad existe para cerrar, y que `build-state.json` no puede ver porque el hash es +# input-addressed y no se mueve por esto. +# +# El valor sale de `SOURCE_DATE_EPOCH`, que el sandbox de hammer YA fija a 1 para todas las recetas. +# Es mejor que una constante escrita a mano: usa el mecanismo de hermeticidad que ya existe, en vez +# de inventar un segundo. Alpine hace exactamente lo mismo en su APKBUILD. [build.phases] configure = ''' @@ -183,6 +183,7 @@ export RUST_TARGET=x86_64-alpine-linux-musl # El `export` con valor vacío es lo que hace llegar la variable PRESENTE y vacía; desexportarla la # dejaría sin definir y volvería al default, que acá es «exigir firma». export MOZ_REQUIRE_SIGNING= +export MOZ_BUILD_DATE="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" # ── LOS PARCHES ROMPEN EL CHECKSUM DE LOS CRATES VENDORIZADOS ───────────────────────────────── # `error: the listed checksum of third_party/rust/zeitstempel/src/unix.rs has changed`. Los crates @@ -275,6 +276,7 @@ export RUST_TARGET=x86_64-alpine-linux-musl # ver la nota en la fase configure # aceptó — 50 minutos de build para descubrirlo al abrir el navegador. Es exactamente la razón por # la que `RUST_TARGET` se repite en las tres fases. export MOZ_REQUIRE_SIGNING= +export MOZ_BUILD_DATE="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" # ídem: ver configure export MOZBUILD_STATE_PATH="$PWD/.mozbuild" export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system export MOZ_NOSPAM=1 @@ -287,6 +289,7 @@ echo "mach build -j$j (MemTotal ${gib} GiB, nproc $n)" install = ''' export RUST_TARGET=x86_64-alpine-linux-musl # ver la nota en la fase configure export MOZ_REQUIRE_SIGNING= # ídem +export MOZ_BUILD_DATE="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" # ídem export MOZBUILD_STATE_PATH="$PWD/.mozbuild" export MACH_BUILD_PYTHON_NATIVE_PACKAGE_SOURCE=system DESTDIR=/out ./mach install @@ -310,6 +313,20 @@ if "MOZ_REQUIRE_SIGNING: false" not in t: "las fases (son shells distintos y mach re-ejecuta configure).") print("guardián: MOZ_REQUIRE_SIGNING = false en el artefacto") PY + +# ── GUARDIÁN: QUE EL BuildID NO SEA UNA FECHA ──────────────────────────────────────────────── +# Mismo razonamiento que el de arriba, y el mismo modo de fallo: si `MOZ_BUILD_DATE` no llega, el +# BuildID vuelve a ser la hora del build y el artefacto deja de reproducir SIN QUE NADA LO DIGA — +# el ArtifactHash es input-addressed y no se mueve por esto, así que `build-state.json` seguiría en +# verde. Se comprueba contra el valor que `SOURCE_DATE_EPOCH=1` obliga. +esperado="$(date -u -d "@${SOURCE_DATE_EPOCH:-1}" +%Y%m%d%H%M%S)" +real="$(sed -n 's/^BuildID=//p' /out/usr/lib/firefox/application.ini)" +if [ "$real" != "$esperado" ]; then + echo "guardián: BuildID=$real y esperaba $esperado — el artefacto NO reproduce." >&2 + echo " Revisá que MOZ_BUILD_DATE se exporte en TODAS las fases." >&2 + exit 1 +fi +echo "guardián: BuildID = $real (determinista, de SOURCE_DATE_EPOCH)" ''' [deps]