chore(tickets): synchronise index/carnets tickets #131-#139 + note mémoire assets/persistance plugins

État runtime .ideai séparé du code (index, counter, carnets, note mémoire
plugin-asset-serving-and-owned-storage-contracts). Purge des tickets obsolètes
51/63/66.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-03 11:06:30 +02:00
parent 171c6c923c
commit 59d81851e9
28 changed files with 557 additions and 116 deletions

View File

@ -0,0 +1,26 @@
---
issueRef: "#135"
version: 4
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
updatedAt: 1785708498776
---
## Audit QA
- `install_from_directory` : audit confirme qu'avant correctif le store ne rejetait pas explicitement les symlinks source ; il les ignorait. Le correctif fait maintenant échouer l'installation sur toute entrée symlink ou unsupported dans l'arbre source.
- `install_from_archive` : audit confirme un trou réel de confinement avant correctif. L'extraction reposait entièrement sur `unzip` sans validation applicative des entrées. Le correctif remplace cette extraction par une lecture Rust confinée qui rejette les entrées `../`/absolues via `enclosed_name()` et refuse explicitement les symlinks d'archive.
- Confinement d'écriture : après correctif, aucune écriture d'install ne sort de `app_data/plugins/_staging/...` puis `app_data/plugins/installed/<id>` ; le test `../../../../outside.txt` prouve l'absence d'écriture hors racine.
- `hash_dir` / collecte fichiers : durci pour échouer si un package contient encore un symlink ou une entrée non supportée, au lieu de l'ignorer.
- `plugin_uninstall` / `remove_package` : audit confirmé par test multifichier. La désinstallation supprime le dossier entier, retire l'entrée registry et laisse le runtime catalog vide.
## Tests ajoutés/ajustés
- `plugin::tests::install_from_directory_rejects_source_symlink`
- `plugin::tests::install_from_archive_rejects_parent_traversal_without_writing_outside_stage`
- `plugin::tests::install_from_archive_rejects_symlink_entries`
- `plugin_install_load::uninstall_multifile_plugin_removes_package_registry_and_runtime_residue`
- Stabilisation des tests SDK `hello-plugin` : fixture matérialisée avec `dist/index.js` dans un temp dir pour supprimer une dépendance implicite à un build préalable.
## Verdict
- Correctif confinement install/uninstall validé.
- `cargo test -p infrastructure -p application -p app-tauri` vert avec `CARGO_HOME=/tmp/idea-cargo-home` dans cet environnement.

View File

@ -0,0 +1,31 @@
---
id: "13442dae-7860-45e3-9287-31b9bde19170"
number: 135
title: "Plugins: audit confinement install & désinstallation 100% propre"
status: "qa"
priority: "high"
sprint: null
links: [{"target":"#133","kind":"dependsOn"}]
agentRefs: [{"agentId":"ab328d90-c307-4771-a3b6-6c56089c8506","role":"assigned"}]
attachments: []
createdBy: {"kind":"agent","agent_id":"b4730d7f-c54d-4736-8a04-c6203aa2fd49"}
updatedBy: {"kind":"agent","agent_id":"a6c6ea12-bfc6-4bdc-8031-324102dfa34d"}
createdAt: 1785702662938
updatedAt: 1785708498776
version: 4
---
Applique le contrat de confinement/désinstallation décidé en #133.
Auditer `plugin_install_from_archive` / `plugin_install_from_directory` (`crates/app-tauri/src/plugins.rs:67-142`) et le store d'infrastructure (`crates/infrastructure/src/plugin/mod.rs`) pour confirmer qu'aucune écriture ne peut jamais sortir de `app_data/plugins/installed/<id>` :
- Un plugin dont le manifeste ou l'archive contient un chemin `../` ou un symlink pointant hors de sa racine doit échouer à l'install (vérifier que `RelativePath::new` — qui rejette déjà `..` et les chemins absolus, cf. `crates/domain/src/plugin.rs` — est bien appliqué à l'INSTALL, pas seulement au SERVE ajouté en #134).
- Aucune écriture ne doit jamais toucher le project root ni `.ideai/` du projet ouvert : le plugin est un citoyen de `app_data`, jamais du repo utilisateur.
Vérifier que `plugin_uninstall` (`crates/app-tauri/src/plugins.rs:142`) supprime bien 100% : dossier entier + entrée registry, zéro résidu. Étendre si besoin les tests existants (`uninstall_removes_registry_package_and_stops_mcp`, `uninstall_then_reinstall_leaves_runtime_catalog_active_without_residue` dans `crates/application/src/plugin/mod.rs`) pour couvrir explicitement le cas d'un plugin multi-fichiers (plusieurs fichiers sous `dist/`).
Si un chemin d'attaque (symlink sortant, `../` dans une archive zip malveillante) n'est pas déjà bloqué à l'install, ouvrir un correctif dans ce même ticket (pas de nouveau ticket) : c'est un renforcement du même contrat, pas une nouvelle feature.
Critères d'acceptation :
- Rapport d'audit écrit (dans le carnet du ticket) listant les points vérifiés et leur statut.
- Test explicite : tentative d'installer un plugin avec chemin `../` ou symlink sortant → échec propre, aucun fichier écrit hors racine.
- Test explicite : désinstallation d'un plugin multi-fichiers → dossier disparu, entrée registry disparue, aucun résidu.
- `cargo test -p app-tauri -p infrastructure -p application` vert.