atuq §7.duodecies: el sembrador entra a las cuatro imágenes — y cifraba la seed de todos con una palabra pública
El §7.undecies dejó la bóveda declarada y a NADIE capaz de abrirla: ninguna imagen traía un binario que sembrara `pacha_llavero::SEED_IDENTIDAD`. Esta es esa unidad. De las dos formas posibles entra `agora-cli`, y el motivo no es que sea mejor: el wizard `churay-welcome-llimphi` SÍ tiene binario (medido: `src/main.rs` sin `[[bin]]`, o sea que cargo lo descubre), pero decide además backend de IA, dotfiles, fondo de pantalla y chasqui — la experiencia de primer arranque entera, que no se decide dentro de una unidad del navegador. ⚠ Y antes de poder declararlo apareció lo que lo volvía imposible: sin `AGORA_PASSPHRASE`, `Sesion::abrir()` caía en la frase de desarrollo "agora-dev" con un aviso por stderr y un ✓ en pantalla. La cadena que eso toca: frase → Argon2id → ChaCha20-Poly1305 que cifra la seed → la clave con la que `boveda` descifra su base. O sea, en una imagen de escritorio, la bóveda de todo el mundo cerrada con una palabra escrita en el fuente, y nada que falle. Arreglado en tawasuyu (`fd08dc03a`): variable > terminal (se pregunta, sin eco, y DOS veces en la génesis, donde un error de tipeo no se nota hasta que la seed ya no se recupera) > desarrollo sólo si no hay a quién preguntarle. La decisión vive en una función pura con cuatro tests, probada AL REVÉS: con el brazo `Preguntar` borrado falla con `left: Desarrollo / right: Preguntar`. Pin `9967b02c` → `da5fb8968` ⇒ `b3:46529e14`, 1,9 M, sellado en el worker con la guarda PEGADA al build. Mirado por dentro (regla 3) y probado como artefacto, con control negativo: `identity new` + `unlock` deja `user pacha:id:default: 32` en `/proc/keys`, y con la frase equivocada contesta «autenticación fallida» y NO re-siembra. El muro del `Cargo.lock` por cuarta vez, con la causa cambiada: esta vez no la puso quien tocó el lock sino otro agente que metió `shuma-taller` en un `Cargo.toml`. Cerrado en el worker, donde el registro está completo: +1 línea. Y el lock del árbol compartido traía otra vez el malo (índice y árbol con dos versiones distintas, las dos rotas), así que el commit se armó con `commit-tree` sin pasar por el índice. Corrección al §7.undecies: el verbo es `agora-cli unlock`, no `agora-cli identity unlock`. El guardián de coherencia pasa de SEIS lugares a SIETE, con su cuarto control negativo; los cuatro, en verde. Queda: la herencia del llavero de SESIÓN entre procesos hermanos (sin medir — y `/proc/keys` como root no la mide), y `pacha`/`pacha-secretos` en `perfil.servidor` con el mismo hueco.
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -352,6 +352,39 @@ paquetes = [
|
|||||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
"boveda",
|
"boveda",
|
||||||
"shuma-pregunta",
|
"shuma-pregunta",
|
||||||
|
# ── …Y QUIÉN SIEMBRA LA IDENTIDAD CON LA QUE ESA BÓVEDA SE ABRE (SDD 26 §7.duodecies — 2026-09-21)
|
||||||
|
# Declarar al dueño y al diálogo dejó la función ANDANDO y todavía IMPOSIBLE de usar, y esto se
|
||||||
|
# midió el mismo día. `boveda` abre su base con una clave derivada de la seed de identidad, que
|
||||||
|
# `pacha-boveda-llimphi` saca del llavero de SESIÓN bajo `pacha_llavero::SEED_IDENTIDAD`. En todo
|
||||||
|
# tawasuyu esa clave la ESCRIBEN dos binarios —`agora-cli unlock` y el wizard de
|
||||||
|
# bienvenida `churay-welcome-llimphi`—: el primero estaba sellado con `perfiles: []` y además
|
||||||
|
# pineado al 2026-06-18, donde el verbo todavía no existe; el segundo no tiene receta. ⇒ en las
|
||||||
|
# cuatro imágenes `abrir()` daba `Err(boveda-cerrada)` SIEMPRE, y no por falta de desbloqueo:
|
||||||
|
# por falta de CON QUÉ. Es la misma forma de fallo del renglón de arriba una capa más abajo, y
|
||||||
|
# por eso los dos bloques viven juntos: la bóveda sin dueño y el dueño sin identidad se ven igual
|
||||||
|
# desde el navegador — `{"ok":true,"locked":true}`, que es una respuesta exitosa.
|
||||||
|
# `agora-cli` el sembrador: `identity new --name <nombre>` crea la identidad y `unlock` la
|
||||||
|
# deja en el llavero de la sesión. **1,9 M** medidos sobre el artefacto sellado
|
||||||
|
# (`b3:46529e14`), contra los ~43 M de las dos de arriba. Es CLI: no tiene
|
||||||
|
# lanzador ni lo necesita, así que no hay `.desktop` que comprobar acá.
|
||||||
|
# Medido contra el ARTEFACTO, no contra el commit (regla 3): en el worker, con el binario que va
|
||||||
|
# a la imagen, `identity new` + `unlock` deja `user pacha:id:default: 32` en `/proc/keys` — la
|
||||||
|
# seed, sus 32 bytes. Y con el control negativo puesto: con la frase equivocada contesta
|
||||||
|
# «autenticación fallida» y NO re-siembra.
|
||||||
|
# ⚠ NO es el camino de diseño y conviene que quede escrito: el de diseño es el wizard, que pide
|
||||||
|
# la frase en un campo en vez de en una terminal. Pero ese wizard decide además backend de IA,
|
||||||
|
# dotfiles, fondo de pantalla y chasqui — traerlo es decidir la experiencia de primer arranque
|
||||||
|
# entera, y eso no se hace de paso. Ésta hace UNA cosa y es la que el propio tawasuyu nombra como
|
||||||
|
# «la que siembra el login» (comentario de `pacha-secretos`).
|
||||||
|
# ⚠ Y queda un eslabón SIN MEDIR, dicho como tal: el llavero es el de SESIÓN
|
||||||
|
# (`KEY_SPEC_SESSION_KEYRING`), que lo crea el login, y en takana no lo crea nadie —`shadow`
|
||||||
|
# compila `--without-libpam`, así que el `login` de consola no pasa por PAM y `pam_keyinit` no
|
||||||
|
# corre, aunque el módulo viaje en la imagen dentro de `linux-pam`—. De ahí se SIGUE que dos
|
||||||
|
# procesos hermanos puedan no compartir anillo, y entonces desbloquear en una terminal no le
|
||||||
|
# serviría a la app lanzada desde el menú; el camino bueno sería la misma rama de procesos
|
||||||
|
# (desbloquear en consola y lanzar el compositor desde ahí). Eso se mide con el guardián de
|
||||||
|
# metal, no desde acá: `add_key` da EPERM en la jaula y `keyctl` da ENOSYS en el LXC del worker.
|
||||||
|
"agora-cli",
|
||||||
# ── CAPTURA Y STREAMING ──────────────────────────────────────────────────────────────────────
|
# ── CAPTURA Y STREAMING ──────────────────────────────────────────────────────────────────────
|
||||||
# `obs-studio` (2026-09-04). A diferencia de mpv, ésta vive en ESTA COLA y no en el corpus, y no
|
# `obs-studio` (2026-09-04). A diferencia de mpv, ésta vive en ESTA COLA y no en el corpus, y no
|
||||||
# es preferencia: su frontend es Qt6 y las 13 recetas Qt viven sólo en `incoming-kde`. Un qtbase
|
# es preferencia: su frontend es Qt6 y las 13 recetas Qt viven sólo en `incoming-kde`. Un qtbase
|
||||||
@@ -657,6 +690,39 @@ paquetes = [
|
|||||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
"boveda",
|
"boveda",
|
||||||
"shuma-pregunta",
|
"shuma-pregunta",
|
||||||
|
# ── …Y QUIÉN SIEMBRA LA IDENTIDAD CON LA QUE ESA BÓVEDA SE ABRE (SDD 26 §7.duodecies — 2026-09-21)
|
||||||
|
# Declarar al dueño y al diálogo dejó la función ANDANDO y todavía IMPOSIBLE de usar, y esto se
|
||||||
|
# midió el mismo día. `boveda` abre su base con una clave derivada de la seed de identidad, que
|
||||||
|
# `pacha-boveda-llimphi` saca del llavero de SESIÓN bajo `pacha_llavero::SEED_IDENTIDAD`. En todo
|
||||||
|
# tawasuyu esa clave la ESCRIBEN dos binarios —`agora-cli unlock` y el wizard de
|
||||||
|
# bienvenida `churay-welcome-llimphi`—: el primero estaba sellado con `perfiles: []` y además
|
||||||
|
# pineado al 2026-06-18, donde el verbo todavía no existe; el segundo no tiene receta. ⇒ en las
|
||||||
|
# cuatro imágenes `abrir()` daba `Err(boveda-cerrada)` SIEMPRE, y no por falta de desbloqueo:
|
||||||
|
# por falta de CON QUÉ. Es la misma forma de fallo del renglón de arriba una capa más abajo, y
|
||||||
|
# por eso los dos bloques viven juntos: la bóveda sin dueño y el dueño sin identidad se ven igual
|
||||||
|
# desde el navegador — `{"ok":true,"locked":true}`, que es una respuesta exitosa.
|
||||||
|
# `agora-cli` el sembrador: `identity new --name <nombre>` crea la identidad y `unlock` la
|
||||||
|
# deja en el llavero de la sesión. **1,9 M** medidos sobre el artefacto sellado
|
||||||
|
# (`b3:46529e14`), contra los ~43 M de las dos de arriba. Es CLI: no tiene
|
||||||
|
# lanzador ni lo necesita, así que no hay `.desktop` que comprobar acá.
|
||||||
|
# Medido contra el ARTEFACTO, no contra el commit (regla 3): en el worker, con el binario que va
|
||||||
|
# a la imagen, `identity new` + `unlock` deja `user pacha:id:default: 32` en `/proc/keys` — la
|
||||||
|
# seed, sus 32 bytes. Y con el control negativo puesto: con la frase equivocada contesta
|
||||||
|
# «autenticación fallida» y NO re-siembra.
|
||||||
|
# ⚠ NO es el camino de diseño y conviene que quede escrito: el de diseño es el wizard, que pide
|
||||||
|
# la frase en un campo en vez de en una terminal. Pero ese wizard decide además backend de IA,
|
||||||
|
# dotfiles, fondo de pantalla y chasqui — traerlo es decidir la experiencia de primer arranque
|
||||||
|
# entera, y eso no se hace de paso. Ésta hace UNA cosa y es la que el propio tawasuyu nombra como
|
||||||
|
# «la que siembra el login» (comentario de `pacha-secretos`).
|
||||||
|
# ⚠ Y queda un eslabón SIN MEDIR, dicho como tal: el llavero es el de SESIÓN
|
||||||
|
# (`KEY_SPEC_SESSION_KEYRING`), que lo crea el login, y en takana no lo crea nadie —`shadow`
|
||||||
|
# compila `--without-libpam`, así que el `login` de consola no pasa por PAM y `pam_keyinit` no
|
||||||
|
# corre, aunque el módulo viaje en la imagen dentro de `linux-pam`—. De ahí se SIGUE que dos
|
||||||
|
# procesos hermanos puedan no compartir anillo, y entonces desbloquear en una terminal no le
|
||||||
|
# serviría a la app lanzada desde el menú; el camino bueno sería la misma rama de procesos
|
||||||
|
# (desbloquear en consola y lanzar el compositor desde ahí). Eso se mide con el guardián de
|
||||||
|
# metal, no desde acá: `add_key` da EPERM en la jaula y `keyctl` da ENOSYS en el LXC del worker.
|
||||||
|
"agora-cli",
|
||||||
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
||||||
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
||||||
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
||||||
@@ -1056,6 +1122,39 @@ paquetes = [
|
|||||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
"boveda",
|
"boveda",
|
||||||
"shuma-pregunta",
|
"shuma-pregunta",
|
||||||
|
# ── …Y QUIÉN SIEMBRA LA IDENTIDAD CON LA QUE ESA BÓVEDA SE ABRE (SDD 26 §7.duodecies — 2026-09-21)
|
||||||
|
# Declarar al dueño y al diálogo dejó la función ANDANDO y todavía IMPOSIBLE de usar, y esto se
|
||||||
|
# midió el mismo día. `boveda` abre su base con una clave derivada de la seed de identidad, que
|
||||||
|
# `pacha-boveda-llimphi` saca del llavero de SESIÓN bajo `pacha_llavero::SEED_IDENTIDAD`. En todo
|
||||||
|
# tawasuyu esa clave la ESCRIBEN dos binarios —`agora-cli unlock` y el wizard de
|
||||||
|
# bienvenida `churay-welcome-llimphi`—: el primero estaba sellado con `perfiles: []` y además
|
||||||
|
# pineado al 2026-06-18, donde el verbo todavía no existe; el segundo no tiene receta. ⇒ en las
|
||||||
|
# cuatro imágenes `abrir()` daba `Err(boveda-cerrada)` SIEMPRE, y no por falta de desbloqueo:
|
||||||
|
# por falta de CON QUÉ. Es la misma forma de fallo del renglón de arriba una capa más abajo, y
|
||||||
|
# por eso los dos bloques viven juntos: la bóveda sin dueño y el dueño sin identidad se ven igual
|
||||||
|
# desde el navegador — `{"ok":true,"locked":true}`, que es una respuesta exitosa.
|
||||||
|
# `agora-cli` el sembrador: `identity new --name <nombre>` crea la identidad y `unlock` la
|
||||||
|
# deja en el llavero de la sesión. **1,9 M** medidos sobre el artefacto sellado
|
||||||
|
# (`b3:46529e14`), contra los ~43 M de las dos de arriba. Es CLI: no tiene
|
||||||
|
# lanzador ni lo necesita, así que no hay `.desktop` que comprobar acá.
|
||||||
|
# Medido contra el ARTEFACTO, no contra el commit (regla 3): en el worker, con el binario que va
|
||||||
|
# a la imagen, `identity new` + `unlock` deja `user pacha:id:default: 32` en `/proc/keys` — la
|
||||||
|
# seed, sus 32 bytes. Y con el control negativo puesto: con la frase equivocada contesta
|
||||||
|
# «autenticación fallida» y NO re-siembra.
|
||||||
|
# ⚠ NO es el camino de diseño y conviene que quede escrito: el de diseño es el wizard, que pide
|
||||||
|
# la frase en un campo en vez de en una terminal. Pero ese wizard decide además backend de IA,
|
||||||
|
# dotfiles, fondo de pantalla y chasqui — traerlo es decidir la experiencia de primer arranque
|
||||||
|
# entera, y eso no se hace de paso. Ésta hace UNA cosa y es la que el propio tawasuyu nombra como
|
||||||
|
# «la que siembra el login» (comentario de `pacha-secretos`).
|
||||||
|
# ⚠ Y queda un eslabón SIN MEDIR, dicho como tal: el llavero es el de SESIÓN
|
||||||
|
# (`KEY_SPEC_SESSION_KEYRING`), que lo crea el login, y en takana no lo crea nadie —`shadow`
|
||||||
|
# compila `--without-libpam`, así que el `login` de consola no pasa por PAM y `pam_keyinit` no
|
||||||
|
# corre, aunque el módulo viaje en la imagen dentro de `linux-pam`—. De ahí se SIGUE que dos
|
||||||
|
# procesos hermanos puedan no compartir anillo, y entonces desbloquear en una terminal no le
|
||||||
|
# serviría a la app lanzada desde el menú; el camino bueno sería la misma rama de procesos
|
||||||
|
# (desbloquear en consola y lanzar el compositor desde ahí). Eso se mide con el guardián de
|
||||||
|
# metal, no desde acá: `add_key` da EPERM en la jaula y `keyctl` da ENOSYS en el LXC del worker.
|
||||||
|
"agora-cli",
|
||||||
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
# ── VISOR DE IMÁGENES, TAMBIÉN EN LAS CUATRO ─────────────────────────────────────────────────
|
||||||
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
# `swayimg` y no `imv`, que era lo que proponía `docs/plan-apps-usuario-final.md`: imv dibuja con
|
||||||
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
# OpenGL de función fija (`glBegin`/`glOrtho`) y esta distro NO tiene proveedor de GL de
|
||||||
@@ -1318,6 +1417,39 @@ paquetes = [
|
|||||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||||
"boveda",
|
"boveda",
|
||||||
"shuma-pregunta",
|
"shuma-pregunta",
|
||||||
|
# ── …Y QUIÉN SIEMBRA LA IDENTIDAD CON LA QUE ESA BÓVEDA SE ABRE (SDD 26 §7.duodecies — 2026-09-21)
|
||||||
|
# Declarar al dueño y al diálogo dejó la función ANDANDO y todavía IMPOSIBLE de usar, y esto se
|
||||||
|
# midió el mismo día. `boveda` abre su base con una clave derivada de la seed de identidad, que
|
||||||
|
# `pacha-boveda-llimphi` saca del llavero de SESIÓN bajo `pacha_llavero::SEED_IDENTIDAD`. En todo
|
||||||
|
# tawasuyu esa clave la ESCRIBEN dos binarios —`agora-cli unlock` y el wizard de
|
||||||
|
# bienvenida `churay-welcome-llimphi`—: el primero estaba sellado con `perfiles: []` y además
|
||||||
|
# pineado al 2026-06-18, donde el verbo todavía no existe; el segundo no tiene receta. ⇒ en las
|
||||||
|
# cuatro imágenes `abrir()` daba `Err(boveda-cerrada)` SIEMPRE, y no por falta de desbloqueo:
|
||||||
|
# por falta de CON QUÉ. Es la misma forma de fallo del renglón de arriba una capa más abajo, y
|
||||||
|
# por eso los dos bloques viven juntos: la bóveda sin dueño y el dueño sin identidad se ven igual
|
||||||
|
# desde el navegador — `{"ok":true,"locked":true}`, que es una respuesta exitosa.
|
||||||
|
# `agora-cli` el sembrador: `identity new --name <nombre>` crea la identidad y `unlock` la
|
||||||
|
# deja en el llavero de la sesión. **1,9 M** medidos sobre el artefacto sellado
|
||||||
|
# (`b3:46529e14`), contra los ~43 M de las dos de arriba. Es CLI: no tiene
|
||||||
|
# lanzador ni lo necesita, así que no hay `.desktop` que comprobar acá.
|
||||||
|
# Medido contra el ARTEFACTO, no contra el commit (regla 3): en el worker, con el binario que va
|
||||||
|
# a la imagen, `identity new` + `unlock` deja `user pacha:id:default: 32` en `/proc/keys` — la
|
||||||
|
# seed, sus 32 bytes. Y con el control negativo puesto: con la frase equivocada contesta
|
||||||
|
# «autenticación fallida» y NO re-siembra.
|
||||||
|
# ⚠ NO es el camino de diseño y conviene que quede escrito: el de diseño es el wizard, que pide
|
||||||
|
# la frase en un campo en vez de en una terminal. Pero ese wizard decide además backend de IA,
|
||||||
|
# dotfiles, fondo de pantalla y chasqui — traerlo es decidir la experiencia de primer arranque
|
||||||
|
# entera, y eso no se hace de paso. Ésta hace UNA cosa y es la que el propio tawasuyu nombra como
|
||||||
|
# «la que siembra el login» (comentario de `pacha-secretos`).
|
||||||
|
# ⚠ Y queda un eslabón SIN MEDIR, dicho como tal: el llavero es el de SESIÓN
|
||||||
|
# (`KEY_SPEC_SESSION_KEYRING`), que lo crea el login, y en takana no lo crea nadie —`shadow`
|
||||||
|
# compila `--without-libpam`, así que el `login` de consola no pasa por PAM y `pam_keyinit` no
|
||||||
|
# corre, aunque el módulo viaje en la imagen dentro de `linux-pam`—. De ahí se SIGUE que dos
|
||||||
|
# procesos hermanos puedan no compartir anillo, y entonces desbloquear en una terminal no le
|
||||||
|
# serviría a la app lanzada desde el menú; el camino bueno sería la misma rama de procesos
|
||||||
|
# (desbloquear en consola y lanzar el compositor desde ahí). Eso se mide con el guardián de
|
||||||
|
# metal, no desde acá: `add_key` da EPERM en la jaula y `keyctl` da ENOSYS en el LXC del worker.
|
||||||
|
"agora-cli",
|
||||||
# `dunst` es LA OTRA MITAD, y sólo hace falta acá: KDE la atiende con plasma-workspace, GNOME con
|
# `dunst` es LA OTRA MITAD, y sólo hace falta acá: KDE la atiende con plasma-workspace, GNOME con
|
||||||
# gnome-shell y COSMIC con cosmic-notifications; sway no tenía a NADIE escuchando
|
# gnome-shell y COSMIC con cosmic-notifications; sway no tenía a NADIE escuchando
|
||||||
# `org.freedesktop.Notifications`, así que una página que pedía notificar mandaba el mensaje al bus
|
# `org.freedesktop.Notifications`, así que una página que pedía notificar mandaba el mensaje al bus
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#
|
#
|
||||||
# `boveda` abre su base con una clave derivada de la seed de identidad
|
# `boveda` abre su base con una clave derivada de la seed de identidad
|
||||||
# └─ que `pacha-boveda-llimphi` saca del llavero de SESIÓN, clave `pacha_llavero::SEED_IDENTIDAD`
|
# └─ que `pacha-boveda-llimphi` saca del llavero de SESIÓN, clave `pacha_llavero::SEED_IDENTIDAD`
|
||||||
# └─ que en TODO tawasuyu escriben dos binarios: `agora-cli identity unlock`
|
# └─ que en TODO tawasuyu escriben dos binarios: `agora-cli unlock`
|
||||||
# y el onboarding `churay-welcome-llimphi`
|
# y el onboarding `churay-welcome-llimphi`
|
||||||
# └─ `agora-cli` estaba en ninguna imagen · `churay-welcome` no tiene receta
|
# └─ `agora-cli` estaba en ninguna imagen · `churay-welcome` no tiene receta
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -4,9 +4,10 @@
|
|||||||
python3 scripts/test-atuq-boveda-coherente.py
|
python3 scripts/test-atuq-boveda-coherente.py
|
||||||
python3 scripts/test-atuq-boveda-coherente.py --negative-control
|
python3 scripts/test-atuq-boveda-coherente.py --negative-control
|
||||||
python3 scripts/test-atuq-boveda-coherente.py --negative-control-perfil
|
python3 scripts/test-atuq-boveda-coherente.py --negative-control-perfil
|
||||||
|
python3 scripts/test-atuq-boveda-coherente.py --negative-control-sembrador
|
||||||
|
|
||||||
── QUÉ MIRA, Y POR QUÉ ESTE GUARDIÁN EXISTE APARTE ───────────────────────────────────────────
|
── QUÉ MIRA, Y POR QUÉ ESTE GUARDIÁN EXISTE APARTE ───────────────────────────────────────────
|
||||||
Una extensión de `atuq` está enchufada en SEIS lugares distintos, y ninguno da error si falta:
|
Una extensión de `atuq` está enchufada en SIETE lugares distintos, y ninguno da error si falta:
|
||||||
|
|
||||||
manifest.json el id que la extensión declara
|
manifest.json el id que la extensión declara
|
||||||
distribution/policies.json la política que la instala
|
distribution/policies.json la política que la instala
|
||||||
@@ -14,6 +15,7 @@ Una extensión de `atuq` está enchufada en SEIS lugares distintos, y ninguno da
|
|||||||
atuq.cfg las preferencias que la acompañan
|
atuq.cfg las preferencias que la acompañan
|
||||||
recipes/puriy-costura.toml el COMMIT del host, que decide si sus verbos existen
|
recipes/puriy-costura.toml el COMMIT del host, que decide si sus verbos existen
|
||||||
docs/state/targets.toml quién DECLARA al dueño y al diálogo en las imágenes
|
docs/state/targets.toml quién DECLARA al dueño y al diálogo en las imágenes
|
||||||
|
recipes/agora-cli.toml quién puede SEMBRAR la identidad con la que la base se abre
|
||||||
|
|
||||||
Si falta la política, la extensión no se instala y el usuario ve un navegador sin la función. Si
|
Si falta la política, la extensión no se instala y el usuario ve un navegador sin la función. Si
|
||||||
falta el permiso del host, la extensión se instala y **se conecta a nada** —`connectNative` falla
|
falta el permiso del host, la extensión se instala y **se conecta a nada** —`connectNative` falla
|
||||||
@@ -23,17 +25,21 @@ extensión conecta, manda `vault.match` y recibe «verbo desconocido» —que `f
|
|||||||
bóveda» y se calla—. Y si `boveda` y `shuma-pregunta` no están declaradas en el perfil, la
|
bóveda» y se calla—. Y si `boveda` y `shuma-pregunta` no están declaradas en el perfil, la
|
||||||
extensión se instala, conecta, manda `vault.match` y el host contesta `{"ok":true,"locked":true}`
|
extensión se instala, conecta, manda `vault.match` y el host contesta `{"ok":true,"locked":true}`
|
||||||
—«cerrada», que es una respuesta EXITOSA— porque del otro lado del socket no hay nadie: el dueño
|
—«cerrada», que es una respuesta EXITOSA— porque del otro lado del socket no hay nadie: el dueño
|
||||||
está sellado y en ninguna imagen. Ninguno de los cinco se ve como un error: se ven como «no anda».
|
está sellado y en ninguna imagen. Y si la imagen no trae un sembrador de identidad, el dueño SÍ
|
||||||
|
está, abre su ventana, dice por qué no hay bóveda… y el navegador vuelve a ver `locked:true` —
|
||||||
|
correcto y para siempre, porque nadie tiene con qué desbloquearla (§7.undecies).
|
||||||
|
Ninguno de los seis se ve como un error: se ven como «no anda».
|
||||||
|
|
||||||
Éste NO reemplaza al guardián de metal (servidor HTTP, navegador real, login real, el diálogo de
|
Éste NO reemplaza al guardián de metal (servidor HTTP, navegador real, login real, el diálogo de
|
||||||
consentimiento a la vista). Lo precede: mide lo que se puede medir sin construir nada, en un
|
consentimiento a la vista). Lo precede: mide lo que se puede medir sin construir nada, en un
|
||||||
segundo, y ahorra descubrir en metal un renglón que faltaba en un JSON.
|
segundo, y ahorra descubrir en metal un renglón que faltaba en un JSON.
|
||||||
|
|
||||||
── LOS TRES CONTROLES NEGATIVOS, UNO POR AFIRMACIÓN ──────────────────────────────────────────
|
── LOS CUATRO CONTROLES NEGATIVOS, UNO POR AFIRMACIÓN ────────────────────────────────────────
|
||||||
`--negative-control` saca el permiso del host de una copia en memoria y exige que esto lo detecte.
|
`--negative-control` saca el permiso del host de una copia en memoria y exige que esto lo detecte.
|
||||||
`--negative-control-verbo` le manda al quinto chequeo un verbo inventado y exige lo mismo.
|
`--negative-control-verbo` le manda al quinto chequeo un verbo inventado y exige lo mismo.
|
||||||
`--negative-control-perfil` saca a `boveda` de los cuatro perfiles de escritorio, también en
|
`--negative-control-perfil` saca a `boveda` de los cuatro perfiles de escritorio, también en
|
||||||
memoria, y exige que el sexto lo vea. Sin ellos, un guardián que siempre dice que sí se vería
|
memoria, y exige que el sexto lo vea. `--negative-control-sembrador` hace lo mismo con `agora-cli`
|
||||||
|
y exige que el séptimo lo vea. Sin ellos, un guardián que siempre dice que sí se vería
|
||||||
idéntico a uno que funciona.
|
idéntico a uno que funciona.
|
||||||
|
|
||||||
Y el quinto chequeo trae además un control POSITIVO —`sct.observe`, que el host pineado tiene que
|
Y el quinto chequeo trae además un control POSITIVO —`sct.observe`, que el host pineado tiene que
|
||||||
@@ -209,6 +215,97 @@ def revisar_los_perfiles(sin_esta=None):
|
|||||||
bien(f"{perfil} declara el dueño y el diálogo ({RAIZ_CONTROL} de control)")
|
bien(f"{perfil} declara el dueño y el diálogo ({RAIZ_CONTROL} de control)")
|
||||||
|
|
||||||
|
|
||||||
|
# ── 10. EL SÉPTIMO LUGAR: ¿hay en la imagen alguien capaz de SEMBRAR la identidad? ────────────
|
||||||
|
# El sexto lugar pregunta si el DUEÑO de la base está en la imagen. Éste pregunta lo que queda
|
||||||
|
# debajo y es lo que costó el §7.undecies: el dueño abre la bóveda con una clave derivada de la
|
||||||
|
# seed de identidad, que saca del llavero de sesión (`pacha_llavero::SEED_IDENTIDAD`). Si nadie
|
||||||
|
# la sembró, `abrir()` da `Err(boveda-cerrada)` SIEMPRE — no «todavía no la desbloqueaste»: nunca.
|
||||||
|
#
|
||||||
|
# Y el 2026-09-21, en las cuatro imágenes, no había con qué: en todo tawasuyu sólo DOS binarios
|
||||||
|
# escriben esa clave —`agora-cli identity unlock` y el onboarding `churay-welcome-runner`—, y
|
||||||
|
# `agora-cli` estaba sellado con `perfiles: []` (en ninguna imagen) y además pineado a un commit
|
||||||
|
# de junio donde el verbo todavía no existía, mientras que `churay-welcome` no tiene receta.
|
||||||
|
#
|
||||||
|
# Se comprueba en los dos planos, porque fallan distinto y los dos en silencio:
|
||||||
|
# a) el COMMIT que la receta pinea sabe sembrar (si no: «unknown subcommand», o peor, un binario
|
||||||
|
# que hace otra cosa con el mismo nombre);
|
||||||
|
# b) algún perfil de escritorio lo DECLARA (si no: sellado ≠ instalado, la lección de `foot`).
|
||||||
|
SEMBRADORES = {"agora-cli": os.path.join(ROOT, "recipes/agora-cli.toml")}
|
||||||
|
# Lo que un sembrador TIENE que hacer, leído del commit pineado y no de la memoria: guardar la
|
||||||
|
# seed bajo la constante canónica. Un `identity unlock` que no llame a esto no siembra nada.
|
||||||
|
SIEMBRA = "guardar(pacha_llavero::SEED_IDENTIDAD"
|
||||||
|
# El control POSITIVO del grep, por lo mismo de siempre: este chequeo espera ENCONTRAR, y un
|
||||||
|
# «no encontré» puede ser una ausencia o un patrón equivocado. La constante se define en
|
||||||
|
# `pacha-llavero` y tiene que estar en cualquier commit del monorepo.
|
||||||
|
SIEMBRA_CONTROL = 'SEED_IDENTIDAD: &str'
|
||||||
|
|
||||||
|
|
||||||
|
def pin_de(receta):
|
||||||
|
with open(receta, encoding="utf-8") as f:
|
||||||
|
m = re.search(r'^commit\s*=\s*"([0-9a-f]{7,40})"', f.read(), re.M)
|
||||||
|
return m.group(1) if m else None
|
||||||
|
|
||||||
|
|
||||||
|
def hay_en(commit, patron):
|
||||||
|
r = subprocess.run(
|
||||||
|
["git", "-C", TAWASUYU, "grep", "-qF", patron, commit, "--", "*.rs"],
|
||||||
|
capture_output=True,
|
||||||
|
)
|
||||||
|
return r.returncode == 0
|
||||||
|
|
||||||
|
|
||||||
|
def revisar_el_sembrador(sin_sembrador=None):
|
||||||
|
if not os.path.isdir(os.path.join(TAWASUYU, ".git")):
|
||||||
|
mal(f"no hay clon de tawasuyu en {TAWASUYU}: el séptimo lugar queda SIN COMPROBAR "
|
||||||
|
f"(se cambia con TAWASUYU=/ruta)")
|
||||||
|
return
|
||||||
|
|
||||||
|
# a) el commit pineado sabe sembrar
|
||||||
|
for nombre, receta in SEMBRADORES.items():
|
||||||
|
if not os.path.exists(receta):
|
||||||
|
mal(f"no existe {os.path.relpath(receta, ROOT)}: {nombre} no está en el corpus")
|
||||||
|
continue
|
||||||
|
commit = pin_de(receta)
|
||||||
|
if not commit:
|
||||||
|
mal(f"{os.path.relpath(receta, ROOT)} no pinea ningún commit")
|
||||||
|
continue
|
||||||
|
if subprocess.run(["git", "-C", TAWASUYU, "cat-file", "-e", f"{commit}^{{commit}}"],
|
||||||
|
capture_output=True).returncode != 0:
|
||||||
|
mal(f"el clon de tawasuyu no conoce el pin {commit[:9]} de {nombre}: "
|
||||||
|
f"hace falta un `git fetch` antes de creerle a este guardián")
|
||||||
|
continue
|
||||||
|
if not hay_en(commit, SIEMBRA_CONTROL):
|
||||||
|
mal(f"CONTROL ROTO: {SIEMBRA_CONTROL!r} tampoco aparece en {commit[:9]}. El grep mira "
|
||||||
|
f"el sitio equivocado y su «no está» no prueba nada")
|
||||||
|
continue
|
||||||
|
if hay_en(commit, SIEMBRA):
|
||||||
|
bien(f"{nombre} pineado ({commit[:9]}) SÍ siembra {SIEMBRA[:-1]}…)")
|
||||||
|
else:
|
||||||
|
mal(f"{nombre} pineado ({commit[:9]}) NO siembra la seed de identidad: la bóveda "
|
||||||
|
f"contesta `boveda-cerrada` siempre y nadie tiene con qué abrirla")
|
||||||
|
|
||||||
|
# b) alguien lo declara en cada perfil de escritorio
|
||||||
|
try:
|
||||||
|
with open(TARGETS, "rb") as f:
|
||||||
|
perfiles = tomllib.load(f)["perfil"]
|
||||||
|
except Exception as e:
|
||||||
|
mal(f"no se pudo leer {os.path.relpath(TARGETS, ROOT)} ({e})")
|
||||||
|
return
|
||||||
|
for perfil in PERFILES_ESCRITORIO:
|
||||||
|
raices = list(perfiles.get(perfil, {}).get("paquetes", []))
|
||||||
|
if sin_sembrador:
|
||||||
|
raices = [r for r in raices if r != sin_sembrador]
|
||||||
|
if RAIZ_CONTROL not in raices:
|
||||||
|
mal(f"CONTROL ROTO: {perfil} no declara {RAIZ_CONTROL}, así que lo de abajo no mide")
|
||||||
|
continue
|
||||||
|
presentes = [n for n in SEMBRADORES if n in raices]
|
||||||
|
if presentes:
|
||||||
|
bien(f"{perfil} trae un sembrador de identidad ({', '.join(presentes)})")
|
||||||
|
else:
|
||||||
|
mal(f"{perfil} NO trae ningún sembrador de identidad ({'/'.join(SEMBRADORES)}): la "
|
||||||
|
f"bóveda está declarada y NADIE puede abrirla — `locked:true` para siempre")
|
||||||
|
|
||||||
|
|
||||||
fallas = []
|
fallas = []
|
||||||
|
|
||||||
|
|
||||||
@@ -226,7 +323,7 @@ def leer(p):
|
|||||||
return f.read()
|
return f.read()
|
||||||
|
|
||||||
|
|
||||||
def revisar(permisos_host, verbo_extra=None, sin_perfil=None):
|
def revisar(permisos_host, verbo_extra=None, sin_perfil=None, sin_sembrador=None):
|
||||||
# 1. La extensión existe y declara el id que todos los demás nombran.
|
# 1. La extensión existe y declara el id que todos los demás nombran.
|
||||||
try:
|
try:
|
||||||
m = json.loads(leer("extensions/boveda/manifest.json"))
|
m = json.loads(leer("extensions/boveda/manifest.json"))
|
||||||
@@ -293,11 +390,15 @@ def revisar(permisos_host, verbo_extra=None, sin_perfil=None):
|
|||||||
# 9. Y el sexto, que vive en el manifiesto de objetivo: quién la pone en la imagen.
|
# 9. Y el sexto, que vive en el manifiesto de objetivo: quién la pone en la imagen.
|
||||||
revisar_los_perfiles(sin_perfil)
|
revisar_los_perfiles(sin_perfil)
|
||||||
|
|
||||||
|
# 10. Y el séptimo: quién puede sembrar la identidad con la que esa bóveda se abre.
|
||||||
|
revisar_el_sembrador(sin_sembrador)
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
control = "--negative-control" in sys.argv
|
control = "--negative-control" in sys.argv
|
||||||
control_verbo = "--negative-control-verbo" in sys.argv
|
control_verbo = "--negative-control-verbo" in sys.argv
|
||||||
control_perfil = "--negative-control-perfil" in sys.argv
|
control_perfil = "--negative-control-perfil" in sys.argv
|
||||||
|
control_sembrador = "--negative-control-sembrador" in sys.argv
|
||||||
host = json.loads(leer("native-messaging/puriy_costura.json"))
|
host = json.loads(leer("native-messaging/puriy_costura.json"))
|
||||||
permisos = list(host.get("allowed_extensions", []))
|
permisos = list(host.get("allowed_extensions", []))
|
||||||
verbo_extra = None
|
verbo_extra = None
|
||||||
@@ -315,9 +416,15 @@ def main():
|
|||||||
# lo ve faltar, está contestando que sí en vez de mirar `targets.toml`.
|
# lo ve faltar, está contestando que sí en vez de mirar `targets.toml`.
|
||||||
sin_perfil = "boveda"
|
sin_perfil = "boveda"
|
||||||
print(f"⚠ control negativo: se saca {sin_perfil} de los perfiles de escritorio")
|
print(f"⚠ control negativo: se saca {sin_perfil} de los perfiles de escritorio")
|
||||||
|
sin_sembrador = None
|
||||||
|
if control_sembrador:
|
||||||
|
# El sembrador, sacado de la misma copia en memoria: si el séptimo chequeo no lo ve
|
||||||
|
# faltar, está contestando que sí en vez de mirar quién puede abrir la bóveda.
|
||||||
|
sin_sembrador = "agora-cli"
|
||||||
|
print(f"⚠ control negativo: se saca {sin_sembrador} de los perfiles de escritorio")
|
||||||
|
|
||||||
print(f"── la bóveda en atuq ──")
|
print(f"── la bóveda en atuq ──")
|
||||||
revisar(permisos, verbo_extra, sin_perfil)
|
revisar(permisos, verbo_extra, sin_perfil, sin_sembrador)
|
||||||
|
|
||||||
if control:
|
if control:
|
||||||
if any("allowed_extensions" in f for f in fallas):
|
if any("allowed_extensions" in f for f in fallas):
|
||||||
@@ -337,6 +444,12 @@ def main():
|
|||||||
return 0
|
return 0
|
||||||
print("\n✗ el control del perfil NO lo detectó: el sexto chequeo no mide nada")
|
print("\n✗ el control del perfil NO lo detectó: el sexto chequeo no mide nada")
|
||||||
return 1
|
return 1
|
||||||
|
if control_sembrador:
|
||||||
|
if any("sembrador de identidad" in f and "NO trae" in f for f in fallas):
|
||||||
|
print("\n✓ el control negativo del sembrador lo detectó")
|
||||||
|
return 0
|
||||||
|
print("\n✗ el control del sembrador NO lo detectó: el séptimo chequeo no mide nada")
|
||||||
|
return 1
|
||||||
if fallas:
|
if fallas:
|
||||||
print(f"\n✗ {len(fallas)} problema(s)")
|
print(f"\n✗ {len(fallas)} problema(s)")
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
Reference in New Issue
Block a user