3.9 KiB
context-hub — correctif securite MCP + table memory_entries typee
Date : 30/07/2026 Contexte : Nabil a juge context-hub sous-exploite et decide de le faire evoluer en memoire IA dediee coding (best practices, erreurs communes), avec MD comme representation durable et l'API/MCP comme jonction read/write instantanee. Avant d'ouvrir a plus d'agents (Antigravity, futurs repos/IA), inspection du code reel a revele une faille et un modele de donnees inadapte.
Faille identifiee et corrigee
app/routes/mcp.py, handle_call_tool : la couche REST (api.py, X-API-Key -> get_current_agent) authentifie correctement, y compris pour ouvrir la connexion SSE /mcp. Mais le handler MCP global ne recevait aucun contexte d'identite lie a cette connexion :
get_rulesetsearch_rules: aucun controlehas_scope_access, quel que soit l'appelant.get_agent_config/get_my_context/update_rule: controlaient l'acces sur un champagent/namedeclare par le client dans les arguments, jamais verifie contre la cle API reelle. Un agent authentifie GEMINI pouvait se declarerCLAUDEen argument et lire/ecrire hors de son perimetre.
Fix : contextvars.ContextVar pose dans run_server() au moment de l'etablissement SSE (current_agent_var.set(agent), agent = identite reelle resolue par get_current_agent), lu par handle_call_tool a la place de arguments.get("agent"). Applique uniformement aux 7 tools, y compris get_ports/check_port qui n'etaient pas gates du tout cote MCP (alors que l'equivalent REST /api/ports exige le scope infra).
Nouveau modele : memory_entries
Le PATCH existant (app/models.py, set_rule) fait un dict.update() plat par scope — une cle reecrite ecrase silencieusement la precedente. Inadapte a une liste croissante de decisions/erreurs/best practices. Ajout d'une table dediee, sans toucher rules (aucune rupture pour infra/llm/nyora/perso/tt existants) :
memory_entries(id, scope, project, type, title, body, tags, status, superseded_by, created_by, created_at, updated_at)
memory_entries_fts(FTS5) + triggers de sync insert/update/delete.
type in {decision, constraint, best-practice, common-error, do-not-use} — id sequentiel genere par scope-abbr-NNNN (ex: coding-err-0007). status in {active, archived, superseded} — pas de suppression dure, tombstone via supersede_memory_entry/archive_memory_entry (meme principe que do-not-use.md dans MemoryCustodian, evalue puis ecarte au profit de cette integration native context-hub).
Fonctions ajoutees dans models.py : add_memory_entry, list_memory_entries, search_memory_entries (FTS5), supersede_memory_entry, archive_memory_entry. Testees en conditions reelles dans le container (insert/list/search/supersede) — toutes OK. Pas encore d'endpoint HTTP/MCP expose (prochaine phase : scope coding + tools record_lesson/get_context_pack).
Piege deploiement
docker compose up -d --build echoue depuis ssh nas-host (Best0f) : .env est en 600 root:root, Best0f (uid 1026) n'a pas les droits de lecture, et sudo necessite un mot de passe interactif (regle deja actee : pas de sudo agent). Pour un changement Python pur (pas de Dockerfile touche), pas besoin de --build : le bind mount ./app:/app/app est live, un simple docker restart context-hub suffit et evite le probleme .env. docker est joignable en direct sans sudo (/usr/local/bin/docker, Best0f est dans le groupe docker gid 65538) mais absent du PATH non-interactif SSH — utiliser le chemin complet.
Push Gitea sans git
git absent de mcp-nas et de la session SSH nas-host. Push via API Contents Gitea (PUT .../contents/{path} avec sha courant recupere par un GET prealable, POST si creation) plutot que git push — pattern deja documente dans common/git-push-depuis-mcp-nas.md, confirme fonctionnel ici aussi pour des fichiers Python (pas seulement Markdown).