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
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>
196 lines
7.4 KiB
Python
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
|