Files
rpa_vision_v3/tests/unit/test_agent_config.py
Dom 4f61741420
Some checks failed
security-audit / Bandit (scan statique) (push) Successful in 14s
security-audit / pip-audit (CVE dépendances) (push) Successful in 10s
security-audit / Scan secrets (grep) (push) Successful in 8s
tests / Lint (ruff + black) (push) Successful in 13s
tests / Tests unitaires (sans GPU) (push) Failing after 14s
tests / Tests sécurité (critique) (push) Has been skipped
feat: journée 17 avril — tests E2E validés, dashboard fleet+audit, VWB bridge, cleaner C2
Pipeline E2E complet validé :
  Capture VM → streaming → serveur → cleaner → replay → audit trail
  Mode apprentissage supervisé fonctionne (Léa échoue → humain → reprise)

Dashboard :
  - Cleanup 14→10 onglets (RCE supprimée)
  - Fleet : enregistrer/révoquer agents, tokens, ZIP pré-configuré téléchargeable
  - Audit trail MVP (/audit) : filtres, tableau, export CSV, conformité AI Act/RGPD
  - Formulaire Fleet simplifié (nom + email, machine_id auto)

VWB bridge Léa→VWB :
  - Compound décomposés en N steps (saisie + raccourci visibles)
  - Layout serpentin 3 colonnes (plus colonne verticale)
  - Badge OS 🪟/🐧, filtre OS retiré (admin Linux voit Windows)
  - Fix import SQLite readonly

Cleaner intelligent :
  - Descriptions lisibles (UIA/C2) + détection doublons
  - Logique C2 : UIElement identifié = jamais parasite
  - Patterns parasites resserrés
  - Message Léa : "Je n'y arrive pas, montrez-moi comment faire"

Config agent (INC-1 à INC-7) :
  - SERVER_URL + SERVER_BASE unifiés
  - RPA_OLLAMA_HOST séparé
  - allow_redirects=False sur POST
  - Middleware réécriture URL serveur

CI Gitea : fix token + Flask-SocketIO + ruff propre
Fleet endpoints : /agents/enroll|uninstall|fleet + agent_registry SQLite
Backup : script quotidien workflows.db + audit

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-17 17:46:40 +02:00

196 lines
7.4 KiB
Python

# tests/unit/test_agent_config.py
"""
Tests unitaires pour la convention de configuration agent (INC-1 a INC-7).
Verifie que :
- STREAMING_ENDPOINT contient /api/v1/traces/stream
- SERVER_BASE est l'URL sans /api/v1 (pour /health)
- Le health check utilise la racine, pas /api/v1
- OLLAMA_HOST est separe de SERVER_URL
"""
import os
import pytest
class TestAgentConfig:
"""Tests de la resolution d'URL dans agent_v1.config."""
def test_streaming_endpoint_includes_api_v1(self, monkeypatch):
"""STREAMING_ENDPOINT doit contenir /api/v1/traces/stream."""
monkeypatch.setenv("RPA_SERVER_URL", "http://192.168.1.40:5005/api/v1")
# Recharger le module config pour prendre en compte la variable
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
assert "/api/v1/traces/stream" in config.STREAMING_ENDPOINT
assert config.STREAMING_ENDPOINT == "http://192.168.1.40:5005/api/v1/traces/stream"
def test_streaming_endpoint_default(self, monkeypatch):
"""Endpoint par defaut (localhost:5005)."""
monkeypatch.delenv("RPA_SERVER_URL", raising=False)
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
assert config.STREAMING_ENDPOINT == "http://localhost:5005/api/v1/traces/stream"
def test_server_base_strips_api_v1(self, monkeypatch):
"""SERVER_BASE doit etre l'URL sans /api/v1."""
monkeypatch.setenv("RPA_SERVER_URL", "http://192.168.1.40:5005/api/v1")
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
assert config.SERVER_BASE == "http://192.168.1.40:5005"
assert "/api/v1" not in config.SERVER_BASE
def test_server_base_https_domain(self, monkeypatch):
"""SERVER_BASE avec un domaine HTTPS (reverse proxy)."""
monkeypatch.setenv(
"RPA_SERVER_URL", "https://lea.labs.laurinebazin.design/api/v1"
)
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
assert config.SERVER_BASE == "https://lea.labs.laurinebazin.design"
def test_health_url_is_root_not_api_v1(self, monkeypatch):
"""Le health check doit etre sur SERVER_BASE/health (racine)."""
monkeypatch.setenv(
"RPA_SERVER_URL", "https://lea.labs.laurinebazin.design/api/v1"
)
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
health_url = f"{config.SERVER_BASE}/health"
assert health_url == "https://lea.labs.laurinebazin.design/health"
assert "/api/v1/health" not in health_url
def test_ollama_host_separate_from_server(self, monkeypatch):
"""OLLAMA_HOST est independant de SERVER_URL."""
monkeypatch.setenv(
"RPA_SERVER_URL", "https://lea.labs.laurinebazin.design/api/v1"
)
monkeypatch.delenv("RPA_OLLAMA_HOST", raising=False)
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
# Par defaut, Ollama est en local
assert config.OLLAMA_HOST == "localhost"
def test_ollama_host_custom(self, monkeypatch):
"""OLLAMA_HOST peut etre configure separement."""
monkeypatch.setenv("RPA_OLLAMA_HOST", "192.168.1.40")
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
assert config.OLLAMA_HOST == "192.168.1.40"
def test_no_double_api_v1(self, monkeypatch):
"""Aucune URL ne doit contenir /api/v1/api/v1 (double prefixe)."""
monkeypatch.setenv("RPA_SERVER_URL", "http://192.168.1.40:5005/api/v1")
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
all_urls = [
config.SERVER_URL,
config.SERVER_BASE,
config.STREAMING_ENDPOINT,
config.UPLOAD_ENDPOINT,
]
for url in all_urls:
assert "/api/v1/api/v1" not in url, f"Double /api/v1 dans : {url}"
class TestServerClientUrls:
"""Tests de la resolution d'URL dans lea_ui.server_client."""
def test_stream_url_includes_api_v1(self, monkeypatch):
"""_stream_url doit contenir /api/v1."""
monkeypatch.setenv("RPA_SERVER_URL", "http://192.168.1.40:5005/api/v1")
from agent_v0.lea_ui.server_client import LeaServerClient
client = LeaServerClient()
assert "/api/v1" in client._stream_url
assert client._stream_url.endswith("/api/v1")
def test_stream_base_no_api_v1(self, monkeypatch):
"""_stream_base ne doit PAS contenir /api/v1."""
monkeypatch.setenv("RPA_SERVER_URL", "http://192.168.1.40:5005/api/v1")
from agent_v0.lea_ui.server_client import LeaServerClient
client = LeaServerClient()
assert "/api/v1" not in client._stream_base
def test_health_on_root(self, monkeypatch):
"""Le health check doit pointer sur la racine."""
monkeypatch.setenv(
"RPA_SERVER_URL", "https://lea.labs.laurinebazin.design/api/v1"
)
from agent_v0.lea_ui.server_client import LeaServerClient
client = LeaServerClient()
health_url = f"{client._stream_base}/health"
assert health_url == "https://lea.labs.laurinebazin.design/health"
def test_workflows_url_no_double_api_v1(self, monkeypatch):
"""L'URL workflows ne doit pas avoir /api/v1/api/v1."""
monkeypatch.setenv("RPA_SERVER_URL", "http://192.168.1.40:5005/api/v1")
from agent_v0.lea_ui.server_client import LeaServerClient
client = LeaServerClient()
workflows_url = f"{client._stream_url}/traces/stream/workflows"
assert "/api/v1/api/v1" not in workflows_url
assert workflows_url == "http://192.168.1.40:5005/api/v1/traces/stream/workflows"
class TestScenarios:
"""Validation des 3 scenarios de deploiement."""
@pytest.mark.parametrize(
"server_url,expected_stream,expected_base,expected_health",
[
# Scenario 1 : LAN interne
(
"http://192.168.1.40:5005/api/v1",
"http://192.168.1.40:5005/api/v1/traces/stream",
"http://192.168.1.40:5005",
"http://192.168.1.40:5005/health",
),
# Scenario 2 : Internet via NPM
(
"https://lea.labs.laurinebazin.design/api/v1",
"https://lea.labs.laurinebazin.design/api/v1/traces/stream",
"https://lea.labs.laurinebazin.design",
"https://lea.labs.laurinebazin.design/health",
),
# Scenario 3 : Dev local (defaut)
(
"http://localhost:5005/api/v1",
"http://localhost:5005/api/v1/traces/stream",
"http://localhost:5005",
"http://localhost:5005/health",
),
],
ids=["lan", "internet", "localhost"],
)
def test_scenario_urls(
self, monkeypatch, server_url, expected_stream, expected_base, expected_health
):
"""Valider la matrice URL pour chaque scenario de deploiement."""
monkeypatch.setenv("RPA_SERVER_URL", server_url)
import importlib
from agent_v0.agent_v1 import config
importlib.reload(config)
assert config.STREAMING_ENDPOINT == expected_stream
assert config.SERVER_BASE == expected_base
assert f"{config.SERVER_BASE}/health" == expected_health