Spaces:
Running
Running
| # .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 | |