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.
|
||||
"boveda",
|
||||
"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 ──────────────────────────────────────────────────────────────────────
|
||||
# `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
|
||||
@@ -657,6 +690,39 @@ paquetes = [
|
||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||
"boveda",
|
||||
"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 ─────────────────────────────────────────────────
|
||||
# `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
|
||||
@@ -1056,6 +1122,39 @@ paquetes = [
|
||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||
"boveda",
|
||||
"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 ─────────────────────────────────────────────────
|
||||
# `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
|
||||
@@ -1318,6 +1417,39 @@ paquetes = [
|
||||
# y el control de contestar que NO (§7.novies)—. Por eso entran hoy y no antes.
|
||||
"boveda",
|
||||
"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
|
||||
# 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
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# `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 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`
|
||||
# └─ `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 --negative-control
|
||||
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 ───────────────────────────────────────────
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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.
|
||||
|
||||
── 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-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
|
||||
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.
|
||||
|
||||
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)")
|
||||
|
||||
|
||||
# ── 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 = []
|
||||
|
||||
|
||||
@@ -226,7 +323,7 @@ def leer(p):
|
||||
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.
|
||||
try:
|
||||
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.
|
||||
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():
|
||||
control = "--negative-control" in sys.argv
|
||||
control_verbo = "--negative-control-verbo" 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"))
|
||||
permisos = list(host.get("allowed_extensions", []))
|
||||
verbo_extra = None
|
||||
@@ -315,9 +416,15 @@ def main():
|
||||
# lo ve faltar, está contestando que sí en vez de mirar `targets.toml`.
|
||||
sin_perfil = "boveda"
|
||||
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 ──")
|
||||
revisar(permisos, verbo_extra, sin_perfil)
|
||||
revisar(permisos, verbo_extra, sin_perfil, sin_sembrador)
|
||||
|
||||
if control:
|
||||
if any("allowed_extensions" in f for f in fallas):
|
||||
@@ -337,6 +444,12 @@ def main():
|
||||
return 0
|
||||
print("\n✗ el control del perfil NO lo detectó: el sexto chequeo no mide nada")
|
||||
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:
|
||||
print(f"\n✗ {len(fallas)} problema(s)")
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user