Vai al contenuto principale o al footer

Accessibilità nella pipeline, prima del merge

Ci stiamo chiedendo se i controlli di accessibilità sul codice possano entrare nella pipeline e fermare una Merge Request, cioè una proposta di modifica, prima che venga unita al resto. Per capirlo abbiamo costruito una Proof of Concept (PoC) con Playwright e axe-core. È il tema di uno dei nostri talk al DrupalCamp Italy 2026. In fondo trovi sette domande per capire da dove partire sul tuo portale.

A cura del team bmeme

  • Roberto MarianiTechnical Director & Innovation Lead

Da dove nasce la domanda

Nei nostri progetti l'accessibilità si verifica durante la progettazione e lo sviluppo, con strumenti automatici e verifiche manuali. Quando le pagine sono già generate, in test o in produzione, le controlliamo in blocco con MAUVE++, il validatore del CNR-ISTI, a cui il laboratorio ci ha dato accesso per i nostri progetti. Ne ricaviamo una fotografia del portale in quel momento, che però invecchia a ogni rilascio perché nel frattempo il codice continua a cambiare.

Basta una modifica che tolga il nome a un pulsante o riduca un link a un'icona perché il problema arrivi alle pagine, dove il controllo lo trova solo dopo, quando il codice è già stato unito e a volte è già online.

Nella sicurezza i controlli automatici sono già entrati nella pipeline, così ci siamo chiesti se si possa fare lo stesso con l'accessibilità, fissando le regole prima invece di discuterle a ogni rilascio. Chiamiamo questa idea Accessibility-as-Code, sapendo che per ora è un'ipotesi più che una pratica consolidata. La PoC nasce per metterla alla prova e nelle sezioni che seguono raccontiamo come l'abbiamo costruita, come lavora la pipeline e dove si ferma.

La cornice normativa, in breve

L'accessibilità dei servizi digitali è regolata per legge, con norme diverse per le pubbliche amministrazioni e per i privati che offrono alcuni servizi ai consumatori. Qui sotto le riassumiamo in modo orientativo, senza valore di consulenza legale. In entrambi i casi l'obbligo è del titolare del servizio. Una pipeline come quella della PoC non lo sposta su chi sviluppa, ma può dare a chi risponde dell'accessibilità, che nella PA è il Responsabile per la Transizione Digitale, evidenze tecniche a supporto del suo lavoro.

Pubbliche amministrazioni

Vale la Legge 4/2004, detta Legge Stanca, con la dichiarazione di accessibilità da pubblicare ogni anno. AgID ne promuove l'applicazione e vigila sui servizi.

Privati che offrono servizi ai consumatori

Per servizi come commercio elettronico, servizi bancari, trasporto passeggeri e comunicazioni elettroniche vale l'European Accessibility Act, la Direttiva (UE) 2019/882, applicata dal 28 giugno 2025. Anche qui l'autorità di vigilanza è AgID.

Un ente inventato, un problema reale

La PoC gira su un Drupal 11 di base, con il profilo standard e il tema Olivero, dove abbiamo costruito il portale di un ente dichiaratamente fittizio, il «Portale Servizi al Cittadino», con un login, un'area riservata e un modulo che si chiude con una finestra di conferma, così da simulare un servizio pubblico. Il sito si installa da codice, con contenuti sintetici e senza dump di database, quindi ogni pipeline parte sempre dallo stesso punto.

Gli strumenti che stiamo mettendo alla prova sono due e lavorano in sequenza. Playwright apre il browser, entra nell'area riservata e porta la pagina nello stato da controllare, poi axe-core la analizza e restituisce le violazioni, ognuna con un livello di gravità che va da critical a serious, moderate e minor. axe-core, che usiamo solo nella PoC, fa un lavoro diverso da MAUVE++, perché lavora sul codice di una Merge Request prima che venga unito, mentre MAUVE++ fotografa le pagine già generate.

Nel repository ci sono tre Merge Request, ognuna con la sua pipeline eseguita davvero. Nella prima la finestra di conferma del modulo ha un pulsante di chiusura senza nome accessibile, la pipeline la blocca e nel commit successivo basta aggiungere un'etichetta al pulsante per sbloccarla. Nella seconda il titolo della finestra passa da h2 a h4 e la pipeline lascia passare la modifica con un avviso. Nella terza un intervento urgente riduce il link «Paga online» a una sola icona, la pipeline la blocca e la Merge Request si sblocca solo con la procedura di deroga che descriviamo più avanti.

Come funziona la pipeline

01

Il job a11y:audit misura

Dentro la CI il job avvia DDEV, installa il sito e lancia con Playwright la spec che visita le pagine, salvando per ognuna il report di axe-core in un file JSON. Il suo compito è solo misurare, perché le decisioni le prende il job successivo.

02

Un solo login per tutti i test

Prima dei test gira una volta sola un progetto di setup, che apre la pagina di login, compila nome utente e password e preme il pulsante di accesso. Il setup considera riuscito il login solo quando compare il link per uscire, poi salva la sessione in un file che tutti gli altri test riusano senza ripetere l'accesso. Le credenziali restano fuori dal repository. In locale stanno in un file non versionato, mentre in CI arrivano dalle variabili del progetto.

03

Il job a11y:gate decide

Uno script in Node.js legge i report e applica tre regole scritte nel codice, cioè il Severity Budget, il registro del debito noto e il Break-Glass. La misura sono i report di axe-core prodotti dai test nel job precedente, la decisione è quello che il gate ne ricava applicando le regole. Tenerle in due job separati permette di cambiare le regole senza toccare i test.

04

GitLab mostra l'esito

Il gate esce con 0 se non c'è nulla da segnalare, con 1 se blocca, con 3 se tollera e con 4 se c'è una deroga. GitLab mostra il 3 e il 4 come «passed with warnings», così la Merge Request resta sbloccata mentre l'avviso rimane scritto nel log.

Pipeline Poc Playwright Axecore

La pipeline non è ottimizzata e dura diversi minuti, quasi tutti spesi a costruire l'immagine con i browser. Va bene così, perché una PoC serve a provare il metodo e non a essere installata in produzione.

Il falso verde

Un test può passare anche quando il difetto c'è. Nel repository lo mostra e2e/tests/naive.spec.ts, una spec ingenua che gira solo in locale. Apre la pagina della richiesta di servizio e lancia subito l'analisi di axe-core, quando la finestra di conferma non è ancora nel DOM, quindi axe-core non vede il pulsante di chiusura senza nome e il test risulta verde. È quello che chiamiamo falso verde.

La spec usata dalla pipeline, e2e/tests/ci-audit.spec.ts, prima di lanciare l'analisi preme invece il pulsante «Invia richiesta» e aspetta la finestra con

await expect(page.getByRole('dialog')).toBeVisible()

È la riga che manca alla spec ingenua, quella che permette di trovare il difetto e bloccare la Merge Request.

Lo stesso principio vale per il login in e2e/tests/auth.setup.ts, che si considera riuscito solo quando

expect(page.getByRole('link', { name: 'Log out' })).toBeVisible()

trova il link per uscire. Il test cresce insieme alla funzionalità e scriverlo bene fa parte del lavoro, perché una pipeline verde vale quanto i test che la compongono.

Severity Budget, le soglie decise prima del rilascio

Il Severity Budget è l'insieme delle soglie che stabiliscono, per ogni livello di gravità, se una modifica passa, passa con un avviso o si blocca. Le soglie sono scritte nel codice e versionate, quindi valgono per tutti e ogni cambio resta tracciato. A deciderle non è chi sviluppa da solo ma chi risponde dell'accessibilità insieme al team.

Bloccare

Una violazione critical o serious ferma la Merge Request. Lo stesso accade quando i report di axe-core mancano o sono malformati, perché in quel caso il gate non ha elementi per decidere.

Tollerare

Se restano solo violazioni moderate o minor la pipeline passa con un avviso, come succede nella PoC quando un titolo scende da h2 a h4.

Derogare

Una violazione bloccante si supera solo con il Break-Glass, la procedura d'emergenza che descriviamo più avanti.

Dichiarare

Un difetto già noto e registrato resta nel log ma non conta nel budget, finché la sua voce resta valida.

Il debito noto si dichiara

Non tutto quello che la pipeline trova dipende dal team, come il difetto che axe-core segnala sulla pagina di login, che viene dal tema Olivero di Drupal core ed è già segnalato su drupal.org. Bloccare ogni rilascio per questo non avrebbe senso, ma nemmeno ignorarlo.

Per questo nel repository c'è un registro versionato, il file a11y-known-issues.json, in cui ogni voce dice quale regola, su quale pagina e su quale elemento, da dove viene il difetto, dove è stato segnalato a monte, chi ne è responsabile, perché è lì ed entro quando va rivisto, come nella voce per il difetto della pagina di login.

[
  {
    "rule": "region",
    "url": "/user/login",
    "target": "#primary-tabs-title",
    "origin": "Drupal core (Olivero)",
    "upstream": "https://drupal.org/i/3318396",
    "owner": "bmeme",
    "reason": "Titolo nascosto delle schede primarie fuori da un landmark; correzione attesa in core",
    "review_by": "2026-12-31"
  }
]

Finché la voce è valida la violazione compare nel log come debito noto senza contare nel budget. Quando la data di revisione è passata torna a contare, se il difetto sparisce il gate avvisa che la voce è obsoleta e se il registro è scritto male blocca la pipeline, perché un registro sbagliato è un errore di governance. Il nuovo debito si blocca, quello noto si governa.</p><p>Il limite è che chi può modificare il branch può anche aggiungere voci, ma le aggiunte compaiono nel diff della Merge Request, che è il posto dove rivederle.</p>

Break-Glass, la deroga che lascia traccia

01

Si chiede la deroga

Il Break-Glass è la procedura d'emergenza per superare un blocco quando c'è un'urgenza vera. Si avvia a mano una pipeline sul branch compilando tre campi, cioè la richiesta di deroga, il motivo e il ticket di correzione.

02

La pipeline controlla la richiesta

GitLab rifiuta subito un ticket nel formato sbagliato, poi il gate verifica che il motivo sia di almeno dieci caratteri e che il ticket sia valido. Se la richiesta è incompleta la pipeline si blocca, anche quando non ci sarebbero violazioni bloccanti.

03

Resta l'Audit Trail

Se la richiesta è valida il gate esce con 4 e la Merge Request si sblocca senza cambiare il codice. Negli artifact della pipeline resta l'Audit Trail, un registro che non scade con chi ha derogato, quando, perché, con quale ticket, su quale commit e per quali violazioni, insieme ai report di axe-core usati per decidere, che vale come evidenza tecnica a supporto e non come prova legale.

04

Il vetro non è blindato

Nella PoC chiunque possa avviare una pipeline può attivare il Break-Glass, quindi la procedura scoraggia e traccia ma non decide chi può derogare, perché questo spetta al processo dell'organizzazione. Per rafforzarla GitLab offre i branch protetti già nel piano Free, mentre approvazioni obbligatorie e Code Owners, che chiedono una seconda persona per il merge, sono nei piani Premium e Ultimate. Questi ultimi li abbiamo letti nella documentazione senza provarli, perché la PoC usa il piano Free.

Break Glass Poc Playwright Axecore

Dove si ferma l'automazione

Trova una parte dei problemi

I test automatici trovano solo una parte dei problemi di accessibilità, quindi audit manuali e test con persone con disabilità restano necessari. La pipeline serve a togliere di mezzo la parte ripetitiva, lasciando più tempo per loro.

A volte dice «non lo so»

Su alcuni contrasti del tema Olivero axe-core risponde «incomplete», perché lo sfondo sfumato non gli permette di decidere. In quei casi il gate non li conta e serve una verifica umana.

Non vede tutto

Il comportamento della tastiera dentro una finestra di dialogo, il cosiddetto focus trap, non ha una regola in axe-core e va verificato a mano.

Contenuti e PDF

I contenuti che la redazione carica ogni giorno, come testi, immagini e documenti, restano fuori dalla pipeline del codice perché chi sviluppa non può correggerli. Hanno bisogno di un lavoro dedicato con strumenti propri, mentre i PDF allegati sono fuori perimetro.

Non è una certificazione

La pipeline impedisce le regressioni che sa riconoscere e produce evidenze tecniche, ma la conformità di un servizio richiede una valutazione completa, che resta un'attività a parte.

Non è in produzione

La PoC serve a provare il metodo, che ora stiamo portando nella nostra produzione con un lavoro più complesso di una PoC.

Il codice della PoC

Il repository è pubblico su GitLab, con le Merge Request dei casi descritti qui e un README con le istruzioni per ripetere le prove.

Sette domande per cominciare

1. Sai quando è stata verificata l'ultima volta l'accessibilità del portale e su quali pagine?

2. Dopo un rilascio, chi si accorge per primo di un problema di accessibilità?

3. I rilasci passano già da controlli automatici, come test o revisione del codice?

4. Sai distinguere i problemi del codice da quelli dei contenuti caricati dalla redazione?

5. Le aree riservate e i moduli sono inclusi nelle verifiche?

6. È deciso chi stabilisce quali problemi bloccano un rilascio e quali si possono tollerare?

7. In un'urgenza, è scritto chi può rilasciare comunque e cosa deve restare tracciato?

Rispondi a tutte le domande per vedere il risultato.