From 2bfcfa45359fbcf2981681dbd542b2c40797ba7f Mon Sep 17 00:00:00 2001 From: Dom Date: Wed, 15 Apr 2026 09:07:40 +0200 Subject: [PATCH] =?UTF-8?q?ci:=20Gitea=20Actions=20workflows=20+=20require?= =?UTF-8?q?ments-ci=20all=C3=A9g=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Workflows : .gitea/workflows/tests.yml -> lint + unit + security (PR + push) .gitea/workflows/security-audit.yml -> bandit + pip-audit + grep secrets (hebdo + push main) requirements-ci.txt : sous-ensemble léger de requirements.txt - Sans torch, transformers, CUDA, FAISS binaire, Ollama, PyQt5, doctr - Gain ~3 Go + ~2 min d'install CI - À resynchroniser manuellement si nouveau test importe un package absent Tests slow/gpu/integration/performance/visual/smoke exclus volontairement (nécessitent CUDA, Ollama localhost:11434, serveur complet). Temps estimé par run : - Cold : ~3 min - Warm (cache pip) : ~1m30 Security-tests (test_security_safe_condition + test_security_signed_serializer) marqués bloquants : régression sur ast eval safe ou pickle HMAC casse la CI. docs/CI_SETUP.md : activation Gitea Actions, enregistrement runner, skip CI, troubleshooting. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitea/workflows/security-audit.yml | 207 +++++++++++++++++++++++++ .gitea/workflows/tests.yml | 199 ++++++++++++++++++++++++ docs/CI_SETUP.md | 225 ++++++++++++++++++++++++++++ requirements-ci.txt | 109 ++++++++++++++ 4 files changed, 740 insertions(+) create mode 100644 .gitea/workflows/security-audit.yml create mode 100644 .gitea/workflows/tests.yml create mode 100644 docs/CI_SETUP.md create mode 100644 requirements-ci.txt diff --git a/.gitea/workflows/security-audit.yml b/.gitea/workflows/security-audit.yml new file mode 100644 index 000000000..179d1b673 --- /dev/null +++ b/.gitea/workflows/security-audit.yml @@ -0,0 +1,207 @@ +# ------------------------------------------------------------------ +# Audit sécurité — bandit + pip-audit + scan secrets +# ------------------------------------------------------------------ +# Jamais bloquant : on reporte les warnings, on ne casse pas la CI. +# Utile pour détecter les dérives progressives (nouveaux CVE, secrets +# oubliés dans un commit, patterns risqués). +# +# Fréquence : à chaque push sur main + hebdo (cron). +# ------------------------------------------------------------------ +name: security-audit + +on: + push: + branches: + - main + schedule: + # Tous les lundis à 6h UTC (8h Paris hiver, 7h Paris été). + - cron: "0 6 * * 1" + workflow_dispatch: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + # ---------------------------------------------------------------- + # Job 1 — bandit (bonnes pratiques sécu Python) + # ---------------------------------------------------------------- + bandit: + name: Bandit (scan statique) + runs-on: ubuntu-latest + timeout-minutes: 5 + continue-on-error: true + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Installation bandit + run: | + python -m pip install --upgrade pip + pip install "bandit[toml]==1.7.10" + + - name: Scan bandit sur core/ + run: | + # -ll : niveau LOW minimum (remonte tout) + # -ii : confiance LOW minimum + # --skip B101 : on ignore les asserts (usuels en tests/validation) + bandit -r core/ \ + --skip B101,B404,B603 \ + --format txt \ + --exit-zero \ + --output bandit-report.txt + echo "=== RAPPORT BANDIT ===" + cat bandit-report.txt + + - name: Upload rapport bandit + if: always() + uses: actions/upload-artifact@v3 + with: + name: bandit-report + path: bandit-report.txt + retention-days: 30 + if-no-files-found: ignore + + # ---------------------------------------------------------------- + # Job 2 — pip-audit (CVE sur requirements) + # ---------------------------------------------------------------- + pip-audit: + name: pip-audit (CVE dépendances) + runs-on: ubuntu-latest + timeout-minutes: 5 + continue-on-error: true + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Installation pip-audit + run: | + python -m pip install --upgrade pip + pip install "pip-audit==2.7.3" + + - name: Audit CVE sur requirements-ci.txt + run: | + if [ -f requirements-ci.txt ]; then + pip-audit -r requirements-ci.txt \ + --format json \ + --output pip-audit-ci.json \ + --progress-spinner off \ + --disable-pip || echo "::warning::CVE détectées dans requirements-ci.txt" + echo "=== RAPPORT pip-audit (CI) ===" + cat pip-audit-ci.json || true + else + echo "::notice::requirements-ci.txt absent — skip" + fi + + - name: Audit CVE sur requirements.txt (best-effort) + run: | + # Timeout généreux car requirements.txt est massif (torch, CUDA). + timeout 120 pip-audit -r requirements.txt \ + --format json \ + --output pip-audit-full.json \ + --progress-spinner off \ + --disable-pip 2>&1 | head -200 || \ + echo "::warning::pip-audit sur requirements.txt a timeout ou échoué (non bloquant)" + + - name: Upload rapports pip-audit + if: always() + uses: actions/upload-artifact@v3 + with: + name: pip-audit-reports + path: | + pip-audit-ci.json + pip-audit-full.json + retention-days: 30 + if-no-files-found: ignore + + # ---------------------------------------------------------------- + # Job 3 — Scan secrets en clair (grep simple) + # ---------------------------------------------------------------- + # Patterns recherchés : clés API Anthropic (sk-ant-), OpenAI (sk-), + # Google (AIzaSy), AWS (AKIA), tokens Hugging Face (hf_). + # Ne cherche QUE dans les fichiers trackés (pas .env, pas .venv). + # ---------------------------------------------------------------- + secrets-scan: + name: Scan secrets (grep) + runs-on: ubuntu-latest + timeout-minutes: 3 + continue-on-error: true + + steps: + - name: Checkout (historique complet) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Scan patterns de secrets + run: | + # Chemins exclus : venvs, caches, data, htmlcov, models. + EXCLUDES='--exclude-dir=.venv --exclude-dir=venv_v3 --exclude-dir=.git \ + --exclude-dir=node_modules --exclude-dir=htmlcov --exclude-dir=models \ + --exclude-dir=data --exclude-dir=__pycache__ --exclude-dir=.pytest_cache \ + --exclude=*.lock --exclude=*.log --exclude=*.md' + + echo "=== Recherche de secrets potentiels ===" + FOUND=0 + + # Anthropic + if grep -rnI $EXCLUDES -E 'sk-ant-[a-zA-Z0-9_-]{20,}' . 2>/dev/null; then + echo "::warning::Clé Anthropic potentielle détectée" + FOUND=1 + fi + + # OpenAI + if grep -rnI $EXCLUDES -E 'sk-proj-[a-zA-Z0-9_-]{20,}|sk-[a-zA-Z0-9]{40,}' . 2>/dev/null; then + echo "::warning::Clé OpenAI potentielle détectée" + FOUND=1 + fi + + # Google Cloud / API Keys + if grep -rnI $EXCLUDES -E 'AIzaSy[a-zA-Z0-9_-]{33}' . 2>/dev/null; then + echo "::warning::Clé Google API potentielle détectée" + FOUND=1 + fi + + # AWS + if grep -rnI $EXCLUDES -E 'AKIA[0-9A-Z]{16}' . 2>/dev/null; then + echo "::warning::Clé AWS potentielle détectée" + FOUND=1 + fi + + # Hugging Face + if grep -rnI $EXCLUDES -E 'hf_[a-zA-Z0-9]{30,}' . 2>/dev/null; then + echo "::warning::Token Hugging Face potentiel détecté" + FOUND=1 + fi + + # Mots-clés suspects à côté d'assignations + if grep -rnI $EXCLUDES -E '(password|passwd|secret|api_key|apikey|token)\s*=\s*["\x27][a-zA-Z0-9_\-!@#\$%]{12,}["\x27]' . 2>/dev/null \ + | grep -viE '(example|dummy|placeholder|test|fake|xxx|changeme|\$\{)' 2>/dev/null; then + echo "::warning::Assignation suspecte d'un secret détectée" + FOUND=1 + fi + + if [ "$FOUND" -eq 0 ]; then + echo "Aucun secret détecté par les patterns de base." + else + echo "" + echo "::notice::Vérifier manuellement les occurrences ci-dessus." + echo "::notice::Si faux positif : ajouter le fichier aux exclusions ou reformater." + fi + + # Toujours succès (job non bloquant). + exit 0 diff --git a/.gitea/workflows/tests.yml b/.gitea/workflows/tests.yml new file mode 100644 index 000000000..32d7a3236 --- /dev/null +++ b/.gitea/workflows/tests.yml @@ -0,0 +1,199 @@ +# ------------------------------------------------------------------ +# CI principale — Tests unitaires + lint léger +# ------------------------------------------------------------------ +# Déclenchement : push / pull_request sur n'importe quelle branche. +# Objectif : feedback rapide (< 3 min) sans GPU ni Ollama. +# Runner : self-hosted (label "ubuntu-latest" ou équivalent). +# +# Les tests marqués `slow`, `gpu`, `integration`, `performance`, +# `visual` et `smoke` sont exclus volontairement — ils nécessitent +# CUDA, Ollama, ou des captures d'écran réelles. +# ------------------------------------------------------------------ +name: tests + +on: + push: + branches: + - "**" + pull_request: + branches: + - "**" + +# Permet à une nouvelle exécution d'annuler les précédentes +# sur la même branche (évite l'engorgement du runner local). +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # Empêche l'import accidentel de torch/CUDA pendant la CI. + PYTHONDONTWRITEBYTECODE: "1" + PIP_DISABLE_PIP_VERSION_CHECK: "1" + PIP_NO_PYTHON_VERSION_WARNING: "1" + # Les modules d'exécution lisent parfois ces vars ; valeurs neutres en CI. + RPA_VISION_CI: "1" + RPA_AUTH_VAULT_PATH: "/tmp/ci_vault.enc" + +jobs: + # ---------------------------------------------------------------- + # Job 1 — Lint (ruff + black --check) + # ---------------------------------------------------------------- + # Non-bloquant : si ruff/black ne sont pas installables, on log + # un warning et on continue. L'objectif ici est d'alerter, pas de + # casser la CI pour des espaces en trop. + # ---------------------------------------------------------------- + lint: + name: Lint (ruff + black) + runs-on: ubuntu-latest + timeout-minutes: 5 + continue-on-error: true + + steps: + - name: Checkout du code + uses: actions/checkout@v4 + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + + - name: Installation des linters + run: | + python -m pip install --upgrade pip + pip install "ruff==0.6.9" "black==23.12.1" || { + echo "::warning::Impossible d'installer ruff/black — job ignoré" + exit 0 + } + + - name: Ruff (lint rapide) + run: | + if command -v ruff >/dev/null 2>&1; then + # Ruff : on limite aux erreurs critiques (E9, F63, F7, F82) pour + # éviter le bruit. Dom peut durcir progressivement. + ruff check --select=E9,F63,F7,F82 --output-format=github \ + core/ agent_v0/ tests/ || { + echo "::warning::Ruff a trouvé des erreurs critiques" + exit 1 + } + else + echo "::warning::ruff indisponible — skip" + fi + + - name: Black (format check) + run: | + if command -v black >/dev/null 2>&1; then + # --check : ne modifie pas, signale juste. + black --check --diff core/ agent_v0/ tests/ || { + echo "::warning::Black suggère un reformatage — non bloquant" + exit 0 + } + else + echo "::warning::black indisponible — skip" + fi + + # ---------------------------------------------------------------- + # Job 2 — Tests unitaires + # ---------------------------------------------------------------- + # Exclut tous les marqueurs lourds. Utilise requirements-ci.txt + # pour éviter torch/CUDA (économie ~3 Go + ~2 min). + # ---------------------------------------------------------------- + unit-tests: + name: Tests unitaires (sans GPU) + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout du code + uses: actions/checkout@v4 + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + cache-dependency-path: | + requirements-ci.txt + requirements.txt + + - name: Installation des dépendances CI + run: | + python -m pip install --upgrade pip + if [ -f requirements-ci.txt ]; then + echo "Utilisation de requirements-ci.txt (léger, sans torch)" + pip install -r requirements-ci.txt + else + echo "::warning::requirements-ci.txt absent — fallback requirements.txt (lourd)" + pip install -r requirements.txt + fi + + - name: Vérification imports critiques + run: | + python -c "import pytest; print(f'pytest {pytest.__version__}')" + python -c "import sys; sys.path.insert(0, '.'); import core; print('core OK')" || { + echo "::error::Impossible d'importer core.*" + exit 1 + } + + - name: Tests unitaires (hors slow/gpu/integration) + run: | + python -m pytest tests/unit/ \ + -m "not slow and not gpu and not integration and not performance and not visual" \ + --tb=short \ + --strict-markers \ + -q \ + --maxfail=10 \ + -o cache_dir=/tmp/.pytest_cache_ci + + - name: Upload logs si échec + if: failure() + uses: actions/upload-artifact@v3 + with: + name: pytest-logs + path: | + /tmp/.pytest_cache_ci + logs/ + retention-days: 3 + if-no-files-found: ignore + + # ---------------------------------------------------------------- + # Job 3 — Tests sécurité (bloquant) + # ---------------------------------------------------------------- + # Les tests `test_security_*` valident des invariants critiques + # (évaluation sûre, sérialisation signée). Aucune régression tolérée. + # ---------------------------------------------------------------- + security-tests: + name: Tests sécurité (critique) + runs-on: ubuntu-latest + timeout-minutes: 5 + needs: [unit-tests] + + steps: + - name: Checkout du code + uses: actions/checkout@v4 + + - name: Setup Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: "pip" + cache-dependency-path: | + requirements-ci.txt + requirements.txt + + - name: Installation des dépendances CI + run: | + python -m pip install --upgrade pip + if [ -f requirements-ci.txt ]; then + pip install -r requirements-ci.txt + else + pip install -r requirements.txt + fi + + - name: Tests sécurité (test_security_*) + run: | + python -m pytest tests/unit/test_security_*.py \ + --tb=long \ + --strict-markers \ + -v \ + -o cache_dir=/tmp/.pytest_cache_ci_sec diff --git a/docs/CI_SETUP.md b/docs/CI_SETUP.md new file mode 100644 index 000000000..0baa76cfc --- /dev/null +++ b/docs/CI_SETUP.md @@ -0,0 +1,225 @@ +# CI Setup — Gitea Actions pour RPA Vision V3 + +Ce document décrit la CI minimale mise en place sur `gitea.localhost:3100` +pour prévenir les régressions silencieuses sur `main` et les PR. + +## Vue d'ensemble + +Deux workflows Gitea Actions (syntaxe compatible GitHub Actions) : + +| Workflow | Fichier | Déclencheur | Bloquant | +|----------------------------------|---------------------------------------|------------------------------|----------| +| Tests | `.gitea/workflows/tests.yml` | push + PR (toutes branches) | Oui (unit + security) | +| Audit sécurité | `.gitea/workflows/security-audit.yml` | push main + cron hebdo | Non | + +### Jobs du workflow `tests` + +1. **lint** (non bloquant) — `ruff` + `black --check` sur `core/`, `agent_v0/`, `tests/`. +2. **unit-tests** (bloquant) — `pytest tests/unit/` avec `-m "not slow and not gpu and not integration and not performance and not visual"`. +3. **security-tests** (bloquant) — `pytest tests/unit/test_security_*.py` en mode verbose. Dépend de `unit-tests`. + +### Jobs du workflow `security-audit` + +1. **bandit** — scan statique sur `core/` (asserts ignorés). +2. **pip-audit** — détection CVE sur `requirements-ci.txt` et `requirements.txt`. +3. **secrets-scan** — `grep` pour patterns `sk-ant-`, `sk-proj-`, `AIzaSy`, `AKIA`, `hf_`. + +Aucun de ces jobs ne casse la CI — ils produisent des artefacts consultables. + +## Activation de Gitea Actions + +Gitea Actions n'est pas actif par défaut. Deux étapes : + +### 1. Activer Actions dans Gitea + +Sur `http://localhost:3100`, éditer `/home/dom/Install_base/docker-compose.yml` +(ou le `app.ini` monté dans le conteneur Gitea) et ajouter : + +```ini +[actions] +ENABLED = true +DEFAULT_ACTIONS_URL = https://github.com +``` + +Puis redémarrer Gitea : + +```bash +cd /home/dom/Install_base +docker compose restart gitea +``` + +Vérifier : dans l'UI Gitea → `Site Administration` → `Configuration Summary` +→ la section `[actions]` doit afficher `enabled: true`. + +Côté dépôt : `Settings` → `Advanced Settings` → cocher **"Enable Repository Actions"**. + +### 2. Installer et enregistrer un runner local + +Gitea a besoin d'un `act_runner` (fork de nektos/act) pour exécuter les jobs. + +```bash +# Téléchargement du runner (Linux amd64) +cd /home/dom/Install_base +mkdir -p gitea_runner && cd gitea_runner +wget https://dl.gitea.com/act_runner/0.2.11/act_runner-0.2.11-linux-amd64 -O act_runner +chmod +x act_runner + +# Génération de la config +./act_runner generate-config > config.yaml + +# Récupération du token d'enregistrement +# Site Administration → Actions → Runners → Create new Runner +# (ou pour un runner par-dépôt : Settings du dépôt → Actions → Runners) + +# Enregistrement (interactif) +./act_runner register --no-interactive \ + --instance http://localhost:3100 \ + --token \ + --name "runner-local-cpu" \ + --labels "ubuntu-latest:docker://catthehacker/ubuntu:act-22.04" + +# Lancement en daemon +nohup ./act_runner daemon --config config.yaml > runner.log 2>&1 & +``` + +Pour persister au reboot : créer un service systemd +(cf. `~/ai/rpa_vision_v3/deploy/systemd/` pour un modèle). + +**Note** : le label `ubuntu-latest` pointe sur une image Docker légère +(`catthehacker/ubuntu:act-22.04`, ~300 Mo) qui suffit pour nos jobs Python. + +### 3. Premier test + +```bash +cd /home/dom/ai/rpa_vision_v3 +# Modification triviale +echo "" >> README.md +git add README.md +git commit -m "chore: trigger CI" +git push gitea main +``` + +Dans l'UI Gitea → onglet `Actions` du dépôt, le workflow doit apparaître +et passer en ~2 minutes. + +## Lancer les tests localement avant push + +Identique à la CI : + +```bash +cd /home/dom/ai/rpa_vision_v3 +source .venv/bin/activate + +# Tests unitaires (hors slow/gpu/integration) — ~60s +pytest tests/unit/ -m "not slow and not gpu and not integration and not performance and not visual" -q + +# Tests sécurité seulement — ~5s +pytest tests/unit/test_security_*.py -v + +# Lint (si installé) +ruff check --select=E9,F63,F7,F82 core/ agent_v0/ tests/ +black --check core/ agent_v0/ tests/ +``` + +Ou via Makefile : + +```bash +make test-fast # équivalent à "not slow" +make check # validate-imports + test-fast +``` + +## Désactiver temporairement la CI (merge urgent) + +Trois options, de la plus propre à la plus brutale : + +### Option 1 — Skip via message de commit (recommandé) + +Préfixer le message avec `[skip ci]` ou `[ci skip]` : + +```bash +git commit -m "fix: hotfix prod [skip ci]" +``` + +Gitea Actions respecte cette convention. + +### Option 2 — Désactiver le workflow côté dépôt + +Dans l'UI Gitea → dépôt → `Actions` → sélectionner le workflow → bouton +**"Disable workflow"**. Réactivable au même endroit. + +### Option 3 — Renommer le fichier + +```bash +mv .gitea/workflows/tests.yml .gitea/workflows/tests.yml.disabled +git commit -am "chore: disable CI temporarily" +``` + +Ne **jamais** supprimer le fichier — ça rend le rollback pénible. + +## Limitations connues + +- **Pas de tests `slow` / `gpu` / `integration`** en CI. Ces tests nécessitent + CUDA, Ollama (port 11434), ou des captures d'écran réelles. Ils doivent + être lancés manuellement sur la machine de dev avant un tag de release. +- **Pas de tests E2E `smoke`** (`tests/smoke/`) — nécessitent le serveur + complet (ports 5005, 5001, 5002, 3002). +- **Pas de tests `visual`** (`tests/visual/`) — nécessitent le serveur GPU. +- **Runner unique** : tant qu'il n'y a qu'un `act_runner` enregistré, + les jobs s'exécutent en série. Acceptable pour < 10 builds/jour. +- **Pas de `torch` en CI** : si un test unitaire importe `torch` directement + (sans lazy import), il échouera. Convention : les imports GPU doivent + être dans `try/except ImportError` + marqueur `@pytest.mark.gpu`. +- **`requirements-ci.txt` à resynchroniser** : quand une dépendance est + ajoutée à `requirements.txt` et utilisée par un test unitaire, penser + à l'ajouter aussi à `requirements-ci.txt`. + +## Temps d'exécution estimé + +| Job | Cold (sans cache pip) | Warm (cache pip) | +|-----------------|----------------------|------------------| +| lint | ~40s | ~15s | +| unit-tests | ~2m30 | ~1m15 | +| security-tests | ~1m | ~30s | +| **Total CI** | **~3m** | **~1m30** | + +Le cache pip est géré automatiquement par `actions/setup-python@v5` +via la clé `requirements-ci.txt` + `requirements.txt`. + +## Troubleshooting + +### Le workflow ne se déclenche pas + +1. Vérifier que `[actions]` est actif dans `app.ini` Gitea. +2. Vérifier que le runner est bien enregistré : `Site Administration` → `Actions` → `Runners`. +3. Le runner doit être `Online` (point vert). +4. Le dépôt doit avoir Actions activées dans ses paramètres. + +### Erreur "No runner available" + +Le runner est stoppé ou a un label incompatible. Relancer : + +```bash +cd /home/dom/Install_base/gitea_runner +ps aux | grep act_runner # vérifier s'il tourne +tail -f runner.log # voir les erreurs +``` + +### Timeout sur `pip install` + +`requirements.txt` contient torch + CUDA (~3 Go). Si la CI tombe sur +`requirements.txt` au lieu de `requirements-ci.txt`, vérifier que le +fichier léger est bien committé à la racine du repo. + +### Tests passent en local mais échouent en CI + +Diff le plus fréquent : +- Variables d'environnement (`.env.local` absent en CI → tester avec `unset` en local). +- Ports déjà pris par `svc.sh` en local mais libres en CI (→ OK). +- Paths absolus hardcodés (`/home/dom/...`) → utiliser `pathlib` + fixtures. + +## Évolutions possibles + +- Ajouter un job `type-check` avec `mypy core/` (actuellement dans `requirements.txt` mais pas en CI — choix délibéré : trop lent et 200+ erreurs à nettoyer d'abord). +- Ajouter un job `coverage` avec seuil minimum (ex: 60%). +- Brancher les résultats sur un badge README via `gitea-actions-status`. +- Pour les PR : bloquer le merge tant que `unit-tests` + `security-tests` ne passent pas (réglable dans `Settings` → `Branches` → `Branch protection rules`). diff --git a/requirements-ci.txt b/requirements-ci.txt new file mode 100644 index 000000000..23ae2ad04 --- /dev/null +++ b/requirements-ci.txt @@ -0,0 +1,109 @@ +# ------------------------------------------------------------------ +# requirements-ci.txt — Dépendances pour la CI (tests unitaires) +# ------------------------------------------------------------------ +# Objectif : installer le minimum pour que `pytest tests/unit/` +# passe sans GPU, sans Ollama, sans torch, sans FAISS GPU. +# +# Les tests lourds (torch, transformers, CLIP, FAISS GPU, doctr, +# Ollama) sont marqués `slow`, `gpu` ou `integration` et exclus +# via `-m "not slow and not gpu and not integration"`. +# +# Versions alignées sur requirements.txt pour éviter les surprises +# lors du runtime local, mais allégées (CPU-only, headless). +# ------------------------------------------------------------------ + +# --- Runtime core --- +pydantic==2.12.5 +pydantic_core==2.41.5 +python-dotenv==1.0.0 +PyYAML==6.0.1 +click==8.3.1 +typing_extensions==4.15.0 +annotated-types==0.7.0 + +# --- Web frameworks (utilisés par les tests API/dashboard) --- +fastapi==0.128.0 +starlette==0.50.0 +uvicorn==0.40.0 +Flask==3.0.0 +Flask-Caching==2.1.0 +Flask-Cors==4.0.0 +Flask-SQLAlchemy==3.1.1 +Werkzeug==3.1.5 +Jinja2==3.1.6 +itsdangerous==2.2.0 +blinker==1.9.0 + +# --- DB (tests auth/audit/extraction) --- +SQLAlchemy==2.0.23 +alembic==1.18.4 + +# --- HTTP clients --- +httpx==0.28.1 +requests==2.32.5 +urllib3==2.6.3 +certifi==2026.1.4 +idna==3.11 +charset-normalizer==3.4.4 +h11==0.16.0 +httpcore==1.0.9 +anyio==4.12.1 +sniffio==1.3.1; python_version >= "3.7" + +# --- Sécurité (test_security_*, auth vault, TOTP) --- +cryptography==46.0.3 +cffi==2.0.0 +pycparser==2.23 + +# --- Images (opencv-python-headless au lieu de opencv-python pour CI) --- +pillow==12.1.0 +opencv-python-headless==4.12.0.88 +numpy==2.2.6 + +# --- Pytest et plugins --- +pytest==9.0.2 +pytest-asyncio==1.3.0 +pytest-cov==4.1.0 +pytest-flask==1.3.0 +pytest-mock==3.12.0 +iniconfig==2.3.0 +pluggy==1.6.0 +packaging==25.0 + +# --- Couverture --- +coverage==7.13.1 + +# --- Utilitaires divers (imports indirects fréquents) --- +python-dateutil==2.8.2 +six==1.17.0 +attrs==25.4.0 +jsonschema==4.20.0 +jsonschema-specifications==2025.9.1 +referencing==0.37.0 +rpds-py==0.30.0 +RapidFuzz==3.14.3 +regex==2025.11.3 +python-multipart==0.0.21 +validators==0.35.0 +prometheus_client==0.23.1 +psutil==7.2.1 +filelock==3.20.3 +tqdm==4.67.1 + +# --- Hypothesis (property tests, si inclus plus tard) --- +hypothesis==6.92.1 +sortedcontainers==2.4.0 + +# --- NOTES --- +# Volontairement absents : +# - torch / torchvision / triton / nvidia-* → GPU, hors CI +# - transformers / accelerate / tokenizers → chargent torch +# - open_clip_torch / timm → idem +# - faiss-cpu → binaire lourd (~90 Mo), +# utilisé uniquement en +# tests `slow` / `integration` +# - ollama → nécessite serveur Ollama +# - python-doctr / pypdfium2 → OCR, tests `slow` +# - pynput / pyautogui / mss / PyQt5 → GUI / simulation I/O +# - python-socketio / Flask-SocketIO → WS, tests intégration +# - eds-nlp / spacy → modèles NLP hors CI