1 line
14 KiB
JSON
1 line
14 KiB
JSON
{"repo": "akiroussama/rabit", "files": {"docker-compose.local.yml": {"271e669145a919807cadf502c5c0affec117ce4f": {"t": 1785747411.5307617, "n": 4726, "h": "e082b992fc8a4f11", "c": "# Pile locale complète, sans aucune dépendance externe (§15.7).\n#\n# Objectif : exercer le parcours `/v1/chat/completions` de bout en bout — clé,\n# réservation, appel amont, règlement, débit du solde — sans clé DeepSeek, sans\n# réseau sortant, et sans argent. Le fournisseur est remplacé par\n# `infra/fake-llm/server.mjs`, qui renvoie des compteurs d'usage EXACTS : c'est\n# ce qui permet d'affirmer « 40 + 30×2 = 100 crédits » plutôt que de constater\n# « le solde a baissé ».\n#\n# Ce fichier ne remplace pas `docker-compose.yml` (dépendances de dev seules) ni\n# `docker-compose.prod.yml` (déploiement). Il est délibérément séparé pour\n# qu'une variable de test ne puisse pas se retrouver en production par copie.\n#\n# docker compose -f docker-compose.local.yml up -d --build\n# bash scripts/verify-money-path.sh\n# docker compose -f docker-compose.local.yml down -v\n\nname: rabit-local\n\nservices:\n faux-llm:\n image: node:22-alpine\n restart: unless-stopped\n working_dir: /app\n command: [\"node\", \"infra/fake-llm/server.mjs\"]\n environment:\n FAKE_LLM_PORT: \"8080\"\n volumes:\n # Monté en lecture seule : le fournisseur n'a aucune raison d'écrire.\n - ./infra/fake-llm:/app/infra/fake-llm:ro\n healthcheck:\n test: [\"CMD\", \"node\", \"-e\", \"fetch('http://127.0.0.1:8080/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\"]\n interval: 5s\n timeout: 3s\n retries: 10\n start_period: 5s\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n command: [\"redis-server\", \"--appendonly\", \"yes\"]\n ports:\n - \"6380:6379\"\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n interval: 5s\n timeout: 3s\n retries: 10\n\n litellm-db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: litellm\n POSTGRES_PASSWORD: litellm-local\n POSTGRES_DB: litellm\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U litellm -d litellm\"]\n interval: 5s\n timeout: 3s\n retries: 20\n\n litellm:\n # EXACTEMENT l'image de production, digest compris. Une pile locale qui\n # valide une autre version que celle déployée valide le mauvais composant —\n # et le callback quota est justement sensible aux hooks de LiteLLM.\n image: ghcr.io/berriai/litellm:v1.91.1@sha256:47afa74b495c802317712e5b8c8a65e7ca30c96636e9b618a5f8130eec72a8ee\n restart: unless-stopped\n environment:\n LITELLM_MASTER_KEY: sk-local-master-non-secret\n DATABASE_URL: postgresql://litellm:litellm-local@litellm-db:5432/litellm\n REDIS_URL: redis://redis:6379\n MAX_OUTPUT_TOKENS: \"4000\"\n RABIT_OUTPUT_TOKEN_MULTIPLIER: \"2\"\n RABIT_USAGE_STREAM: rabit:usage_events\n # Le routage vers le faux fournisseur vit dans config.local.yaml, pas\n # ici : voir l'en-tête de ce fichier pour la raison.\n command: [\"--config\", \"/app/config.yaml\", \"--host\", \"0.0.0.0\", \"--port\", \"4000\"]\n ports:\n - \"4001:4000\"\n volumes:\n - ./infra/litellm/config.local.yaml:/app/config.yaml:ro\n - ./infra/litellm/rabit_quota.py:/app/rabit_quota.py:ro\n depends_on:\n faux-llm:\n condition: service_healthy\n redis:\n condition: service_healthy\n litellm-db:\n condition: service_healthy\n healthcheck:\n test: [\"CMD-SHELL\", \"python -c \\\"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:4000/health/readiness', timeout=5).status==200 else 1)\\\"\"]\n interval: 10s\n timeout: 8s\n retries: 30\n start_period: 60s\n\n # Caddy, avec le MÊME Caddyfile que la production.\n #\n # Il est ici pour une seule raison : sans lui, les en-têtes de sécurité\n # seraient écrits dans un fichier de configuration que rien n'exercerait. Une\n # protection non vérifiée est une protection supposée.\n #\n # `RABIT_PRIMARY_HOST` vaut `:8088` — une adresse réduite à un port fait\n # servir Caddy en HTTP simple, sans tenter d'obtenir un certificat pour un\n # nom qui n'existe pas. Le reste du fichier, en-têtes compris, est identique.\n #\n # L'amont pointe vers l'hôte : l'application tourne en local (`next start`),\n # pas dans cette pile, pour ne pas imposer une construction d'image de\n # plusieurs minutes à chaque vérification.\n caddy:\n image: caddy:2-alpine\n restart: unless-stopped\n environment:\n RABIT_PRIMARY_HOST: \":8088\"\n RABIT_UPSTREAM: \"host.docker.internal:3313\"\n ports:\n - \"8088:8088\"\n volumes:\n - ./infra/caddy/Caddyfile:/etc/caddy/Caddyfile:ro\n extra_hosts:\n - \"host.docker.internal:host-gateway\"\n healthcheck:\n test: [\"CMD\", \"caddy\", \"validate\", \"--config\", \"/etc/caddy/Caddyfile\"]\n interval: 10s\n timeout: 5s\n retries: 5\n"}, "022b639cacca458caa6f3388a04411a7954bb014": {"t": 1785773134.4490936, "n": 4726, "h": "e082b992fc8a4f11", "c": "# Pile locale complète, sans aucune dépendance externe (§15.7).\n#\n# Objectif : exercer le parcours `/v1/chat/completions` de bout en bout — clé,\n# réservation, appel amont, règlement, débit du solde — sans clé DeepSeek, sans\n# réseau sortant, et sans argent. Le fournisseur est remplacé par\n# `infra/fake-llm/server.mjs`, qui renvoie des compteurs d'usage EXACTS : c'est\n# ce qui permet d'affirmer « 40 + 30×2 = 100 crédits » plutôt que de constater\n# « le solde a baissé ».\n#\n# Ce fichier ne remplace pas `docker-compose.yml` (dépendances de dev seules) ni\n# `docker-compose.prod.yml` (déploiement). Il est délibérément séparé pour\n# qu'une variable de test ne puisse pas se retrouver en production par copie.\n#\n# docker compose -f docker-compose.local.yml up -d --build\n# bash scripts/verify-money-path.sh\n# docker compose -f docker-compose.local.yml down -v\n\nname: rabit-local\n\nservices:\n faux-llm:\n image: node:22-alpine\n restart: unless-stopped\n working_dir: /app\n command: [\"node\", \"infra/fake-llm/server.mjs\"]\n environment:\n FAKE_LLM_PORT: \"8080\"\n volumes:\n # Monté en lecture seule : le fournisseur n'a aucune raison d'écrire.\n - ./infra/fake-llm:/app/infra/fake-llm:ro\n healthcheck:\n test: [\"CMD\", \"node\", \"-e\", \"fetch('http://127.0.0.1:8080/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\"]\n interval: 5s\n timeout: 3s\n retries: 10\n start_period: 5s\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n command: [\"redis-server\", \"--appendonly\", \"yes\"]\n ports:\n - \"6380:6379\"\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n interval: 5s\n timeout: 3s\n retries: 10\n\n litellm-db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: litellm\n POSTGRES_PASSWORD: litellm-local\n POSTGRES_DB: litellm\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U litellm -d litellm\"]\n interval: 5s\n timeout: 3s\n retries: 20\n\n litellm:\n # EXACTEMENT l'image de production, digest compris. Une pile locale qui\n # valide une autre version que celle déployée valide le mauvais composant —\n # et le callback quota est justement sensible aux hooks de LiteLLM.\n image: ghcr.io/berriai/litellm:v1.91.1@sha256:47afa74b495c802317712e5b8c8a65e7ca30c96636e9b618a5f8130eec72a8ee\n restart: unless-stopped\n environment:\n LITELLM_MASTER_KEY: sk-local-master-non-secret\n DATABASE_URL: postgresql://litellm:litellm-local@litellm-db:5432/litellm\n REDIS_URL: redis://redis:6379\n MAX_OUTPUT_TOKENS: \"4000\"\n RABIT_OUTPUT_TOKEN_MULTIPLIER: \"2\"\n RABIT_USAGE_STREAM: rabit:usage_events\n # Le routage vers le faux fournisseur vit dans config.local.yaml, pas\n # ici : voir l'en-tête de ce fichier pour la raison.\n command: [\"--config\", \"/app/config.yaml\", \"--host\", \"0.0.0.0\", \"--port\", \"4000\"]\n ports:\n - \"4001:4000\"\n volumes:\n - ./infra/litellm/config.local.yaml:/app/config.yaml:ro\n - ./infra/litellm/rabit_quota.py:/app/rabit_quota.py:ro\n depends_on:\n faux-llm:\n condition: service_healthy\n redis:\n condition: service_healthy\n litellm-db:\n condition: service_healthy\n healthcheck:\n test: [\"CMD-SHELL\", \"python -c \\\"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:4000/health/readiness', timeout=5).status==200 else 1)\\\"\"]\n interval: 10s\n timeout: 8s\n retries: 30\n start_period: 60s\n\n # Caddy, avec le MÊME Caddyfile que la production.\n #\n # Il est ici pour une seule raison : sans lui, les en-têtes de sécurité\n # seraient écrits dans un fichier de configuration que rien n'exercerait. Une\n # protection non vérifiée est une protection supposée.\n #\n # `RABIT_PRIMARY_HOST` vaut `:8088` — une adresse réduite à un port fait\n # servir Caddy en HTTP simple, sans tenter d'obtenir un certificat pour un\n # nom qui n'existe pas. Le reste du fichier, en-têtes compris, est identique.\n #\n # L'amont pointe vers l'hôte : l'application tourne en local (`next start`),\n # pas dans cette pile, pour ne pas imposer une construction d'image de\n # plusieurs minutes à chaque vérification.\n caddy:\n image: caddy:2-alpine\n restart: unless-stopped\n environment:\n RABIT_PRIMARY_HOST: \":8088\"\n RABIT_UPSTREAM: \"host.docker.internal:3313\"\n ports:\n - \"8088:8088\"\n volumes:\n - ./infra/caddy/Caddyfile:/etc/caddy/Caddyfile:ro\n extra_hosts:\n - \"host.docker.internal:host-gateway\"\n healthcheck:\n test: [\"CMD\", \"caddy\", \"validate\", \"--config\", \"/etc/caddy/Caddyfile\"]\n interval: 10s\n timeout: 5s\n retries: 5\n"}, "448ae3fb20e0b17279508085112752ffbe27bd50": {"t": 1785773136.1416135, "n": 3546, "h": "db40dcb9b38e2e8a", "c": "# Pile locale complète, sans aucune dépendance externe (§15.7).\n#\n# Objectif : exercer le parcours `/v1/chat/completions` de bout en bout — clé,\n# réservation, appel amont, règlement, débit du solde — sans clé DeepSeek, sans\n# réseau sortant, et sans argent. Le fournisseur est remplacé par\n# `infra/fake-llm/server.mjs`, qui renvoie des compteurs d'usage EXACTS : c'est\n# ce qui permet d'affirmer « 40 + 30×2 = 100 crédits » plutôt que de constater\n# « le solde a baissé ».\n#\n# Ce fichier ne remplace pas `docker-compose.yml` (dépendances de dev seules) ni\n# `docker-compose.prod.yml` (déploiement). Il est délibérément séparé pour\n# qu'une variable de test ne puisse pas se retrouver en production par copie.\n#\n# docker compose -f docker-compose.local.yml up -d --build\n# bash scripts/verify-money-path.sh\n# docker compose -f docker-compose.local.yml down -v\n\nname: rabit-local\n\nservices:\n faux-llm:\n image: node:22-alpine\n restart: unless-stopped\n working_dir: /app\n command: [\"node\", \"infra/fake-llm/server.mjs\"]\n environment:\n FAKE_LLM_PORT: \"8080\"\n volumes:\n # Monté en lecture seule : le fournisseur n'a aucune raison d'écrire.\n - ./infra/fake-llm:/app/infra/fake-llm:ro\n healthcheck:\n test: [\"CMD\", \"node\", \"-e\", \"fetch('http://127.0.0.1:8080/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))\"]\n interval: 5s\n timeout: 3s\n retries: 10\n start_period: 5s\n\n redis:\n image: redis:7-alpine\n restart: unless-stopped\n command: [\"redis-server\", \"--appendonly\", \"yes\"]\n ports:\n - \"6380:6379\"\n healthcheck:\n test: [\"CMD\", \"redis-cli\", \"ping\"]\n interval: 5s\n timeout: 3s\n retries: 10\n\n litellm-db:\n image: postgres:16-alpine\n restart: unless-stopped\n environment:\n POSTGRES_USER: litellm\n POSTGRES_PASSWORD: litellm-local\n POSTGRES_DB: litellm\n healthcheck:\n test: [\"CMD-SHELL\", \"pg_isready -U litellm -d litellm\"]\n interval: 5s\n timeout: 3s\n retries: 20\n\n litellm:\n # EXACTEMENT l'image de production, digest compris. Une pile locale qui\n # valide une autre version que celle déployée valide le mauvais composant —\n # et le callback quota est justement sensible aux hooks de LiteLLM.\n image: ghcr.io/berriai/litellm:v1.91.1@sha256:47afa74b495c802317712e5b8c8a65e7ca30c96636e9b618a5f8130eec72a8ee\n restart: unless-stopped\n environment:\n LITELLM_MASTER_KEY: sk-local-master-non-secret\n DATABASE_URL: postgresql://litellm:litellm-local@litellm-db:5432/litellm\n REDIS_URL: redis://redis:6379\n MAX_OUTPUT_TOKENS: \"4000\"\n RABIT_OUTPUT_TOKEN_MULTIPLIER: \"2\"\n RABIT_USAGE_STREAM: rabit:usage_events\n # Le routage vers le faux fournisseur vit dans config.local.yaml, pas\n # ici : voir l'en-tête de ce fichier pour la raison.\n command: [\"--config\", \"/app/config.yaml\", \"--host\", \"0.0.0.0\", \"--port\", \"4000\"]\n ports:\n - \"4001:4000\"\n volumes:\n - ./infra/litellm/config.local.yaml:/app/config.yaml:ro\n - ./infra/litellm/rabit_quota.py:/app/rabit_quota.py:ro\n depends_on:\n faux-llm:\n condition: service_healthy\n redis:\n condition: service_healthy\n litellm-db:\n condition: service_healthy\n healthcheck:\n test: [\"CMD-SHELL\", \"python -c \\\"import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:4000/health/readiness', timeout=5).status==200 else 1)\\\"\"]\n interval: 10s\n timeout: 8s\n retries: 30\n start_period: 60s\n"}}}} |