Files
chlova/infra/docker-compose.yml
T
Kantin-Petit 2bfa58f440 feat: outil propose_asset + auto-extension exposée, fin Phase 5 v1 (v0.27.0)
Outil local sanctionné chlova.propose_asset : l'agent propose un asset →
write+commit+version+doc → need-review (privilégié = BLOQUÉ). Notion
ToolSpec.sanctioned (autorisé par gatekeeper, audité). Flag
CHLOVA_AUTOEXT_ENABLED (off défaut) + CHLOVA_REPO_ROOT. Prompt impose un
palier honnête. 75 tests, 0 vuln, compose OK.

Palier de risque : privilégié (l'agent écrit+commit) — derrière flag +
Phase 2 ; l'asset produit n'est jamais exécuté, il reste sous review.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 06:38:45 +02:00

128 lines
5.3 KiB
YAML

# CHLOVA — stack d'orchestration.
# Règles : une seule surface exposée (backend), tout le reste interne, images
# épinglées (jamais :latest), secrets par référence (voir ../.env.example).
#
# ⚠️ Les tags ci-dessous sont des points d'épinglage à CONFIRMER avant tout
# déploiement réel : `docker pull <image>:<tag>` puis remplacer par
# `<image>:<tag>@sha256:<digest>` pour une immuabilité complète (docs/versioning.md).
# Aucun déploiement réel n'est lancé depuis ce dépôt sans validation explicite.
name: chlova
services:
# ── Ollama : proxy authentifié vers les modèles cloud (ollama.com) ──────
ollama:
image: ollama/ollama:0.6.8 # TODO épingler le digest
restart: unless-stopped
environment:
# Clé du proxy cloud — injectée depuis .env, jamais en dur.
OLLAMA_API_KEY: ${OLLAMA_API_KEY:?OLLAMA_API_KEY requis}
OLLAMA_HOST: 0.0.0.0:11434
volumes:
- ollama-data:/root/.ollama
networks:
- chlova-internal # joignable par le backend
- chlova-egress # seul service autorisé à sortir
# AUCUN port publié : Ollama n'a pas d'auth native, jamais exposé.
# ── socket-proxy : accès Docker filtré (voir socket-proxy/README.md) ────
socket-proxy:
image: tecnativa/docker-socket-proxy:0.3.0 # TODO épingler le digest
restart: unless-stopped
environment:
# Phase 1 — LECTURE SEULE : lecture autorisée, mutation refusée.
CONTAINERS: 1
IMAGES: 1
NETWORKS: 1
VOLUMES: 1
SERVICES: 1
TASKS: 1
NODES: 1
INFO: 1
VERSION: 1
POST: 0 # refuse toute mutation
EXEC: 0 # refuse exec dans un conteneur
AUTH: 0
SECRETS: 0
CONFIGS: 0
BUILD: 0
COMMIT: 0
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # seul à monter le socket
networks:
- chlova-internal
# AUCUN port publié.
# ── MCP n8n : NATIF (instance n8n ≥ 2.18.4) — pas de conteneur dédié ─────
# n8n expose son propre serveur MCP. À activer côté instance n8n (variable
# d'env d'instance + activation par workflow), puis copier l'URL + le "MCP
# Access Token" depuis n8n → Connection details. Le backend s'y connecte via
# MCP_N8N_URL (réseau interne). n8n doit être attaché à chlova-internal.
# ── MCP Portainer (portainer/portainer-mcp) — read-only en Phase 1 ──────
mcp-portainer:
image: portainer/portainer-mcp:0.6.0 # TODO confirmer tag/transport + épingler digest
restart: unless-stopped
environment:
PORTAINER_URL: ${PORTAINER_URL}
PORTAINER_MCP_AUTH_TOKEN: ${PORTAINER_MCP_AUTH_TOKEN:?requis}
PORTAINER_READ_ONLY: ${PORTAINER_READ_ONLY:-true} # P1 : NE PAS passer à false
# Docker via socket-proxy uniquement, jamais le socket brut.
DOCKER_HOST: tcp://socket-proxy:2375
depends_on:
- socket-proxy
networks:
- chlova-internal
# AUCUN port publié.
# ── Backend CHLOVA : SEULE surface, cerveau (boucle agent) ──────────────
backend:
build:
context: .. # racine du dépôt (image = API + SPA web)
dockerfile: orchestrator/Dockerfile
image: chlova/backend:0.2.0 # tag versionné local (API+UI)
restart: unless-stopped
env_file: ../.env
environment:
CHLOVA_ENV: ${CHLOVA_ENV:-production}
CHLOVA_PHASE: ${CHLOVA_PHASE:-1} # 1 = lecture seule (défaut) ; 2 = écriture sous review
ALERT_WEBHOOK_URL: ${ALERT_WEBHOOK_URL:-} # Phase 3 : vide = alertes log-only
CHLOVA_AUTOEXT_ENABLED: ${CHLOVA_AUTOEXT_ENABLED:-false} # Phase 5 : off par défaut
CHLOVA_REPO_ROOT: ${CHLOVA_REPO_ROOT:-/app/repo}
OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://ollama:11434}
MCP_N8N_URL: ${MCP_N8N_URL} # endpoint MCP natif de n8n
MCP_PORTAINER_URL: ${MCP_PORTAINER_URL:-http://mcp-portainer:3000}
volumes:
- chlova-data:/app/data # SQLite (table assets, P2+)
# Auto-extension (Phase 5, off par défaut) : monter le dépôt git ici pour
# que CHLOVA puisse committer les assets créés.
# - /srv/chlova-repo:/app/repo
depends_on:
- ollama
- mcp-portainer
networks:
- chlova-internal
- traefik-public # API/UI exposée via Traefik (Phase 4)
# Phase 4 : SEUL service exposé, via Traefik + TLS (jamais de port publié en
# direct). L'API/UI ne s'active que si l'auth est configurée (.env).
labels:
traefik.enable: "true"
traefik.docker.network: traefik-public
traefik.http.routers.chlova.rule: Host(`${CHLOVA_DOMAIN:-chlova.example.com}`)
traefik.http.routers.chlova.entrypoints: websecure
traefik.http.routers.chlova.tls: "true"
traefik.http.routers.chlova.tls.certresolver: le
traefik.http.services.chlova.loadbalancer.server.port: "8080"
networks:
chlova-internal:
internal: true # aucune route vers l'extérieur
chlova-egress:
driver: bridge # sortie contrôlée (Ollama → ollama.com), egress filtré côté hôte
traefik-public:
external: true # réseau Traefik existant du homelab
volumes:
ollama-data:
chlova-data: