Vai al contenuto

Guida

Checklist pratica per la code review del codice generato dall’AI prima del merge

Dieci controlli sul codice scritto da un assistente AI: dipendenze inventate, controlli di accesso solo nel browser, errori ignorati e test che non verificano nulla.

· 9 min di lettura · A cura del team vetkit

Un robot presenta con orgoglio una finestra di codice mentre uno sviluppatore spunta le voci di una grande checklist su un portablocco.Un robot presenta con orgoglio una finestra di codice mentre uno sviluppatore spunta le voci di una grande checklist su un portablocco.

Il codice scritto da un assistente di solito compila, si legge bene e fa più o meno quello che hai chiesto. Ed è proprio per questo che è facile approvarlo senza guardarlo troppo. Gli errori raramente sono di sintassi. Sono decisioni che il modello ha preso in silenzio: una dipendenza che ha dato per scontato esistesse, un controllo dei permessi messo nel posto sbagliato, un errore che ha deciso di ignorare.

Questa è la checklist che usiamo quando rivediamo modifiche scritte con l’aiuto dell’AI. Non riguarda l’eleganza del codice. Riguarda quella manciata di problemi che si trasformano in incidenti.

Perché il codice AI richiede una revisione diversa

Quando è un collega a scrivere il codice, di solito puoi fidarti delle parti che non ha menzionato. Conosceva la codebase, ha testato la modifica in locale e ti avrebbe detto se qualcosa era incompleto. Un modello non ha nulla di questo contesto, a meno che tu non glielo abbia fornito, e tende a colmare le lacune con qualcosa di plausibile invece che con una domanda. Così la revisione passa da “è scritto bene?” a “cosa ha dato per scontato?”.

1. Dipendenze

Controlla ogni pacchetto che la modifica aggiunge. Esiste nel registry? È il pacchetto consigliato dalla documentazione ufficiale o uno dal nome simile? È stato pubblicato la settimana scorsa? A volte i modelli inventano nomi di pacchetti, e alcuni di questi nomi vengono registrati da attaccanti. La nostra guida allo slopsquatting spiega come verificare un pacchetto in un minuto.

Guarda anche le versioni. Una versione fissata su qualcosa che non è mai stato rilasciato romperà la prossima installazione da zero, e una dipendenza non fissata significa che il codice che hai rivisto non è quello che gira.

2. Segreti e variabili pubbliche

Cerca nel diff chiavi, token e password, anche nei file di test e negli esempi. Poi guarda le variabili d’ambiente con prefissi pubblici come VITE_, NEXT_PUBLIC_ o EXPO_PUBLIC_. Tutto ciò che ha questi prefissi viene copiato nel bundle del browser in fase di build. Un assistente potrebbe rinominare un segreto con uno di questi prefissi per far funzionare una funzionalità nel browser. Questa guida analizza la variante di questo errore che riguarda le chiavi API degli LLM.

3. Dove viene controllato l’accesso

Trova la riga che decide se l’utente corrente può fare questa operazione. Se si trova in un componente React, in una route guard o in un pulsante nascosto, è una funzione di user experience, non di sicurezza. Chiunque può chiamare direttamente la tua API. Il controllo deve avvenire sul server, a ogni richiesta, sulla risorsa a cui si accede: non solo “questo utente ha effettuato l’accesso?” ma “questa fattura appartiene a questo utente?”.

Fai attenzione alle nuove route API senza alcun middleware di autenticazione e ai backend come Supabase o Firebase, in cui il database è raggiungibile dal browser. Lì, la protezione sono le regole del database stesso. Una tabella Supabase senza row level security è aperta a chiunque abbia la tua anon key pubblica.

4. Input non attendibile

Segui l’input dell’utente dal punto in cui entra a quello in cui viene usato. SQL costruito concatenando stringhe, comandi di shell assemblati dai campi della richiesta, percorsi di file presi dai parametri della query, HTML generato da contenuti degli utenti e URL richiesti per conto di un utente sono i classici schemi di injection, path traversal, XSS e SSRF. Gli assistenti li producono ancora, soprattutto quando il codice circostante fa già qualcosa di simile.

text
// Looks harmless, is an injectiondb.query(`SELECT * FROM users WHERE email = '${req.query.email}'`); // Parameterizeddb.query('SELECT * FROM users WHERE email = $1', [req.query.email]);

5. Codice incompleto

Le generazioni lunghe a volte si interrompono prima del tempo. Cerca nella modifica i segnaposto: TODO, “implement later”, “rest of the code here”, funzioni che restituiscono dati di esempio hard-coded, credenziali fittizie e file con nomi come utils copy.ts. Cerca anche soppressioni generalizzate come // @ts-ignore, eslint-disable in cima a un file, o any usato per zittire il type checker. Spesso nascondono proprio il problema che il modello non è riuscito a risolvere.

6. Gestione degli errori

Un blocco catch che scrive un log e prosegue, oppure che cattura tutto e restituisce un risultato vuoto, trasforma un errore evidente in una perdita di dati silenziosa. Chiediti cosa dovrebbe succedere quando questa chiamata fallisce e se il codice fa davvero quello. Diffida dei retry senza limiti e degli errori convertiti in risposte di successo.

7. Test

I test generati vanno letti riga per riga. Problemi comuni: test che non verificano mai nulla, test che fanno il mock proprio della funzione che stanno testando, asserzioni che controllano solo che una funzione sia stata chiamata, e .only o .skip dimenticati. Una test suite che passa non dimostra nulla finché non sai che può fallire. Rompi il codice di proposito una volta e verifica se un test se ne accorge.

8. Timeout e chiamate bloccanti

Le chiamate HTTP in uscita senza timeout sono un incidente in produzione che aspetta solo una dipendenza lenta. Molti client diffusi attendono all’infinito di default, tra cui requests di Python e http.DefaultClient di Go. In Node.js, operazioni sincrone sui file o l’hashing delle password dentro un request handler bloccano tutte le altre richieste su quel processo. Raramente emergono nei test in locale, perché il tuo portatile e le tue dipendenze sono veloci e scarichi.

9. Accesso ai dati

Cerca query dentro i cicli (il problema N+1), endpoint di elenco che restituiscono tutte le righe senza paginazione e client del database creati a ogni richiesta invece che condivisi. Controlla con attenzione anche le migrazioni: una sincronizzazione dello schema eseguita all’avvio, o una migrazione che elimina e ricrea una tabella, può cancellare i dati di produzione al deploy successivo.

10. Funzionalità basate su LLM

Se la modifica chiama un modello, tratta l’output del modello come input non attendibile. Non deve mai essere eseguito, concatenato in una query SQL o renderizzato come HTML grezzo. Verifica che la chiave API resti sul server, che la route che chiama il modello richieda un utente autenticato e abbia un rate limit, e che la lunghezza dell’output sia limitata. Se un agent ha dei tool, verifica cosa possono fare quei tool e se il testo di documenti o pagine web può pilotarli.

Rendilo una routine

Dieci controlli per ogni pull request sono tanti da fare a mano, e lo scopo di una checklist è smettere di affidarsi alla memoria. La maggior parte di queste voci si può automatizzare, almeno in parte. Così la tua attenzione resta libera per le cose in cui i tool sono scarsi, come capire se la modifica fa ciò di cui il prodotto ha davvero bisogno.

vetkit raggruppa questi controlli in suite: sicurezza (segreti, dipendenze vulnerabili, vulnerabilità del codice, configurazione dell’infrastruttura), qualità del codice, sostenibilità, rischi del codice AI (pacchetti inventati, codice incompleto, insidie delle piattaforme per app, sicurezza di LLM e agent) e prontezza per la produzione (timeout, chiamate bloccanti, uso del database, basi operative). Legge il tuo codice senza installarlo, compilarlo o eseguirlo, e riporta ciò che trova con file, riga e una correzione suggerita. Come qualsiasi analisi statica, può non vedere qualcosa e può sbagliare, quindi supporta una revisione invece di sostituirla.

Richiedi l’accesso anticipato

Raccontaci qualcosa del tuo team e dei repository che vuoi sottoporre ad audit. Accogliamo i team a piccoli gruppi e ti risponderemo via email.

Usiamo questi dati solo per rispondere alla tua richiesta. Informativa sulla privacy