j'ai gitea + sonarqube auto hébger tu me conseiler quoi en plus pour analyser le code php 13:35 Bonne question ! Avec Gitea + SonarQube déjà en place, voici ce que je te recommanderais pour compléter ta chaîne d'analyse PHP : Analyse statique complémentaire — Tu utilises déjà PHPStan via SonarQube, mais le lancer aussi en standalone (niveau max) te donne un feedback plus rapide dans ta CI. Psalm est une alternative/complément intéressant, surtout pour l'analyse de type et la détection de dead code. Les deux peuvent coexister. Style & standards — PHP CS Fixer ou PHP_CodeSniffer pour enforcer un coding standard (PSR-12 ou custom). PHP CS Fixer s'intègre bien dans un pre-commit hook ou un job CI Gitea Actions/Drone. Sécurité — Snyk ou Trivy pour scanner les dépendances Composer (CVE). Trivy est self-hostable et peut aussi scanner tes images Docker, ce qui colle bien avec ton stack. Semgrep est aussi un bon choix pour des règles de sécurité custom sur le code PHP (OWASP patterns, injections SQL, XSS). Complexité & dette technique — PHPMetrics génère des rapports HTML visuels sur la complexité cyclomatique, le couplage, la maintenabilité. Ça complète bien SonarQube avec une vue plus "architecturale". dePHPend analyse les dépendances entre classes/packages pour détecter les couplages problématiques. Tests & couverture — Si pas déjà en place, PHPUnit + Infection (mutation testing) pour mesurer la qualité réelle de tes tests, pas juste le coverage brut. SonarQube peut ingérer les rapports de coverage PHPUnit. En priorité pour ton contexte (multi-tenant, ~85 sites ESY-WEB), je partirais sur : PHPStan niveau max en CI (si pas déjà fait en standalone) Trivy (scan dépendances Composer + images Docker — tu as déjà le stack Docker) PHP CS Fixer en pre-commit PHPMetrics pour le reporting visuel Tout ça s'orchestre bien avec des Gitea Actions ou un pipeline Makefile, ce qui colle avec ton workflow habituel. Tu veux que je t'aide à mettre en place un de ces outils en particulier ? name: CI on: push: branches: - master - main pull_request: jobs: sonarqube: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POS pasted j'ai deja tout sa 13:36 Ah ok, t'es déjà bien équipé ! Ton pipeline est solide. Voici ce qui manque et qui aurait une vraie valeur ajoutée : Sécurité applicative — Semgrep pour de l'analyse SAST orientée patterns PHP (injections SQL, XSS, SSRF, deserialize unsafe). OWASP Dependency-Check couvre les dépendances, mais pas le code lui-même. Semgrep est gratuit en CLI et s'ajoute en une step. Qualité / dette — PHPMetrics pour un rapport HTML visuel (complexité cyclomatique, couplage, maintenabilité par classe). SonarQube donne des métriques mais PHPMetrics a une vue "bubble chart" par classe qui aide à prioriser le refacto. Très rapide à ajouter, pas besoin de services. Tests — Infection (mutation testing). Tu as déjà PHPUnit + coverage, mais le coverage seul ne dit pas si tes tests détectent vraiment les régressions. Infection mute ton code et vérifie que les tests cassent. Ça s'intègre bien avec le coverage.xml que tu génères déjà. Infra/Docker — Trivy en remplacement ou complément de Hadolint. Hadolint lint les Dockerfiles, Trivy scanne les images buildées (CVE dans les packages OS + dépendances). Vu ton stack multi-container c'est pertinent. Frontend — Lighthouse CI si tu as des pages publiques côté E-Cosplay. Perf, accessibilité, SEO en une step. En résumé les ajouts concrets : yaml - name: Semgrep SAST run: | pip install semgrep --break-system-packages semgrep scan --config=auto --json -o semgrep-report.json src/ || true - name: PHPMetrics run: | composer global require phpmetrics/phpmetrics --no-interaction phpmetrics --report-html=phpmetrics-report src/ - name: Infection (mutation testing) run: | vendor/bin/infection --threads=4 --min-msi=50 --min-covered-msi=60 --logger-json=infection-report.json || true Semgrep est le plus impactant vu que t'as zéro SAST sur le code source actuellement — OWASP DC ne couvre que les dépendances. Tu veux que je t'intègre ça proprement dans ton workflow complet ? name: CI on: push: branches: - master - main pull_request: jobs: sonarqube: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POS pasted 13:37 Nickel, t'as intégré les trois. Ton pipeline est maintenant très complet. Quelques remarques d'optimisation : Problème potentiel avec Infection — il a besoin du coverage.xml généré par PHPUnit, mais il faut lui passer explicitement. Vérifie que ton infection.json5 pointe bien dessus, sinon ajoute --coverage=coverage.xml ou mieux, utilise le flag --skip-initial-tests si tu veux qu'il réutilise le coverage existant. PHPMetrics — composer global require peut être lent en CI. Une alternative plus rapide : yaml - name: PHPMetrics run: | wget -qO phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar php phpmetrics.phar --report-html=phpmetrics-report src/ Semgrep — pip install en CI c'est aussi un peu lent. L'image Docker officielle est plus rapide : yaml - name: Semgrep SAST run: | docker run --rm -v "${GITHUB_WORKSPACE}:/src" semgrep/semgrep semgrep scan --config=auto --json -o /src/semgrep-report.json /src/src/ || true Mais vu que t'es sur Gitea Actions (pas GitHub), vérifie que le Docker-in-Docker fonctionne dans ton runner. Sinon le pip install reste le plus safe. Ce qui manque pour boucler — tous ces rapports (semgrep, phpmetrics, infection, hadolint) sont générés mais pas exploités. Deux options : SonarQube — configure sonar.externalIssuesReportPaths dans ton sonar-project.properties pour ingérer les JSON de Semgrep et Hadolint. SonarQube les affichera comme "external issues". Artifacts — upload les rapports comme artifacts de build pour les consulter après : yaml - name: Upload reports uses: actions/upload-artifact@v3 with: name: ci-reports path: | semgrep-report.json phpmetrics-report/ infection-report.json hadolint-*.json dependency-check-report.* eslint-report.json phpstan-report.json Ça te permettrait de consulter le rapport PHPMetrics HTML directement. Tu veux que je te génère le sonar-project.properties adapté avec l'import des rapports externes ? name: CI on: push: branches: - master - main pull_request: jobs: sonarqube: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POS pasted 13:38 OK, quelques corrections à faire sur ton workflow actuel : PHPMetrics — tu mélanges les deux approches. Tu fais composer global require mais ensuite php phpmetrics.phar (qui n'existe pas puisque t'as pas téléchargé le phar). Choisis l'un ou l'autre : yaml # Option A : phar (plus rapide) - name: PHPMetrics run: | wget -qO phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar php phpmetrics.phar --report-html=phpmetrics-report src/ # Option B : composer global - name: PHPMetrics run: | composer global require phpmetrics/phpmetrics --no-interaction ~/.composer/vendor/bin/phpmetrics --report-html=phpmetrics-report src/ Semgrep Docker — attention, sur Gitea Actions le ${GITHUB_WORKSPACE} n'existe probablement pas. Selon ton runner Gitea, ça sera plutôt ${GITEA_WORKSPACE} ou ${{ github.workspace }} (si ton runner est compatible). Vérifie, sinon reviens au pip install qui est plus portable : yaml - name: Semgrep SAST run: | pip install semgrep --break-system-packages semgrep scan --config=auto --json -o semgrep-report.json src/ || true Upload des artifacts + sonar-project.properties — tu veux que je te génère les deux fichiers ? Le sonar-project.properties avec l'import de tous tes rapports externes (Semgrep, PHPStan, ESLint, Hadolint, coverage), et la step d'upload artifacts à ajouter en fin de pipeline ? sort tout le workflow stp 13:38 Voici le workflow complet corrigé : Presenting files Presenting files Workflow CI complet corrigé avec tous les outils d'analyse ci.yml sonar-project.properties avec import de tous les rapports externes sonar-project.properties Presenting file(s)... Claude est une IA et peut faire des erreurs. Veuillez vérifier les réponses. Ci · YML Copier name: CI on: push: branches: - master - main pull_request: jobs: ci: runs_on: ubuntu-latest services: database: image: postgres:16-alpine env: POSTGRES_USER: app POSTGRES_PASSWORD: secret POSTGRES_DB: crm_ecosplay options: >- --health-cmd "pg_isready -U app -d crm_ecosplay" --health-interval 5s --health-timeout 5s --health-retries 5 redis: image: redis:7-alpine options: >- --health-cmd "redis-cli ping" --health-interval 5s --health-timeout 5s --health-retries 5 meilisearch: image: getmeili/meilisearch:latest env: MEILI_MASTER_KEY: test MEILI_ENV: development env: DATABASE_URL: "postgresql://app:secret@database:5432/crm_ecosplay?serverVersion=16&charset=utf8" MESSENGER_TRANSPORT_DSN: "redis://redis:6379/messages" MAILER_DSN: "null://null" MEILISEARCH_URL: "http://meilisearch:7700" MEILISEARCH_API_KEY: "test" APP_ENV: test steps: # ─── Setup ─────────────────────────────────────────────── - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup PHP uses: shivammathur/setup-php@v2 with: php-version: '8.4' extensions: intl, pdo_pgsql, zip, gd, redis, imagick coverage: xdebug - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '22' - name: Setup Bun uses: oven-sh/setup-bun@v1 # ─── Dependencies ──────────────────────────────────────── - name: Install PHP dependencies run: composer install --no-interaction --prefer-dist - name: Install JS dependencies run: | bun install npm install # ─── Security audits ───────────────────────────────────── - name: Composer security audit run: composer audit # ─── Linting ───────────────────────────────────────────── - name: Lint Twig run: php bin/console lint:twig templates/ - name: Lint YAML run: php bin/console lint:yaml config/ - name: Lint Container run: php bin/console lint:container - name: PHP CS Fixer run: vendor/bin/php-cs-fixer fix --dry-run --diff - name: ESLint report run: bunx eslint assets/ --ext .js,.ts -f json -o eslint-report.json || true - name: Stylelint run: bunx stylelint "assets/**/*.scss" # ─── Static analysis ───────────────────────────────────── - name: PHPStan report run: vendor/bin/phpstan analyse src/ --level=6 --no-progress --error-format=json > phpstan-report.json || true - name: Semgrep SAST run: | pip install semgrep --break-system-packages semgrep scan --config=auto --json -o semgrep-report.json src/ || true # ─── Build ─────────────────────────────────────────────── - name: Build assets run: bun run build # ─── Tests ─────────────────────────────────────────────── - name: JS tests with coverage run: bun run test:coverage - name: Create test database run: php bin/console doctrine:database:create --env=test --if-not-exists - name: Create database schema run: php bin/console doctrine:schema:create --env=test - name: PHPUnit with coverage run: vendor/bin/phpunit --testdox --coverage-clover coverage.xml --coverage-text - name: Infection (mutation testing) run: | vendor/bin/infection \ --threads=4 \ --skip-initial-tests \ --coverage=. \ --min-msi=50 \ --min-covered-msi=60 \ --logger-json=infection-report.json || true # ─── Metrics ───────────────────────────────────────────── - name: PHPMetrics run: | wget -qO phpmetrics.phar https://github.com/phpmetrics/PhpMetrics/releases/latest/download/phpmetrics.phar php phpmetrics.phar --report-html=phpmetrics-report src/ # ─── Docker linting ────────────────────────────────────── - name: Hadolint run: | wget -qO hadolint https://github.com/hadolint/hadolint/releases/latest/download/hadolint-Linux-x86_64 chmod +x hadolint ./hadolint docker/php/dev/Dockerfile -f json > hadolint-dev.json || true ./hadolint docker/php/prod/Dockerfile -f json > hadolint-prod.json || true # ─── Dependency vulnerability scan ─────────────────────── - name: OWASP Dependency-Check uses: dependency-check/Dependency-Check_Action@main with: project: 'crm-ecosplay' path: '.' format: 'JSON,HTML' args: > --scan composer.lock --scan package.json --out . --disableAssembly --nvdApiKey ${{ secrets.NVD_API_KEY }} continue-on-error: true - name: Rename Dependency-Check reports run: | mv dependency-check-report.json dc-report.json 2>/dev/null || true mv dependency-check-report.html dc-report.html 2>/dev/null || true # ─── SonarQube ─────────────────────────────────────────── - name: SonarQube Scan uses: sonarsource/sonarqube-scan-action@v5 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} SONAR_HOST_URL: https://sn.esy-web.dev # ─── Upload reports ────────────────────────────────────── - name: Upload CI reports uses: actions/upload-artifact@v3 if: always() with: name: ci-reports retention-days: 30 path: | coverage.xml phpstan-report.json eslint-report.json semgrep-report.json infection-report.json hadolint-dev.json hadolint-prod.json dc-report.* phpmetrics-report/