# mcp-nas — Référence opérationnelle (consolidée) **Date** : 2026-07-09 (fusionne MCP-NAS-SCRIPTING.md 2026-06-23 + mcp-nas-run-command-v2.md 2026-07-04, + contraintes post-audit 2026-07-08) **Tags** : infra, mcp-nas, scripting, securite ## Environnement du container (vérifié 09/07/2026, image post-audit) | Propriété | Valeur | |-----------|--------| | Shell | `/bin/bash`, user root uid=0, **cap_drop: [ALL]** + no-new-privileges | | Python | 3.11 — requests, sqlite3, json, urllib, subprocess | | `git` | **ABSENT** (retiré au rebuild post-audit) → API HTTP Gitea obligatoire | | `docker` CLI / docker.sock | **ABSENTS** (socket retiré P0 audit 08/07) → API Portainer | | `/mnt/docker` | = /volume1/docker, RW | | Réseau | host via `172.17.0.1` ou alias `nas.internal` (extra_hosts). 192.168.100.33 **inaccessible** | ## run_command v2 (P0 du 04/07, commit 30560984fa) La commande est écrite dans un script par Python (zéro parsing shell) puis sourcée dans tmux : - Heredocs natifs (`<<'EOF'`, quotes, `$VAR`, backticks) ; testé 5 250 chars en un appel. - Busy-check : pane occupé → refus propre (options : capture_pane, send_keys, reset_session). - Timeout intelligent : Ctrl-C + sonde ; session préservée si le shell répond. - `reset_session` : reprise d'une session bloquée SANS destruction (vim : `send_keys ':q!'` d'abord). - Cleanup au boot : sessions tmux orphelines + `/tmp/mcp_*` purgés. - Denylist ancrée (P1, commit 7fb13c5) : patterns ancrés en début de segment, heredocs exclus. Défense en profondeur, PAS une frontière de sécurité. - Interdits toujours actifs : reboot, mkfs, dd of=/dev/*, rm -rf racines critiques, docker rm -f, syno*… **Ne plus utiliser** : workaround base64 2 appels, découpage printf-append, limite 350 chars — tout cela date de la v1. ## Contraintes post-audit sécurité (08/07/2026) — vérifiées le 09/07 1. **`cap_drop: [ALL]` → pas de CAP_DAC_OVERRIDE** : les dossiers `0700` appartenant à uid 1026 (ex. `hermes-*/data/`) sont **illisibles même en root**. C'est voulu. Lecture des data/ Hermes → passer par un autre canal (Mac, ou décision Nabil). 2. **`~/.ssh` du container vidé au rebuild** : plus de clé pour `ssh Best0f@172.17.0.1:22222`. SSH host depuis mcp-nas = indisponible tant que la clé n'est pas re-provisionnée (décision Nabil — l'audit recommandait justement de sortir les clés). 3. **docker.sock retiré** → gestion containers via **API Portainer** (`http://nas.internal:9000`, POST /api/auth → jwt, endpoint_id=2 ; l'ID container change après recreate, toujours le re-résoudre). 4. **Gitea** : API HTTP avec `GITEA_DEPLOY_TOKEN` (repo-scopé, dans hermes-platform/.env) — **jamais** le mot de passe bolbol dans une URL (fuite audit.log + ps). Lire le token dans une variable depuis le fichier, pas en clair dans la commande. 5. Rebuild du container : **depuis le Mac** (`ssh -p 22222 Best0f@192.168.100.33`, `cd /volume1/docker/linux-mcp-nas && sudo docker compose build && up -d --force-recreate`), jamais depuis mcp-nas lui-même. ## Services internes depuis mcp-nas `nas.internal` (= 172.17.0.1) : Gitea `:3232`, Portainer `:9000`, NyoraNotes `:8787`, nyora-doc-api `:3050`, Bifrost `:3085` (LAN) / `http://bifrost:8080` (réseau n8n), context-hub `:3093`. ## Bonnes pratiques - Scripts Python : heredoc `cat <<'EOF' > /tmp/s.py … EOF` puis `python3 /tmp/s.py`. - Session par défaut `claude` fiable ; `reset_session` avant de créer une session neuve. - Secrets : toujours via variable lue depuis .env (`export GT=$(grep … | cut -d= -f2)`), jamais inline — audit.log journalise chaque commande.