Perché centralizzare invece di copiare
In una enterprise senza governo dell’automazione lo stesso blocco di build, di scansione o di deploy finisce copiato in centinaia di repository. Ogni copia diverge: quando cambia un requisito di sicurezza, l’amministratore non ha un punto unico su cui intervenire ma un censimento da fare. GitHub offre tre meccanismi distinti per evitarlo, ed è la loro distinzione — non la loro sintassi — che devi padroneggiare come amministratore.
Il primo sono le actions personalizzate, componenti riusabili invocati da uno step. Il secondo sono i reusable workflow, workflow interi che un altro workflow chiama a runtime. Il terzo sono i workflow templates, modelli che l’organizzazione mette a disposizione e che chi crea un nuovo workflow copia nel proprio repository. Il tuo compito non è scriverli, ma decidere dove vivono, chi può usarli e che cosa succede quando cambiano.
L’impostazione Access: il vero interruttore
Un repository pubblico espone naturalmente le proprie action e i propri reusable workflow. Un repository private o internal, invece, per impostazione predefinita non li espone a nessuno: il workflow chiamante fallisce perché non riesce a risolvere il riferimento. Il rimedio sta nel repository che contiene il componente, non in quello che lo consuma.
Nel repository sorgente vai su Settings, poi Actions e General, e scorri fino alla sezione Access. Le opzioni sono tre: Not accessible, che è il comportamento predefinito, Accessible from repositories in the ‘ORGANIZATION’ organization e Accessible from repositories in the ‘ENTERPRISE’ enterprise. La seconda apre il componente agli altri repository private e internal della stessa organizzazione; la terza estende il raggio a tutte le organizzazioni che appartengono allo stesso enterprise account. Un’organizzazione fuori dall’enterprise non vede nulla, qualunque impostazione tu scelga.
Restano però i vincoli di visibilità, che nessuna impostazione aggira: un componente ospitato in un repository private non può essere usato da repository public o internal, e un componente in un repository internal non può essere usato da repository public. Il flusso di condivisione va sempre verso il basso in termini di visibilità, mai verso l’alto. Quando un workflow consuma un componente da un repository privato, il runner riceve un token di installazione con ambito ristretto e sola lettura, valido per un’ora. Da qui una conseguenza che gli amministratori sottovalutano: gli outside collaborator del repository consumatore possono vedere i log di esecuzione e quindi ottenere visibilità indiretta sul contenuto del repository privato che ospita l’action.
Nell’esame questo è il punto trabocchetto più frequente su questo obiettivo. Lo scenario tipico descrive un reusable workflow che funziona nel proprio repository ma dà errore quando lo chiama un altro repository dell’organizzazione: la risposta corretta è quasi sempre configurare Access nel repository sorgente, non concedere permessi all’utente, non cambiare i workflow permissions e non aggiungere segreti.
Template che si copiano, reusable workflow che restano centrali
I workflow templates di un’organizzazione vivono in un repository chiamato esattamente .github dentro l’organizzazione, in una directory chiamata workflow-templates. Ogni modello richiede due file: il workflow con estensione .yml e un file di metadati omonimo con estensione .properties.json, che deve contenere almeno name e description — i valori con cui il modello verrà presentato agli utenti — e può includere icona, categorie e pattern sui file per suggerire il modello solo ai repository pertinenti.
La differenza pratica con un reusable workflow è tutta qui: il template viene copiato nel repository che lo adotta. Da quel momento è codice locale, l’organizzazione perde ogni controllo su di esso e una correzione al modello non raggiunge chi lo ha già usato. Il reusable workflow invece resta dove sta e viene chiamato a runtime; il repository consumatore ne referenzia una versione, e se punti a un tag mobile aggiorni tutti i chiamanti pubblicando una nuova versione.
Il reusable workflow dichiara il trigger on: workflow_call e viene invocato a livello di job — non dentro uno step — con jobs.<job_id>.uses nella forma owner/repo/.github/workflows/file@ref, dove il riferimento può essere un SHA di commit, un tag o un branch.
jobs:
build:
uses: octo-org/shared-workflows/.github/workflows/build.yml@v1
with:
config-path: .github/labeler.yml
secrets: inherit
Due limiti da ricordare: puoi concatenare al massimo dieci livelli di workflow, cioè il chiamante più nove livelli di workflow chiamati, e un singolo file di workflow può richiamare al massimo cinquanta reusable workflow distinti. secrets: inherit passa i segreti del chiamante ai workflow della stessa organizzazione o dello stesso enterprise. Attenzione invece alle variabili definite in un contesto env a livello di workflow nel chiamante: non vengono propagate al workflow chiamato, e per condividere valori servono gli input, gli output o le variabili di organizzazione.
Le policy che stanno sopra le tue scelte
Anche un componente correttamente condiviso può essere bloccato da una policy superiore. A livello di enterprise, in Policies e poi Actions, l’owner sceglie fra Allow all actions and reusable workflows, Allow enterprise actions and reusable workflows — che ammette solo ciò che nasce dentro l’enterprise, e quindi blocca anche action ufficiali come actions/checkout — e Allow enterprise, and select non-enterprise, actions and reusable workflows, che sblocca i tre interruttori aggiuntivi Allow actions created by GitHub, Allow Marketplace actions by verified creators e Allow or block specified actions and reusable workflows con una lista di pattern. Esiste inoltre Require actions to be pinned to a full-length commit SHA, che impone il pinning alle action pur consentendo ai reusable workflow di essere referenziati per tag. Le action locali sul filesystem del runner, quelle il cui percorso inizia con ./, non vengono mai limitate da queste policy.
Il riuso si intreccia infine con l’enforcement: la regola di ruleset Require workflows to pass before merging ti permette di imporre un workflow ospitato in un repository sorgente a tutti i repository dell’organizzazione, con le stesse regole di visibilità già viste e con la necessità, se la sorgente è internal o private, di aver concesso l’accesso ai suoi componenti. Su GitHub Enterprise Server verifica sempre nella tua versione quali di queste opzioni siano presenti, perché la disponibilità delle policy a livello di enterprise cambia fra release.