overmind-mcp 2.8.21 β†’ 2.8.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,351 @@
1
+ # πŸ›‘οΈ PLAN SΓ‰CURITΓ‰ OVERMIND β€” GuΓ©rison ComplΓ¨te
2
+
3
+ > **Date** : 28 Mai 2026
4
+ > **Auteur** : Sniper Analyste Financier (via audit Discord)
5
+ > **Relecteur** : sley_73350 (validation en cours)
6
+ > **Version** : 1.0 β€” Brouillon pour validation
7
+
8
+ ---
9
+
10
+ ## πŸ” Γ‰TAT DES LIEUX β€” Diagnostic Critique
11
+
12
+ ### Surface d'attaque actuelle
13
+
14
+ ```
15
+ ╔═══════════════════════════════════════════════════════════════════════════╗
16
+ ║ TRANSPORT │ PROTOCOLE │ POINT D'ENTRÉE │ AUTH? │ PORT ║
17
+ ╠═══════════════════════════════════════════════════════════════════════════╣
18
+ β•‘ STDIO β”‚ JSON-RPC 2.0 β”‚ stdin β†’ stdout β”‚ ❌ β”‚ N/A β•‘
19
+ β•‘ HTTP Stream β”‚ JSON-RPC 2.0 β”‚ POST /mcp β”‚ ❌ β”‚ 3099 β•‘
20
+ β•‘ HTTP Stream β”‚ SSE β”‚ POST /mcp (stream) β”‚ ❌ β”‚ 3099 β•‘
21
+ β•‘ HTTP Stream β”‚ REST β”‚ GET /health β”‚ ❌ β”‚ 3099 β•‘
22
+ β•‘ HTTPS (SSL) β”‚ JSON-RPC 2.0 β”‚ POST /mcp β”‚ ❌ β”‚ 3099 β•‘
23
+ β•‘ HTTPS (SSL) β”‚ SSE β”‚ POST /mcp (stream) β”‚ ❌ β”‚ 3099 β•‘
24
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
25
+
26
+ πŸ” CONSTAT : TOUS les endpoints sont OUVERTS β€” 0 authentification cΓ΄tΓ© serveur
27
+ ```
28
+
29
+ ### 14 Outils MCP exposΓ©s sans protection
30
+
31
+ ```
32
+ # β”‚ TOOL β”‚ RISQUE
33
+ ───┼─────────────────────────┼──────────
34
+ 01 β”‚ run_agent β”‚ πŸ”΄ CRITIQUE
35
+ 02 β”‚ run_agents_parallel β”‚ πŸ”΄ CRITIQUE
36
+ 03 β”‚ create_agent β”‚ 🟠 Γ‰LEVΓ‰
37
+ 04 β”‚ delete_agent β”‚ 🟠 Γ‰LEVΓ‰
38
+ 05 β”‚ update_agent_config β”‚ πŸ”΄ CRITIQUE
39
+ 06 β”‚ list_agents β”‚ 🟑 MOYEN
40
+ 07 β”‚ get_agent_configs β”‚ πŸ”΄ CRITIQUE (fuites clΓ©s API)
41
+ 08 β”‚ create_prompt β”‚ 🟑 MOYEN
42
+ 09 β”‚ edit_prompt β”‚ 🟑 MOYEN
43
+ 10 β”‚ memory_search β”‚ 🟑 MOYEN
44
+ 11 β”‚ memory_store β”‚ 🟑 MOYEN
45
+ 12 β”‚ memory_runs β”‚ 🟒 FAIBLE
46
+ 13 β”‚ config_example β”‚ 🟒 FAIBLE
47
+ 14 β”‚ agent_control β”‚ πŸ”΄ CRITIQUE (kill process)
48
+ ```
49
+
50
+ ### Modules bibliothèque — Couverture Bearer
51
+
52
+ ```
53
+ MODULE │ TYPE │ ENVOIE BEARER │ REÇOIT/VERIFY │ STATUS
54
+ ────────────────────────┼─────────┼───────────────┼───────────────┼───────
55
+ overmind-client.ts β”‚ Client β”‚ βœ… OUI β”‚ N/A β”‚ βœ… OK
56
+ cli.ts (serveur) β”‚ Serveur β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
57
+ server.ts (FastMCP) β”‚ Serveur β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
58
+ run_agent.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
59
+ run_agents_parallel.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
60
+ create_agent.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
61
+ manage_agents.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
62
+ memory_store.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
63
+ memory_search.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
64
+ agent_control.ts β”‚ Tool β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
65
+ config.ts β”‚ Config β”‚ N/A β”‚ ❌ NON β”‚ 🟑
66
+ processRegistry.ts β”‚ Runtime β”‚ N/A β”‚ ❌ NON β”‚ πŸ”΄ GAP
67
+ ```
68
+
69
+ ---
70
+
71
+ ## πŸ—οΈ ARCHITECTURE CIBLE β€” AprΓ¨s GuΓ©rison
72
+
73
+ ```
74
+ πŸ” MIDDLEWARE AUTH ACTIF πŸ”
75
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Bearer β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
76
+ β”‚ Client β”‚ ──────────▢ β”‚ FastMCP │───▢│ 14 Tools β”‚
77
+ β”‚ (TS/JS) β”‚ Header βœ“ β”‚ v4.0.1 β”‚ β”‚ MCP β”‚
78
+ β”‚ β”‚ β”‚ βœ… CHECK βœ“ β”‚ β”‚ (protΓ©gΓ©s)β”‚
79
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
80
+ β”‚
81
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
82
+ β”‚ Transports sΓ©curisΓ©s β”‚
83
+ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
84
+ β”‚ stdio (pipe local) β”‚
85
+ β”‚ httpStream (port 3099) β”‚
86
+ β”‚ endpoint: /mcp β”‚
87
+ β”‚ βœ… Bearer: REQUIRED β”‚
88
+ β”‚ stateless: true β”‚
89
+ β”‚ SSL: ACTIF β”‚
90
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
91
+ ```
92
+
93
+ ---
94
+
95
+ ## πŸ“‹ PLAN D'IMPLΓ‰MENTATION β€” 5 Phases
96
+
97
+ ### PHASE 1 — Middleware Serveur Bearer (PRIORITÉ MAX)
98
+
99
+ **Objectif** : Bloquer tout accès non authentifié sur HTTP/RPC
100
+
101
+ **Fichier cible** : `src/cli.ts` + `src/server.ts`
102
+
103
+ **TΓ’ches** :
104
+ - [ ] CrΓ©er `src/lib/bearerMiddleware.ts`
105
+ - Fonction `verifyBearer(request): boolean`
106
+ - Lecture `OVERMIND_AUTH` depuis `.env`
107
+ - Comparaison via `crypto.timingSafeEqual()` (anti timing attack)
108
+ - Retourner 401 + message JSON si token absent/invalide
109
+ - [ ] Injecter le middleware dans FastMCP httpStream
110
+ - Hook AVANT `server.start()`
111
+ - Exempter UNIQUEMENT `GET /health` (monitoring)
112
+ - Bloquer tout le reste si token absent
113
+ - [ ] Logger chaque accès (audit trail)
114
+ - IP source, timestamp, tool appelΓ©, rΓ©sultat auth
115
+
116
+ **Code de rΓ©fΓ©rence** :
117
+ ```typescript
118
+ // src/lib/bearerMiddleware.ts
119
+ import crypto from 'crypto';
120
+
121
+ export function verifyBearer(authHeader: string | undefined): boolean {
122
+ const expected = process.env.OVERMIND_AUTH;
123
+ if (!expected) {
124
+ console.warn('[AUTH] ⚠️ OVERMIND_AUTH non dΓ©fini β€” accΓ¨s refusΓ© par dΓ©faut');
125
+ return false;
126
+ }
127
+ if (!authHeader?.startsWith('Bearer ')) return false;
128
+
129
+ const token = authHeader.slice(7);
130
+ const expectedBuf = Buffer.from(expected);
131
+ const tokenBuf = Buffer.from(token);
132
+
133
+ if (tokenBuf.length !== expectedBuf.length) return false;
134
+ return crypto.timingSafeEqual(tokenBuf, expectedBuf);
135
+ }
136
+ ```
137
+
138
+ **Validation** :
139
+ - [ ] Tester sans token β†’ 401
140
+ - [ ] Tester avec mauvais token β†’ 401
141
+ - [ ] Tester avec bon token β†’ 200
142
+ - [ ] GET /health sans token β†’ 200 (exemptΓ©)
143
+
144
+ ---
145
+
146
+ ### PHASE 2 — Intégration dans tous les modules de la bibliothèque
147
+
148
+ **Objectif** : Chaque module serveur vΓ©rifie le Bearer
149
+
150
+ **Fichiers cibles** :
151
+ - `src/cli.ts` (serveur principal)
152
+ - `src/server.ts` (FastMCP)
153
+ - Chaque tool MCP (run_agent, memory_store, etc.)
154
+
155
+ **TΓ’ches** :
156
+ - [ ] Importer `verifyBearer` dans chaque point d'entrΓ©e serveur
157
+ - [ ] Ajouter un wrapper `withAuth(toolHandler)` qui :
158
+ 1. Extrait le header Authorization du contexte MCP
159
+ 2. VΓ©rifie via `verifyBearer()`
160
+ 3. Si Γ©chec β†’ retourne erreur MCP avec code d'auth
161
+ 4. Si succès → exécute le tool normalement
162
+ - [ ] Valider que les 14 tools sont couverts
163
+
164
+ **Code de rΓ©fΓ©rence** :
165
+ ```typescript
166
+ // src/lib/withAuth.ts
167
+ import { verifyBearer } from './bearerMiddleware';
168
+
169
+ export function withAuth(handler: Function) {
170
+ return async (args: any, context: any) => {
171
+ const authHeader = context?.request?.headers?.authorization;
172
+ if (!verifyBearer(authHeader)) {
173
+ throw new Error('[AUTH] ❌ AccΓ¨s refusΓ© β€” Bearer token invalide');
174
+ }
175
+ return handler(args, context);
176
+ };
177
+ }
178
+ ```
179
+
180
+ ---
181
+
182
+ ### PHASE 3 β€” Propagation aux configs agents (.mcp.json)
183
+
184
+ **Objectif** : Chaque agent injecte le Bearer dans ses appels
185
+
186
+ **TΓ’ches** :
187
+ - [ ] VΓ©rifier que `overmind-client.ts` envoie bien le Bearer βœ… (dΓ©jΓ  fait)
188
+ - [ ] Mettre Γ  jour les templates `.mcp.json` des agents
189
+ - Ajouter `Authorization: Bearer ${OVERMIND_AUTH}` dans les headers
190
+ - [ ] Scripts externes β†’ utiliser `OVERMIND_AUTH` depuis `.env`
191
+ - [ ] Documenter la variable dans le README Overmind
192
+
193
+ **Exemple .mcp.json** :
194
+ ```json
195
+ {
196
+ "mcpServers": {
197
+ "overmind": {
198
+ "url": "http://localhost:3099/mcp",
199
+ "headers": {
200
+ "Authorization": "Bearer ${OVERMIND_AUTH}"
201
+ }
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
207
+ ---
208
+
209
+ ### PHASE 4 β€” SSL/TLS + Durcissement RΓ©seau
210
+
211
+ **Objectif** : Chiffrer les communications + rΓ©duire la surface
212
+
213
+ **TΓ’ches** :
214
+ - [ ] Activer SSL sur le port 3099 (HTTPS)
215
+ - GΓ©nΓ©rer certificat auto-signΓ© ou Let's Encrypt
216
+ - Configurer dans FastMCP httpStream
217
+ - [ ] Restreindre le bind Γ  `localhost` uniquement (sauf besoin externe)
218
+ - [ ] Ajouter rate-limiting sur les endpoints
219
+ - Max 100 req/min par IP
220
+ - Ban temporaire après 5 échecs d'auth consécutifs
221
+ - [ ] CORS restrictif (si besoin)
222
+ - [ ] Firewall : bloquer le port 3099 Γ  l'extΓ©rieur sauf reverse proxy
223
+
224
+ ---
225
+
226
+ ### PHASE 5 β€” Audit Trail & Monitoring
227
+
228
+ **Objectif** : Traçabilité complète des accès
229
+
230
+ **TΓ’ches** :
231
+ - [ ] Logger chaque requΓͺte MCP :
232
+ - Timestamp ISO 8601
233
+ - IP source
234
+ - Tool appelΓ©
235
+ - RΓ©sultat auth (success/fail)
236
+ - Agent demandeur
237
+ - [ ] Stocker les logs dans PostgreSQL (table `audit_log`)
238
+ ```sql
239
+ CREATE TABLE audit_log (
240
+ id SERIAL PRIMARY KEY,
241
+ timestamp TIMESTAMPTZ DEFAULT NOW(),
242
+ ip VARCHAR(45),
243
+ tool VARCHAR(100),
244
+ agent VARCHAR(100),
245
+ auth_result BOOLEAN,
246
+ details JSONB
247
+ );
248
+ ```
249
+ - [ ] Alertes Discord automatiques :
250
+ - 3 Γ©checs d'auth consΓ©cutifs β†’ alerte embed
251
+ - Tool critique appelΓ© β†’ notification
252
+ - [ ] Dashboard simple (endpoint `/audit/stats`)
253
+
254
+ ---
255
+
256
+ ## πŸ§ͺ PLAN DE TEST β€” Validation par Phase
257
+
258
+ ### Tests Phase 1 (Middleware)
259
+ ```
260
+ TEST │ DESCRIPTION │ RÉSULTAT ATTENDU
261
+ ─────┼────────────────────────────────┼──────────────────
262
+ T1.1 β”‚ curl POST /mcp sans header β”‚ 401 Unauthorized
263
+ T1.2 β”‚ curl POST /mcp mauvais token β”‚ 401 Unauthorized
264
+ T1.3 β”‚ curl POST /mcp bon token β”‚ 200 OK
265
+ T1.4 β”‚ curl GET /health sans token β”‚ 200 OK (exemptΓ©)
266
+ T1.5 β”‚ curl GET /health mauvais token β”‚ 200 OK (exemptΓ©)
267
+ T1.6 β”‚ Token vide β”‚ 401 Unauthorized
268
+ T1.7 β”‚ OVERMIND_AUTH non dΓ©fini β”‚ 500 / 403
269
+ ```
270
+
271
+ ### Tests Phase 2 (Couverture modules)
272
+ ```
273
+ TEST │ DESCRIPTION │ RÉSULTAT ATTENDU
274
+ ─────┼───────────────────────────────────────┼──────────────────
275
+ T2.1 β”‚ Appeler run_agent sans Bearer β”‚ Erreur MCP auth
276
+ T2.2 β”‚ Appeler run_agent avec Bearer β”‚ ExΓ©cution normale
277
+ T2.3 β”‚ Appeler memory_search sans Bearer β”‚ Erreur MCP auth
278
+ T2.4 β”‚ Appeler agent_control sans Bearer β”‚ Erreur MCP auth
279
+ T2.5 β”‚ VΓ©rifier les 14 tools couverts β”‚ 14/14 βœ…
280
+ ```
281
+
282
+ ### Tests Phase 3 (Propagation)
283
+ ```
284
+ TEST │ DESCRIPTION │ RÉSULTAT ATTENDU
285
+ ─────┼──────────────────────────────────────────┼──────────────────
286
+ T3.1 β”‚ Agent Claude appelle overmind sans Bearer β”‚ Connexion refusΓ©e
287
+ T3.2 β”‚ Agent Kilo appelle overmind avec Bearer β”‚ Connexion OK
288
+ T3.3 β”‚ Script externe sans OVERMIND_AUTH β”‚ Γ‰chec auth
289
+ T3.4 │ Script externe avec OVERMIND_AUTH │ Succès
290
+ ```
291
+
292
+ ### Tests Phase 4 (SSL + Durcissement)
293
+ ```
294
+ TEST │ DESCRIPTION │ RÉSULTAT ATTENDU
295
+ ─────┼──────────────────────────────────────────┼──────────────────
296
+ T4.1 │ Accès HTTP (non SSL) │ Connexion refusée
297
+ T4.2 │ Accès HTTPS avec cert valide │ 200 OK
298
+ T4.3 β”‚ Rate limit : 100+ req/min β”‚ 429 Too Many
299
+ T4.4 β”‚ 5 Γ©checs auth consΓ©cutifs β”‚ Ban temporaire
300
+ T4.5 │ Bind localhost uniquement │ Pas d'accès externe
301
+ ```
302
+
303
+ ### Tests Phase 5 (Audit)
304
+ ```
305
+ TEST │ DESCRIPTION │ RÉSULTAT ATTENDU
306
+ ─────┼──────────────────────────────────────────┼──────────────────
307
+ T5.1 β”‚ Appel tool β†’ vΓ©rifier log PostgreSQL β”‚ EntrΓ©e prΓ©sente
308
+ T5.2 β”‚ Γ‰chec auth β†’ vΓ©rifier log β”‚ EntrΓ©e avec auth_result=false
309
+ T5.3 β”‚ 3 Γ©checs consΓ©cutifs β†’ alerte Discord β”‚ Embed envoyΓ©
310
+ T5.4 β”‚ GET /audit/stats β”‚ JSON statistiques
311
+ ```
312
+
313
+ ---
314
+
315
+ ## πŸ“Š PRIORISATION & EFFORT
316
+
317
+ ```
318
+ PHASE │ PRIORITÉ │ EFFORT │ IMPACT │ DÉPENDANCE
319
+ ──────┼─────────────┼───────────┼────────────┼────────────
320
+ 1 β”‚ πŸ”΄ CRITIQUE β”‚ 🟑 Moyen β”‚ 🟒 MAX β”‚ Aucune
321
+ 2 β”‚ 🟠 Γ‰LEVΓ‰ β”‚ 🟑 Moyen β”‚ 🟒 Γ‰LEVΓ‰ β”‚ Phase 1
322
+ 3 β”‚ 🟑 MOYEN β”‚ 🟒 Faible β”‚ 🟑 MOYEN β”‚ Phase 1
323
+ 4 β”‚ 🟑 MOYEN β”‚ πŸ”΄ Γ‰LEVΓ‰ β”‚ 🟒 Γ‰LEVΓ‰ β”‚ Phase 1
324
+ 5 β”‚ 🟒 FAIBLE β”‚ 🟑 Moyen β”‚ 🟑 MOYEN β”‚ Phase 1+2
325
+ ```
326
+
327
+ **Recommandation** : Phase 1 immΓ©diate β†’ Phase 2 le mΓͺme jour β†’ Phase 3 le lendemain β†’ Phase 4-5 dans la semaine
328
+
329
+ ---
330
+
331
+ ## πŸ”‘ LIVRABLES
332
+
333
+ 1. `src/lib/bearerMiddleware.ts` β€” Middleware de vΓ©rification Bearer
334
+ 2. `src/lib/withAuth.ts` β€” Wrapper pour les handlers MCP
335
+ 3. `.env` β€” Ajout de `OVERMIND_AUTH=<token_sΓ©curisΓ©>`
336
+ 4. `audit_log` table PostgreSQL β€” TraΓ§abilitΓ©
337
+ 5. Documentation mise Γ  jour β€” README + SECURITY.md
338
+
339
+ ---
340
+
341
+ ## ⚠️ POINTS D'ATTENTION (Sley à vérifier)
342
+
343
+ - Le Bearer middleware doit-il Γͺtre dans `cli.ts` OU dans un hook FastMCP ?
344
+ - FastMCP v4.0.1 supporte-t-il un middleware natif ou faut-il un workaround Express ?
345
+ - STDIO doit-il aussi Γͺtre protΓ©gΓ© ou est-il trusted par design (local pipe) ?
346
+ - Le token doit-il Γͺtre rotatif ou statique ?
347
+ - Faut-il un système de scopes (admin vs lecture seule) ?
348
+
349
+ ---
350
+
351
+ *πŸ“ Document en attente de validation par sley_73350*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overmind-mcp",
3
- "version": "2.8.21",
3
+ "version": "2.8.23",
4
4
  "description": "Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mΓ©moire (Private Memory Context) et le support pour QwenCli et Nous Hermes. Installation automatique des dΓ©pendances Docker (PostgreSQL, pgvector) inclus.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,6 +18,10 @@
18
18
  "import": "./dist/index.js",
19
19
  "types": "./dist/index.d.ts"
20
20
  },
21
+ "./bridge": {
22
+ "import": "./dist/bridge/index.js",
23
+ "types": "./dist/bridge/index.d.ts"
24
+ },
21
25
  "./package.json": "./package.json"
22
26
  },
23
27
  "files": [
@@ -0,0 +1,238 @@
1
+ #!/usr/bin/env bash
2
+ # ============================================================================
3
+ # Overmind Bridge - Smoke Test (post-install validation)
4
+ # ============================================================================
5
+ #
6
+ # Verifie en moins de 10s qu'un bridge nouvellement installe repond
7
+ # correctement. A lancer apres "systemctl start overmind-bridge".
8
+ #
9
+ # Usage:
10
+ # ./scripts/bridge-smoke-test.sh
11
+ # ./scripts/bridge-smoke-test.sh --host 192.168.1.10 --port 3100
12
+ # ./scripts/bridge-smoke-test.sh --auth-token secret
13
+ #
14
+ # Exit codes:
15
+ # 0 = tous les tests OK
16
+ # 1 = au moins un test a echoue
17
+ #
18
+ # Dependances : bash 4+, curl, jq (optionnel)
19
+ # ============================================================================
20
+
21
+ set -uo pipefail
22
+
23
+ # === Defaults ===
24
+ HOST="127.0.0.1"
25
+ PORT="3100"
26
+ AUTH_TOKEN_VAL=""
27
+ ENV_FILE="/etc/overmind/bridge.env"
28
+ TIMEOUT=5
29
+
30
+ # === Couleurs, auto-desactivees si pas TTY ===
31
+ if [[ -t 1 ]]; then
32
+ C_RED=$'\033[0;31m'
33
+ C_GREEN=$'\033[0;32m'
34
+ C_YELLOW=$'\033[1;33m'
35
+ C_BLUE=$'\033[0;34m'
36
+ C_BOLD=$'\033[1m'
37
+ C_RESET=$'\033[0m'
38
+ else
39
+ C_RED=""
40
+ C_GREEN=""
41
+ C_YELLOW=""
42
+ C_BLUE=""
43
+ C_BOLD=""
44
+ C_RESET=""
45
+ fi
46
+
47
+ # === Args parsing ===
48
+ while [[ $# -gt 0 ]]; do
49
+ case "$1" in
50
+ --host) HOST="$2"; shift 2 ;;
51
+ --port) PORT="$2"; shift 2 ;;
52
+ --auth-token) AUTH_TOKEN_VAL="$2"; shift 2 ;;
53
+ --env-file) ENV_FILE="$2"; shift 2 ;;
54
+ --timeout) TIMEOUT="$2"; shift 2 ;;
55
+ -h|--help)
56
+ sed -n '2,20p' "$0" | sed 's/^# *//'
57
+ exit 0
58
+ ;;
59
+ *)
60
+ echo "Unknown arg: $1" >&2
61
+ exit 2
62
+ ;;
63
+ esac
64
+ done
65
+
66
+ # === Load token from env file si pas fourni ===
67
+ if [[ -z "${AUTH_TOKEN_VAL:-}" && -f "$ENV_FILE" ]]; then
68
+ AUTH_TOKEN_VAL="$(grep '^BRIDGE_AUTH_TOKEN=' "$ENV_FILE" | cut -d= -f2- | tr -d '"' | tr -d "'" || true)"
69
+ fi
70
+
71
+ BASE_URL="http://${HOST}:${PORT}"
72
+ PASS=0
73
+ FAIL=0
74
+
75
+ # === Helpers ===
76
+ have_jq() { command -v jq >/dev/null 2>&1; }
77
+
78
+ check() {
79
+ local name="$1"
80
+ local result="$2"
81
+ if [[ "$result" == "ok" ]]; then
82
+ echo -e " ${C_GREEN}OK${C_RESET} $name"
83
+ PASS=$((PASS + 1))
84
+ else
85
+ echo -e " ${C_RED}FAIL${C_RESET} $name"
86
+ FAIL=$((FAIL + 1))
87
+ fi
88
+ }
89
+
90
+ section() {
91
+ echo
92
+ echo -e "${C_BOLD}${C_BLUE}>> $1${C_RESET}"
93
+ }
94
+
95
+ # === Banner ===
96
+ echo -e "${C_BOLD}=======================================================${C_RESET}"
97
+ echo -e "${C_BOLD} Overmind Bridge - Smoke Test${C_RESET}"
98
+ echo -e "${C_BOLD} Target: ${BASE_URL}${C_RESET}"
99
+ echo -e "${C_BOLD}=======================================================${C_RESET}"
100
+
101
+ # === Test 1 : service joignable ===
102
+ section "1. Reachability"
103
+ HTTP_CODE=$(curl -sS --max-time "$TIMEOUT" -o /dev/null -w "%{http_code}" \
104
+ "$BASE_URL/health" 2>/dev/null || echo "000")
105
+ if echo "$HTTP_CODE" | grep -qE '^(200|401|403)$'; then
106
+ check "HTTP /health repond [200/401/403]" ok
107
+ else
108
+ check "HTTP /health ne repond pas - bridge down" fail
109
+ echo
110
+ echo -e "${C_RED}Bridge inaccessible. Abandon.${C_RESET}"
111
+ echo -e " Verifier : ${C_YELLOW}systemctl status overmind-bridge${C_RESET}"
112
+ exit 1
113
+ fi
114
+
115
+ # === Test 2 : /health retourne un JSON valide ===
116
+ section "2. /health endpoint"
117
+ HEALTH_BODY=$(curl -sS --max-time "$TIMEOUT" "$BASE_URL/health" 2>/dev/null || true)
118
+
119
+ if have_jq; then
120
+ HEALTH_STATUS=$(echo "$HEALTH_BODY" | jq -r '.status // "missing"' 2>/dev/null)
121
+ else
122
+ HEALTH_STATUS=$(echo "$HEALTH_BODY" | grep -oE '"status"[[:space:]]*:[[:space:]]*"[^"]+"' | head -1 | cut -d'"' -f4)
123
+ fi
124
+
125
+ if [[ -n "${HEALTH_STATUS:-}" && "$HEALTH_STATUS" != "missing" ]]; then
126
+ check "/health expose un status : $HEALTH_STATUS" ok
127
+ else
128
+ check "/health n expose pas de status - endpoint casse" fail
129
+ fi
130
+
131
+ # === Build AUTH_HEADER array for reuse ===
132
+ AUTH_HEADER=()
133
+ if [[ -n "${AUTH_TOKEN_VAL:-}" ]]; then
134
+ AUTH_HEADER=(-H "Authorization: Bearer ${AUTH_TOKEN_VAL}")
135
+ fi
136
+
137
+ # === Test 3 : auth requise si token configure ===
138
+ section "3. Authentication"
139
+ if [[ -n "${AUTH_TOKEN_VAL:-}" ]]; then
140
+ HTTP_NO_AUTH=$(curl -sS --max-time "$TIMEOUT" -o /dev/null -w "%{http_code}" \
141
+ -X POST "$BASE_URL/rpc" \
142
+ -H 'Content-Type: application/json' \
143
+ -d '{"jsonrpc":"2.0","id":1,"method":"health.ping","params":{}}' 2>/dev/null || echo "000")
144
+
145
+ if [[ "$HTTP_NO_AUTH" == "401" ]]; then
146
+ check "Sans token -> 401, auth actif" ok
147
+ else
148
+ check "Sans token -> $HTTP_NO_AUTH [attendu: 401]" fail
149
+ fi
150
+
151
+ HTTP_WITH_AUTH=$(curl -sS --max-time "$TIMEOUT" -o /dev/null -w "%{http_code}" \
152
+ -X POST "$BASE_URL/rpc" \
153
+ "${AUTH_HEADER[@]}" \
154
+ -H 'Content-Type: application/json' \
155
+ -d '{"jsonrpc":"2.0","id":1,"method":"health.ping","params":{}}' 2>/dev/null || echo "000")
156
+
157
+ if [[ "$HTTP_WITH_AUTH" == "200" ]]; then
158
+ check "Avec token -> 200, auth OK" ok
159
+ else
160
+ check "Avec token -> $HTTP_WITH_AUTH [attendu: 200]" fail
161
+ fi
162
+ else
163
+ HTTP_OPEN=$(curl -sS --max-time "$TIMEOUT" -o /dev/null -w "%{http_code}" \
164
+ -X POST "$BASE_URL/rpc" \
165
+ -H 'Content-Type: application/json' \
166
+ -d '{"jsonrpc":"2.0","id":1,"method":"health.ping","params":{}}' 2>/dev/null || echo "000")
167
+
168
+ if [[ "$HTTP_OPEN" == "200" ]]; then
169
+ check "/rpc ouvert, auth non configuree" ok
170
+ else
171
+ check "/rpc ouvert -> $HTTP_OPEN [attendu: 200]" fail
172
+ fi
173
+ fi
174
+
175
+ # === Test 4 : health.ping RPC ===
176
+ section "4. JSON-RPC methods"
177
+ PING_BODY=$(curl -sS --max-time "$TIMEOUT" \
178
+ "${AUTH_HEADER[@]}" \
179
+ -H 'Content-Type: application/json' \
180
+ -X POST "$BASE_URL/rpc" \
181
+ -d '{"jsonrpc":"2.0","id":1,"method":"health.ping","params":{}}' 2>/dev/null || true)
182
+
183
+ if echo "$PING_BODY" | grep -q '"pong"[[:space:]]*:[[:space:]]*true'; then
184
+ check "RPC health.ping repond" ok
185
+ else
186
+ check "RPC health.ping echoue - body: ${PING_BODY:0:100}" fail
187
+ fi
188
+
189
+ # === Test 5 : JSON-RPC validation (params invalides) ===
190
+ section "5. Error handling"
191
+ INVALID_BODY=$(curl -sS --max-time "$TIMEOUT" \
192
+ "${AUTH_HEADER[@]}" \
193
+ -H 'Content-Type: application/json' \
194
+ -X POST "$BASE_URL/rpc" \
195
+ -d '{"jsonrpc":"2.0","id":1,"method":"agent.run","params":{}}' 2>/dev/null || true)
196
+
197
+ if echo "$INVALID_BODY" | grep -q '"code"[[:space:]]*:[[:space:]]*-32602'; then
198
+ check "Params invalides -> -32602 Invalid params" ok
199
+ else
200
+ check "Params invalides - code attendu: -32602, recu: $INVALID_BODY" fail
201
+ fi
202
+
203
+ # === Test 6 : batch request ===
204
+ section "6. Batch RPC"
205
+ BATCH_BODY=$(curl -sS --max-time "$TIMEOUT" \
206
+ "${AUTH_HEADER[@]}" \
207
+ -H 'Content-Type: application/json' \
208
+ -X POST "$BASE_URL/rpc" \
209
+ -d '[\
210
+ {"jsonrpc":"2.0","id":1,"method":"health.ping","params":{}},\
211
+ {"jsonrpc":"2.0","id":2,"method":"health.ping","params":{}}\
212
+ ]' 2>/dev/null || true)
213
+
214
+ BATCH_COUNT=$(echo "$BATCH_BODY" | grep -oE '"id"[[:space:]]*:[[:space:]]*[12]' | wc -l | tr -d ' ')
215
+ if [[ "$BATCH_COUNT" == "2" ]]; then
216
+ check "Batch RPC retourne 2 reponses" ok
217
+ else
218
+ check "Batch RPC - recu: $BATCH_COUNT reponses [attendu: 2]" fail
219
+ fi
220
+
221
+ # === Resume ===
222
+ echo
223
+ echo -e "${C_BOLD}=======================================================${C_RESET}"
224
+ if [[ $FAIL -eq 0 ]]; then
225
+ echo -e "${C_GREEN}${C_BOLD} OK $PASS tests OK, 0 echec${C_RESET}"
226
+ echo -e "${C_GREEN} Bridge operationnel sur ${BASE_URL}${C_RESET}"
227
+ echo -e "${C_BOLD}=======================================================${C_RESET}"
228
+ exit 0
229
+ else
230
+ echo -e "${C_RED}${C_BOLD} FAIL $FAIL echec(s), $PASS tests OK${C_RESET}"
231
+ echo
232
+ echo -e " ${C_YELLOW}Diagnostic :${C_RESET}"
233
+ echo -e " 1. ${C_YELLOW}systemctl status overmind-bridge${C_RESET}"
234
+ echo -e " 2. ${C_YELLOW}journalctl -u overmind-bridge -n 100${C_RESET}"
235
+ echo -e " 3. ${C_YELLOW}curl -v $BASE_URL/health${C_RESET}"
236
+ echo -e "${C_BOLD}=======================================================${C_RESET}"
237
+ exit 1
238
+ fi