Saltar al contenido

El reparto completo, de principio a fin

Un ejemplo real llevado hasta el final: una aplicación con cuatro ventanas, sus permisos repartidos, y el recorrido de decisiones que llevó a cada línea.

La aplicación

Un catálogo de problemas de programación —el mismo caso que el desktop/ de este monorepo—, con cuatro ventanas:

ventana etiqueta qué hace
principal main lista los problemas, abre uno, sincroniza el catálogo
ajustes settings un formulario de preferencias
documento doc-* muestra y edita un problema
vista previa preview renderiza el enunciado en formato enriquecido, que viene del catálogo

La cuarta es la interesante: el enunciado no lo escribiste tú. Viene de un catálogo que se sincroniza, así que es contenido ajeno y merece el trato del nivel 28.2.

El reparto

JSON
// capabilities/base.json — el suelo, para todas{  "identifier": "base",  "description": "Lo mínimo para que una ventana pueda invocar y escuchar. Sin esto no hay puente.",  "windows": ["main", "settings", "doc-*"],  "permissions": ["core:default"]}

Fíjate en que preview no está. No es un olvido: esa ventana no debe poder invocar nada, ni siquiera lo básico. Es la decisión más importante del fichero.

JSON
// capabilities/principal.json{  "identifier": "principal",  "description": "La ventana principal abre proyectos que el usuario elige, y lanza la sincronización del catálogo",  "windows": ["main"],  "platforms": ["macOS", "windows", "linux"],  "permissions": [    "dialog:allow-open",    "opener:allow-open-url",    { "identifier": "fs:allow-read", "allow": [{ "path": "$APPDATA/catalogo/**" }] }  ]}

Cuatro decisiones ahí:

  • dialog:allow-open y no el conjunto por defecto, que además concedería guardar. La principal no guarda con diálogo.
  • opener:allow-open-url acotado, para abrir la documentación en el navegador. El nivel 30 le pondrá ámbito de dominio.
  • Lectura con ámbito al directorio del catálogo, no al de datos entero.
  • Plataformas de escritorio, porque esta ventana no existe en móvil.
JSON
// capabilities/ajustes.json{  "identifier": "ajustes",  "description": "Un formulario. Solo necesita leer y escribir preferencias.",  "windows": ["settings"],  "permissions": ["store:allow-get", "store:allow-set", "store:allow-save"]}

Tres permisos, y ninguno de ficheros. Es la ventana que más se beneficia del reparto: con una capability global tendría diálogos, lectura de disco y apertura de enlaces sin necesitar nada de eso.

JSON
// capabilities/documentos.json{  "identifier": "documentos",  "description": "Cada ventana de documento lee y escribe SU problema, nada más",  "windows": ["doc-*"],  "permissions": [    { "identifier": "fs:allow-read",  "allow": [{ "path": "$APPDATA/catalogo/problemas/**" }] },    { "identifier": "fs:allow-write", "allow": [{ "path": "$APPDATA/catalogo/problemas/**" }] }  ]}

Una decisión discutible y deliberada: el ámbito es todos los problemas, no el suyo. Acotarlo a uno exigiría una capability por ventana generada en tiempo de ejecución, cosa que el modelo declarativo no hace. La alternativa correcta cuando eso importa es la del nivel 14.4: que la escritura no pase por el plugin de ficheros sino por un comando propio que resuelva la ruta desde el identificador del documento. Aquí se acepta el ámbito ancho porque el contenido es del propio usuario.

JSON
// capabilities/vista-previa.json  →  NO EXISTE

Y ésta es la lección del nivel: la ventana de vista previa no tiene fichero. No hay nada que conceder. Si el enunciado que renderiza lleva algo malicioso, se ejecuta en una webview sin ninguna vía hacia el core.

Lo que la vista previa sí puede hacer

Porque tiene que mostrar algo, y ahí está el diseño:

Con un matiz importante que el nivel 31 desarrolla: esa ventana sigue pudiendo hacer peticiones de red desde su JavaScript si la política de contenido lo permite. Quitarle las capabilities cierra la puerta al core y no la de la red — y por eso la política de contenido es el complemento obligatorio.

La comprobación

El reparto se sostiene con cuatro afirmaciones, en la prueba del nivel 28.4:

TXT
main     puede abrir un diálogo             ✓settings NO puede abrir un diálogo          ✓  ← la que importadoc-1    puede escribir en problemas        ✓preview  NO puede invocar nada              ✓  ← la que más importa

Las dos negativas son las que impiden que el reparto se relaje en seis meses sin que nadie se entere.