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: