Confrontation Audit -- ai-orchestrator
Date : 15/02/2026 05:00
Status : IMPLEMENTEE
Auditeur senior : Claude Opus 4.6 (confrontation finale)
Methode : Lecture integrale des 3 passes, cross-reference avec le code source, arbitrage des divergences
Resume executif
| Metrique |
Valeur |
| Findings CONFIRMES (2-3 passes) |
22 |
| Findings UNIQUES (1 seule passe) |
14 |
| Faux positifs elimines |
3 |
| Contradictions resolues |
5 |
| Total findings retenus |
33 |
Les 3 passes convergent fortement sur les problemes structurels majeurs (cloud jobs sans tracking, race condition budget Anthropic, credentials hardcodes, Ollama generate sans num_ctx). Les divergences portent principalement sur les niveaux de severite et sur quelques findings peripheriques.
Findings CONFIRMES (2-3 passes concordantes)
C-01 : Cloud jobs (Anthropic) dispatches sans tracking ni limite de concurrence
- Confirme par : Pass 1 (F05) + Pass 2 (F01) + Pass 3 (F-07)
- Severite definitive : BUG CERTAIN
- Description consolidee : Quand un job
tool_id in CLOUD_TOOLS est poppe de Redis, il est dispatche via asyncio.create_task(process_single_job(job_id, tool_id)) (ligne 4269). La variable task locale n'est jamais stockee dans aucune structure (gpu_slots, liste dediee, etc.). Consequences : (1) parallelisme illimite -- si 100 jobs Anthropic sont en queue, 100 requetes HTTP partent simultanement ; (2) au shutdown (lignes 4318-4327), seules les taches dans gpu_slots sont annulees, pas les cloud tasks ; (3) le watchdog GPU (lignes 4193-4222) ne surveille pas ces tasks ; (4) la variable locale task est garbage-collectee, risquant un warning asyncio "Task was destroyed but it is pending".
- Impact : Depassement de budget, epuisement des descripteurs de fichiers, pas de cleanup au shutdown.
- Priorite de correction : CRITIQUE
C-02 : Race condition budget Anthropic (TOCTOU)
- Confirme par : Pass 1 (F06) + Pass 2 (F02) + Pass 3 (F-08)
- Severite definitive : BUG CERTAIN
- Description consolidee :
check_anthropic_budget() (ligne 2895+) lit SUM(cost_usd) WHERE status='completed' en DB. Le cout d'un job n'est ecrit qu'a la fin (db_update_job_status("completed", cost_usd=...)). Combine avec C-01 (pas de limite de concurrence), N jobs Anthropic concurrents voient tous le meme budget restant et passent tous le check. Budget=$120, deja=$119, 10 jobs simultanes : chacun voit $119 < $120, depense ~$1 chacun. Total final = $129.
- Impact : Depassement de budget garanti sous charge concurrente.
- Priorite de correction : CRITIQUE
C-03 : Credentials Redis et PostgreSQL hardcodes dans le code source
- Confirme par : Pass 1 (F01) + Pass 2 (F11) + Pass 3 (F-03)
- Severite definitive : BUG CERTAIN
- Description consolidee :
REDIS_PASSWORD et POSTGRES_PASSWORD ont des valeurs par defaut hardcodees (lignes 35-40). La conf.prod.gouroubleu.yml ne definit PAS ces variables d'env, donc ce sont les valeurs hardcodees qui sont utilisees en production. Le repo GitLab prive expose ces credentials a tout lecteur. Toute rotation de mot de passe necessite un rebuild.
- Impact : Fuite de credentials si le repo est expose. Impossibilite de rotation sans rebuild.
- Priorite de correction : HAUTE
C-04 : Ollama generate sans num_ctx --> OOM possible
- Confirme par : Pass 1 (F14) uniquement, mais verification de code directe confirme le bug
- Severite definitive : BUG CERTAIN
- Description consolidee : Pour le job_type
chat, num_ctx est bien passe dans les options (lignes 2577-2588). Mais pour le job_type generate (mode par defaut, lignes 2654-2663), num_ctx n'est PAS passe dans les options. Ollama utilisera le context window par defaut du modele (128k+ pour Qwen3), causant une allocation VRAM massive.
- Verification directe : Confirme par lecture du code -- l'objet
request_data["options"] en mode generate ne contient que temperature et num_predict, pas de num_ctx.
- Note : Pass 2 et Pass 3 ne l'ont pas explicitement mentionne, mais c'est un bug factuel verifie dans le code.
- Impact : OOM Ollama = crash = tous les jobs LLM echouent.
- Priorite de correction : CRITIQUE
C-05 : CORS allow_origins=["*"] avec allow_credentials=True
- Confirme par : Pass 1 (F16) + Pass 2 (F12) + Pass 3 (F-16)
- Severite definitive : RISQUE THEORIQUE
- Description consolidee : La config CORS (lignes 176-182) combine
allow_origins=["*"] avec allow_credentials=True. Invalide selon la spec CORS. Les 3 passes s'accordent sur le fait que l'impact est quasi nul car le service n'utilise pas de cookies/auth et les appels viennent principalement de connectors-api (server-to-server), pas de navigateurs.
- Impact : Nul actuellement. Deviendrait un probleme si une authentification est ajoutee.
- Priorite de correction : BASSE
C-06 : Variable is_cloud redefinie inutilement dans le meme scope
- Confirme par : Pass 1 (F23) + Pass 2 (F03) + Pass 3 (F-17)
- Severite definitive : RISQUE THEORIQUE
- Description consolidee :
is_cloud = tool_id in CLOUD_TOOLS est calculee en ligne 3943, puis recalculee a l'identique en ligne 4045. Code redondant issu d'un refactoring incomplet. Les 3 passes convergent : pas de bug actuel, mais risque de confusion lors de modifications futures.
- Impact : Aucun. Code cleanup.
- Priorite de correction : BASSE
C-07 : Commentaire set_parallel_jobs incoherent avec le code (1-5 vs 1-10)
- Confirme par : Pass 1 (F04) + Pass 2 (F19) + Pass 3 (F-28)
- Severite definitive : RISQUE THEORIQUE
- Description consolidee : Le docstring dit "1-5", le commentaire inline dit "1 and 5", mais le code fait
max(1, min(10, count)). Un utilisateur peut configurer 10 jobs paralleles Ollama ce qui pourrait causer un OOM sur le GPU 2070S (8 GB VRAM).
- Impact : Confusion. Potentiel OOM si l'utilisateur configure 10 jobs paralleles sur GPU1.
- Priorite de correction : BASSE
C-08 : Batch API httpx : client reutilise pendant 2h de polling
- Confirme par : Pass 1 (F10) + Pass 2 (F04) + Pass 3 (F-15)
- Severite definitive : BUG PROBABLE
- Description consolidee : Le
httpx.AsyncClient pour le batch Anthropic est cree avec timeout=30s et utilise pendant toute la duree du polling (jusqu'a 2h). Bien que le timeout soit par requete et non global, les connexions TCP sous-jacentes peuvent etre fermees par des intermediaires. De plus (identifie par Pass 2 et Pass 3), le code ne distingue pas les erreurs fatales (401, 404) des erreurs transitoires (500, 429) -- toutes recoivent un continue et le polling recommence pour 240 iterations.
- Impact : Un batch avec auth revokee ou batch invalide poll en boucle pendant 2h. Gaspillage de ressources.
- Priorite de correction : MOYENNE
C-09 : SadTalker cleanup : task orpheline et zombie process
- Confirme par : Pass 1 (F13) + Pass 2 (F10) + Pass 3 (F-26)
- Severite definitive : BUG CERTAIN
- Description consolidee :
asyncio.create_task(asyncio.create_subprocess_shell(cleanup_cmd)) (ligne 3824) cree une task qui spawne un process SSH. Le Process retourne n'est jamais wait()ed, ce qui laisse un zombie. La task elle-meme n'est ni stockee ni awaitee, donc perdue au GC ou en cas de shutdown. Les fichiers temporaires sur win11 (I:\SadTalker\inputs\) ne sont pas toujours nettoyes.
- Impact : Accumulation de fichiers temporaires sur win11. Zombie process.
- Priorite de correction : BASSE
C-10 : Job poppe de Redis mais DB echoue --> job perdu
- Confirme par : Pass 2 (F05) + Pass 3 (F-02 partiellement, F-05 partiellement)
- Severite definitive : BUG PROBABLE
- Description consolidee : Le worker fait
queue_pop_job() (rpop Redis, ligne 4248) puis db_get_job(job_id) (ligne 4256). Si la DB est temporairement indisponible, l'exception est capturee par le except Exception global et le job est perdu (retire de Redis, jamais traite). Le /api/queue/sync existe mais necessite une intervention manuelle, et n'est PAS appele au demarrage.
- Impact : Perte de job en cas de panne DB transitoire.
- Priorite de correction : HAUTE
C-11 : Absence de queue_sync au demarrage
- Confirme par : Pass 3 (F-02, F-05) + Pass 2 (implicite dans la section gestion d'etat)
- Severite definitive : BUG PROBABLE
- Description consolidee : L'endpoint
/api/queue/sync existe pour resynchroniser Redis et PostgreSQL, mais il n'est JAMAIS appele automatiquement au demarrage du container (la fonction lifespan ne l'appelle pas). Apres un crash, des jobs "pending" en DB mais absents de Redis ne seront jamais traites.
- Impact : Jobs fantomes apres un crash/restart. Necessite intervention manuelle.
- Priorite de correction : HAUTE
C-12 : Requeue infini sans compteur de retry
- Confirme par : Pass 2 (F06) + Pass 3 (implicite dans l'analyse du requeue pattern)
- Severite definitive : BUG PROBABLE
- Description consolidee : Quand un job est requeue (GPU unreachable, tool busy, etc.), aucun compteur de retry n'est incremente. Le champ
retry_count du modele Job n'est jamais ecrit. Un job qui demande un tool definitivement casse sera requeue indefiniment (pop -> check -> requeue -> pop...) a raison d'un cycle toutes les 5 secondes.
- Impact : Consommation de cycles et de logs. Pas de blocage des autres jobs grace au FIFO, mais le job problematique ne sera jamais marque comme echoue.
- Priorite de correction : MOYENNE
C-13 : SSH process non kill en cas de timeout dans run_ssh_command
- Confirme par : Pass 2 (F18) + Pass 3 (F-09)
- Severite definitive : BUG PROBABLE
- Description consolidee : Dans
run_ssh_command (lignes 810-826), quand asyncio.wait_for leve TimeoutError, le process SSH sous-jacent n'est pas kill()ed. Il reste orphelin en arriere-plan. Avec les health checks toutes les 30s et les commandes SSH frequentes, les processes s'accumulent.
- Impact : Accumulation de processus zombies SSH. Potentiel epuisement de descripteurs de fichiers.
- Priorite de correction : MOYENNE
C-14 : Watchdog GPU parse "N/A" --> ValueError silencieux
- Confirme par : Pass 1 (F07) + Pass 3 (F-14)
- Severite definitive : BUG CERTAIN (mais sans impact fonctionnel grace au try/except)
- Description consolidee : Le watchdog fait
int(gpu.vram_used.replace(" Mo", "")) (ligne 4206). Quand GPU unreachable, vram_used="N/A", ce qui leve ValueError. Le except Exception: pass (ligne 4221) avale l'erreur. Le watchdog est silencieusement desactive quand le GPU est unreachable. Les 2 passes s'accordent : ce n'est pas grave en soi, mais c'est du code fragile.
- Impact : Watchdog inactif quand GPU unreachable. Acceptable.
- Priorite de correction : BASSE
C-15 : Bare except clauses attrapent CancelledError et SystemExit
- Confirme par : Pass 1 (F18) + Pass 3 (F-10)
- Severite definitive : BUG PROBABLE
- Description consolidee : Au moins 11 occurrences de
except: sans type d'exception (Pass 1 liste les lignes). Cela attrape CancelledError, SystemExit, KeyboardInterrupt. En particulier, check_tool_health (ligne 842) avale CancelledError, ce qui casse le protocole de cancellation asyncio et peut ralentir le shutdown du container.
- Impact : Shutdown plus lent. Protocol de cancellation asyncio casse a certains endroits.
- Priorite de correction : MOYENNE
C-16 : Pas de validation de taille sur les uploads
- Confirme par : Pass 2 (F13) + Pass 3 (F-23)
- Severite definitive : RISQUE THEORIQUE
- Description consolidee :
POST /api/upload fait content = await file.read() sans limite de taille. Un fichier de plusieurs Go serait lu entierement en memoire, causant un OOM kill du container.
- Impact : DoS possible par upload massif. Service interne donc risque attenue.
- Priorite de correction : BASSE
C-17 : Pas d'authentification sur aucun endpoint
- Confirme par : Pass 2 (F14) + Pass 3 (implicite dans les sections securite)
- Severite definitive : RISQUE THEORIQUE
- Description consolidee : Aucun endpoint n'a de middleware d'authentification. L'acces est restreint par le reseau (nginx reverse proxy avec split-DNS). Mais toute personne sur le LAN a un controle total : creer des jobs Anthropic (cout), pauser le worker, supprimer des fichiers.
- Impact : Risque budgetaire et d'integrite si un utilisateur non autorise est sur le LAN.
- Priorite de correction : BASSE (service interne, reseau prive)
C-18 : costs_summary avec year/month hardcodes en default
- Confirme par : Pass 1 (F15) + Pass 3 (F-29)
- Severite definitive : BUG CERTAIN
- Description consolidee :
async def costs_summary(period: str = "month", year: int = 2026, month: int = 2) (ligne 4595). A partir de mars 2026, l'endpoint retourne par defaut les couts de fevrier. Devrait utiliser datetime.now().year et datetime.now().month.
- Impact : Donnees erronees si l'utilisateur n'envoie pas les parametres.
- Priorite de correction : MOYENNE
C-19 : tools_state et active_tools en memoire sans resynchronisation automatique
- Confirme par : Pass 2 (F07) + Pass 3 (F-18 partiellement)
- Severite definitive : BUG PROBABLE
- Description consolidee :
tools_state et active_tools sont des dictionnaires en memoire initialises au demarrage. Si un outil crash sur win11, tools_state dit toujours RUNNING. Le seul moyen de resynchroniser est /api/tools/refresh qui n'est JAMAIS appele automatiquement. Le worker fait des health checks ponctuels (avant chaque job) mais ne met pas a jour tools_state globalement.
- Impact : Les endpoints API
/api/tools et /api/gpu retournent des informations potentiellement fausses.
- Priorite de correction : BASSE
C-20 : Path traversal via chemins absolus dans les fonctions d'execution
- Confirme par : Pass 1 (F21) + Pass 2 (F21 tangentiellement)
- Severite definitive : BUG CERTAIN
- Description consolidee : Cinq fonctions d'execution (facefusion, applio, triposr, yolo, sadtalker) acceptent des chemins absolus dans les
input_params via le pattern if not file.startswith("/") else file. Cela bypasse le prefixe INPUTS_PATH et permet de lire/transmettre n'importe quel fichier du container.
- Impact : Lecture de fichiers arbitraires du container (volumes montes inclus : ai-data et .ssh). Risque attenue car service interne.
- Priorite de correction : HAUTE
C-21 : SSH injection via facefusion params (face_swapper_model, face_enhancer_model)
- Confirme par : Pass 1 (F11) + Pass 2 (section 7.2 securite)
- Severite definitive : BUG CERTAIN
- Description consolidee : Les parametres
face_swapper_model et face_enhancer_model sont interpoles directement dans la commande CLI passee a SSH (lignes 2390-2407). Un parametre contenant & del /s C:\ pourrait etre execute sur win11 via cmd /c. La commande utilise cmd /c sur Windows, et && est un separateur valide sur Windows.
- Impact : Execution de commandes arbitraires sur win11. Attenue car service interne et les parametres viennent de l'API (pas d'UI directe).
- Priorite de correction : HAUTE
C-22 : Nginx conf sans private:true --> API potentiellement exposee publiquement
- Confirme par : Pass 1 (F27) uniquement, mais verification de conf.prod.gouroubleu.yml confirme l'absence
- Severite definitive : BUG CERTAIN
- Description consolidee : La section
nginx: de conf.prod.gouroubleu.yml a enabled: true et ssl: true mais PAS private: true. Smart-deploy ne genere donc pas de restriction IP. Le domaine ai-orchestrator.33800.nowhere84.com pointe vers l'IP publique (82.65.119.221). Si le port 443 est forward par la Freebox vers nginx, l'API est accessible depuis internet sans authentification.
- Verification directe : Confirme -- la conf lue ne contient pas
private: true.
- Note : Pass 2 et Pass 3 ne l'ont pas explicitement mentionne car ils se sont concentres sur le code Python, pas sur la conf de deploiement.
- Impact : Si le port forwarding est actif, n'importe qui peut creer des jobs (cout Anthropic), pauser le worker, uploader des fichiers.
- Priorite de correction : CRITIQUE
Findings UNIQUES (1 seule passe)
U-01 : WIN11_HOST defini deux fois (constante ecrase l'env var)
- Source : Pass 1 (F02)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Les passes 2 et 3 se sont concentrees sur les data flows et l'integration inter-services, pas sur les details de configuration.
- Verdict : CONFIRME. La ligne 185 est une reassignation constante qui ecrase toute variable d'env. Bug reel mais sans impact actuel (la valeur est identique).
U-02 : Race condition requeue au crash (pop Redis -> crash -> jamais requeue)
- Source : Pass 1 (F03)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Pass 2 (F05) et Pass 3 (F-02) traitent des aspects proches (job perdu entre Redis et DB) mais pas exactement le meme scenario de crash entre pop et requeue.
- Verdict : CONFIRME. Risque theorique couvert par
/api/queue/sync.
U-03 : VRAM estimation Ollama multi-modeles sous-estimee (max vs sum)
- Source : Pass 1 (F09)
- Severite : BUG PROBABLE
- Pourquoi les autres passes ne l'ont pas trouve : Les passes 2 et 3 n'ont pas analyse en detail la logique
can_dispatch et l'estimation VRAM.
- Verdict : CONFIRME. Si deux jobs demandent des modeles differents avec
keep_alive > 0, le VRAM reel est la somme, pas le max. Peut causer un OOM Ollama.
U-04 : Upload ecrasement silencieux de fichiers existants
- Source : Pass 1 (F12)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Pas considere comme un probleme significatif par les autres passes.
- Verdict : CONFIRME. Comportement potentiellement voulu pour un service interne, mais non documente.
U-05 : Pas de init.py dans app/
- Source : Pass 1 (F17)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Detail de packaging Python, pas dans le scope des analyses data flow ou integration.
- Verdict : CONFIRME. Bonne pratique mais pas un bug.
U-06 : SSH StrictHostKeyChecking=no partout
- Source : Pass 1 (F19)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Pass 2 et 3 le mentionnent dans leur analyse SSH mais ne l'ont pas classe comme finding distinct.
- Verdict : CONFIRME. Risque MITM minimal sur LAN prive.
U-07 : Imports repetes dans les fonctions (11x import aiohttp)
- Source : Pass 1 (F22)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Style/maintenabilite, pas de bug fonctionnel.
- Verdict : CONFIRME. Cleanup de code.
U-08 : Fooocus seed 2^63 vs 2^32
- Source : Pass 1 (F26)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Detail tres specifique d'un seul outil.
- Verdict : A VERIFIER. Depend de l'implementation interne de Fooocus. Probablement sans impact.
U-09 : SadTalker job_id interpole sans validation explicite
- Source : Pass 1 (F28)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Le job_id est un UUID genere internement, donc safe. Les passes 2 et 3 ont considere cela implicitement.
- Verdict : CONFIRME. Defense in depth, pas de bug actuel.
U-10 : Applio 60 parametres positionels fragiles
- Source : Pass 1 (F29)
- Severite : BASSE
- Pourquoi les autres passes ne l'ont pas trouve : Detail specifique a un seul outil.
- Verdict : CONFIRME. Fragile mais fonctionnel pour la version actuelle.
U-11 : Schema SQL absent du repo
- Source : Pass 3 (F-04)
- Severite : BUG PROBABLE
- Pourquoi les autres passes ne l'ont pas trouve : Pass 1 et 2 ont audite le code existant en supposant que la table existe. Pass 3 a eu le reflexe de verifier la presence du schema dans le repo.
- Verdict : CONFIRME. Impossible de reconstruire l'infrastructure a partir du repo seul. Cela devrait etre un fichier
schema.sql ou un systeme de migrations.
U-12 : Health endpoint crash si Redis est down
- Source : Pass 3 (F-06)
- Severite : BUG CERTAIN
- Pourquoi les autres passes ne l'ont pas trouve : Pass 1 a regarde le health endpoint mais n'a pas trace le chemin d'erreur si Redis est down. Pass 2 l'a mentionne dans la section "gestion d'etat" mais ne l'a pas classe comme finding distinct.
- Verification directe : Confirme --
/health fait await redis_client.get(WORKER_PAUSED_KEY) sans try/except. Si Redis est down, le healthcheck retourne 500, Docker restart le container, boucle de restart.
- Verdict : CONFIRME. Bug important qui peut causer une boucle de restart du container.
U-13 : stop_tool et refresh_tools_status ne filtrent pas les CLOUD_TOOLS
- Source : Pass 3 (F-12, F-13)
- Severite : BUG PROBABLE
- Pourquoi les autres passes ne l'ont pas trouve : Pass 1 et 2 se sont concentrees sur le dispatching cloud, pas sur les operations de management (stop/refresh) appliquees aux outils cloud.
- Verdict : CONFIRME.
stop_tool("anthropic") envoie des commandes SSH inutiles pour tester le port 0 sur win11. refresh_tools_status passe le status d'anthropic de RUNNING a STOPPED apres chaque refresh. Cree aussi une entree parasite active_tools[-1].
U-14 : Anthropic batch ne verifie pas result.type "succeeded" vs "errored"
- Source : Pass 3 (F-25)
- Severite : BUG PROBABLE
- Pourquoi les autres passes ne l'ont pas trouve : Pass 1 et 2 ont audite la mecanique du polling mais pas le parsing du resultat JSONL en detail.
- Verdict : CONFIRME. Un batch errored retourne une reponse vide au lieu d'un message d'erreur clair.
Contradictions resolues
Contradiction 1 : Severite des credentials hardcodes
- Pass 1 : BASSE (service interne, git prive)
- Pass 2 : RISQUE THEORIQUE (meme justification)
- Pass 3 : BUG CERTAIN
- Arbitrage : BUG CERTAIN, priorite HAUTE. Le code utilise effectivement les valeurs hardcodees en production (verifie : conf.prod.gouroubleu.yml ne definit pas ces variables). C'est factuellement un bug de pratique, meme si le risque immediat est faible. La severite n'est pas CRITIQUE car le repo est prive et le reseau local.
Contradiction 2 : Severite du batch httpx polling
- Pass 1 : BASSE (THEORIQUE)
- Pass 2 : BUG CERTAIN
- Pass 3 : BUG PROBABLE
- Arbitrage : BUG PROBABLE, priorite MOYENNE. Le client httpx reutilise pendant 2h n'est pas un bug "certain" car httpx gere le pool de connexions et reessaie. Cependant, l'absence de distinction entre erreurs fatales (401) et transitoires (500) dans le polling EST un bug probable reel -- identifie par les passes 2 et 3 mais pas la passe 1.
Contradiction 3 : Classification du double escaping backslash Windows
- Pass 1 : BASSE (THEORIQUE, "castle de cards qui fonctionne par accident")
- Pass 3 : BUG PROBABLE (incoherence d'escaping entre start_tool et run_ssh_command)
- Arbitrage : RISQUE THEORIQUE, priorite BASSE. Ca fonctionne en production. Les 2 passes reconnaissent que le resultat est correct grace au double desescaping SSH+cmd.exe. Pass 3 a raison de noter l'incoherence entre start_tool (escape manuel) et run_ssh_command (escape different), mais tant que ca marche, ne pas y toucher. Conforme a la regle "JAMAIS changer ce qui fonctionne".
Contradiction 4 : Severite de la race condition cancel/worker
- Pass 1 : Non identifie comme finding distinct
- Pass 2 : F16, RISQUE THEORIQUE
- Pass 3 : F-01, BUG CERTAIN
- Arbitrage : RISQUE THEORIQUE. La fenetre de race est tres etroite. Le worker verifie
status != "pending" apres le pop (ligne 4261). Le scenario ou le cancel s'execute apres le pop mais avant le check status, et ou le check voit encore "pending", est possible mais extremement improbable. Le resultat (job execute malgre cancel) n'est pas catastrophique.
Contradiction 5 : Severite CORS
- Pass 1 : BASSE
- Pass 2 : RISQUE THEORIQUE
- Pass 3 : BUG PROBABLE
- Arbitrage : RISQUE THEORIQUE, priorite BASSE. Les 3 passes s'accordent sur le fait que l'impact est nul actuellement. Pass 3 le classe "BUG PROBABLE" car les navigateurs refuseraient les requetes avec credentials, mais en pratique aucun navigateur n'appelle directement l'API avec credentials. Le service est appele par connectors-api (server-to-server).
Faux positifs elimines
FP-01 : Path traversal via job_id dans download_output (Pass 1 F12 discussion, Pass 2 F21)
- Justification : Les 2 passes qui l'ont examine ont conclu que FastAPI
{job_id} est un segment de path qui n'accepte pas les /. Un job_id de .. est theoriquement possible mais ne sort que d'un niveau (dans ai-data/ au lieu de outputs/), et le job_id est toujours un UUID genere internement. Pas exploitable en pratique.
FP-02 : docker-compose.yml ne declare pas Redis/Postgres (Pass 3 F-21)
- Justification : Le docker-compose.yml n'est PAS utilise en production (c'est conf.prod.gouroubleu.yml + smart-deploy qui orchestre). Le docker-compose.yml est pour le dev local. L'absence de variables Redis/Postgres dans docker-compose.yml est un detail de configuration dev, pas un bug de production. Le vrai probleme (credentials hardcodes) est deja couvert par C-03.
FP-03 : ANTHROPIC_API_KEY vide dans conf.prod.gouroubleu.yml (Pass 3 F-22)
- Justification : La cle API Anthropic est probablement injectee via le fichier
prod.env de smart-deploy (qui contient les secrets). L'entrée ANTHROPIC_API_KEY: "" dans la conf est un placeholder qui est override par le mecanisme de secrets. Si la cle etait reellement vide, TOUS les jobs Anthropic auraient echoue depuis toujours, ce qui n'est manifestement pas le cas (le systeme de tracking des couts Anthropic implique des jobs reussis).
Top 10 actions prioritaires
| # |
Finding |
Priorite |
Effort |
Description |
| 1 |
C-04 |
CRITIQUE |
5 min |
Ajouter num_ctx: 8192 dans le mode generate d'Ollama -- peut causer un OOM a tout moment |
| 2 |
C-22 |
CRITIQUE |
2 min |
Ajouter private: true dans la section nginx de conf.prod.gouroubleu.yml -- si port forwarding actif, API exposee publiquement sans auth |
| 3 |
C-01 + C-02 |
CRITIQUE |
1h |
Tracker les cloud tasks + limiter la concurrence Anthropic (asyncio.Semaphore + liste de tasks). Resout aussi la race condition budget car les jobs sont serialises. |
| 4 |
U-12 |
HAUTE |
5 min |
Proteger le healthcheck contre Redis down -- wrapper dans try/except, retourner "worker_paused": "unknown" si Redis indisponible |
| 5 |
C-20 |
HAUTE |
15 min |
Supprimer le bypass startswith("/") dans les fonctions d'execution -- path traversal dans 5 fonctions |
| 6 |
C-21 |
HAUTE |
15 min |
Sanitiser face_swapper_model et face_enhancer_model avec whitelist alphanumerique ou liste de modeles valides |
| 7 |
C-11 |
HAUTE |
10 min |
Ajouter queue_sync au demarrage dans la fonction lifespan -- resynchronise Redis/PostgreSQL apres crash |
| 8 |
C-03 |
HAUTE |
15 min |
Externaliser les credentials dans conf.prod.gouroubleu.yml (REDIS_PASSWORD, POSTGRES_PASSWORD) et lever une erreur si absents |
| 9 |
C-13 |
MOYENNE |
10 min |
Ajouter proc.kill() + await proc.wait() dans run_ssh_command en cas de timeout -- evite l'accumulation de processus zombies |
| 10 |
C-15 |
MOYENNE |
20 min |
Remplacer except: par except Exception: partout (11+ occurrences) -- corrige le protocole de cancellation asyncio |