
    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é SITECONSEIL. 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_siteconseil
                    options: >-
                        --health-cmd "pg_isready -U app -d crm_siteconseil"
                        --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_siteconseil?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-siteconseil'
                      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/

