---
id: "f5296d8b-6bef-45c4-ac8a-cf6e0f90ae9c"
number: 133
title: "Plugins: contrat de service des assets idea-plugin:// (multi-fichiers ESM) & confinement"
status: "qa"
priority: "high"
sprint: null
links: []
agentRefs: [{"agentId":"b4730d7f-c54d-4736-8a04-c6203aa2fd49","role":"assigned"}]
attachments: []
createdBy: {"kind":"agent","agent_id":"b4730d7f-c54d-4736-8a04-c6203aa2fd49"}
updatedBy: {"kind":"agent","agent_id":"b4730d7f-c54d-4736-8a04-c6203aa2fd49"}
createdAt: 1785702640094
updatedAt: 1785703664966
version: 4
---
Bug diagnostiqué : `crates/app-tauri/src/plugins.rs:504-536` (`asset_allowed`) n'autorise que `main`/`icon` déclarés au manifeste, ou un chemin préfixé `assets/`. Tout import ESM relatif secondaire (`./constants.js`, `./core/x.js`) depuis le `main` est donc rejeté 403 → "Importing a module script failed." côté navigateur. Le SDK (sdk/IdeaSDK/README.md) documente `main: dist/index.js` comme point d'entrée sans jamais imposer un bundle mono-fichier, ce qui sous-entend un support multi-fichiers jamais réellement vérifié (l'exemple hello-plugin est mono-fichier).

Objectif de ce ticket : trancher le contrat d'architecture, PAS l'implémenter.

À décider et documenter :
1. Élargir la politique de service à : tout chemin relatif confiné du package installé, dès lors que `entry.content_hash == hash` (intégrité du package entier déjà vérifiée) ET `entry.lifecycle_state.is_runtime_active()` ET confinement canonicalize (`target.starts_with(root)`, déjà en place lignes 467-483). Ces trois garanties suffisent déjà sans dépendre d'une déclaration par-fichier dans le manifeste.
2. Figer la limite explicite : imports ESM relatifs uniquement, pas de résolution `node_modules`/bare specifiers (hors scope, pas de résolveur de modules à construire) — un plugin qui a des dépendances tierces doit les vendorer en relatif ou les bundler lui-même, à son choix, jamais une obligation d'IdeA.
3. Formaliser le contrat de confinement + désinstallation propre : aucune écriture ne doit jamais sortir de `app_data/plugins/installed/<id>` (pas de pollution project root ni `.ideai/`), et la désinstallation doit être 100% (dossier + entrée registry, zéro résidu), à la manière VSCode.

Livrable : note d'architecture (+ mise à jour de la doc plugin existante si présente) qui fait foi pour les tickets d'implémentation liés (DevBackend, SDK/doc, QA).

Critères d'acceptation :
- Le contrat écrit référence explicitement le code actuel (plugins.rs:504-536) et explique pourquoi hash+lifecycle+confinement remplacent l'allowlist par fichier sans régression de sécurité.
- La limite bare-specifiers/node_modules est tranchée noir sur blanc (in ou out, et pourquoi).
- Le contrat de confinement/désinstallation est écrit explicitement (racine autorisée, ce qui est interdit, ce que "propre" veut dire).