docs(arje): organiza core/ + seeds canónicas + boot reproducible
- crates/core/README.md: agrupamiento lógico de los 31 crates absorbidos
de arje (ente-*) y del protocolo brahman (brahman-*) en 6 grupos —
Init/PID 1, contratos, discovery, IPC+CAS, cerebro, 14 shims compat
systemd. No se movieron crates físicamente (rompería paths
cross-workspace).
- seeds/arje-minimal.card.json: PID1 + /bin/sh, smoke test QEMU.
- seeds/arje-prod.card.json: PID1 + 14 shims compat + tmpfiles/binfmt
one-shots + echo + getty (16 children). Validados con
brahman_card::Card::validate.
- seeds/validate.sh: carga la seed vía ente-zero en dev mode.
- scripts/build-arje-initrd.sh: empaqueta CPIO+gzip newc layout
/init→/sbin/ente-zero, /usr/sbin/ente-*-compat, /ente/seed.card.json,
/bin/{sh,...} (busybox o glibc+ldd). Tested: produce 20 MB initrd OK.
- scripts/run-arje-qemu.sh: qemu-system-x86_64 con KVM auto-detect,
-kernel/-initrd/-append "rdinit=/init console=ttyS0,115200 panic=10".
- docs/arje-boot.md: doc end-to-end — layout initramfs, QEMU (con kernel
del host o externo), GRUB bare metal, Proxmox/libvirt args:, schema
de Card con todas las validaciones, debugging (sockets de
introspección, snapshot/restore, metrics), checklist pre-deploy.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -3,3 +3,4 @@
|
||||
Cargo.lock.bak
|
||||
.DS_Store
|
||||
.claude/
|
||||
/out/
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
# `crates/core/` — Init Arje (absorbido) + Protocolo Brahman
|
||||
|
||||
El directorio agrupa **dos linajes** que se fusionaron al absorberse arje
|
||||
dentro del workspace de brahman:
|
||||
|
||||
| linaje | prefijo | función |
|
||||
| ----------- | ------------ | ------------------------------------------------ |
|
||||
| `arje` | `ente-*` | Init (PID 1), encarnación Linux, compat systemd |
|
||||
| `brahman` | `brahman-*` | Tarjeta canónica, handshake, broker, admin |
|
||||
|
||||
No están en sub-carpetas físicas porque el workspace declara los paths uno
|
||||
a uno en `Cargo.toml` raíz y muchos `Cargo.toml` hijos usan `path =
|
||||
"../ente-X"`. El agrupamiento siguiente es **lógico**: cada crate se
|
||||
encuentra como `crates/core/<nombre>`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Init / PID 1
|
||||
|
||||
| crate | tipo | resumen |
|
||||
| --------------- | ---------- | ------------------------------------------------------------------ |
|
||||
| `ente-zero` | binario | PID 1 del fractal. Bucle primordial (reap + bus + handshake). |
|
||||
| `ente-kernel` | lib | `bootstrap_kernel_surface()`, subreaper, SIGCHLD/uevent streams. |
|
||||
| `ente-soma` | lib (shim) | Re-export sobre `crates/shared/ente-incarnate` (clone+ns+cgroup). |
|
||||
| `ente-snapshot` | lib | `FractalSnapshot` JSON — checkpoint/restore del grafo de Cards. |
|
||||
|
||||
## 2. Contratos canónicos
|
||||
|
||||
| crate | resumen |
|
||||
| ------------------ | -------------------------------------------------------------------- |
|
||||
| `brahman-card` | `Card { soma, payload, flow, permissions, supervision, genesis }`. |
|
||||
| `brahman-card-wit` | Extracción de interfaces WIT de componentes WASM. |
|
||||
| `brahman-cards` | Helpers para construir Cards típicas (consumer/producer/broker). |
|
||||
| `ente-card` | Alias histórico — re-export de `brahman-card` con nombres legacy. |
|
||||
|
||||
## 3. Discovery / Routing
|
||||
|
||||
| crate | resumen |
|
||||
| -------------------- | ------------------------------------------------------------------ |
|
||||
| `brahman-handshake` | Protocolo Init↔módulo (Hello, Ping, ListSessions) postcard/Unix. |
|
||||
| `brahman-broker` | Service locator: empareja `flow.input` ↔ `flow.output` por tipo. |
|
||||
| `brahman-admin` | Socket separado para snapshots de sesiones + matches. |
|
||||
|
||||
## 4. IPC interno + Storage
|
||||
|
||||
| crate | resumen |
|
||||
| ------------- | ----------------------------------------------------------------------- |
|
||||
| `ente-bus` | Unix SOCK_STREAM con framing postcard. `Announce`/`Invoke`/`ListEntes`. |
|
||||
| `ente-cas` | Content-addressed storage SHA-256 (blobs Wasm, audit log). |
|
||||
| `ente-wasm` | Encarna `Payload::Wasm` vía `wasmi` en thread dedicado. |
|
||||
|
||||
## 5. Cerebro / Observabilidad
|
||||
|
||||
| crate | resumen |
|
||||
| ------------- | ------------------------------------------------------------------------ |
|
||||
| `ente-brain` | Rule engine + observer estadístico + audit log con hash chain a CAS. |
|
||||
| `ente-echo` | Ente de prueba — provee `Capability::Endpoint(echo)` para smoke tests. |
|
||||
|
||||
## 6. Compat systemd (shims D-Bus)
|
||||
|
||||
Cada shim es un binario que se anuncia con un nombre well-known
|
||||
`org.freedesktop.X1` y traduce las llamadas al bus interno. Esto permite
|
||||
que GNOME/KDE/aplicaciones legacy arranquen sobre arje sin systemd:
|
||||
|
||||
| binario | reemplaza | nombre D-Bus |
|
||||
| --------------------------- | --------------------- | ----------------------------------- |
|
||||
| `ente-logind-compat` | `systemd-logind` | `org.freedesktop.login1` |
|
||||
| `ente-hostnamed-compat` | `systemd-hostnamed` | `org.freedesktop.hostname1` |
|
||||
| `ente-timedated-compat` | `systemd-timedated` | `org.freedesktop.timedate1` |
|
||||
| `ente-localed-compat` | `systemd-localed` | `org.freedesktop.locale1` |
|
||||
| `ente-journald-compat` | `systemd-journald` | `org.freedesktop.LogControl1` |
|
||||
| `ente-resolved-compat` | `systemd-resolved` | `org.freedesktop.resolve1` |
|
||||
| `ente-polkit-compat` | `polkitd` | `org.freedesktop.PolicyKit1` |
|
||||
| `ente-machined-compat` | `systemd-machined` | `org.freedesktop.machine1` |
|
||||
| `ente-systemd1-compat` | `systemd` (Manager) | `org.freedesktop.systemd1` |
|
||||
| `ente-notify-compat` | `sd_notify` socket | `/run/systemd/notify` (datagram) |
|
||||
| `ente-timer-compat` | `systemd-timer` | (cron-like, sin D-Bus) |
|
||||
| `ente-tmpfiles-compat` | `systemd-tmpfiles` | (aplica tmpfiles.d al boot) |
|
||||
| `ente-binfmt-compat` | `systemd-binfmt` | (registra binfmt_misc handlers) |
|
||||
| `ente-policy-provider` | (interno) | proveedor de decisiones polkit |
|
||||
|
||||
---
|
||||
|
||||
## Crates relacionados fuera de `core/`
|
||||
|
||||
Dependen del Init pero viven en `crates/shared/`:
|
||||
|
||||
- `ente-incarnate` — rutina pura de `clone(2) + namespaces + cgroup +
|
||||
rlimits + cpu_affinity`. Reusable por shipote y supervisores no-PID-1.
|
||||
- `brahman-net` — malla P2P opcional (libp2p) que extiende el handshake.
|
||||
- `brahman-sidecar` — helper `spawn(card)` para que las apps se presenten
|
||||
al Init sin reimplementar el cliente del handshake.
|
||||
|
||||
## Convención de uso
|
||||
|
||||
Para arrancar el Init y ejecutar Cards, ver:
|
||||
|
||||
- **Seeds estándar** en `seeds/`.
|
||||
- **Build de initramfs** con `scripts/build-arje-initrd.sh`.
|
||||
- **Boot en QEMU / bare metal** documentado en `docs/arje-boot.md`.
|
||||
@@ -0,0 +1,317 @@
|
||||
# Booteando arje — initramfs, QEMU y bare metal
|
||||
|
||||
`arje` es el init absorbido por brahman: `ente-zero` corre como PID 1, lee
|
||||
la **Tarjeta Semilla** (`/ente/seed.card.json`), monta `/proc /sys /dev
|
||||
/sys/fs/cgroup`, y encarna recursivamente cada Card declarada en
|
||||
`genesis` vía `ente-incarnate::Incarnator` (`clone(2)` + namespaces + cgroup v2).
|
||||
|
||||
Este documento describe el ciclo completo:
|
||||
|
||||
1. **Layout** del initramfs.
|
||||
2. **Build** del initrd (`scripts/build-arje-initrd.sh`).
|
||||
3. **Boot en QEMU** (`scripts/run-arje-qemu.sh`).
|
||||
4. **Boot en bare metal / VM persistente** (entrada de GRUB).
|
||||
5. **Tarjeta Semilla** — qué pone, qué valida, cómo customizar.
|
||||
6. **Debugging**: tracing, sockets de introspección, snapshot/restore.
|
||||
|
||||
---
|
||||
|
||||
## 1. Layout del initramfs
|
||||
|
||||
El initrd es un **CPIO + gzip** (formato `newc`, estándar Linux). Su raíz:
|
||||
|
||||
```
|
||||
/init wrapper sh, ejecuta /sbin/ente-zero
|
||||
/sbin/ente-zero PID 1
|
||||
/usr/sbin/ente-echo
|
||||
/usr/sbin/ente-policy-provider
|
||||
/usr/sbin/ente-*-compat 13 shims D-Bus (logind, hostnamed, …)
|
||||
/ente/seed.card.json Tarjeta Semilla canónica
|
||||
/bin/{sh,ls,mount,…} busybox-static (o glibc dinámica + libs)
|
||||
/etc, /dev, /proc, /sys, /run mountpoints vacíos
|
||||
/sys/fs/cgroup mountpoint cgroup v2
|
||||
```
|
||||
|
||||
Path canónico de la semilla en **prod**: `/ente/seed.card.json` (ver
|
||||
`crates/core/ente-zero/src/seed.rs`). En **dev** (no PID 1):
|
||||
`./seed.card.json` en el cwd, o se sintetiza una mínima.
|
||||
|
||||
## 2. Build del initrd
|
||||
|
||||
Requisitos host: `cargo`, `cpio`, `gzip`, y opcionalmente `busybox-static`
|
||||
(en Debian/Ubuntu: `apt install busybox-static`).
|
||||
|
||||
```bash
|
||||
# Default: semilla de prod, sale en out/arje.initrd.cpio.gz
|
||||
scripts/build-arje-initrd.sh
|
||||
|
||||
# Customizar:
|
||||
scripts/build-arje-initrd.sh seeds/arje-minimal.card.json out/min.cpio.gz
|
||||
|
||||
# Sin busybox del sistema, apuntar a uno propio:
|
||||
BUSYBOX_BIN=/path/to/busybox scripts/build-arje-initrd.sh
|
||||
|
||||
# Vendorear binarios extra (separados por espacio):
|
||||
EXTRA_BINS="/usr/bin/strace /usr/bin/gdb" scripts/build-arje-initrd.sh
|
||||
```
|
||||
|
||||
El script:
|
||||
|
||||
1. Corre `cargo build --release` para `ente-zero` + los 14 shims compat.
|
||||
2. Valida la seed con `seeds/validate.sh` (parse + `Card::validate`).
|
||||
3. Stage en un tmpdir → copia binarios + crea mountpoints + escribe `/init`.
|
||||
4. Empaqueta `find . | cpio -o -H newc | gzip -9`.
|
||||
|
||||
Tamaño típico: ~15-25 MB descomprimido, 5-8 MB el `.cpio.gz`.
|
||||
|
||||
## 3. Boot en QEMU
|
||||
|
||||
Requisito: un kernel Linux + qemu-system-x86_64.
|
||||
|
||||
### 3a. Con kernel del host
|
||||
|
||||
```bash
|
||||
# Default: usa /boot/vmlinuz-$(uname -r)
|
||||
scripts/run-arje-qemu.sh
|
||||
|
||||
# Con kernel explícito:
|
||||
scripts/run-arje-qemu.sh out/arje.initrd.cpio.gz /boot/vmlinuz-6.6.0
|
||||
```
|
||||
|
||||
El script invoca:
|
||||
|
||||
```
|
||||
qemu-system-x86_64
|
||||
-accel kvm (si /dev/kvm está, fallback tcg)
|
||||
-m 1024 -smp 2
|
||||
-kernel <vmlinuz>
|
||||
-initrd out/arje.initrd.cpio.gz
|
||||
-append "rdinit=/init console=ttyS0,115200 panic=10"
|
||||
-nographic -serial mon:stdio
|
||||
-no-reboot
|
||||
```
|
||||
|
||||
`rdinit=/init` le dice al kernel que el primer programa a ejecutar es
|
||||
nuestro `/init`, no `/sbin/init`. `console=ttyS0,115200` redirige el log
|
||||
del kernel + nuestro tracing a la serial → stdio del host. Salida con
|
||||
`Ctrl-A X`.
|
||||
|
||||
### 3b. Sin kernel del host
|
||||
|
||||
Bajar un kernel mínimo (ej. Ubuntu cloud kernel):
|
||||
|
||||
```bash
|
||||
wget -O /tmp/vmlinuz \
|
||||
https://cloud-images.ubuntu.com/jammy/current/unpacked/jammy-server-cloudimg-amd64-vmlinuz-generic
|
||||
scripts/run-arje-qemu.sh out/arje.initrd.cpio.gz /tmp/vmlinuz
|
||||
```
|
||||
|
||||
O usar el kernel de Alpine (más liviano, ~10 MB):
|
||||
|
||||
```bash
|
||||
wget -O /tmp/vmlinuz \
|
||||
https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/netboot/vmlinuz-lts
|
||||
```
|
||||
|
||||
### 3c. Override del cmdline
|
||||
|
||||
`KERNEL_CMD="ente.log=debug"` se concatena al cmdline. Cosas útiles:
|
||||
|
||||
| flag | efecto |
|
||||
| -------------------------- | --------------------------------------------------- |
|
||||
| `panic=10` | reboot 10 s tras kernel panic (debug) |
|
||||
| `loglevel=7` | log del kernel hasta debug |
|
||||
| `quiet` | silencia banner kernel |
|
||||
| `RUST_LOG=trace` | (no se interpreta; usar env en `/init`) |
|
||||
| `init=/sbin/ente-zero` | salta `/init`, ejecuta directo (no recomendado) |
|
||||
|
||||
`ente-zero` lee `RUST_LOG` y `BRAHMAN_*` del env. Para setearlas, editar
|
||||
`/init` antes de empaquetar, o agregar `-fw_cfg name=opt/foo,...` a qemu.
|
||||
|
||||
### 3d. Smoke test esperado
|
||||
|
||||
Con `seeds/arje-prod.card.json`:
|
||||
|
||||
```
|
||||
ente-zero despierta como PID 1
|
||||
Tarjeta Semilla cargada y validada path=/ente/seed.card.json
|
||||
bus interno escuchando path=/run/ente-bus.sock
|
||||
brahman handshake escuchando (Unix) socket=/run/brahman-init.sock
|
||||
brahman admin escuchando socket=/run/brahman-admin.sock
|
||||
instanciando genesis seed=arje.seed.prod count=16
|
||||
Ente compat-logind encarnado pid=...
|
||||
Ente compat-hostnamed encarnado pid=...
|
||||
...
|
||||
arje# ← shell en tty
|
||||
```
|
||||
|
||||
Con `seeds/arje-minimal.card.json`: solo el shell.
|
||||
|
||||
## 4. Boot en bare metal / VM persistente
|
||||
|
||||
El mismo `.cpio.gz` sirve como initramfs estándar de Linux. Entrada
|
||||
GRUB típica (`/etc/grub.d/40_custom` + `update-grub`):
|
||||
|
||||
```
|
||||
menuentry "arje" {
|
||||
linux /boot/vmlinuz-6.6.0 rdinit=/init console=tty1 panic=10
|
||||
initrd /boot/arje.initrd.cpio.gz
|
||||
}
|
||||
```
|
||||
|
||||
Copiar a `/boot/`:
|
||||
|
||||
```bash
|
||||
sudo cp out/arje.initrd.cpio.gz /boot/arje.initrd.cpio.gz
|
||||
sudo update-grub
|
||||
```
|
||||
|
||||
Para una VM (Proxmox, libvirt, etc.) basta con apuntar el "Direct Kernel
|
||||
Boot" al vmlinuz y al initrd. En Proxmox: editar `/etc/pve/qemu-server/<vmid>.conf`:
|
||||
|
||||
```
|
||||
args: -kernel /boot/vmlinuz-6.6.0 -initrd /boot/arje.initrd.cpio.gz \
|
||||
-append "rdinit=/init console=ttyS0,115200 panic=10"
|
||||
serial0: socket
|
||||
```
|
||||
|
||||
### 4a. Sin pivot_root (initramfs es el rootfs final)
|
||||
|
||||
El initrd actual **no hace pivot_root** — se queda como rootfs. Esto es
|
||||
intencional: arje no asume nada del disco. Para persistencia, las Cards
|
||||
hijas deben montar el FS de disco a demanda (ej. `genesis: [{ label:
|
||||
"mount-data", payload: Native("/bin/mount", ["/dev/sda1", "/mnt"]), … }]`).
|
||||
|
||||
Cuando necesites pivot_root a un FS real (instalación full-disk), agregar
|
||||
un Ente que haga `switch_root` antes de instanciar el resto — pendiente
|
||||
de implementar como `Capability::SwitchRoot`.
|
||||
|
||||
## 5. Tarjeta Semilla — detalles
|
||||
|
||||
### 5a. Seeds estándar
|
||||
|
||||
| seed | uso |
|
||||
| ----------------------------- | ----------------------------------------------------- |
|
||||
| `seeds/arje-minimal.card.json` | PID 1 + 1 shell `/bin/sh`. Smoke test para QEMU. |
|
||||
| `seeds/arje-prod.card.json` | Constelación completa: 14 compat shims + getty. |
|
||||
|
||||
### 5b. Validación
|
||||
|
||||
```bash
|
||||
seeds/validate.sh seeds/arje-prod.card.json
|
||||
```
|
||||
|
||||
El script carga la Card vía `ente_brain::load_card_file()` (que llama a
|
||||
`brahman_card::Card::validate()`) y verifica que `ente-zero` la encarne
|
||||
hasta `instanciando genesis`.
|
||||
|
||||
### 5c. Customizar
|
||||
|
||||
Estructura de un genesis-child:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "<ULID Crockford base32 — no I L O U>",
|
||||
"label": "mi-servicio",
|
||||
"provides": ["Journal"],
|
||||
"requires": [],
|
||||
"permissions": {
|
||||
"networking": "loopback",
|
||||
"filesystem": "read-write",
|
||||
"ipc": { "allow": ["wit-v1"] },
|
||||
"processes": false
|
||||
},
|
||||
"soma": {
|
||||
"namespaces": { "mount": true, "pid": true, "net": false, ...},
|
||||
"rlimits": { "mem_bytes": 268435456 },
|
||||
"cgroup": { "path": "ente.slice/mi-servicio", "cpu_weight": 100 }
|
||||
},
|
||||
"payload": { "Native": { "exec": "/usr/sbin/mi-bin", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon",
|
||||
"priority": "normal",
|
||||
"flow": { "input": [], "output": [] },
|
||||
"genesis": []
|
||||
}
|
||||
```
|
||||
|
||||
Validación clave (`brahman_card::Card::validate`):
|
||||
|
||||
- `schema_version == 1`.
|
||||
- `label` no vacío, ≤ 256 bytes.
|
||||
- ULID válido (Crockford base32, **sin `I L O U`**).
|
||||
- `provides ∩ requires == ∅`.
|
||||
- `Payload::Native.exec` no vacío.
|
||||
- `Payload::Wasm.module_sha256` no todo ceros.
|
||||
- rlimits: `mem_bytes > 0 && < 1 TiB`, `nproc ∈ [1, 65535]`, `nofile ∈ [1, 1M]`.
|
||||
- `cgroup.cpu_weight`, `io_weight ∈ [1, 10000]`.
|
||||
- `flow.input` y `flow.output` con nombres únicos.
|
||||
- Recursivo sobre `genesis`.
|
||||
|
||||
## 6. Debugging
|
||||
|
||||
### 6a. Tracing
|
||||
|
||||
`ente-zero` usa `tracing-subscriber`. Default: `ente_zero=debug,info`.
|
||||
Override con `RUST_LOG`:
|
||||
|
||||
```bash
|
||||
# En el initrd: editar /init antes de empaquetar
|
||||
echo 'export RUST_LOG="trace"' >> wrapper
|
||||
```
|
||||
|
||||
### 6b. Sockets de introspección (Unix, dentro del initrd)
|
||||
|
||||
| socket | servicio |
|
||||
| ---------------------------- | ------------------------------------------------- |
|
||||
| `/run/ente-bus.sock` | bus interno (postcard, `BusRequest::Invoke/...`) |
|
||||
| `/run/brahman-init.sock` | handshake brahman |
|
||||
| `/run/brahman-admin.sock` | snapshots de sesiones + matches |
|
||||
| `/run/ente-brain.sock` | introspección del cerebro |
|
||||
|
||||
Conectar desde un Ente hijo: `socat - UNIX-CONNECT:/run/brahman-admin.sock`.
|
||||
(El initrd debe tener `socat` o equivalente; agregalo con `EXTRA_BINS`.)
|
||||
|
||||
### 6c. Snapshot / restore
|
||||
|
||||
```
|
||||
ente-zero --checkpoint /ente/checkpoint.json # escribe al cerrar
|
||||
ente-zero --restore /ente/checkpoint.json # reconstruye al boot
|
||||
```
|
||||
|
||||
Snapshot adjunto del cerebro: `/ente/checkpoint.brain.json`.
|
||||
|
||||
### 6d. Metrics
|
||||
|
||||
```
|
||||
ente-zero --metrics-addr 127.0.0.1:9911
|
||||
```
|
||||
|
||||
Endpoint Prometheus desde dentro de la VM. Para exponerlo al host bajo
|
||||
QEMU, agregar `-netdev user,hostfwd=tcp::9911-:9911 -device virtio-net,netdev=…`.
|
||||
|
||||
### 6e. Modo DEV en host (sin PID 1)
|
||||
|
||||
`ente-zero` detecta si su PID != 1 y entra en **DEV MODE**: no monta
|
||||
kernel surface, no se vuelve subreaper, sale tras 4 s. Útil para
|
||||
iterar Cards en el host:
|
||||
|
||||
```bash
|
||||
mkdir /tmp/arje-test && cp seeds/arje-minimal.card.json /tmp/arje-test/seed.card.json
|
||||
cd /tmp/arje-test && target/release/ente-zero
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Apéndice — checklist pre-deploy
|
||||
|
||||
- [ ] `cargo build --release -p ente-zero` sin warnings.
|
||||
- [ ] `seeds/validate.sh seeds/arje-prod.card.json` → OK.
|
||||
- [ ] `scripts/build-arje-initrd.sh` produce `out/arje.initrd.cpio.gz`.
|
||||
- [ ] `scripts/run-arje-qemu.sh` arranca y muestra `Tarjeta Semilla cargada
|
||||
y validada` + `instanciando genesis count=16` (o el count que toque).
|
||||
- [ ] Si vas a bare metal: tener un kernel `vmlinuz` rescue (ej. Alpine
|
||||
netboot) en `/boot/` por si arje no levanta.
|
||||
- [ ] Para VMs Proxmox/libvirt: serial console habilitada para ver el
|
||||
arranque sin display.
|
||||
Executable
+140
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env bash
|
||||
# build-arje-initrd.sh — empaqueta ente-zero + shims compat + Tarjeta Semilla
|
||||
# en un initramfs CPIO+gzip listo para arrancar bajo QEMU o como /init real.
|
||||
#
|
||||
# Layout del initrd resultante:
|
||||
# /init → wrapper sh que exec /sbin/ente-zero
|
||||
# /sbin/ente-zero → PID 1
|
||||
# /usr/sbin/ente-*-compat → shims systemd
|
||||
# /usr/sbin/ente-echo, ente-policy-provider
|
||||
# /ente/seed.card.json → Tarjeta Semilla
|
||||
# /bin/{sh,ls,cat,...} → busybox o glibc-static (depende del flag)
|
||||
# /dev, /proc, /sys, /run → puntos de montaje (ente-zero los monta)
|
||||
#
|
||||
# Uso:
|
||||
# scripts/build-arje-initrd.sh [seed.card.json] [out.cpio.gz]
|
||||
#
|
||||
# seed default: seeds/arje-prod.card.json
|
||||
# out default: out/arje.initrd.cpio.gz
|
||||
#
|
||||
# Env:
|
||||
# BUSYBOX_BIN path a un busybox-static (default: $(which busybox))
|
||||
# EXTRA_BINS binarios extra a copiar, separados por espacio
|
||||
#
|
||||
# Requisitos: cpio, gzip, ldd (sólo si no usás busybox-static).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SEED="${1:-seeds/arje-prod.card.json}"
|
||||
OUT="${2:-out/arje.initrd.cpio.gz}"
|
||||
BUSYBOX_BIN="${BUSYBOX_BIN:-$(command -v busybox 2>/dev/null || true)}"
|
||||
EXTRA_BINS="${EXTRA_BINS:-}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$REPO_DIR"
|
||||
|
||||
if [ ! -f "$SEED" ]; then
|
||||
echo "[build-initrd] seed no encontrada: $SEED" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# 1. Build release de ente-zero y todos los compat shims.
|
||||
echo "[build-initrd] cargo build --release de ente-zero + shims"
|
||||
cargo build --release \
|
||||
-p ente-zero \
|
||||
-p ente-echo \
|
||||
-p ente-logind-compat \
|
||||
-p ente-hostnamed-compat \
|
||||
-p ente-timedated-compat \
|
||||
-p ente-localed-compat \
|
||||
-p ente-journald-compat \
|
||||
-p ente-resolved-compat \
|
||||
-p ente-polkit-compat \
|
||||
-p ente-machined-compat \
|
||||
-p ente-systemd1-compat \
|
||||
-p ente-notify-compat \
|
||||
-p ente-timer-compat \
|
||||
-p ente-tmpfiles-compat \
|
||||
-p ente-binfmt-compat \
|
||||
-p ente-policy-provider
|
||||
|
||||
# 2. Validar la seed.
|
||||
if ! seeds/validate.sh "$SEED" >/dev/null 2>&1; then
|
||||
echo "[build-initrd] seed inválida: $SEED" >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# 3. Stage root del initrd.
|
||||
STAGE="$(mktemp -d -t arje-initrd.XXXXXX)"
|
||||
trap 'rm -rf "$STAGE"' EXIT
|
||||
mkdir -p "$STAGE"/{bin,sbin,usr/sbin,etc,ente,proc,sys,dev,run,tmp,sys/fs/cgroup}
|
||||
|
||||
# 4. Copiar binarios arje.
|
||||
install -m 0755 target/release/ente-zero "$STAGE/sbin/ente-zero"
|
||||
for b in ente-echo ente-policy-provider \
|
||||
ente-logind-compat ente-hostnamed-compat ente-timedated-compat \
|
||||
ente-localed-compat ente-journald-compat ente-resolved-compat \
|
||||
ente-polkit-compat ente-machined-compat ente-systemd1-compat \
|
||||
ente-notify-compat ente-timer-compat ente-tmpfiles-compat \
|
||||
ente-binfmt-compat; do
|
||||
install -m 0755 "target/release/$b" "$STAGE/usr/sbin/$b"
|
||||
done
|
||||
|
||||
# 5. Userspace mínimo (sh, ls, mount, mkdir, ...). Dos rutas:
|
||||
# (a) busybox-static apuntado por $BUSYBOX_BIN → 1 binario, todo simlink.
|
||||
# (b) sin busybox → copiar /bin/sh + deps con ldd (libc dinámica).
|
||||
if [ -n "$BUSYBOX_BIN" ] && [ -x "$BUSYBOX_BIN" ]; then
|
||||
echo "[build-initrd] usando busybox-static: $BUSYBOX_BIN"
|
||||
install -m 0755 "$BUSYBOX_BIN" "$STAGE/bin/busybox"
|
||||
( cd "$STAGE/bin" && for app in sh ls cat mount umount mkdir cp mv \
|
||||
echo grep sed awk ps kill sleep insmod modprobe poweroff reboot \
|
||||
sysctl dmesg ip ifconfig; do
|
||||
ln -sf busybox "$app"
|
||||
done )
|
||||
else
|
||||
echo "[build-initrd] sin busybox — copiando /bin/sh + deps via ldd"
|
||||
install -m 0755 /bin/sh "$STAGE/bin/sh"
|
||||
copy_lib() {
|
||||
local lib="$1"
|
||||
[ -f "$lib" ] || return 0
|
||||
local dest="$STAGE${lib}"
|
||||
mkdir -p "$(dirname "$dest")"
|
||||
cp -L "$lib" "$dest"
|
||||
}
|
||||
for b in /bin/sh /bin/ls /bin/cat /bin/mount /bin/umount /bin/mkdir; do
|
||||
[ -x "$b" ] || continue
|
||||
cp -L "$b" "$STAGE${b}"
|
||||
while read -r lib; do copy_lib "$lib"; done < <(
|
||||
ldd "$b" 2>/dev/null | awk '{ for (i=1;i<=NF;i++) if ($i ~ /^\//) print $i }'
|
||||
)
|
||||
done
|
||||
fi
|
||||
|
||||
# 6. Tarjeta Semilla. Path canónico en prod: /ente/seed.card.json
|
||||
install -m 0644 "$SEED" "$STAGE/ente/seed.card.json"
|
||||
|
||||
# 7. /init wrapper. El kernel pasa control a /init; nosotros invocamos
|
||||
# ente-zero como PID 1 real con su env mínimo.
|
||||
cat > "$STAGE/init" <<'EOF'
|
||||
#!/bin/sh
|
||||
# arje /init — kernel → este script → ente-zero (PID 1 lo hereda via exec)
|
||||
export PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
||||
export RUST_LOG="${RUST_LOG:-ente_zero=info,brahman_handshake=info,info}"
|
||||
# ente-zero monta /proc /sys /dev /sys/fs/cgroup él mismo.
|
||||
exec /sbin/ente-zero
|
||||
EOF
|
||||
chmod 0755 "$STAGE/init"
|
||||
|
||||
# 8. Binarios extra a vendorear.
|
||||
if [ -n "$EXTRA_BINS" ]; then
|
||||
for b in $EXTRA_BINS; do
|
||||
[ -x "$b" ] || { echo "[build-initrd] EXTRA_BINS: $b no existe"; exit 4; }
|
||||
install -m 0755 "$b" "$STAGE/usr/sbin/$(basename "$b")"
|
||||
done
|
||||
fi
|
||||
|
||||
# 9. Empaquetar CPIO + gzip. Formato newc (estándar para Linux initramfs).
|
||||
mkdir -p "$(dirname "$OUT")"
|
||||
( cd "$STAGE" && find . -print0 | cpio -o -H newc --null --quiet ) | gzip -9 > "$OUT"
|
||||
echo "[build-initrd] generado: $OUT ($(du -h "$OUT" | cut -f1))"
|
||||
Executable
+90
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
# run-arje-qemu.sh — bootea el initrd de arje bajo qemu-system-x86_64.
|
||||
#
|
||||
# Uso:
|
||||
# scripts/run-arje-qemu.sh [initrd] [kernel]
|
||||
#
|
||||
# Defaults:
|
||||
# initrd out/arje.initrd.cpio.gz
|
||||
# kernel $(uname -r) o /boot/vmlinuz-* (primer match)
|
||||
#
|
||||
# Env:
|
||||
# QEMU binario de qemu (default: qemu-system-x86_64)
|
||||
# KERNEL_CMD extra cmdline kernel (se concatena al fijo)
|
||||
# MEM RAM en MB (default: 1024)
|
||||
# SMP CPUs virtuales (default: 2)
|
||||
# ACCEL kvm|tcg (default: kvm si /dev/kvm existe)
|
||||
# HEADLESS 1 → sin display (consola en stdio)
|
||||
#
|
||||
# El initrd contiene su propio /init → ente-zero corre como PID 1 real.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
INITRD="${1:-out/arje.initrd.cpio.gz}"
|
||||
KERNEL="${2:-}"
|
||||
QEMU="${QEMU:-qemu-system-x86_64}"
|
||||
MEM="${MEM:-1024}"
|
||||
SMP="${SMP:-2}"
|
||||
KERNEL_CMD="${KERNEL_CMD:-}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$REPO_DIR"
|
||||
|
||||
if [ ! -f "$INITRD" ]; then
|
||||
echo "[run-qemu] initrd no encontrado: $INITRD" >&2
|
||||
echo " Generalo primero con: scripts/build-arje-initrd.sh" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ -z "$KERNEL" ]; then
|
||||
# En orden: /boot/vmlinuz-$(uname -r), primer vmlinuz-*, /boot/bzImage.
|
||||
for cand in "/boot/vmlinuz-$(uname -r)" /boot/vmlinuz-* /boot/bzImage*; do
|
||||
if [ -f "$cand" ]; then KERNEL="$cand"; break; fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$KERNEL" ] || [ ! -f "$KERNEL" ]; then
|
||||
echo "[run-qemu] kernel no encontrado." >&2
|
||||
echo " Pasalo como 2do arg o instalá linux-image-amd64." >&2
|
||||
echo " También podés bajar uno: " >&2
|
||||
echo " wget https://kernel.ubuntu.com/...vmlinuz" >&2
|
||||
exit 3
|
||||
fi
|
||||
|
||||
# KVM si está disponible.
|
||||
ACCEL="${ACCEL:-}"
|
||||
if [ -z "$ACCEL" ]; then
|
||||
if [ -e /dev/kvm ] && [ -r /dev/kvm ] && [ -w /dev/kvm ]; then
|
||||
ACCEL="kvm"
|
||||
else
|
||||
ACCEL="tcg"
|
||||
fi
|
||||
fi
|
||||
|
||||
DISPLAY_ARGS=()
|
||||
if [ "${HEADLESS:-0}" = "1" ]; then
|
||||
DISPLAY_ARGS+=( -nographic -serial mon:stdio )
|
||||
KERNEL_CMD="console=ttyS0,115200 $KERNEL_CMD"
|
||||
else
|
||||
DISPLAY_ARGS+=( -nographic -serial mon:stdio )
|
||||
KERNEL_CMD="console=ttyS0,115200 $KERNEL_CMD"
|
||||
fi
|
||||
|
||||
CMDLINE="rdinit=/init panic=10 loglevel=4 $KERNEL_CMD"
|
||||
|
||||
echo "[run-qemu] kernel: $KERNEL"
|
||||
echo "[run-qemu] initrd: $INITRD ($(du -h "$INITRD" | cut -f1))"
|
||||
echo "[run-qemu] accel: $ACCEL"
|
||||
echo "[run-qemu] mem: ${MEM}M, smp: $SMP"
|
||||
echo "[run-qemu] cmdline: $CMDLINE"
|
||||
echo "[run-qemu] (Ctrl-A X en stdio mode para salir)"
|
||||
|
||||
exec "$QEMU" \
|
||||
-accel "$ACCEL" \
|
||||
-m "$MEM" -smp "$SMP" \
|
||||
-kernel "$KERNEL" \
|
||||
-initrd "$INITRD" \
|
||||
-append "$CMDLINE" \
|
||||
"${DISPLAY_ARGS[@]}" \
|
||||
-no-reboot
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZP0M0M0M0M0M0M0M0M1",
|
||||
"lineage": null,
|
||||
"label": "arje.seed.minimal",
|
||||
"provides": ["Spawn", "Journal"],
|
||||
"requires": [],
|
||||
"permissions": {
|
||||
"networking": "none",
|
||||
"filesystem": "read-write",
|
||||
"ipc": { "allow": [] },
|
||||
"processes": true
|
||||
},
|
||||
"soma": {
|
||||
"namespaces": {
|
||||
"mount": false, "pid": false, "net": false,
|
||||
"uts": false, "ipc": false, "user": false, "cgroup": false
|
||||
},
|
||||
"rlimits": { "mem_bytes": null, "nproc": null, "nofile": null },
|
||||
"cgroup": { "path": "ente.slice/zero", "cpu_weight": null, "io_weight": null },
|
||||
"cpu_affinity": null
|
||||
},
|
||||
"payload": "Virtual",
|
||||
"supervision": "OneShot",
|
||||
"lifecycle": "daemon",
|
||||
"priority": "critical",
|
||||
"flow": { "input": [], "output": [] },
|
||||
"genesis": [
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZP0M0M0M0M0M0M0M0M2",
|
||||
"lineage": null,
|
||||
"label": "shell",
|
||||
"provides": [],
|
||||
"requires": [],
|
||||
"permissions": {
|
||||
"networking": "none",
|
||||
"filesystem": "read-write",
|
||||
"ipc": { "allow": [] },
|
||||
"processes": true
|
||||
},
|
||||
"soma": {
|
||||
"namespaces": { "mount": false, "pid": false, "net": false, "uts": false, "ipc": false, "user": false, "cgroup": false },
|
||||
"rlimits": { "mem_bytes": null, "nproc": null, "nofile": null },
|
||||
"cgroup": { "path": "ente.slice/shell", "cpu_weight": null, "io_weight": null },
|
||||
"cpu_affinity": null
|
||||
},
|
||||
"payload": {
|
||||
"Native": {
|
||||
"exec": "/bin/sh",
|
||||
"argv": ["-i"],
|
||||
"envp": [["PATH", "/bin:/usr/bin"], ["TERM", "linux"], ["PS1", "arje# "]]
|
||||
}
|
||||
},
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon",
|
||||
"priority": "high",
|
||||
"flow": { "input": [], "output": [] },
|
||||
"genesis": []
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0M0",
|
||||
"lineage": null,
|
||||
"label": "arje.seed.prod",
|
||||
"provides": ["Spawn", "Journal"],
|
||||
"requires": [],
|
||||
"permissions": {
|
||||
"networking": "loopback",
|
||||
"filesystem": "read-write",
|
||||
"ipc": { "allow": ["wit-v1"] },
|
||||
"processes": true
|
||||
},
|
||||
"soma": {
|
||||
"namespaces": {
|
||||
"mount": false, "pid": false, "net": false,
|
||||
"uts": false, "ipc": false, "user": false, "cgroup": false
|
||||
},
|
||||
"rlimits": { "mem_bytes": null, "nproc": null, "nofile": null },
|
||||
"cgroup": { "path": "ente.slice/zero", "cpu_weight": null, "io_weight": null },
|
||||
"cpu_affinity": null
|
||||
},
|
||||
"payload": "Virtual",
|
||||
"supervision": "OneShot",
|
||||
"lifecycle": "daemon",
|
||||
"priority": "critical",
|
||||
"flow": { "input": [], "output": [] },
|
||||
"genesis": [
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0M1",
|
||||
"lineage": null,
|
||||
"label": "tmpfiles-boot",
|
||||
"provides": [],
|
||||
"requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-tmpfiles-compat", "argv": ["--boot"], "envp": [] } },
|
||||
"supervision": "OneShot",
|
||||
"lifecycle": "oneshot",
|
||||
"priority": "critical",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0M2",
|
||||
"lineage": null,
|
||||
"label": "binfmt-boot",
|
||||
"provides": [],
|
||||
"requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-binfmt-compat", "argv": [], "envp": [] } },
|
||||
"supervision": "OneShot",
|
||||
"lifecycle": "oneshot",
|
||||
"priority": "high",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0H0",
|
||||
"lineage": null,
|
||||
"label": "compat-hostnamed",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-only", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-hostnamed-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0T0",
|
||||
"lineage": null,
|
||||
"label": "compat-timedated",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-only", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-timedated-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0X0",
|
||||
"lineage": null,
|
||||
"label": "compat-localed",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-only", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-localed-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0J0",
|
||||
"lineage": null,
|
||||
"label": "compat-journald",
|
||||
"provides": ["Journal"], "requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-journald-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "high",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0R0",
|
||||
"lineage": null,
|
||||
"label": "compat-resolved",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "outbound", "filesystem": "read-write", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-resolved-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0P0",
|
||||
"lineage": null,
|
||||
"label": "compat-polkit",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-only", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-polkit-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0Q0",
|
||||
"lineage": null,
|
||||
"label": "policy-provider",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-only", "ipc": { "allow": ["wit-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-policy-provider", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0M0",
|
||||
"lineage": null,
|
||||
"label": "compat-machined",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-only", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-machined-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0S0",
|
||||
"lineage": null,
|
||||
"label": "compat-systemd1",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-write", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-systemd1-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "high",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0N0",
|
||||
"lineage": null,
|
||||
"label": "compat-notify",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-notify-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "normal",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0Y0",
|
||||
"lineage": null,
|
||||
"label": "compat-logind",
|
||||
"provides": ["LegacyLogind"], "requires": [],
|
||||
"permissions": { "networking": "loopback", "filesystem": "read-write", "ipc": { "allow": ["dbus-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-logind-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "high",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0Z0",
|
||||
"lineage": null,
|
||||
"label": "compat-timer",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": true },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/compat","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-timer-compat", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 1000, "max": 60000 } },
|
||||
"lifecycle": "daemon", "priority": "low",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0E0",
|
||||
"lineage": null,
|
||||
"label": "echo-smoke",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-only", "ipc": { "allow": ["wit-v1"] }, "processes": false },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/test","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": { "Native": { "exec": "/usr/sbin/ente-echo", "argv": [], "envp": [] } },
|
||||
"supervision": { "Restart": { "initial": 200, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "low",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
},
|
||||
{
|
||||
"schema_version": 1,
|
||||
"id": "01J8YVKZQ0M0M0M0M0M0M0M0G0",
|
||||
"lineage": null,
|
||||
"label": "getty-tty1",
|
||||
"provides": [], "requires": [],
|
||||
"permissions": { "networking": "none", "filesystem": "read-write", "ipc": { "allow": [] }, "processes": true },
|
||||
"soma": { "namespaces": {"mount":false,"pid":false,"net":false,"uts":false,"ipc":false,"user":false,"cgroup":false},
|
||||
"rlimits": {"mem_bytes":null,"nproc":null,"nofile":null},
|
||||
"cgroup": {"path":"ente.slice/getty","cpu_weight":null,"io_weight":null},
|
||||
"cpu_affinity": null },
|
||||
"payload": {
|
||||
"Native": {
|
||||
"exec": "/bin/sh",
|
||||
"argv": ["-i"],
|
||||
"envp": [["PATH", "/usr/sbin:/usr/bin:/sbin:/bin"], ["TERM", "linux"], ["PS1", "arje# "]]
|
||||
}
|
||||
},
|
||||
"supervision": { "Restart": { "initial": 100, "max": 30000 } },
|
||||
"lifecycle": "daemon", "priority": "high",
|
||||
"flow": { "input": [], "output": [] }, "genesis": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Executable
+40
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env bash
|
||||
# Valida una Tarjeta Semilla pasándola por el parser+validate de brahman-card.
|
||||
# Uso: seeds/validate.sh seeds/arje-prod.card.json
|
||||
#
|
||||
# Método: copiamos la Card como `seed.card.json` en un cwd vacío y corremos
|
||||
# ente-zero en dev-mode 4 s. Si carga, valida, e instancia genesis, la
|
||||
# Card es estructuralmente correcta — los binarios de los hijos pueden
|
||||
# faltar en el host (vivirán en /usr/sbin del initrd).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "uso: $0 <ruta/seed.card.json>" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
SEED="$(realpath "$1")"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
BIN="$REPO_DIR/target/release/ente-zero"
|
||||
|
||||
if [ ! -x "$BIN" ]; then
|
||||
echo "[validate] compilando ente-zero (release)…"
|
||||
(cd "$REPO_DIR" && cargo build --quiet --release -p ente-zero)
|
||||
fi
|
||||
|
||||
SCRATCH="$(mktemp -d -t arje-validate.XXXXXX)"
|
||||
trap 'rm -rf "$SCRATCH"' EXIT
|
||||
cp "$SEED" "$SCRATCH/seed.card.json"
|
||||
|
||||
cd "$SCRATCH"
|
||||
timeout 5 "$BIN" 2>&1 | tee /tmp/arje-validate.log | \
|
||||
grep -E "Tarjeta Semilla cargada|semilla inválida|JSON no contiene|Caused by" | head -5
|
||||
|
||||
if grep -q "Tarjeta Semilla cargada y validada" /tmp/arje-validate.log; then
|
||||
echo "[validate] OK: $SEED"
|
||||
exit 0
|
||||
fi
|
||||
echo "[validate] FALLÓ: $SEED" >&2
|
||||
exit 1
|
||||
Reference in New Issue
Block a user