journal-query CLI, machined, polkit con grants reales, GNOME boot test
- ente-journalctl: bin nuevo en ente-journald-compat. Lee ~/.local/share/ente/journal/index.log, parse timestamp:source:unit:sha, filtra --unit/--source/--since/--grep/--tail, restituye blobs desde CAS y formatea (pretty | --json). Default extrae MESSAGE de journald native. - compat-machined: org.freedesktop.machine1.Manager con ListMachines/GetMachine/Register/Terminate. Lista vacía + NotFound — apps que llaman al boot ya no quedan en timeout. - compat-polkit: query_policy() consulta el bus interno por el cap POLKIT_DECISION_IFACE con blob (pid_be|uid_be|action_id_utf8). Si hay proveedor su byte de respuesta gobierna; si no, default-allow. Anuncia POLKIT_SERVICE_IFACE (separado para evitar recursión). - docs/gnome-boot-test.md: procedimiento end-to-end para arrancar GNOME con ente-zero como PID 1 en QEMU. scripts/build-rootfs.sh overlaya binarios + symlink /init. scripts/run-vm.sh boot QEMU con KVM y GTK. docs/seed-gnome-test.k Card Semilla con genesis para 8 shims + dbus-daemon + NetworkManager + gdm. 8 compat-shims operativos en paralelo cubriendo: logind, hostnamed, timedated, localed, journald, resolved, polkit, machined. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
# Boot test: GNOME bajo Ente #0 (sin systemd)
|
||||
|
||||
Procedimiento para verificar que GNOME 45+ arranca con `ente-zero` como
|
||||
PID 1 y los 8 D-Bus shims (logind, hostnamed, timedated, localed,
|
||||
journald, resolved, polkit, machined) cubren las llamadas que el
|
||||
escritorio realiza durante la sesión.
|
||||
|
||||
## Qué se prueba
|
||||
|
||||
1. **PID 1 boot**: el kernel arranca, mounta initramfs, transfiere control
|
||||
a `/init` que es `ente-zero` con la Card Semilla.
|
||||
2. **Genesis spawning**: ente-zero encarna el bus D-Bus (dbus-daemon),
|
||||
los 8 compat-shims, NetworkManager, y gdm/sddm (display manager).
|
||||
3. **D-Bus interception**: los compat-shims toman los nombres
|
||||
`org.freedesktop.{logind,hostname1,timedate1,locale1,resolve1,
|
||||
PolicyKit1,machine1}` antes que cualquier sondeo de systemd.
|
||||
4. **GNOME session**: gdm autenticación → GNOME shell → settings panels
|
||||
funcionan (Region & Language, Date & Time, About, Network).
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- QEMU (`qemu-system-x86_64`) con KVM.
|
||||
- Imagen base con kernel + GNOME instalados — sugerencia: una Arch Linux
|
||||
o Fedora minimal modificada (más abajo). NixOS también es razonable.
|
||||
- ~10 GiB libre.
|
||||
|
||||
## Esqueleto del rootfs
|
||||
|
||||
`scripts/build-rootfs.sh` genera un overlay sobre una imagen base que:
|
||||
|
||||
1. Compila el workspace en modo release (`cargo build --workspace --release`)
|
||||
2. Copia los binarios a `<rootfs>/usr/local/bin/`:
|
||||
- `ente-zero`
|
||||
- `ente-{logind,hostnamed,timedated,localed,journald,resolved,polkit,machined}-compat`
|
||||
- `ente-echo`, `brainctl`, `busctl`, `ente-journalctl`
|
||||
3. Renombra el `/init` original a `/sbin/init.systemd` (backup)
|
||||
4. Symlink `/init` → `/usr/local/bin/ente-zero`
|
||||
5. Coloca la Card Semilla en `/ente/seed.card.k`
|
||||
6. Desinstala los services systemd que ahora son shims (logind, etc) o
|
||||
los enmascara con `systemctl mask` (en la imagen base, antes de
|
||||
reescribir `/init`)
|
||||
|
||||
## Card Semilla para el boot test
|
||||
|
||||
`/ente/seed.card.k` debe declarar como genesis los Entes esenciales:
|
||||
- D-Bus daemon (`/usr/bin/dbus-daemon --system`)
|
||||
- Los 8 compat-shims
|
||||
- NetworkManager
|
||||
- udev daemon (kernel events ya manejados por nuestro Netlink stream;
|
||||
udev añade reglas de userspace — opcional)
|
||||
- gdm o sddm
|
||||
|
||||
Ejemplo mínimo:
|
||||
|
||||
```kcl
|
||||
import .card
|
||||
|
||||
seed = EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQ_BOOT_SEED_GNOME_TEST_0"
|
||||
label = "boot-gnome-test"
|
||||
provides = [
|
||||
Capability {kind = "Spawn"}
|
||||
Capability {kind = "Journal"}
|
||||
]
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Virtual"}
|
||||
supervision = Supervision {kind = "OneShot"}
|
||||
genesis = [
|
||||
# dbus-daemon — todo lo demás depende de él.
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQ_BOOT_DBUS_DAEMON__________"
|
||||
label = "dbus-daemon"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {
|
||||
kind = "Native"
|
||||
exec = "/usr/bin/dbus-daemon"
|
||||
argv = ["--system", "--nofork"]
|
||||
}
|
||||
supervision = Supervision {
|
||||
kind = "Restart"
|
||||
initial_ms = 100
|
||||
max_ms = 30000
|
||||
}
|
||||
}
|
||||
# Aquí los 8 compat-shims (mismo patrón) ...
|
||||
# Aquí gdm o sddm ...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Boot
|
||||
|
||||
```bash
|
||||
scripts/run-vm.sh /path/to/base.qcow2 /path/to/built-rootfs.iso
|
||||
```
|
||||
|
||||
QEMU arranca con:
|
||||
- `-kernel` el kernel de la imagen base
|
||||
- `-initrd` (opcional) si la imagen no es bootable directa
|
||||
- `-append "init=/usr/local/bin/ente-zero rd.break=initqueue"` para
|
||||
redirigir PID 1 desde el initramfs.
|
||||
- `-display gtk,gl=on` para ver la sesión gráfica.
|
||||
|
||||
## Verificaciones
|
||||
|
||||
### Console
|
||||
- ente-zero arranca como PID 1 (`/proc/1/comm` == `ente-zero`).
|
||||
- Genesis instancia los 8 shims: logs `Ente encarnado label=compat-X`.
|
||||
- D-Bus daemon responde: `busctl list` muestra los nombres tomados por
|
||||
los shims (deberían aparecer como `org.freedesktop.X1`).
|
||||
|
||||
### gdm
|
||||
- Llega al greeter — significa que polkit, logind, hostnamed responden.
|
||||
- Login funciona — verifica que `Inhibit`, `CreateSession`, `ListSessions`
|
||||
no bloquean la pila de PAM.
|
||||
|
||||
### GNOME shell
|
||||
- Settings → About: hostname y OS info pobladas (hostnamed properties).
|
||||
- Settings → Date & Time: timezone correcta (timedated).
|
||||
- Settings → Region & Language: locale actual visible (localed).
|
||||
- Settings → Network: NetworkManager opera, los DNS lookups funcionan
|
||||
(resolved).
|
||||
- "Restart" en menú: invoca `org.freedesktop.login1.Reboot` → llega a
|
||||
nuestro stub → log en journal.
|
||||
|
||||
### Journal
|
||||
- `ente-journalctl --tail 100` muestra mensajes capturados durante el boot.
|
||||
- Filtros `--unit gdm.service` y `--source syslog` funcionan.
|
||||
|
||||
## Limitaciones conocidas
|
||||
|
||||
- **systemd-units**: GNOME no usa systemd unit files directamente, pero
|
||||
algunas apps los crean dinámicamente (e.g., gnome-terminal con
|
||||
`systemd-run --user`). Esas calls fallarán con NotSupported y la app
|
||||
caerá a un fallback no-systemd.
|
||||
- **sd_notify**: services que usan `Type=notify` para anunciar readiness
|
||||
fallan silenciosamente (NOTIFY_SOCKET no se setea). Reemplazables con
|
||||
`Type=simple` y nuestro Supervision::Restart.
|
||||
- **systemd-tmpfiles**: tmpfiles.d no se procesa. Aplicar manualmente
|
||||
o portar el comportamiento a un Ente.
|
||||
- **systemd journal binary export**: nuestro journal usa CAS por hash,
|
||||
no el formato `.journal` binario. Apps que llamen
|
||||
`journalctl --output=export` no son compatibles. `ente-journalctl`
|
||||
cubre los casos típicos.
|
||||
|
||||
## Plan de regresión
|
||||
|
||||
Hacer boot test en CI tras cada cambio en los compat-shims:
|
||||
|
||||
1. `cargo build --workspace --release`
|
||||
2. `scripts/build-rootfs.sh` (overlay sobre imagen base inmutable)
|
||||
3. `scripts/run-vm.sh --headless --timeout 120` con script de comprobación
|
||||
automatizado (xdotool o similar, o screen-shotting).
|
||||
4. Capturar `dmesg` + `ente-journalctl` outputs como artefactos.
|
||||
|
||||
Output esperado en stdout del test:
|
||||
```
|
||||
PASS: ente-zero como PID 1
|
||||
PASS: 8 compat-shims encarnados
|
||||
PASS: gdm greeter mostrado
|
||||
PASS: settings panels operativos
|
||||
```
|
||||
@@ -0,0 +1,155 @@
|
||||
# Card Semilla para el boot test de GNOME bajo Ente #0.
|
||||
#
|
||||
# Este archivo se valida con `kcl run` contra el schema en
|
||||
# crates/ente-card/schema/card.k antes de que ente-zero lo cargue.
|
||||
#
|
||||
# Genesis declara la constelación mínima para que GNOME arranque sin
|
||||
# systemd: D-Bus daemon, los 8 compat-shims, NetworkManager, gdm.
|
||||
|
||||
import .ente_card.schema.card
|
||||
|
||||
# Card "supervisor genérico" reutilizable — dispara un binario con Restart.
|
||||
schema NativeRestart(EnteBase):
|
||||
soma = SomaSpec {
|
||||
rlimits = ResourceLimits {nofile = 16384}
|
||||
}
|
||||
supervision = Supervision {
|
||||
kind = "Restart"
|
||||
initial_ms = 100
|
||||
max_ms = 30000
|
||||
}
|
||||
|
||||
|
||||
# ----- La Semilla -----
|
||||
|
||||
seed = EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTSEEDFRACTAL00"
|
||||
label = "boot-gnome-test"
|
||||
provides = [
|
||||
Capability {kind = "Spawn"}
|
||||
Capability {kind = "Journal"}
|
||||
]
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Virtual"}
|
||||
supervision = Supervision {kind = "OneShot"}
|
||||
|
||||
genesis = [
|
||||
# 1. dbus-daemon — pivote del system bus, todos los demás dependen de él.
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTDBUSDAEMON___"
|
||||
label = "dbus-daemon"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {
|
||||
kind = "Native"
|
||||
exec = "/usr/bin/dbus-daemon"
|
||||
argv = ["--system", "--nofork", "--nopidfile"]
|
||||
}
|
||||
supervision = Supervision {
|
||||
kind = "Restart"
|
||||
initial_ms = 100
|
||||
max_ms = 30000
|
||||
}
|
||||
}
|
||||
|
||||
# 2-9. Los 8 compat-shims D-Bus.
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTLOGIND_______"
|
||||
label = "compat-logind"
|
||||
provides = [Capability {kind = "LegacyLogind"}]
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {
|
||||
kind = "Native"
|
||||
exec = "/usr/local/bin/ente-logind-compat"
|
||||
}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTHOSTNAMED____"
|
||||
label = "compat-hostnamed"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-hostnamed-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTTIMEDATED____"
|
||||
label = "compat-timedated"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-timedated-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTLOCALED______"
|
||||
label = "compat-localed"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-localed-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTJOURNALD_____"
|
||||
label = "compat-journald"
|
||||
provides = [Capability {kind = "Journal"}]
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-journald-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTRESOLVED_____"
|
||||
label = "compat-resolved"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-resolved-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTPOLKIT_______"
|
||||
label = "compat-polkit"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-polkit-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTMACHINED_____"
|
||||
label = "compat-machined"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {kind = "Native", exec = "/usr/local/bin/ente-machined-compat"}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 100, max_ms = 30000}
|
||||
}
|
||||
|
||||
# 10. NetworkManager — la mayoría de distros lo prefieren sobre networkd.
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTNETWORKMGR___"
|
||||
label = "NetworkManager"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {
|
||||
kind = "Native"
|
||||
exec = "/usr/sbin/NetworkManager"
|
||||
argv = ["--no-daemon"]
|
||||
}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 200, max_ms = 30000}
|
||||
}
|
||||
|
||||
# 11. gdm — display manager. GNOME settings panels via gnome-shell.
|
||||
EntityCard {
|
||||
schema_version = 1
|
||||
id = "01KQABOOTTESTGDMDAEMON____"
|
||||
label = "gdm"
|
||||
soma = SomaSpec {}
|
||||
payload = Payload {
|
||||
kind = "Native"
|
||||
exec = "/usr/bin/gdm"
|
||||
argv = ["--no-daemon"]
|
||||
}
|
||||
supervision = Supervision {kind = "Restart", initial_ms = 500, max_ms = 60000}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user