bootstrap: stage1() ensambla el userland mínimo (Lote 5)

Cross-compila musl + busybox con la semilla de Stage 0 (no el zig del host),
ensambla un rootfs FHS por hardlink y lo sella. CLI: `hammer bootstrap stage1`.

- seed_toolchain_dir(store, hash, kind): primitivo sin SeedSpec, para que Stage 1
  resuelva el toolchain desde (seed_hash, kind) sin re-pasar url/sha256
- RootfsHash = hash de CONTENIDO (componentes ordenados + init), no del árbol en
  disco ⇒ reproducible aunque difieran inodes/timestamps
- assemble_rootfs: esqueleto FHS + hydrate de cada componente + /etc/inittab
  provisional (busybox init); descarta el sidecar .hammer del rootfs
- idempotente (no reensambla si el rootfs ya está sellado); anota línea stage 1
- hammerd (receta Cargo) y arje quedan como slots pendientes (plan M2 / ADR 0007)

+3 tests (rootfs_hash determinista/sensible, assemble_rootfs, recetas del repo
parsean y hashean). Workspace verde; el cross-compile real se valida en la VM.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-06-11 00:43:03 +00:00
co-authored by Claude Opus 4.8
parent c5ab7e4502
commit 60a9451a03
4 changed files with 301 additions and 21 deletions
+6 -1
View File
@@ -183,7 +183,12 @@ Diseño completo en [SDD 11 — Bootstrap from-scratch](11-bootstrap.md). Resume
- **Stage 0** ✅ — crate `hammer-bootstrap` + `hammer bootstrap stage0`: ingiere el toolchain
semilla pinned (`SeedSpec`, hash por identidad), verifica sha256 antes de sellar,
idempotente. Cubierto por 4 unit + 1 e2e de CLI (offline, `file://`).
- **Stage 1** — userland mínimo cross-compilado (musl + busybox/toybox + `arje` + `hammerd`).
- **Stage 1** — userland mínimo cross-compilado. Hecho: recetas pinned `musl` 1.2.5 +
`busybox` 1.36.1 (estáticas, zig cc), `hammer bootstrap stage1` que las construye con la
semilla, ensambla el rootfs FHS (hardlink) y lo sella con un `RootfsHash` de contenido +
init provisional (busybox/inittab). Falta: `hammerd` (receta Cargo, sourcing del plan M2) y
sustituir el init por `arje`. El cross-compile real se valida en la VM (los e2e se saltan
sin `.dev-fs`); el manifiesto anota la línea de Stage 1.
- **Stage 2** ☐ — rebuild nativo dentro del rootfs y diff de hashes ⇒ auto-alojamiento
bit-reproducible.
- Reemplazar el init de Alpine por **tu init** (bus por pipes nativo) — habilita el `CRASHED`
+12 -5
View File
@@ -118,12 +118,19 @@ No introduce mecanismo nuevo de build: encadena recetas y persiste el manifiesto
```rust
// hammer-bootstrap
pub fn stage0(seed: &SeedSpec, store: &Store) -> Result<ArtifactHash>; // ✅ toolchain semilla
pub fn stage1(seed: &ArtifactHash, store: &Store) -> Result<RootfsHash>; // ☐ userland mínimo
pub fn stage2(stage1: &RootfsHash, store: &Store) -> Result<VerifyReport>; // ☐ rebuild + diff
pub fn all(seed: &SeedSpec, store: &Store) -> Result<BootstrapManifest>; // ☐
pub fn stage0(seed: &SeedSpec, store: &Store) -> Result<ArtifactHash>; // ✅ toolchain semilla
pub fn stage1(spec: &Stage1Spec, cfg: &BuildConfig, store: &Store)
-> Result<RootfsHash>; // ◑ musl+busybox+init; hammerd ☐
pub fn stage2(stage1: &RootfsHash, store: &Store) -> Result<VerifyReport>; // ☐ rebuild + diff
pub fn all(seed: &SeedSpec, store: &Store) -> Result<BootstrapManifest>; // ☐
```
`stage1` cross-compila `musl` + `busybox` con la semilla (no el zig del host), ensambla un rootfs
FHS por hardlink y lo sella; el `RootfsHash` se deriva del **contenido** (hashes de componentes +
init), no del árbol en disco, así que es reproducible. El PID 1 es el `init` de busybox vía
`/etc/inittab` provisional. Falta `hammerd` (receta Cargo: ya construible por el lab, pendiente su
sourcing pinned + vendor del plan M2) y la sustitución del init por `arje` (ADR 0007).
`SeedSpec { kind, version, url, sha256 }` es la identidad pinned de la semilla; `seed_hash()`
deriva el `ArtifactHash` de `(kind, version, sha256)` — no del `url` ni del host, así que
cualquier espejo del mismo tarball produce el mismo artefacto.
@@ -132,7 +139,7 @@ CLI (implementado lo de Stage 0; el resto pendiente):
```
hammer bootstrap stage0 --url URL --sha256 HEX --version V [--seed zig|musl-cross-make] # ✅
hammer bootstrap stage1 [--target x86_64-linux-musl] #
hammer bootstrap stage1 --seed-hash HASH [--seed zig] [--recipes DIR] # ◑ musl+busybox
hammer bootstrap stage2 --verify # ☐
hammer bootstrap --all # las tres + reporte de reproducibilidad # ☐
```