Auditarea codului generat cu AI: ce cedează de fapt în producție
Când o aplicație e construită mai ales de AI, un set specific de cedări revine. Verificările pe care le rulăm pe codul generat cu AI, și de ce fiecare lovește la utilizatori.
Cuprins
- Lista de verificare
- 1. Autorizare generată, dar niciodată conectată
- 2. Dependențe fantomă și nepotrivite
- 3. Date de test livrate ca și cum ar fi reale
- 4. Secrete inserate unde se pot scurge
- 5. Gestionare a erorilor doar pe scenariul fericit
- 6. Suprafețe de prompt-injection și apeluri LLM nesigure
- 7. Un model de date croit pentru demo, nu pentru produs
- 8. Aceeași problemă rezolvată în cinci moduri diferite
- 9. Nicio disciplină de cost sau limită de rată pe apelurile către model
- 10. Teste care verifică ieșirea, nu cerința
- Ce faci cu rezultatele
Aceasta e perechea pentru Este codul tău pregătit pentru AI?. Acea listă întreabă dacă codul tău e pregătit să fie predat unui AI. Aceasta întreabă invers: e codul pe care AI-ul deja l-a scris pregătit pentru utilizatori. Cele două împart o fundație (testele, secretele, dependențele, observabilitatea contează în continuare), așa că pentru igiena generală de inginerie, citește-o întâi pe aceea. Aici listăm cedările specifice codului generat cu AI, cele care apar tocmai fiindcă un model l-a scris după feeling, iar un om l-a acceptat după feeling.
Aceste tipare sunt un compozit reprezentativ. Nu numim clienți și nu inventăm cifre. Dar fiecare punct de mai jos e ceva ce am găsit în mod repetat auditând aplicații construite mai ales prin prompting, și fiecare corespunde unei cedări reale în producție.
Lista de verificare
1. Autorizare generată, dar niciodată conectată
Modelul construiește un login și ascunde butonul de admin, și pare control de acces. Nu e. Verificarea care contează (poate acest utilizator atinge această înregistrare, impusă pe server) lipsește frecvent, fiindcă demoul a rulat mereu ca un singur utilizator. Caută endpoint-uri care au încredere în client, securitate la nivel de rând care a fost schițată, dar lăsată permisivă, și flag-uri „e admin" citite dintr-o valoare pe care browserul o poate seta. Asta e cedarea care devine raport de incident.
2. Dependențe fantomă și nepotrivite
Generatoarele importă cu încredere pachete care nu există, fixează versiuni care n-au fost lansate niciodată, sau aduc un nume cu un caracter diferit față de unul real (un typosquat). Verifică dacă fiecare dependență se rezolvă, dacă e pachetul la care te gândești și dacă e chiar folosită. Un import halucinat pe care cineva l-a „reparat" mai târziu instalând orice se potrivea cu numele e o gaură în lanțul de aprovizionare, nu o greșeală de tastare.
3. Date de test livrate ca și cum ar fi reale
Ca să facă demoul să se miște, modelul populează date de tip placeholder și stubează răspunsuri. Acele stub-uri au obiceiul de a supraviețui în producție: o listă hardcodată unde ar trebui o interogare, un „TODO: replace" care a ajuns livrat, o funcție care returnează același obiect-eșantion indiferent de input. Urmărește fiecare cale de date până la o sursă reală. Cele care se înfundă într-un fixture sunt funcții care au mers doar în demo.
4. Secrete inserate unde se pot scurge
Un model care optimizează pentru „fă-l să meargă" va lipi o cheie API în cod client-side, va comite un .env real, sau va hardcoda un token într-un fișier de configurație. Dincolo de verificarea generică a secretelor, caută specific în bundle-ul client și în istoricul git: commit-urile generate cu AI includ adesea cheia funcțională care a făcut rularea locală să reușească.
5. Gestionare a erorilor doar pe scenariul fericit
Codul generat tratează cazul care i-a fost arătat și nimic altceva. Apelul extern care expiră, plata care se face pe jumătate, încărcarea care eșuează la mijloc: acele ramuri nu au fost scrise niciodată, așa că eșuează în tăcere sau crapă. Caută apeluri externe fără cale de eșec, promisiuni fără tratarea respingerii, și blocuri try/catch care înghit eroarea și continuă. E cea mai frecventă sursă de „merge la mine, cedează la ei".
6. Suprafețe de prompt-injection și apeluri LLM nesigure
Dacă aplicația însăși apelează un model, generatorul rareori îl apără. Inputul utilizatorului curge direct într-un prompt, apelurile de tool rulează fără validare, iar ieșirea modelului e tratată ca și cum ar fi cod scris de tine. Verifică dacă inputul neîncrezut nu poate rescrie instrucțiunea, dacă orice acțiune pe care modelul o poate declanșa e autorizată independent, și dacă ieșirea e tratată ca date, nu ca o comandă.
7. Un model de date croit pentru demo, nu pentru produs
Schema se potrivește singurului flux pe care l-a arătat fondatorul. Îi lipsesc constrângerile, indecșii și relațiile în care produsul chiar a crescut, și adesea stochează ca text ce ar trebui tipizat. E punctul cel mai probabil să forțeze o rescriere parțială, fiindcă totul stă deasupra lui. Judecă schema față de ce este produsul acum, nu față de prototipul de la care a pornit.
8. Aceeași problemă rezolvată în cinci moduri diferite
Fără un simț al întregului, un generator rerezolvă fiecare sarcină local. Găsești trei formatoare de date, două moduri de a apela API-ul, și aceeași validare copiată cu mici derive. Nu e doar dezordine: când o regulă se schimbă, acum trebuie să găsești fiecare copie, și vei rata una. Cartografiază duplicarea înainte să estimezi orice schimbare, fiindcă ea stabilește costul real al fiecărei editări viitoare.
9. Nicio disciplină de cost sau limită de rată pe apelurile către model
Funcțiile AI generate fără un ochi pe factură nu au limite de tokenuri, nu au cache pentru munca repetată, și au logică de reîncercare care asaltează furnizorul la eșec. Caută bucle nelimitate în jurul apelurilor către model, timeout-uri lipsă și absența oricărui cache. O singură zi virală sau o singură cale proastă de reîncercare ajunge ca o factură.
10. Teste care verifică ieșirea, nu cerința
Dacă testele există deloc, adesea verifică exact ce a produs modelul („funcția returnează acest string") în loc de ce ar trebui să facă funcția. Blochează comportamentul curent, cu tot cu buguri, și dau un fals sentiment de siguranță. Citește aserțiunile: un test care ar trece în continuare dacă cerința ar fi greșită nu te protejează.
Ce faci cu rezultatele
De la audit la decizie
- 01Auditează după această listăGăsește cedările specifice AI.
- 02Ordonează după severitate și impactÎntâi autorizarea și modelul de date.
- 03Consolidare sau rescrierePunctul 7 (modelul de date) declanșează rescrierea.
- 04Reverifică după fiecare reparațieConfirmă că cedarea chiar a dispărut.
Majoritatea sunt reparabile fără rescriere. Găsite devreme și lucrate în ordinea priorității, mută o aplicație făcută prin vibe coding de la fragilă la de încredere în timp ce rămâne în funcțiune. Excepția e punctul 7: când modelul de date e greșit pentru ce a devenit produsul, o rescriere țintită a stratului de date e de obicei mai ieftină decât peticirea în jurul lui la nesfârșit. Acea decizie consolidare-sau-rescriere e subiectul articolului MVP-ul tău făcut cu AI tocmai a primit utilizatori, și ar trebui luată din această listă, nu dintr-o săptămână stresantă.
Dacă preiei un cod pe care nu l-ai scris, sau moștenești cod moștenit care se întâmplă să aibă câteva luni, același audit se aplică. Rulăm un audit tehnic ca un angajament de sine stătător exact pentru asta: o evaluare onestă a ce e solid, ce e riscant și cât costă să repari, înainte ca cineva să se angajeze să construiască deasupra.
Această listă reflectă practica noastră actuală la Basetool Labs. Se va schimba pe măsură ce uneltele care generează acest cod evoluează.