From 2ff127f68efdbdf6abf9bbe44b8f9c1205de2adc Mon Sep 17 00:00:00 2001 From: william Date: Tue, 15 Sep 2026 16:26:21 +0200 Subject: [PATCH] Phase 4 (CI) : lint-python/lint-js bloquants + sonarqube non-bloquant Les hooks pre-commit locaux (deja tous verts, voir le commit Phase 3) ne protegent que la machine du committeur, jamais un push direct ou une PR mergee depuis ailleurs sans passer par ces hooks. Ajoute donc en CI : - lint-python (ruff check/format, mypy --strict, vulture, bandit, import-linter) et lint-js (eslint, stylelint) : bloquants des maintenant, memes commandes que .pre-commit-config.yaml, deja verts en local donc aucune raison d'attendre. djlint volontairement exclu (49 H021 deja en backlog assume, a ajouter ici une fois ce lot traite). build-and-push en depend desormais (needs), en plus des tests deja en place. - sonarqube : scan contre l'instance self-hebergee (sonar.forgebase.fr) a chaque push. continue-on-error: true au niveau du job (non-bloquant pendant cette premiere periode, le temps de trier le rapport deja analyse en Phase 3 - code smells/vulnerabilites), et absent du needs de build-and-push : un echec ici n'affecte jamais le reste du pipeline, meme si l'infra n'est pas encore prete (echec attendu tant que SONAR_TOKEN n'est pas configure cote Gitea). Secret a ajouter dans Gitea (Parametres du depot > Actions > Secrets) : SONAR_TOKEN (jeton d'analyse genere sur sonar.forgebase.fr, jamais le mot de passe admin). djLint (H021, styles inline) volontairement saute pour ce commit - meme backlog assume que le commit Phase 3, aucun rapport avec ce changement. Co-Authored-By: Claude Sonnet 5 --- .gitea/workflows/deploy.yml | 92 ++++++++++++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 7 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 0fe2b0ed..642f4120 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -4,12 +4,26 @@ on: push: branches: [main, dev] -# Le job "test" tourne sur CHAQUE push (main et dev) : jusqu'ici aucune -# étape de CI n'exécutait la suite de tests, rien n'empêchait un commit -# cassé d'atteindre la production (voir l'audit qualité de la Phase 0 du -# plan). "build-and-push"/"deploy", eux, restent réservés à main (via le -# filtre "if" sur gitea.ref) — un push sur dev ne doit jamais redéployer -# la prod, seulement faire tourner les tests. +# Les jobs "test-*"/"lint-*"/"sonarqube" tournent sur CHAQUE push (main et +# dev) : jusqu'ici aucune étape de CI n'exécutait la suite de tests ni les +# outils qualité, rien n'empêchait un commit cassé d'atteindre la +# production (voir l'audit qualité de la Phase 0 du plan). "build-and- +# push"/"deploy", eux, restent réservés à main (via le filtre "if" sur +# gitea.ref) — un push sur dev ne doit jamais redéployer la prod, seulement +# faire tourner tests/lint/sonar. +# +# lint-python/lint-js rejouent EXACTEMENT les hooks pre-commit locaux +# (.pre-commit-config.yaml) mais bloquants ici dès le départ (déjà tous +# verts en local, voir le commit "Phase 3 : hardening qualite de code") — +# les hooks pre-commit ne protègent que la machine du committeur, jamais +# un push direct ou une PR mergée depuis ailleurs. djlint EXCLU +# volontairement (49 H021 "styles inline" déjà en backlog assumé, voir +# CODE_QUALITY.md) — à ajouter ici quand ce lot sera traité. sonarqube, +# lui, reste NON-BLOQUANT (continue-on-error) pendant cette première +# période — voir CODE_QUALITY.md pour la trajectoire vers un mode +# bloquant une fois le rapport trié (code smells, vulnerabilites) plutôt +# que de bloquer tout de suite sur des centaines de signalements pas +# encore triés. # Secrets à configurer dans Gitea (Paramètres du dépôt > Actions > Secrets) : # REGISTRY_HOST adresse du registre d'images (ex: gitea.exemple.com) @@ -20,6 +34,8 @@ on: # DEPLOY_USER utilisateur SSH sur ce serveur # DEPLOY_SSH_KEY clé privée SSH (au format PEM) autorisée sur ce serveur # DEPLOY_PATH dossier sur le serveur où vit docker-compose.prod.yml (ex: /home/deploy/forge-engine) +# SONAR_TOKEN jeton d'analyse SonarQube (Mon compte > Security > Generate Token +# sur sonar.forgebase.fr) — jamais le mot de passe admin. # # Utilise directement docker/ssh/scp en ligne de commande plutôt que des # actions du marketplace, pour ne pas dépendre de la disponibilité de @@ -79,8 +95,70 @@ jobs: RUN node --test static/js/play/__tests__/*.test.js static/js/scenes/__tests__/*.test.js DOCKERFILE + lint-python: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Qualite Python (ruff/mypy/vulture/bandit/import-linter — memes commandes que .pre-commit-config.yaml) + run: | + # Meme neutralisation de .dockerignore que test-python ci-dessus : + # ruff/mypy typent aussi tests/ (voir le plan de typage strict), + # exclu par defaut de l'image de PROD. + mv .dockerignore .dockerignore.disabled-for-ci + docker build -f - -t forge-lint-python:${{ gitea.sha }} . <<'DOCKERFILE' + FROM python:3.13-slim + WORKDIR /app + COPY requirements.txt requirements-dev.txt ./ + RUN pip install --no-cache-dir -r requirements-dev.txt + COPY . . + RUN ruff check . + RUN ruff format --check . + RUN mypy . + RUN vulture + RUN bandit -c pyproject.toml -r ai auth core db filters publish routes screens scripts app.py build_css.py + RUN lint-imports + DOCKERFILE + + lint-js: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Qualite JS/CSS (eslint/stylelint — memes commandes que .pre-commit-config.yaml, via les scripts npm de package.json) + run: | + docker build -f - -t forge-lint-js:${{ gitea.sha }} . <<'DOCKERFILE' + FROM node:20-slim + WORKDIR /app + COPY package.json package-lock.json ./ + RUN npm ci + COPY . . + RUN npm run lint:js + RUN npm run lint:css + DOCKERFILE + + sonarqube: + runs-on: ubuntu-latest + # Non-bloquant pendant cette premiere periode (voir le bloc de + # commentaires en tete de fichier) — un echec ici n'empeche jamais + # build-and-push/deploy, contrairement a lint-python/lint-js. + continue-on-error: true + steps: + - uses: actions/checkout@v4 + - name: Analyse SonarQube (rapport seul, non-bloquant) + run: | + # Meme neutralisation de .dockerignore que test-python : sonar- + # project.properties couvre aussi tests/ (sonar.tests). + mv .dockerignore .dockerignore.disabled-for-ci + docker build -f - -t forge-sonar:${{ gitea.sha }} . <<'DOCKERFILE' + FROM sonarsource/sonar-scanner-cli:latest + WORKDIR /usr/src + COPY . . + DOCKERFILE + docker run --rm forge-sonar:${{ gitea.sha }} \ + -Dsonar.host.url=https://sonar.forgebase.fr \ + -Dsonar.token=${{ secrets.SONAR_TOKEN }} + build-and-push: - needs: [test-python, test-js] + needs: [test-python, test-js, lint-python, lint-js] if: gitea.ref == 'refs/heads/main' runs-on: ubuntu-latest steps: