Claude
fix(ci): trivy-action 0.24.0 -> v0.36.0 (prefixe v + version existante)
05d1699 unverified
# .github/workflows/ci.yml β€” Picarones CI/CD
#
# Pipeline GitHub Actions (mis Γ  jour Sprint A1 β€” Hardening CI) :
# - Tests sur Python 3.11 / 3.12 / 3.13 (3.13 informationnel, 6 mois)
# - Linux, macOS, Windows
# - Couverture exigΓ©e >= 85 % (--cov-fail-under, plancher 2 pts sous baseline 87 %)
# - Timeout pytest 5 min par test individuel (pytest-timeout, mode thread)
# - Type-check mypy (strict sur picarones/core/, lax ailleurs β€” durci en A11)
# - Scanners sΓ©curitΓ© : bandit (statique) + pip-audit (CVE deps) + trivy (image)
# - Build de la distribution Python
# - VΓ©rification de l'exΓ©cutable demo
name: CI
on:
push:
branches: [main, develop, "feature/**", "sprint/**", "claude/**"]
pull_request:
branches: [main, develop]
workflow_dispatch: # DΓ©clenchement manuel
permissions:
contents: read
# ──────────────────────────────────────────────────────────────────
# Job 1 : Tests unitaires et d'intΓ©gration
# ──────────────────────────────────────────────────────────────────
jobs:
tests:
name: Tests Python ${{ matrix.python-version }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
# 3.13 ajoutΓ© Sprint A1 (item m-8). Reste informationnel
# (continue-on-error sur Linux uniquement) pendant 6 mois pour
# tracker la compat sans bloquer.
python-version: ["3.11", "3.12", "3.13"]
include:
- python-version: "3.13"
os: ubuntu-latest
experimental: true
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip
# ── Tesseract ──────────────────────────────────────────────
- name: Install Tesseract (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update -qq
sudo apt-get install -y tesseract-ocr tesseract-ocr-fra tesseract-ocr-lat
- name: Install Tesseract (macOS)
if: runner.os == 'macOS'
run: |
brew install tesseract tesseract-lang
env:
HOMEBREW_NO_AUTO_UPDATE: "1"
- name: Install Tesseract (Windows)
if: runner.os == 'Windows'
run: |
choco install tesseract -y
echo "C:\Program Files\Tesseract-OCR" >> $env:GITHUB_PATH
shell: pwsh
# ── DΓ©pendances Python ──────────────────────────────────────
# Mise Γ  jour pip/setuptools/wheel en dΓ©but de job (Sprint A1) pour
# Γ©viter les CVE qui dorment dans les images runner GitHub.
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install -e ".[dev,web]"
# ── Tests ───────────────────────────────────────────────────
# Sprint A1 : --cov-fail-under=85 (baseline mesurΓ© 87 %, marge 2 pts).
# pytest-timeout est configurΓ© dans pyproject.toml [tool.pytest.ini_options].
- name: Run tests
# Sur Python 3.13, on continue malgrΓ© une erreur pour ne pas bloquer
# le merge pendant la fenΓͺtre informationnelle de 6 mois (m-8).
continue-on-error: ${{ matrix.python-version == '3.13' }}
shell: bash
run: |
pytest tests/ -q --tb=short --no-header \
--cov=picarones --cov-report=xml --cov-report=term-missing \
--cov-fail-under=85
env:
PYTHONIOENCODING: utf-8
PYTHONUTF8: "1"
# ── Couverture ──────────────────────────────────────────────
- name: Upload coverage to Codecov
if: runner.os == 'Linux' && matrix.python-version == '3.11' && env.CODECOV_TOKEN != ''
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.xml
flags: unittests
name: picarones-coverage
fail_ci_if_error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# ──────────────────────────────────────────────────────────────────
# Job 2 : VΓ©rification du rapport demo
# ──────────────────────────────────────────────────────────────────
demo:
name: Demo end-to-end
runs-on: ubuntu-latest
needs: tests
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install Tesseract
run: |
sudo apt-get update -qq
sudo apt-get install -y tesseract-ocr tesseract-ocr-fra
- name: Install Picarones
run: pip install -e ".[web]"
- name: Run demo
run: |
picarones demo --docs 12 --output rapport_demo_ci.html \
--with-history --with-robustness
ls -lh rapport_demo_ci.html
# VΓ©rifier que le fichier est valide et contient les sections attendues
python -c "
content = open('rapport_demo_ci.html').read()
assert 'Picarones' in content, 'Picarones non trouvΓ© dans le rapport'
assert 'CER' in content, 'CER non trouvΓ© dans le rapport'
assert len(content) > 50000, f'Rapport trop petit : {len(content)} octets'
print(f'Rapport OK : {len(content):,} octets')
"
- name: Upload demo report as artifact
uses: actions/upload-artifact@v4
with:
name: rapport-demo
path: rapport_demo_ci.html
retention-days: 7
# ──────────────────────────────────────────────────────────────────
# Job 3 : Build de la distribution Python
# ──────────────────────────────────────────────────────────────────
build:
name: Build distribution
runs-on: ubuntu-latest
needs: tests
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install build tools
run: pip install --upgrade build twine
- name: Build wheel and sdist
run: python -m build
- name: Check distribution
run: twine check dist/*
- name: Upload distribution as artifact
uses: actions/upload-artifact@v4
with:
name: dist-packages
path: dist/
retention-days: 30
# ──────────────────────────────────────────────────────────────────
# Job 4 : VΓ©rification de la qualitΓ© du code
# La config ruff est centralisΓ©e dans pyproject.toml ([tool.ruff]),
# donc CI, Makefile et invocations locales produisent exactement les
# mΓͺmes rΓ©sultats β€” pas de divergence possible entre flags.
# ──────────────────────────────────────────────────────────────────
lint:
name: Code quality
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install ruff
run: pip install ruff
- name: Run ruff
run: ruff check picarones/ tests/
# ──────────────────────────────────────────────────────────────────
# Job 5 : Type-checking β€” Sprint A1 (item M-4)
#
# mypy est configurΓ© dans pyproject.toml [tool.mypy] :
# - strict sur picarones.core.* (10 modules)
# - lax ailleurs (follow_imports=silent)
# Deux checks prΓ©-existants dΓ©sactivΓ©s (disallow_any_generics et
# warn_return_any), à ré-activer en Sprint A11 après fix des
# ~100 erreurs baseline.
# ──────────────────────────────────────────────────────────────────
typecheck:
name: Type checking (mypy)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
pip install -e ".[dev,web,stats]"
- name: Run mypy on picarones/core (strict)
run: python -m mypy picarones/core/
# ──────────────────────────────────────────────────────────────────
# Job 6 : SΓ©curitΓ© β€” Sprint A1 (item B-7)
#
# bandit : scan statique du code Python (HIGH/MEDIUM bloquants).
# pip-audit : CVEs des dΓ©pendances installΓ©es.
# trivy : scan du Dockerfile + image rΓ©sultante (HIGH/CRITICAL bloquants).
#
# Configuration bandit dans pyproject.toml [tool.bandit] avec exclusions
# documentΓ©es (B310, B608, B615, B701 β€” chacune avec sprint cible).
# ──────────────────────────────────────────────────────────────────
security:
name: Security scanners
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
- name: Install scanners
run: |
python -m pip install --upgrade pip setuptools wheel
pip install -e ".[dev,web]"
# bandit : -ll = LOW + above. La config pyproject.toml exclut les
# informationnels acceptΓ©s ; tout HIGH/MEDIUM nouveau bloque.
- name: Run bandit
run: python -m bandit -r picarones/ -ll -c pyproject.toml
# pip-audit : --skip-editable car picarones n'est pas sur PyPI.
# En CI, l'env est frais (pip Γ  jour grΓ’ce au step prΓ©cΓ©dent) donc
# les CVEs trouvΓ©es sont des vraies vulnΓ©rabilitΓ©s dΓ©clarΓ©es.
# NB : ``--strict`` + ``--skip-editable`` combinΓ©s transforment le
# skip en erreur (incompatibilitΓ© documentΓ©e du tool). On utilise
# uniquement ``--skip-editable`` ; pip-audit retourne dΓ©jΓ  exit 1
# sur CVE dΓ©tectΓ©e β€” le job Γ©chouera donc en cas de vraie vulnΓ©rabilitΓ©.
- name: Run pip-audit
run: python -m pip_audit --skip-editable
# trivy : scan du Dockerfile + image rΓ©sultante. Build local pour
# auditer ce qui sera rΓ©ellement dΓ©ployΓ© sur HuggingFace Space.
- name: Build Docker image for scan
run: docker build -t picarones:ci-scan .
- name: Run Trivy vulnerability scanner (image)
uses: aquasecurity/trivy-action@v0.36.0
with:
image-ref: 'picarones:ci-scan'
format: 'table'
exit-code: '1'
ignore-unfixed: true
severity: 'HIGH,CRITICAL'
vuln-type: 'os,library'
- name: Run Trivy on Dockerfile (config scan)
uses: aquasecurity/trivy-action@v0.36.0
with:
scan-type: 'config'
scan-ref: 'Dockerfile'
exit-code: '1'
severity: 'HIGH,CRITICAL'
# ──────────────────────────────────────────────────────────────────
# Job 7 : CI/CD β€” DΓ©tection de rΓ©gression CER (optionnel)
# CommentΓ© par dΓ©faut β€” activer si vous avez un corpus de rΓ©fΓ©rence
# ──────────────────────────────────────────────────────────────────
# regression-check:
# name: Regression check
# runs-on: ubuntu-latest
# needs: tests
# if: github.event_name == 'pull_request'
#
# steps:
# - name: Checkout
# uses: actions/checkout@v4
#
# - name: Install
# run: pip install -e .
#
# - name: Run benchmark on reference corpus
# run: |
# picarones run \
# --corpus ./tests/fixtures/reference_corpus/ \
# --engines tesseract \
# --output results_pr.json \
# --fail-if-cer-above 15.0