ci: Gitea Actions workflows + requirements-ci allégé
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) <noreply@anthropic.com>
This commit is contained in:
207
.gitea/workflows/security-audit.yml
Normal file
207
.gitea/workflows/security-audit.yml
Normal file
@@ -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
|
||||||
199
.gitea/workflows/tests.yml
Normal file
199
.gitea/workflows/tests.yml
Normal file
@@ -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
|
||||||
225
docs/CI_SETUP.md
Normal file
225
docs/CI_SETUP.md
Normal file
@@ -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 <TOKEN_COPIE_DEPUIS_GITEA> \
|
||||||
|
--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`).
|
||||||
109
requirements-ci.txt
Normal file
109
requirements-ci.txt
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user