Dependency review: guardare il diff delle dipendenze e poi renderlo bloccante

La dependency review appartiene a Supply Chain Security, la famiglia che raccoglie dependency graph e Dependabot sotto le GitHub Security suites, e risponde a una domanda sola: che cosa cambia nell’albero delle dipendenze se faccio il merge di questa pull request. Nella scheda Files changed compare una vista dedicata che elenca le dipendenze aggiunte, rimosse e aggiornate — comprese quelle indirette che emergono dai lock file — con licenza, età e vulnerabilità note.

Qui sta la prima distinzione che l’esame verifica volentieri: quella vista informa, non ferma nessuno. A fermare il merge è la dependency review action, il workflow di GitHub Actions che rianalizza il diff e per impostazione predefinita fallisce quando trova pacchetti vulnerabili. Ma anche un job che fallisce blocca solo se qualcuno lo ha reso obbligatorio: un required status check nella branch protection, oppure — ed è la strada che scala — un repository ruleset dell’organizzazione con l’opzione Require workflows to pass before merging e il workflow aggiunto tramite Add workflow. Il ruleset ha un Enforcement status: in Evaluate valuta e annota senza impedire il merge, in Active blocca davvero. Sui repository pubblici la dependency review è disponibile senza costi; su privati e internal richiede GitHub Code Security, cioè la licenza che la certificazione continua a chiamare GitHub Advanced Security.

Licenze: dall’opzione nel workflow alla policy centrale

L’action non guarda solo le vulnerabilità. Le opzioni che contano davvero sono fail-on-severity (valori critical, high, moderate, low), allow-licenses e deny-licenses, che accettano espressioni SPDX e realizzano rispettivamente una lista chiusa di licenze ammesse e una lista di licenze che bloccano la pull request, allow-ghsas per ignorare singoli advisory identificati dal loro GHSA ID, fail-on-scopes con i valori development, runtime e unknown, e config-file, che sposta la configurazione in un file versionato, eventualmente in un repository esterno (con external-repo-token se è privato).

Sopra a questo livello esiste la license policy, definita per enterprise, organizzazione o repository e applicata da un ruleset con la condizione Requires license compliance results before merging; anche qui gli stati sono Evaluate e Active. Uno sviluppatore che ha bisogno di una dipendenza non conforme può chiedere un’eccezione per pacchetto o per licenza, e la richiesta arriva agli Enterprise Open Source License Managers, gli unici che possono modificare la policy. Non confondere le due leve: le opzioni dell’action vivono nel repository e nel workflow, la license policy è governance centrale.

Regole di aggiornamento: raggruppare invece di annegare

Il file dependabot.yml è dove si decide quante pull request il team riceverà. La chiave groups unisce più aggiornamenti in una sola PR e accetta patterns, exclude-patterns, update-types, dependency-type (produzione o sviluppo) e soprattutto applies-to, che distingue i gruppi di version updates da quelli di security updates; group-by: dependency-name raggruppa la stessa dipendenza su più directory di un monorepo.

version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 5
    groups:
      minor-and-patch:
        applies-to: version-updates
        patterns: ["*"]
        update-types: ["minor", "patch"]

Attorno a questo lavorano open-pull-requests-limit, che limita le PR aperte dai version updates ma non trattiene gli aggiornamenti di sicurezza, versioning-strategy, cooldown (con default-days, semver-major-days, semver-minor-days, semver-patch-days) per non inseguire ogni release appena pubblicata, e la coppia allow e ignore, applicata in quest’ordine: prima si sceglie che cosa mantenere, poi si filtra.

Il rumore si riduce anche a monte, sugli alert. Le auto-triage rules — la preset Dismiss low impact issues for development-scoped dependencies, attiva di default sui repository pubblici e in opt-in sui privati, più le custom rules basate su metadati come severità, nome del pacchetto o CWE — chiudono o rinviano automaticamente ciò che non merita attenzione, e un alert chiuso così resta ripristinabile e si riapre da solo se i metadati cambiano. Attenzione a dove stanno: le auto-triage rules sono nei Global settings dell’organizzazione (Settings, Advanced Security, Global settings), mentre la security configuration è l’insieme di interruttori che si applica ai repository. Ricorda anche che solo gli advisory GitHub-reviewed generano alert Dependabot: quelli unreviewed, importati dal National Vulnerability Database, no, mentre i malware advisory generano alert quando i malware alerts sono abilitati e non hanno una versione di fix.

Permessi, assegnazione e integrazioni

Gli alert li abilitano gli amministratori del repository e gli owner dell’organizzazione, che possono concedere accesso ad altre persone o team; chiunque abbia write access o superiore può assegnare un alert a collaboratori, team o agenti AI, e l’assegnatario riceve la notifica. Per la governance della chiusura c’è il delegated alert dismissal: l’impostazione si chiama Prevent direct alert dismissals e si trova nelle impostazioni Advanced Security del repository o nella sezione Dependency scanning di una custom security configuration. Va tenuta separata dal delegated bypass di Secret Protection, che decide chi può completare un push bloccato per un segreto: uno riguarda il push, l’altro la chiusura di un alert.

Sul fronte notifiche, GitHub scrive via email a chi ha permessi write, maintain o admin, con i canali On GitHub, Email, CLI e GitHub Mobile e l’opzione Email weekly digest; non arriva nulla quando un advisory esistente viene aggiornato, quindi per una vista di squadra servono gli endpoint REST degli alert Dependabot o i webhook, per esempio quello che segnala il cambio di assegnatario. Infine i workflow attivati dalle pull request di Dependabot: si filtrano con github.event.pull_request.user.login == 'dependabot[bot]', leggono i metadati con dependabot/fetch-metadata (che restituisce dependency-names, dependency-type e update-type) e richiedono permessi espliciti come pull-requests: write. Il tranello ricorrente è nei segreti: in questi workflow valgono i Dependabot secrets, non gli Actions secrets.