Skip to content

feat(secrets): smoke de migración legacy aislado + README evidencia (#106 AC2) - #203

Open
sosan wants to merge 3 commits into
egdev6:mainfrom
sosan:feat/secrets-migrate-smoke
Open

sosan wants to merge 3 commits into
egdev6:mainfrom
sosan:feat/secrets-migrate-smoke

Conversation

@sosan

@sosan sosan commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Qué entrega

Ejercita la migración del servicio legacy (criterio AC2 del issue #106) en Secret Service real del CI, respondiendo a la revisión del owner (2026-10-28):

«Confina el smoke a un llavero desechable con aislamiento verificable del bus y del almacenamiento, y sustituye la indicación de ejecutar los tests ignorados directamente en el escritorio por un procedimiento aislado».

Cambios (3 archivos, confinados)

  • src-tauri/src/secrets.rs: smoke #[ignore] linux_legacy_migrate_once_then_legacy_is_gone:
    • Puebla LEGACY_SERVICE (es.egdev.ai-usage) directamente con una clave base de la allowlist (nan_session, sin @; las claves con @ no migran por diseño de get()).
    • get(), con el destino actual vacío, recupera el valor mediante migración (una lectura); el valor queda reescrito en el destino actual (es.egdev.quorb) y el legado devuelve NoEntry.
    • Aislamiento obligatorio: exige QUORB_SECRETS_SMOKE_ISOLATED=1 (exportada solo dentro del dbus-run-session y el gnome-keyring efímero del workflow) y falla antes de tocar nada si no está presente. CleanupGuard se crea antes de cualquier lectura y su Drop vuelve a verificar la variable antes de borrar. La precondición distingue NoEntry de un error de lectura.
    • Se actualizan los comentarios de documentación de ambos smokes: la única vía soportada es el CI aislado, no un escritorio.
  • .github/workflows/linux-ci.yml: el paso «Secret Service smoke» exporta la variable de aislamiento y ejecuta ambos smokes (round trip y migración).
  • docs/linux-l1-evidence/README.md: la migración pasa de «pendiente» a «ejercitada» (run 40651008234) y se documenta la ejecución segura.

Revisión

El cambio fue revisado por un agente rust-reviewer: sin CRITICAL ni HIGH. Se detectaron 1 MEDIUM y 2 LOW, todos corregidos en 9a9764d (reverificación del aislamiento en el Drop del guard, comprobación del aislamiento también en el round trip y documentación del valor sin registrarlo en los logs durante el camino feliz).

Nota

Los cambios no entraron en #176 (ya fusionada); esta PR los aporta sobre main actual (0.8.0), con el diff confinado a los tres archivos.

Resuelve el punto AC2 del issue #106.

sosan added a commit to sosan/quorb that referenced this pull request Oct 28, 2026
…6#203)

El check de CI (Windows) detectaba drift solo en los header tree hashes:
los textos coinciden, cambió la estructura del árbol tras el merge con el
main 0.8.0. Regenerado con node scripts/i18n-inventory.mjs --out.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@egdev6

egdev6 commented Oct 29, 2026

Copy link
Copy Markdown
Owner

@sosan gracias por retomarlo tan rápido. He revisado el diff completo contra main: la precondición que distingue NoEntry de un error de lectura es justo lo que faltaba, y usar una clave base sin @ es correcto. Aun así necesito tres cambios antes de integrarlo.

1. Separar el laboratorio WSL

El cuerpo dice «3 archivos, confinados», pero la PR trae 5: incluye .github/workflows/w3-evidence.yml (501 líneas, el laboratorio de #90) y arrastra unos 27 commits de ese laboratorio desde el main del fork. Añadir un workflow a main es otro alcance: por favor, sácalo de esta PR (por ejemplo, rama nueva desde egdev6/main con solo los commits del smoke) y, si quieres integrarlo, propónlo en su propia PR enlazada a #90.

2. El smoke todavía puede borrar un secreto real

  • El CleanupGuard se crea antes de comprobar que el destino está vacío. Si existe un nan_session real, el assert falla y el Drop borra ese secreto y el legado. Es el caso que señalé en feat(linux): adaptar sesiones, secretos y login CLI nativos #106: mover el guard no basta.
  • La re-verificación de QUORB_SECRETS_SMOKE_ISOLATED en el Drop no protege si la variable está exportada.
  • La precondición no mira el servicio legado: si tenía un valor real, set_password lo sobrescribe.
  • La variable declara el aislamiento, no lo verifica.

Propuesta:

  • Comprobar que el destino actual y el legado están en NoEntry antes de crear el guard, y limpiar solo lo que escribió el test.
  • En el workflow, arrancar gnome-keyring con HOME/XDG_DATA_HOME en un directorio temporal, y que el test compruebe que está en ese entorno (por ejemplo, que XDG_DATA_HOME cuelga del directorio temporal que le pasa el workflow) en lugar de fiarse solo de la variable.

3. Ejecutar el código nuevo

linux-ci.yml solo se lanza a mano y su última ejecución en tu fork es la 40651008234, sobre 0c75fab: el código anterior, sin la variable ni el guard reordenado. Los checks de esta PR no ejecutan los tests #[ignore]. Lanza linux-ci.yml sobre el head de la PR y enlaza esa ejecución en el README y aquí, en lugar de la anterior.

Detalle menor: rustfmt dejó algunos comentarios mal alineados junto a los // gitleaks:allow; si los reubicas al hacer los cambios, se lee mejor.

sosan and others added 3 commits October 31, 2026 00:55
…v6#106, AC2)

Ejercita migrate_legacy() en Secret Service real del CI (run
40651008234) según la revisión del owner (2026-10-28):

- smoke #[ignore] linux_legacy_migrate_once_then_legacy_is_gone: puebla
  LEGACY_SERVICE (es.egdev.ai-usage) con una clave base (nan_session, sin
  @: las claves con @ no migran por diseño), get() la recupera por
  migración, queda reescrita en el destino actual (es.egdev.quorb) y el
  legado devuelve NoEntry. Sin imprimir valores.
- AISLAMIENTO OBLIGATORIO: el smoke exige QUORB_SECRETS_SMOKE_ISOLATED=1
  (definida solo dentro del dbus-run-session + gnome-keyring efímero del
  workflow) y falla antes de tocar nada sin ella — nunca un escritorio
  con llavero real. CleanupGuard creado antes de cualquier lectura y con
  distinción NoEntry vs error de lectura en la precondición.
- linux-ci.yml: el paso "Secret Service smoke" exporta la var de
  aislamiento y corre ambos smokes.
- README de evidencia: la migración pasa de pendiente a ejercitada, con
  el run enlazado y la ejecución segura documentada (solo vía CI aislado,
  no manual en escritorio).

Co-Authored-By: Claude Code <noreply@anthropic.com>
…dev6#106)

Revisión del agente rust-reviewer (2026-10-28), sin CRITICAL/HIGH:

- MEDIUM: el Drop del CleanupGuard re-verifica QUORB_SECRETS_SMOKE_ISOLATED
  antes de borrar; si la precondición de aislamiento falló (entorno con
  llavero real donde la var se filtró y el destino NO estaba vacío), no
  borra nada. El comentario deja claro que la protección real es el
  keyring efímero del CI, no el assert.
- LOW: el round trip (linux_secret_service_round_trip) ahora exige el
  mismo QUORB_SECRETS_SMOKE_ISOLATED=1 antes de tocar nada (coherencia
  doc/código).
- LOW: doc del smoke de migración ajustado — el valor no se loguea en el
  camino feliz (aparece solo en un assert_eq! si algo falla, y es una
  constante de prueba no secreta).

Co-Authored-By: Claude Code <noreply@anthropic.com>
El inventario no se edita a mano: se regenera. Su header declara el
hash del árbol `src-tauri/src/`, que cambia con el smoke de migracion
de secrets. Regenerado y verificado con
`node scripts/i18n-inventory.mjs --check`.

Co-Authored-By: Claude Code <noreply@anthropic.com>
@sosan
sosan force-pushed the feat/secrets-migrate-smoke branch from d9be5b5 to 06131e6 Compare October 31, 2026 00:47
@egdev6

egdev6 commented Oct 31, 2026

Copy link
Copy Markdown
Owner

@sosan, revisé el head 06131e669520f6b077c8d55bca12e6de4c021dc0. El laboratorio WSL ya salió del diff, gracias por separar ese alcance. Quedan cuatro archivos, incluido el hash generado del inventario i18n. Antes de integrar siguen pendientes los otros dos pedidos de la revisión anterior:

  1. Seguridad del smoke y aislamiento. En src-tauri/src/secrets.rs:389 el CleanupGuard todavía se crea antes de comprobar el destino. Si existe un secreto y falla el assert, el Drop borra destino y legado porque la variable de aislamiento sigue en 1. Además, el legado no se comprueba antes de sobrescribirlo. Ambos servicios deben devolver NoEntry antes de crear el guard, y la limpieza debe limitarse a lo que escribió el test. En el workflow, dbus-run-session aísla el bus, pero siguen faltando HOME/XDG_DATA_HOME temporales y una comprobación del entorno desechable: la variable declara aislamiento, no lo verifica. Ajustemos también el README, que hoy garantiza una protección que el código no demuestra.

  2. Evidencia del código actualizado. El README sigue enlazando el run 40651008234, sobre 0c75fab; es también la última ejecución de linux-ci.yml que encontré en el fork, no corresponde al head actual. Los checks de esta PR están verdes, pero no acreditan la ejecución de estos tests #[ignore]. Una vez corregido el aislamiento, ejecuta el workflow sobre el head corregido y enlaza esa ejecución tanto aquí como en el README.

No ejecuté los smokes localmente para no tocar un llavero real. Mantendría la PR sin integrar hasta resolver ambos puntos.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants