Integra con CI/CD

CodeMender può analizzare ogni richiesta di pull nella pipeline di integrazione continua e distribuzione continua (CI/CD). Il controllo non riesce quando CodeMender trova una vulnerabilità con gravità CRITICAL o HIGH nel codice modificato dalla richiesta pull. I risultati nel codice che la richiesta di pull non ha modificato vengono visualizzati nel report, ma non superano il controllo.

Questo documento mostra come:

  • Esegui la scansione delle richieste di pull con GitHub Actions e chiedi a CodeMender di aprire una richiesta di pull con le correzioni.
  • Scansiona le richieste di pull con Cloud Build.
  • Esegui la scansione delle modifiche prima di ogni commit con un hook pre-commit di Git.

Come funzionano le scansioni delle richieste di pull

Per analizzare una richiesta di pull, esegui cm find con il flag --diff e il ramo di base della richiesta di pull:

cm find . --diff=origin/main

In risposta a questo comando, CodeMender esegue le seguenti operazioni:

  1. Confronta il ramo della richiesta di pull con il ramo di base ed esegue la scansione dei file di origine modificati e dei file che dipendono direttamente da questi, ad esempio chiamanti e importatori.
  2. Distingue le nuove vulnerabilità introdotte o esposte dalla richiesta di pull dai risultati preesistenti, etichettati con [LEGACY / UNTOUCHED]. Il controllo dell'integrazione continua blocca solo le vulnerabilità causate dalla richiesta di pull.
  3. Esce con stato 1 quando un risultato causato dalla richiesta di pull corrisponde a una gravità in --fail-on. Il valore predefinito è CRITICAL,HIGH.

Per ulteriori informazioni sul confronto tra --diff e altre modalità di scansione, vedi Modalità di ricerca di CodeMender.

Prima di iniziare

CodeMender è disponibile per un numero limitato di clienti in Anteprima pubblica. Contatta il team di vendita per ottenere l'accesso.

  1. Accedi al tuo account Google Cloud . Se non conosci Google Cloud, crea un account per valutare le prestazioni dei nostri prodotti in scenari reali. I nuovi clienti ricevono anche 300 $di crediti senza costi per l'esecuzione, il test e il deployment dei carichi di lavoro.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. If you're using an existing project for this guide, verify that you have the permissions required to complete this guide. If you created a new project, then you already have the required permissions.

  4. Verify that billing is enabled for your Google Cloud project.

  5. Enable the Agent Platform API and Cloud Resource Manager API APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  6. Install the Google Cloud CLI.

  7. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  8. To initialize the gcloud CLI, run the following command:

    gcloud init
  9. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  10. If you're using an existing project for this guide, verify that you have the permissions required to complete this guide. If you created a new project, then you already have the required permissions.

  11. Verify that billing is enabled for your Google Cloud project.

  12. Enable the Agent Platform API and Cloud Resource Manager API APIs, if any are not already enabled.

    Roles required to enable APIs

    To enable APIs, you need the serviceusage.services.enable permission. If you created the project, then you likely already have this permission through the Owner role (roles/owner). Otherwise, you can get this permission through the Service Usage Admin role (roles/serviceusage.serviceUsageAdmin). Learn how to grant roles.

    Enable the APIs

  13. Install the Google Cloud CLI.

  14. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  15. To initialize the gcloud CLI, run the following command:

    gcloud init

Assicurati che la release della CLI CodeMender supporti le scansioni delle richieste di pull. Le pipeline in questo documento scaricano l'ultima release stabile ogni volta che vengono eseguite. Per controllare un'installazione locale, esegui cm find --help e cerca il flag --diff. Per aggiornare la CLI, esegui cm update. Per saperne di più, consulta Installare e configurare la CLI.

Ruoli obbligatori

Per ottenere le autorizzazioni necessarie per configurare le integrazioni CI/CD per CodeMender, chiedi all'amministratore di concederti i seguenti ruoli IAM sul progetto:

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Potresti anche riuscire a ottenere le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti.

Per assicurarti che il account di servizio CI/CD disponga delle autorizzazioni necessarie per eseguire CodeMender in una pipeline CI/CD, chiedi all'amministratore di concedere i seguenti ruoli IAMaccount di servizioount CI/CD:

  • Agent Platform User (roles/aiplatform.user) sul tuo progetto
  • Scrivi i log di build di Cloud Build: Logs Writer (roles/logging.logWriter) sul tuo progetto
  • Salva i report SARIF in un bucket Cloud Storage: Storage Object User (roles/storage.objectUser) sul bucket

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

L'amministratore potrebbe anche essere in grado di concedere al account di servizio CI/CD le autorizzazioni richieste tramite ruoli personalizzati o altri ruoli predefiniti.

Considerazioni sulla sicurezza

Quando esegui CodeMender in un flusso di lavoro GitHub Actions, in un trigger di build di Cloud Build o in un hook pre-commit Git, CodeMender viene eseguito senza chiedere conferma. Prima di configurare queste integrazioni, tieni presente quanto segue:

  • Prompt di conferma: il flag --yes disattiva i prompt che ti chiedono di confermare i comandi dell'agente e le scritture dei file. Il flag --bypass-warning ignora l'avviso che l'agente può modificare i file ed eseguire comandi sul tuo sistema. Prima di utilizzare questi flag, leggi i termini di anteprima all'inizio di questo documento, inclusi i termini relativi alla disattivazione della conferma umana.
  • Sandbox: le pipeline disattivano la sandbox CodeMender con --sandbox=false. I comandi eseguiti dall'agente, come build e test, quando corregge un risultato, hanno lo stesso accesso del job, incluse le relativeGoogle Cloud credenziali e l'accesso alla rete. Il sandbox Linux utilizza gli spazi dei nomi utente, che alcuni ambienti CI, come i container senza privilegi, non supportano. Disattiva la sandbox solo in ambienti isolati e temporanei. Se il tuo ambiente CI supporta la sandbox, rimuovi --sandbox=false.
  • Runner: esegui il flusso di lavoro GitHub Actions sui runner ospitati da GitHub, ad esempio ubuntu-24.04, che esegue ogni job in una nuova macchina virtuale. Non utilizzare runner self-hosted riutilizzati tra i job.
  • Codice non attendibile: il codice in una richiesta di pull può contenere testo che tenta di indirizzare l'agente. Il flusso di lavoro di GitHub Actions analizza solo le richieste di pull dai rami dello stesso repository, che possono essere create solo dagli utenti con accesso in scrittura. Per Cloud Build, utilizza il controllo dei commenti in modo che un proprietario o un collaboratore debba approvare le build per le richieste pull di altri collaboratori.
  • Accesso: concedi a ogni account di servizio solo i ruoli IAM richiesti per la relativa pipeline.

Scansionare le richieste di pull con GitHub Actions

Il flusso di lavoro in questa sezione analizza ogni richiesta di pull in un repository su GitHub.com. Quando CodeMender rileva una vulnerabilità con gravità CRITICAL o HIGH nelle modifiche della richiesta di pull, il flusso di lavoro esegue le seguenti operazioni:

  • Non supera il controllo CodeMender scan.
  • Esegue cm fix per ogni risultato e apre una richiesta di pull con le correzioni nel ramo della richiesta di pull.

Il flusso di lavoro carica anche i risultati nella scansione del codice di GitHub.

Configura la federazione delle identità per i workload

Il flusso di lavoro esegue l'autenticazione su Google Cloud con la federazione delle identità per i workload, in modo da non memorizzare una chiave account di servizio in GitHub. Esegui i seguenti comandi con Google Cloud CLI:

  1. Imposta le variabili della shell per il progetto e il repository:

    PROJECT_ID="PROJECT_ID"
    GITHUB_ORG="GITHUB_ORG"
    REPO="GITHUB_ORG/REPOSITORY"
    

    Sostituisci quanto segue:

    • PROJECT_ID: il tuo ID progetto Google Cloud .
    • GITHUB_ORG: il nome della tua organizzazione GitHub o il tuo nome utente GitHub per un repository in un account personale.
    • REPOSITORY: il nome del repository GitHub.
  2. Abilita le API utilizzate dalla federazione delle identità per i workload:

    gcloud services enable iam.googleapis.com \
        cloudresourcemanager.googleapis.com iamcredentials.googleapis.com \
        sts.googleapis.com --project="${PROJECT_ID}"
    
  3. Crea un account di servizio per il flusso di lavoro e concedigli il ruolo IAM Utente piattaforma agente (roles/aiplatform.user):

    gcloud iam service-accounts create codemender-ci \
        --project="${PROJECT_ID}" \
        --display-name="CodeMender CI"
    
    gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
        --member="serviceAccount:codemender-ci@${PROJECT_ID}.iam.gserviceaccount.com" \
        --role="roles/aiplatform.user"
    
  4. Crea un pool di identità del workload. Se hai già un pool per GitHub Actions, salta questo passaggio e utilizza l'ID del pool anziché github nei passaggi successivi.

    gcloud iam workload-identity-pools create github \
        --project="${PROJECT_ID}" \
        --location="global" \
        --display-name="GitHub Actions"
    
  5. Crea un provider per GitHub nel pool. La condizione dell'attributo accetta token solo dai repository di proprietà di GITHUB_ORG.

    gcloud iam workload-identity-pools providers create-oidc codemender \
        --project="${PROJECT_ID}" \
        --location="global" \
        --workload-identity-pool="github" \
        --display-name="CodeMender" \
        --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.repository_owner=assertion.repository_owner" \
        --attribute-condition="assertion.repository_owner == '${GITHUB_ORG}'" \
        --issuer-uri="https://token.actions.githubusercontent.com"
    
  6. Consenti ai flussi di lavoro nel tuo repository di utilizzare il account di servizio:

    POOL_ID=$(gcloud iam workload-identity-pools describe github \
        --project="${PROJECT_ID}" \
        --location="global" \
        --format="value(name)")
    
    gcloud iam service-accounts add-iam-policy-binding \
        "codemender-ci@${PROJECT_ID}.iam.gserviceaccount.com" \
        --project="${PROJECT_ID}" \
        --role="roles/iam.workloadIdentityUser" \
        --member="principalSet://iam.googleapis.com/${POOL_ID}/attribute.repository/${REPO}"
    
  7. Ottieni il nome completo del fornitore. Ti servirà nella prossima sezione.

    gcloud iam workload-identity-pools providers describe codemender \
        --project="${PROJECT_ID}" \
        --location="global" \
        --workload-identity-pool="github" \
        --format="value(name)"
    

    L'output è simile al seguente:

    projects/123456789/locations/global/workloadIdentityPools/github/providers/codemender
    

L'applicazione delle modifiche alla federazione delle identità per i workload e a IAM può richiedere fino a 5 minuti. Per ulteriori informazioni, vedi Configurare la federazione delle identità per i carichi di lavoro con le pipeline di deployment.

Aggiungere i secret del repository

Nel repository, vai a Settings (Impostazioni) > Secrets and variables (Secret e variabili) > Actions (Azioni) e aggiungi i seguenti secret del repository:

Secret Valore
GCP_PROJECT_ID L'ID progetto.
GCP_WIF_PROVIDER Il nome completo del fornitore della sezione precedente.
GCP_WIF_SERVICE_ACCOUNT codemender-ci@PROJECT_ID.iam.gserviceaccount.com, dove PROJECT_ID è il tuo ID progetto.

Per maggiori informazioni, consulta Utilizzo dei secret in GitHub Actions.

Configura le impostazioni del repository

  1. Per consentire al job di correzione automatica di aprire le richieste pull, vai a Impostazioni > Azioni > Generali. In Workflow permissions (Autorizzazioni del flusso di lavoro), seleziona Allow GitHub Actions to create and approve pull requests (Consenti a GitHub Actions di creare e approvare le richieste di pull), quindi fai clic su Save (Salva). Un repository in un'organizzazione eredita questa impostazione dall'organizzazione. Se non riesci a modificarlo, chiedi a un proprietario dell'organizzazione. Se non utilizzi la correzione automatica, salta questo passaggio. Per maggiori informazioni, consulta la sezione Gestione delle impostazioni di GitHub Actions per un repository.
  2. Assicurati che la scansione del codice GitHub sia disponibile per il repository. Per i repository privati e interni, la scansione del codice richiede GitHub Code Security. Se la scansione del codice non è disponibile, elimina il passaggio Carica i risultati nella scansione del codice e le autorizzazioni security-events e actions dal job di scansione. In caso contrario, il caricamento non riesce e nemmeno il job di scansione. Per maggiori informazioni, vedi Caricare un file SARIF su GitHub.

Aggiungere il workflow

Esegui il commit del seguente workflow nel repository come .github/workflows/codemender.yml:

name: CodeMender

on:
  pull_request:

permissions: {}

defaults:
  run:
    shell: bash

env:
  CM_DOWNLOAD_URL: https://artifactregistry.googleapis.com/download/v1/projects/cmoc-prod/locations/us/repositories/codemender-cli-production/files/cm%3Astable%3Acm-linux-amd64.zip:download?alt=media

jobs:
  scan:
    name: CodeMender scan
    # Workflows for fork and Dependabot pull requests can't read this
    # repository's secrets, so they can't authenticate to Google Cloud.
    if: >-
      github.event.pull_request.head.repo.full_name == github.repository &&
      github.actor != 'dependabot[bot]'
    runs-on: ubuntu-24.04
    timeout-minutes: 15
    permissions:
      contents: read
      id-token: write         # Workload Identity Federation
      security-events: write  # Upload SARIF to code scanning
      actions: read           # Upload SARIF from a private repository
    outputs:
      findings: ${{ steps.scan.outputs.findings }}
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0  # cm needs the base branch history
          persist-credentials: false

      - uses: google-github-actions/auth@v3
        with:
          project_id: ${{ secrets.GCP_PROJECT_ID }}
          workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
          service_account: ${{ secrets.GCP_WIF_SERVICE_ACCOUNT }}

      - name: Install the CodeMender CLI
        run: |
          curl -fsSL -o "$RUNNER_TEMP/cm.zip" "$CM_DOWNLOAD_URL"
          unzip -q -o "$RUNNER_TEMP/cm.zip" -d "$RUNNER_TEMP/cm"
          echo "$RUNNER_TEMP/cm" >> "$GITHUB_PATH"

      - name: Scan the pull request
        id: scan
        env:
          BASE_REF: ${{ github.base_ref }}
          FAIL_ON: CRITICAL,HIGH
        run: |
          cm init
          status=0
          cm find . \
            --diff="origin/$BASE_REF" \
            --diff-workers=16 \
            --fail-on="$FAIL_ON" \
            --format=sarif \
            --output=codemender.sarif \
            --sandbox=false \
            --yes \
            --bypass-warning || status=$?

          # Save the findings that failed the scan for the autofix job. Like the
          # CI gate, skip findings labeled [LEGACY / UNTOUCHED]: they're in code
          # that the pull request didn't change.
          echo '[]' > "$RUNNER_TEMP/codemender-findings.json"
          if [ "$status" -ne 0 ]; then
            cm report --format=json --status=OPEN \
              | jq --arg fail_on "$FAIL_ON" '
                  ($fail_on | ascii_upcase | split(",")) as $severities
                  | [.[]
                     | select(.title | startswith("[LEGACY / UNTOUCHED]") | not)
                     | select(.severity | ascii_upcase | IN($severities[]))]' \
              > "$RUNNER_TEMP/codemender-findings.json"
          fi
          echo "findings=$(jq length "$RUNNER_TEMP/codemender-findings.json")" >> "$GITHUB_OUTPUT"
          exit "$status"

      - name: Upload results to code scanning
        if: ${{ !cancelled() && hashFiles('codemender.sarif') != '' }}
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: codemender.sarif
          category: codemender

      - name: Save findings for autofix
        if: ${{ !cancelled() && steps.scan.outputs.findings > 0 }}
        uses: actions/upload-artifact@v7
        with:
          name: codemender-findings
          path: ${{ runner.temp }}/codemender-findings.json
          retention-days: 1

  autofix:
    name: CodeMender autofix
    needs: scan
    if: ${{ !cancelled() && needs.scan.outputs.findings > 0 }}
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    permissions:
      contents: write        # Push the fix branch
      pull-requests: write   # Open the fix pull request
      id-token: write        # Workload Identity Federation
    steps:
      - uses: actions/checkout@v7
        with:
          ref: ${{ github.head_ref }}
          persist-credentials: false

      - uses: google-github-actions/auth@v3
        with:
          project_id: ${{ secrets.GCP_PROJECT_ID }}
          workload_identity_provider: ${{ secrets.GCP_WIF_PROVIDER }}
          service_account: ${{ secrets.GCP_WIF_SERVICE_ACCOUNT }}

      - name: Install the CodeMender CLI
        run: |
          curl -fsSL -o "$RUNNER_TEMP/cm.zip" "$CM_DOWNLOAD_URL"
          unzip -q -o "$RUNNER_TEMP/cm.zip" -d "$RUNNER_TEMP/cm"
          echo "$RUNNER_TEMP/cm" >> "$GITHUB_PATH"

      - uses: actions/download-artifact@v8
        with:
          name: codemender-findings
          path: ${{ runner.temp }}/codemender

      - name: Fix findings
        run: |
          # Keep CodeMender state and the auth action's credentials file out of
          # the commits, and out of the `git clean` that cm fix runs.
          printf '%s\n' .cm_project 'gha-creds-*.json' >> .git/info/exclude

          cm init
          # Fix in the repository root instead of each file's directory.
          printf 'project_paths:\n  - "%s"\n' "$GITHUB_WORKSPACE" \
            >> ~/.codemender/config.yaml
          cm report import -f "$RUNNER_TEMP/codemender/codemender-findings.json"

          git config user.name "github-actions[bot]"
          git config user.email \
            "41898282+github-actions[bot]@users.noreply.github.com"

          cm report --format=json --status=OPEN \
            | jq -r '.[] | [.finding_id, .title] | @tsv' \
            > "$RUNNER_TEMP/findings.tsv"
          while IFS=$'\t' read -r id title; do
            # cm fix exits 0 when it makes no edits, so also check for changes.
            if cm fix "$id" \
                 --sandbox=false --yes --bypass-warning < /dev/null &&
               ! git diff --quiet; then
              git commit -q -a -m "Fix $title" -m "CodeMender finding $id"
            else
              echo "::warning::CodeMender didn't fix \"$title\" ($id)."
            fi
            # Discard files the fix agent created, such as test output.
            git reset -q --hard
            git clean -q -fd
          done < "$RUNNER_TEMP/findings.tsv"

      - uses: peter-evans/create-pull-request@v8
        with:
          branch: codemender/fix-pr-${{ github.event.pull_request.number }}
          base: ${{ github.head_ref }}
          title: "CodeMender fixes for #${{ github.event.pull_request.number }}"
          body: |
            CodeMender generated these fixes for findings in #${{ github.event.pull_request.number }}.
            Review each commit before you merge this pull request into `${{ github.head_ref }}`.

Dettagli workflow

Il seguente diagramma mostra come interagiscono le scansioni delle richieste di pull e i job di correzione automatica:

Viene eseguita la scansione di una richiesta di pull. Se non vengono rilevati risultati bloccanti, il controllo viene superato. In caso contrario, il controllo non va a buon fine, CodeMender apre una richiesta di pull di correzione e l'unione delle correzioni esegue di nuovo la scansione della richiesta di pull.

Il job CodeMender scan esegue le seguenti operazioni:

  1. Estrae la richiesta di pull con la relativa cronologia completa. Per le richieste di pull, GitHub estrae un commit di unione del ramo della richiesta di pull nel ramo di base.
  2. Esegue l'autenticazione su Google Cloud e scarica l'ultima release stabile della CLI CodeMender.
  3. Esegue cm find --diff sul ramo di base. Il job non riesce se CodeMender trova una vulnerabilità con una gravità elencata in FAIL_ON nelle modifiche della richiesta pull.
  4. Carica il report nella scansione del codice di GitHub, anche quando la scansione non riesce. Il report include i risultati etichettati come [LEGACY / UNTOUCHED]. La scansione del codice mostra anche un risultato nei controlli della richiesta pull quando tutte le righe del risultato si trovano nel diff della richiesta pull.
  5. Salva i risultati per cui il job non è riuscito per il job di correzione automatica.

Il job di scansione non viene eseguito per le richieste pull dai fork o da Dependabot, perché i workflow per queste richieste pull non possono leggere i segreti del repository. GitHub segnala un job ignorato come riuscito, quindi il controllo non blocca queste pull request, anche se lo rendi un controllo obbligatorio. Esamina queste richieste pull oppure scansionale localmente con cm find --diff.

Il job CodeMender autofix viene eseguito quando il job di scansione salva i risultati. Svolge le seguenti operazioni:

  1. Estrae il ramo della richiesta di pull.
  2. Esegue cm fix per ogni risultato e applica ogni correzione separatamente. Se CodeMender non corregge un risultato, il job registra un avviso. Il job esegue il commit solo delle modifiche ai file già presenti nel repository e ignora tutti i file creati dall'agente di correzione, ad esempio l'output del test.
  3. Apre una richiesta di pull dal ramo codemender/fix-pr-NUMBER al ramo della richiesta di pull, dove NUMBER è il numero della richiesta di pull. Se la richiesta di pull della correzione esiste già, il job la aggiorna. Se CodeMender non corregge alcun problema o se il job raggiunge il timeout di 60 minuti, non viene aperta una richiesta di pull.

Esaminare e unire le correzioni

GitHub non esegue automaticamente i flussi di lavoro per le richieste pull che un flusso di lavoro crea con GITHUB_TOKEN. Per esaminare la richiesta di pull di correzione, un utente con accesso in scrittura al repository fa clic su Approva l'esecuzione dei workflow nella richiesta di pull di correzione.

Quando unisci la richiesta di pull di correzione, il ramo della richiesta di pull cambia e il flusso di lavoro esegue nuovamente la scansione della richiesta di pull originale.

Personalizzare il workflow

Puoi personalizzare il flusso di lavoro nei seguenti modi:

  • Per modificare le gravità che non superano il controllo, nel passaggio Analizza la richiesta di pull, imposta FAIL_ON su un elenco separato da virgole di gravità senza spazi, ad esempio CRITICAL,HIGH,MEDIUM. I valori validi sono CRITICAL, HIGH, MEDIUM e LOW.
  • Per segnalare i risultati senza superare il controllo, imposta FAIL_ON: "". Il workflow carica comunque i risultati nella scansione del codice, ma non esegue il job di correzione automatica.
  • Per analizzare le richieste di pull solo in alcuni rami, aggiungi un filtro branches all'attivatore pull_request. Il flusso di lavoro non esegue la scansione delle richieste di pull di correzione perché la loro base è un ramo della richiesta di pull:

    on:
      pull_request:
        branches: [main]
    
  • Per disattivare la correzione automatica, elimina il job autofix e il passaggio Salva i risultati per la correzione automatica.

Scansiona le richieste di pull con Cloud Build

La build in questa sezione analizza ogni richiesta di pull in un repository GitHub connesso a Cloud Build. La build e il controllo GitHub non riescono quando CodeMender rileva una vulnerabilità con gravità CRITICAL o HIGH nelle modifiche della richiesta pull. La build non corregge i risultati.

Prima di iniziare, segui questi passaggi:

  1. Connetti il repository a Cloud Build come repository di seconda generazione. Per maggiori informazioni, consulta la pagina Connettiti a un repository GitHub.
  2. Abilita l'API Cloud Build e l'API IAM nel progetto che ha accesso a CodeMender. La build utilizza CodeMender nel progetto che esegue la build.

    PROJECT_ID="PROJECT_ID"
    gcloud services enable cloudbuild.googleapis.com iam.googleapis.com \
        --project="${PROJECT_ID}"
    

    Sostituisci PROJECT_ID con il tuo ID progetto Google Cloud.

Crea un account di servizio

Crea un account di servizio per la build. Concedi il ruolo IAM Utente Agent Platform (roles/aiplatform.user) per utilizzare CodeMender e il ruolo Writer log (roles/logging.logWriter) per scrivere i log di build:

SA="codemender-build@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create codemender-build \
    --project="${PROJECT_ID}" \
    --display-name="CodeMender Cloud Build"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${SA}" \
    --role="roles/aiplatform.user"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:${SA}" \
    --role="roles/logging.logWriter"

Per salvare i report SARIF in un bucket Cloud Storage, concedi anche al account di servizio l'accesso al bucket:

BUCKET="BUCKET"

gcloud storage buckets add-iam-policy-binding "gs://${BUCKET}" \
    --member="serviceAccount:${SA}" \
    --role="roles/storage.objectUser"

Sostituisci BUCKET con il nome del tuo bucket Cloud Storage.

Aggiungi la configurazione build

Esegui il commit della seguente configurazione di build nella radice del repository come cloudbuild.yaml:

# Scans a pull request with CodeMender. The build fails when CodeMender finds
# a CRITICAL or HIGH vulnerability in the pull request's changes.
steps:
  - id: install-codemender
    name: gcr.io/google.com/cloudsdktool/google-cloud-cli:slim
    script: |
      #!/usr/bin/env bash
      set -euo pipefail
      curl -fsSL -o /tmp/cm.zip "$_CM_DOWNLOAD_URL"
      python3 -m zipfile -e /tmp/cm.zip /workspace/.codemender-cli
      chmod +x /workspace/.codemender-cli/cm

  - id: fetch-history
    name: gcr.io/google.com/cloudsdktool/google-cloud-cli:slim
    script: |
      #!/usr/bin/env bash
      set -euo pipefail
      : "${_BASE_BRANCH:?Run this build from a pull request trigger.}"
      # Triggers check out only the pull request's commit. CodeMender needs the
      # history back to where the pull request branched from the base branch.
      # Fetch from origin, or from GitHub if origin isn't configured.
      refspec="+refs/heads/$_BASE_BRANCH:refs/remotes/origin/$_BASE_BRANCH"
      git fetch --quiet --unshallow origin "$refspec" ||
        git fetch --quiet --unshallow \
          "https://github.com/$REPO_FULL_NAME.git" "$refspec"
      merge_base=$(git merge-base HEAD "origin/$_BASE_BRANCH")
      echo "Merge base with $_BASE_BRANCH: $merge_base"

  - id: scan
    name: gcr.io/google.com/cloudsdktool/google-cloud-cli:slim
    script: |
      #!/usr/bin/env bash
      set -uo pipefail
      export PATH="/workspace/.codemender-cli:$PATH"
      # The project that has access to CodeMender.
      export GOOGLE_CLOUD_PROJECT="$PROJECT_ID"
      cm init || exit 1
      status=0
      cm find . \
        --diff="origin/$_BASE_BRANCH" \
        --diff-workers=16 \
        --fail-on=CRITICAL,HIGH \
        --format=sarif \
        --output=codemender.sarif \
        --sandbox=false \
        --yes \
        --bypass-warning || status=$?

      # cm find writes the SARIF report when the scan completes.
      if [ -f codemender.sarif ]; then
        # cm find doesn't print finding details, so print them here.
        cm report --status=OPEN --format=md
        if [ -n "${_REPORT_BUCKET:-}" ]; then
          gcloud storage cp codemender.sarif \
            "gs://$_REPORT_BUCKET/codemender/$BUILD_ID.sarif" || status=1
        fi
      fi
      exit "$status"

substitutions:
  _CM_DOWNLOAD_URL: https://artifactregistry.googleapis.com/download/v1/projects/cmoc-prod/locations/us/repositories/codemender-cli-production/files/cm%3Astable%3Acm-linux-amd64.zip:download?alt=media
  _REPORT_BUCKET: ''  # Optional: a bucket to save the SARIF report in.

timeout: 1200s
options:
  automapSubstitutions: true
  logging: CLOUD_LOGGING_ONLY

Crea il trigger

Crea un trigger che esegue la build per ogni richiesta di pull in main:

REGION="REGION"
CONNECTION="CONNECTION"
REPOSITORY="REPOSITORY"

gcloud builds triggers create github \
    --project="${PROJECT_ID}" \
    --region="${REGION}" \
    --name="codemender-scan" \
    --repository="projects/${PROJECT_ID}/locations/${REGION}/connections/${CONNECTION}/repositories/${REPOSITORY}" \
    --pull-request-pattern='^main$' \
    --comment-control=COMMENTS_ENABLED_FOR_EXTERNAL_CONTRIBUTORS_ONLY \
    --build-config=cloudbuild.yaml \
    --service-account="projects/${PROJECT_ID}/serviceAccounts/${SA}"

Sostituisci quanto segue:

  • REGION: la regione della connessione al repository Cloud Build.
  • CONNECTION: il nome della connessione al repository Cloud Build.
  • REPOSITORY: il nome del repository connesso in Cloud Build.

Tieni presente le seguenti opzioni:

  • --pull-request-pattern è un'espressione regolare per il branch di base della richiesta di pull. Utilizza ^ e $ per trovare una corrispondenza con l'intero nome del ramo.
  • Con --comment-control=COMMENTS_ENABLED_FOR_EXTERNAL_CONTRIBUTORS_ONLY, la build viene eseguita automaticamente per le richieste pull dei proprietari del repository e dei collaboratori. Per le richieste di pull di altri collaboratori, la build viene eseguita dopo che un proprietario o un collaboratore commenta /gcbrun la richiesta di pull.
  • Per salvare i report SARIF in un bucket, aggiungi --substitutions=_REPORT_BUCKET="${BUCKET}".

Puoi anche creare il trigger nella console Google Cloud . Per maggiori informazioni, vedi Creazione di repository da GitHub.

Per mostrare i log di build in GitHub, aggiungi --include-logs-with-status quando crei il trigger e concedi al account di servizio il ruolo Visualizzatore log (roles/logging.viewer). Chiunque possa visualizzare il controllo in GitHub può leggere i log di build, inclusi i risultati.

Come funziona la build

La build prevede tre passaggi:

  1. install-codemender scarica l'ultima release stabile della CLI CodeMender.
  2. fetch-history recupera il ramo di base e la cronologia necessari a CodeMender. Cloud Build estrae solo il commit che ha avviato la build. Il passaggio recupera i dati dal repository remoto origin. Se origin non è configurato, il passaggio recupera i dati da GitHub senza credenziali, il che funziona solo per i repository pubblici. In questo caso, un repository privato richiede credenziali, ad esempio una chiave SSH. Per maggiori informazioni, consulta la pagina Accesso a GitHub da una build tramite chiavi SSH.
  3. scan esegue cm find --diff sul ramo di base. Al termine della scansione, il passaggio stampa tutti i risultati nel log di build. Se imposti _REPORT_BUCKET, il passaggio copia anche il report SARIF in gs://BUCKET/codemender/BUILD_ID.sarif.

Per modificare le gravità che non superano la build, modifica --fail-on nel passaggio scan. Se esegui la build senza un trigger di richiesta di pull, l'operazione non va a buon fine e viene visualizzato il messaggio Run this build from a pull request trigger.

Esegui la scansione prima di ogni commit

Un hook pre-commit di Git può analizzare le modifiche in attesa di commit e bloccare il commit quando CodeMender rileva una vulnerabilità con gravità CRITICAL o HIGH. Gli sviluppatori possono ignorare l'hook, quindi utilizzalo in aggiunta alla scansione nelCI9;integrazione continua, non al suo posto.

Ogni sviluppatore che utilizza l'hook ha bisogno di quanto segue:

  • La CLI CodeMender, installata e configurata come descritto in Installare e configurare la CLI, inclusi gcloud auth application-default login e cm init. Il gancio deve essere cm sul PATH.
  • Il ruolo Utente della piattaforma Agent Platform (roles/aiplatform.user) in un progetto con accesso a CodeMender. CodeMender utilizza il progetto nella variabile di ambiente GOOGLE_CLOUD_PROJECT. Se questa variabile non è impostata, CodeMender utilizza il progetto dalle credenziali predefinite dell'applicazione o il progetto predefinito di gcloud CLI.

Per aggiungere l'hook, salva il seguente script come .git/hooks/pre-commit nel tuo repository:

#!/bin/sh
# Scans staged changes with CodeMender before each commit.
if ! cm find . --diff --staged --fail-on=CRITICAL,HIGH \
    --yes --bypass-warning; then
  echo "CodeMender blocked this commit. To see the findings, run:" >&2
  echo "  cm report --status=OPEN" >&2
  echo "To commit anyway, run git commit --no-verify." >&2
  exit 1
fi

Rendi eseguibile lo script, quindi aggiungi .cm_project al file .gitignore in modo da non eseguire il commit del file creato da CodeMender per monitorare il repository:

chmod +x .git/hooks/pre-commit
echo .cm_project >> .gitignore

Quando esegui git commit, l'hook esegue la scansione dei file con modifiche in attesa di commit. La scansione può richiedere alcuni minuti. L'hook non disattiva la sandbox CodeMender.

Per eseguire il commit senza la scansione, esegui git commit --no-verify.

Flag di scansione

I seguenti flag cm find controllano le scansioni delle richieste di pull. Per tutti i flag, esegui cm find --help:

Flag Predefinito Descrizione
--diff[=REF] Off Analizza le modifiche rispetto a REF, ad esempio origin/main. Senza REF, le scansioni modifiche non eseguite ai file monitorati (rispetto a HEAD). Non può essere utilizzato con --deep.
--staged Off Con --diff, vengono analizzate solo le modifiche in attesa di commit.
--diff-depth DEPTH 1 Profondità di attraversamento per l'analisi d'impatto (da 1 a 3, valore predefinito: 1 hop).
--diff-workers COUNT 4 Il numero di file da scansionare contemporaneamente, da 1 a 16.
--diff-max-neighbors COUNT 10 Il numero massimo di file dipendenti da scansionare.
--fail-on SEVERITIES CRITICAL,HIGH Con --diff, le gravità che fanno uscire cm find con stato 1. Con un valore vuoto, i risultati non influiscono sullo stato di uscita.
--fail-on-truncation Off Con --diff, esce con lo stato 1 se CodeMender trova più file dipendenti di quelli consentiti da --diff-max-neighbors.
--format FORMAT table Il formato del report: table, json o sarif.
--output FILE Output standard Il file in cui scrivere il report.

Risoluzione dei problemi

Questa sezione descrive come risolvere i problemi comuni durante l'esecuzione di CodeMender nelle pipeline CI/CD.

Autorizzazione negata

Il log mostra una riga simile alla seguente:

[1/1] ❌ src/app.py: start session failed: StartSession failed with HTTP 403 Forbidden.

Il messaggio può includere anche Permission 'aiplatform.interactions.create' denied. Verifica quanto segue:

  • Il progetto ha accesso a CodeMender.
  • Il account di servizio o l'utente dispone del ruolo Utente della piattaforma dell'agente (roles/aiplatform.user) nel progetto.
  • L'API Agent Platform è abilitata nel progetto.
  • CodeMender utilizza il progetto corretto. In GitHub Actions, controlla il secret GCP_PROJECT_ID. Cloud Build utilizza il progetto che esegue la build. A livello locale, controlla la variabile di ambiente GOOGLE_CLOUD_PROJECT o il progetto predefinito se la variabile non è impostata.

Configurazione della risorsa in corso

Se nel log viene visualizzato Resource setup has just started. Please try again shortly. o Resource setup is in progress. Please try again shortly., CodeMender sta configurando le risorse per il tuo progetto, il che in genere richiede alcuni minuti. Esegui di nuovo il job in un secondo momento.

Flag sconosciuto: --diff

Se cm find non riesce con Error: unknown flag: --diff, la tua release della CLI non supporta le scansioni delle richieste di pull. Esegui cm update o scarica l'ultima release.

Ramo base non trovato

Se cm find non va a buon fine e viene visualizzato un errore simile al seguente, il ramo di base non è nel checkout:

Error: retrieving VCS diff: git diff failed: exit status 128: fatal: ambiguous argument 'origin/main': unknown revision or path not in the working tree.

Recupera il ramo di base e la relativa cronologia prima di eseguire cm find. In GitHub Actions, imposta fetch-depth: 0 in actions/checkout.

File non analizzati

Una riga con ❌, ad esempio [1/1] ❌ src/app.py: start session failed, indica che CodeMender non è riuscito a scansionare il file. Controlla l'errore nella riga, quindi esegui di nuovo il job.

Nessuna richiesta di pull di correzione

Se il flusso di lavoro non apre una richiesta di pull di correzione, controlla quanto segue:

  • Se il job di correzione automatica non riesce a creare la richiesta di pull, attiva l'opzione Consenti a GitHub Actions di creare e approvare le richieste di pull. Per saperne di più, consulta Configurare le impostazioni del repository.
  • Se il job di correzione automatica va a buon fine senza aprire una richiesta di pull, CodeMender non ha corretto alcun risultato. Il log del job mostra un avviso per ogni risultato che CodeMender non ha corretto.

Il caricamento della scansione del codice non riesce

Se il passaggio di caricamento non va a buon fine con GitHub Code Security or GitHub Advanced Security must be enabled for this repository to use code scanning, attiva GitHub Code Security per il repository o elimina il passaggio di caricamento. Per saperne di più, consulta Configurare le impostazioni del repository.

Avviso non confermato

Se cm non riesce a eseguire warning not acknowledged. Please run interactively once to acknowledge or pass --bypass-warning, CodeMender ha bisogno di una conferma che non può richiedere in un ambiente non interattivo. Aggiungi --bypass-warning al comando. Prima di farlo, leggi i termini dell'anteprima nella parte superiore di questa pagina.

Per ulteriore assistenza, contatta il team di vendita.