From 0281c51a48b0ef0583fcdfb0f42d280033ce2e79 Mon Sep 17 00:00:00 2001 From: Gemini Date: Fri, 4 Sep 2026 21:19:14 +0100 Subject: [PATCH] docs(runbook): architecture stub forwarder Bifrost VPS, rollback 5s, piege allow_all_keys et injection session opencode (tickets 010 et 008) --- _INDEX.md | 2 + ...ion-vps-bifrost-stub-forwarder-20260904.md | 152 ++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 common/migration-vps-bifrost-stub-forwarder-20260904.md diff --git a/_INDEX.md b/_INDEX.md index 9dea894..98fa8ed 100644 --- a/_INDEX.md +++ b/_INDEX.md @@ -10,6 +10,7 @@ | Runbook | Date | Tags | |---------|------|------| +| [Architecture stub forwarder Bifrost (NAS -> VPS via socat/SOCKS5 tailscale-nyora-bridge:1055), procédure de rollback immédiat (<5s), piège allow_all_keys / config.json au boot, et injection session x-bf-eh-x-opencode-session sur bifrost-proxy (tickets infra-2026-09-010 et 008)](common/migration-vps-bifrost-stub-forwarder-20260904.md) | 2026-09-04 | infra, bifrost, vps, tailscale, socat, rollback, allow-all-keys, opencode-go | | [Decommission veille-backend/veille-frontend (API FastAPI) au profit d une page statique bolbol.tn/veille (localStorage, tags, recherche, lu/non lu) ; workflow n8n Ingest Opportunites desactive (cible supprimee)](common/veille-decommission-api-page-statique-20260904.md) | 2026-09-04 | veille, veille-nexum, decommission, page-statique, localstorage, n8n, ports-registry | | [mcp-nas : root conteneur bloqué par ACL Synology sur certains dossiers .claude-staging (drwxrws---) — passer par ssh nas-host / claude-ops plutôt que le root namespacé de mcp-nas](common/mcp-nas-acl-synology-claude-staging-20260902.md) | 2026-09-02 | infra, mcp-nas, acl, synology, permissions, ssh, claude-staging, piege | | [Audit indépendant du chantier de désaccentuation systémique (SOUL.md, DSH-VPS, NAS, nyora-doc-api, nyora-veille) — vérification des correctifs Claude, audit nyora-doc-api, détection et correction de 6 foyers résiduels (tourisme-tunisie, veille-ia-automation, nas-executor, hermes-tt api-calls/SOUL, opportunites.py)](common/audit-gemini-accents-20260901.md) | 2026-09-01 | audit, accents, langue, soul-md, dsh, docx, context-hub, nyora-doc-api, qualite-production | @@ -57,6 +58,7 @@ | Runbook | Date | Tags | |---------|------|------| +| [Architecture stub forwarder Bifrost (NAS -> VPS via socat/SOCKS5 tailscale-nyora-bridge:1055), procédure de rollback immédiat (<5s), piège allow_all_keys / config.json au boot, et injection session x-bf-eh-x-opencode-session sur bifrost-proxy (tickets infra-2026-09-010 et 008)](common/migration-vps-bifrost-stub-forwarder-20260904.md) | 2026-09-04 | infra, bifrost, vps, tailscale, socat, rollback, allow-all-keys, opencode-go | | [Passerelle MCP dédiée NyoraNotes (multi-agent, StreamableHTTP port 3098, scoping strict par dossier, connecteur DSH validé)](common/nyora-notes-mcp-gateway-deploiement-20260826.md) | 2026-08-26 | nyora-notes-mcp, mcp, streamable-http, scoping, dsh, tailscale | | [Réduction hermes-hub en dispatcher minimal & stabilisation DSH (historique, WebSockets, mémoire NyoraNotes)](common/decommission-switcher-hub-stabilisation-dsh-20260826.md) | 2026-08-26 | dsh, hermes-hub, dispatcher, websocket, history-fix, nyora-notes | | [Hermes Hub — Déploiement et Exploitation Multi-Univers sur VPS (FastAPI, proxy async, design tokens, Tailscale)](common/hermes-hub-deploiement.md) | 2026-08-19 | hermes, hub, multi-univers, vps, tailscale, cloudflare-access, fastapi | diff --git a/common/migration-vps-bifrost-stub-forwarder-20260904.md b/common/migration-vps-bifrost-stub-forwarder-20260904.md new file mode 100644 index 0000000..09e67b1 --- /dev/null +++ b/common/migration-vps-bifrost-stub-forwarder-20260904.md @@ -0,0 +1,152 @@ +# Architecture Stub Forwarder Bifrost (NAS → VPS) & Injection Sessions OpenCode (04/09/2026) + +## 1. Objectif & Contexte + +Dans le cadre du ticket `infra-2026-09-010`, la passerelle LLM principale **Bifrost** a été migrée du NAS Synology vers le VPS Contabo (`100.94.90.119`). +Pour préserver l'accès LLM des 7+ consommateurs résidant sur le NAS (`context-hub`, `redaction-pro`, `gsparc-mezzouna-api`, `nyora-convert-api`, `nyora-notes-tt`, `reglement-mcp`, et `bifrost-proxy:3086`) **sans modifier aucune de leurs configurations individuelles**, une architecture par **stub forwarder transparent** a été mise en place sur le NAS. + +Parallèlement, pour répondre au ticket `infra-2026-09-008`, le proxy frontal du NAS (`bifrost-proxy`) a été instrumenté pour injecter automatiquement l'en-tête de session requis par OpenCode Go (`x-opencode-session`), transmis de manière transparente par Bifrost. + +--- + +## 2. Architecture Technique + +```mermaid +flowchart LR + subgraph NAS ["NAS Synology (Zone Sud)"] + Hermes["Hermes Agents"] --> Proxy["bifrost-proxy:3086 (Nginx)"] + Proxy -- "x-bf-eh-x-opencode-session" --> Stub + DirectClients["context-hub / redaction-pro / etc."] --> Stub["bifrost (stub socat:3085)"] + Stub --> Bridge["tailscale-nyora-bridge:1055 (SOCKS5)"] + end + + subgraph VPS ["VPS Contabo (100.94.90.119)"] + Bridge -- "Tunnel Tailscale" --> BifrostVPS["bifrost:3085 (maximhq/bifrost)"] + BifrostVPS --> Providers["Providers Externes (Google, OpenCode Go, Anthropic)"] + end +``` + +### Le stub socat sur le NAS +- **Emplacement** : `/volume1/docker/bifrost-stub/docker-compose.yml` +- **Nom du conteneur** : `bifrost` +- **Réseau Docker** : `n8n` (external) +- **Ports exposés** : `"3085:8080"` +- **Commande** : + ```yaml + image: alpine/socat:latest + container_name: bifrost + restart: unless-stopped + command: ["-d", "-d", "TCP-LISTEN:8080,fork,reuseaddr", "SOCKS5-CONNECT:tailscale-nyora-bridge:100.94.90.119:3085,socksport=1055"] + ``` + +--- + +## 3. Procédure de Rollback d'Urgence (< 5 secondes) + +L'ancien conteneur Bifrost local du NAS n'a **jamais été supprimé**. Il a été simplement renommé et stoppé. + +En cas de coupure prolongée du lien Tailscale ou d'anomalie sur le VPS, exécuter sur le NAS : +```bash +# 1. Arrêter et écarter le stub socat +docker stop bifrost +docker rename bifrost bifrost-stub-temp + +# 2. Restaurer le conteneur NAS natif +docker rename bifrost-nas-backup bifrost +docker start bifrost + +# 3. Réactualiser la résolution DNS du proxy frontal +docker restart bifrost-proxy +``` + +*Le rétablissement du service local est immédiat (aucune réimportation de base nécessaire).* + +--- + +## 4. Le Piège `allow_all_keys` et `config.json` au Boot + +### La cause racine +Bifrost (version `maximhq/bifrost:v1.6.11`) possède un comportement spécifique : au redémarrage, il recharge sa configuration depuis `config.json`. Si une clé virtuelle n'est pas explicitement autorisée pour chaque fournisseur dans la base SQLite interne, Bifrost bloque les requêtes avec une erreur HTTP 401 (`key not allowed for provider`). + +### La vraie table SQLite +Contrairement à d'anciennes mentions erronées pointant `config_providers`, la table concernée est : +- **Table** : `governance_virtual_key_provider_configs` +- **Colonne** : `allow_all_keys` (type numeric, booléen) +- **Nombre d'entrées** : 81 configurations actives (combinaisons clés virtuelles / providers) + +### Vérification de l'intégrité (VPS ou NAS) +```bash +python3 -c ' +import sqlite3 +c = sqlite3.connect("/home/dsh-agent/bifrost/data/config.db").cursor() +c.execute("SELECT count(*), sum(allow_all_keys) FROM governance_virtual_key_provider_configs;") +count, active = c.fetchone() +print(f"Configurations conformes : {active}/{count}") +' +``` +*Attendu : `(81, 81)`.* + +### Rattrapage SQL si redéploiement d'une base neuve +Si une nouvelle instance Bifrost est provisionnée : +```sql +UPDATE governance_virtual_key_provider_configs SET allow_all_keys = 1 WHERE allow_all_keys != 1; +``` +Puis redémarrer le conteneur : `docker restart bifrost`. + +--- + +## 5. Injection de Session OpenCode Go (`x-bf-eh-x-opencode-session`) + +### Problème résolu (Ticket infra-2026-09-008) +À partir de septembre 2026, l'API OpenCode Go exige la présence d'un en-tête `x-opencode-session`. +Une tentative de sidecar local sur le VPS échoue car le validateur SSRF interne de Bifrost (`net.IP.IsPrivate()`) interdit toute passerelle locale (`172.25.0.2` ou `127.0.0.1`). + +### Solution native Bifrost +Bifrost supporte nativement le relais d'en-têtes HTTP arbitraires vers les fournisseurs amont via le préfixe `x-bf-eh-*`. Tout en-tête débutant par `x-bf-eh-` est débarrassé de son préfixe par Bifrost et transmis au provider distant en HTTPS public. + +### Implémentation dans `bifrost-proxy` (`/volume1/docker/bifrost-proxy/nginx.conf`) +```nginx +http { + ... + map $http_x_opencode_session $opencode_session { + default $http_x_opencode_session; + "" $resolved_vk; + } + + server { + ... + location / { + ... + proxy_pass http://bifrost:8080; + proxy_http_version 1.1; + proxy_set_header x-bf-vk $resolved_vk; + proxy_set_header x-bf-eh-x-opencode-session $opencode_session; + ... + } + } +} +``` +- Si le client fournit déjà `x-opencode-session`, il est conservé. +- Sinon, la clé virtuelle résolue (`$resolved_vk`) sert d'identifiant de session stable. +- Les autres fournisseurs (Google, Anthropic) ignorent silencieusement cet en-tête supplémentaire sans perturbation. + +--- + +## 6. Vérifications et Tests Rapides + +### 1. Test de connectivité du stub depuis un conteneur NAS +```bash +docker exec context-hub python3 -c ' +import urllib.request +with urllib.request.urlopen("http://bifrost:8080/health", timeout=5) as r: + print("Statut stub NAS -> VPS :", r.status) +' +``` + +### 2. Test d'inférence complète avec injection de session via `bifrost-proxy` +```bash +curl -s -X POST http://127.0.0.1:3086/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer " \ + -d '{"model":"mimo-v2.5","messages":[{"role":"user","content":"ping"}],"max_tokens":10}' +```