Una correzione che aveva ragione a metà
La 1.28.0, uscita ieri notte, chiudeva due segnalazioni sulla cache di pagina e ne portava con sé una terza correzione, trovata pochi minuti prima di pubblicare: il veto alla cache non doveva scattare su un sito che non ha alcun modo di determinare il paese di un visitatore. Se la pagina è identica per tutti, non c’è nessuna variazione da proteggere, e rinunciare alla cache non compra niente.
Il ragionamento era giusto. L’implementazione, in un punto su quattro, no — e questa versione lo sistema.
Il difetto: dipendeva da chi stava chiedendo
Il plugin controlla quattro possibili fonti per il paese di un visitatore: l’header CF-IPCountry di Cloudflare quando il sito ci sta dietro e l’amministratore ha scelto di fidarsene, un modulo GeoIP del server, l’estensione GeoIP di PHP, e il database MaxMind GeoLite2 scaricato in locale. Tre di queste sono proprietà della configurazione: o ci sono o non ci sono, indipendentemente da chi bussa alla porta.
La quarta no. Per Cloudflare il codice pretendeva che l’header fosse presente nella richiesta corrente. E questo rende la risposta dipendente da chi sta chiedendo, il che su un sito con la cache è un problema serio.
Immagina un cache warmer — quei processi che visitano le pagine in anticipo per riempire la cache — oppure un servizio di monitoraggio, o semplicemente qualunque richiesta che raggiunga il server di origine senza passare da Cloudflare. Nessuno di questi porta l’header. Il plugin concludeva «nessuna fonte per il paese», quindi «la pagina non varia», quindi «si può mettere in cache». E quella risposta, generata con le regole di fallback, restava lì.
Poi arrivava un visitatore vero, dietro Cloudflare, con il suo header che diceva perfettamente da dove veniva. E si prendeva la pagina in cache. Con il banner e le regole sbagliate.
Un visitatore europeo che riceve dalla cache un banner di opt-out non è una sfumatura di configurazione: è esattamente la fuga che il veto alla cache esiste per impedire.
La parte che mi ha dato più fastidio
Due righe sopra quel controllo c’era un commento, scritto da me il giorno prima, che diceva testualmente che il predicato riguarda una fonte configurata, non una fonte che ha risolto qualcosa per questo visitatore. Avevo scritto la regola giusta e poi, nell’unico ramo dove la distinzione contava davvero, non l’avevo seguita.
Non l’ho trovato io: l’ha trovato una revisione automatica del codice, guardando quel diff. È il motivo per cui ho aperto una pull request apposta per far rivedere sei commit che erano finiti direttamente sul ramo principale durante il rilascio, senza passare da nessuna revisione. Ne sono usciti cinque rilievi, tutti fondati.
Quanto è grave davvero
Poco raggiungibile, ma non da arrotondare al ribasso.
Serve che l’amministratore abbia esplicitamente attivato la fiducia nell’header di Cloudflare — è una scelta opt-in, spenta di default, perché un header può essere falsificato da chi non passa davvero dalla CDN. E serve che qualcosa raggiunga l’origine senza quell’header mentre la cache è vuota. Molti siti non si trovano mai in questa combinazione.
Ma quando ci si trovano, il risultato è che una persona in Europa riceve il trattamento previsto per una giurisdizione di opt-out. Su un plugin di consenso, la probabilità bassa non compensa la natura dell’errore.
La correzione è che il filtro di fiducia, da solo, basta a dichiarare la fonte configurata — che è quello che «una fonte è configurata» avrebbe sempre dovuto significare. Chi ha bisogno del comportamento opposto ha ancora il filtro faz_has_country_signal_source per dirlo esplicitamente.
E il test che ora lo sorveglia
Il caso di prova aggiunto mette deliberatamente nessun header CF-IPCountry nella richiesta: quell’assenza è tutto il punto. Rimettendo il difetto, il test diventa rosso; togliendolo, il file torna identico byte per byte.
È il metodo che ho adottato per ogni asserzione nuova in questi due rilasci, dopo aver scoperto quanti controlli verdi non stessero verificando nulla. Un test che resta verde quando il difetto c’è non è un test debole: è un test che non esiste, e occupa il posto di quello che servirebbe.
Tre correzioni agli strumenti, invisibili ma non irrilevanti
Insieme al difetto principale sono stati sistemati tre problemi negli script che pubblicano le release. Non toccano il plugin, ma riguardano la cosa che decide come il plugin arriva a voi.
Il comando di prova a vuoto creava davvero la categoria sul blog prima di arrivare al proprio controllo, quindi scriveva in produzione mentre dichiarava di non aver pubblicato nulla. La directory temporanea sul server remoto aveva un nome prevedibile, e su un host condiviso un altro utente avrebbe potuto occuparla in anticipo. E un aggiornamento fallito degli asset veniva silenziato, lasciando proseguire il rilascio con materiale incompleto — una riga che avevo scritto io stessa notte, per correggere un guasto che era costato sette tentativi, e che avevo reso muta sul proprio.
In sintesi
Se hai attivato la fiducia nell’header di Cloudflare e usi una cache di pagina, questo aggiornamento ti riguarda direttamente. Se non l’hai fatto, il difetto non ti ha toccato — ma l’aggiornamento resta consigliato, perché la stessa logica governa tutte le decisioni di cacheabilità del plugin.
Nessuna azione richiesta: la correzione è nel codice, non nelle impostazioni.
