Guvernanța în straturi
19 min de citit
Am deschis manualul cu PocketOS. Aici vine partea din lecție care merită un capitol întreg: guvernanța, pe straturi.
Incidentul PocketOS e cazul de manual pentru ce previn aceste straturi. La fel și incidentul Terraform care urmează. Ambele s-au întâmplat la începutul lui 2026, unor echipe convinse că sunt atente. Ambele ar fi fost blocate de oricare dintre mai multe mecanisme de control pe care echipele respective nu le aveau puse la punct. Capitolul ăsta e catalogul acelor mecanisme: cinci straturi de apărare, fiecare prinzând ce le scapă celorlalte, fiecare ieftin de pus în funcțiune odată ce ai decis să-l pui în funcțiune. Când cei de la securitate sau conducerea te întreabă ce stă între echipa ta și un PocketOS propriu, catalogul ăsta e răspunsul pe care li-l dai.
La sfârșitul lui februarie 2026, Alexey Grigorev de la DataTalks.Club a pierdut doi ani și jumătate de infrastructură de cursuri pentru că Claude Code a lucrat pe un state file Terraform rămas în urmă. Claude nu avea o hartă corectă a infrastructurii existente; a rulat terraform destroy peste ce a interpretat el drept resurse orfane. AWS a restaurat aproximativ 1,94M de rânduri dintr-un snapshot în circa o zi; pierderea de date a fost parțială, dar reală.
Eșecul PocketOS e o poveste despre o credențială pe care agentul n-ar fi trebuit s-o aibă. Eșecul Terraform e o poveste despre o hartă despre care agentul nu știa că îi lipsește. Moduri de eșec diferite; aceeași cauză arhitecturală. Niciunul nu se rezolvă cu un model mai bun. Ambele se rezolvă cu aceeași disciplină de guvernanță: agentul rulează într-un sandbox în care operațiunile distructive cer confirmare explicită, deține doar credențialele necesare pentru task-ul curent și lucrează pe o stare pe care echipa a verificat-o. Straturile din acest capitol există pentru că și PocketOS, și pierderea lui Grigorev s-au întâmplat în 2026, unor echipe convinse că sunt atente.
Ce putem învăța din PocketOS? Multe. Să începem cu lecțiile greșite, pentru că le văd citate la tot pasul.
Lecția greșită numărul unu: „agentul și-a ignorat instrucțiunile”. Da. Asta fac agenții uneori. Modelele mari de limbaj, chiar și cele foarte capabile, nu respectă perfect constrângerile formulate în limbaj natural. Oricine a livrat vreodată un system prompt și apoi a privit modelul cum îl încalcă știe asta. Soluția nu e „scrie system prompt-uri mai bune”. Soluția e să nu te bazezi niciodată pe instrucțiuni din system prompt drept control dur pentru acțiuni distructive.
Lecția greșită numărul doi: „agenții AI sunt nesiguri”. Nu e o concluzie utilă, pentru că orice tool puternic e periculos dacă îl îndrepți spre producție fără controale. O comandă de shell armată e la fel de periculoasă. Un UPDATE în SQL fără clauza WHERE e la fel de periculos. Întrebarea nu e „e tool-ul nesigur în abstract?”. Întrebarea e „ce controale aveam puse la punct și care dintre ele ar fi prins asta?”.
Lecția greșită numărul trei: „n-ar trebui să folosim AI pentru operațiuni pe baze de date”. Asta înseamnă să arunci productivitatea ca să eviți riscul, când utilizarea productivă a AI-ului pentru operațiuni pe baze de date e cât se poate de reală (ajungem și acolo). Lecția corectă nu e abstinența. Lecția corectă sunt controalele în straturi.
Iar acum lecția corectă.
PocketOS avea o instrucțiune în limbaj natural. Asta e mai slab decât stratul unu. Nu avea permisiuni aplicate efectiv, care să clasifice și să blocheze acțiunea distructivă. Nu avea un sandbox care să refuze operațiunea la nivel de OS. Nu avea segregarea secretelor, care să împiedice sesiunea să dețină credențiala de producție. Nu avea un hook care să forțeze aprobarea umană înaintea unei acțiuni distructive asupra infrastructurii. Nu avea telemetrie pe partea de agent, care să alerteze la folosirea unui token de producție în timpul unei sesiuni de coding. Spus în vocabularul Capitolului 1: Permisiuni / Sandbox ar fi prins incidentul de două ori - o dată la stratul de decizie, dacă regula ar fi existat, și o dată la stratul de OS, indiferent de regulă.
Niciun strat perfect, de unul singur, nu i-ar fi salvat cu certitudine. Dar oricare dintre straturile aplicate efectiv putea rupe lanțul, iar mai multe împreună ar fi făcut mult mai puțin probabil un eveniment de nouă secunde cu pierdere de producție.
Apărare în adâncime (defense in depth). Niciun strat nu e suficient singur. Redundanța e controlul.
Până la finalul capitolului vei ști ce face fiecare strat, ce nu poate face fiecare strat și cum le pui în funcțiune pentru munca ta.
Principiul care guvernează toate cele cinci straturi este principiul privilegiului minim: la fiecare nivel - agentul, procesul sub care rulează agentul, credențialele pe care le deține agentul, rețeaua la care ajunge agentul - acorzi minimul care permite muncii să se întâmple, și nimic în plus. Fiecare strat de mai jos e privilegiul minim aplicat pe altă dimensiune: ce poate face agentul, unde poate face, ce poate citi, ce categorii de acțiuni declanșează un gate uman, ce se înregistrează pentru audit. Privilegiul minim e coloana vertebrală. Straturile sunt implementarea.
Trei dintre aceste cinci straturi - permisiunile, hook-urile de securitate, sandbox-ul - sunt suprafețele de configurare ale componentei principale Permisiuni / Sandbox numit în Capitolul 1. Componenta principală e ceea ce livrează orice coding agent major; suprafețele sunt felul în care echipa ta îl configurează pentru codebase-ul tău, pentru modelul tău de amenințări, pentru postura ta de conformitate. Aceeași formă ca la Memory în Capitolul 1: o componentă principală, mai multe suprafețe de configurare. Memory are una (AGENTS.md / CLAUDE.md); Permisiuni / Sandbox are mai multe. Gestionarea secretelor și telemetria sunt controale de guvernanță adiacente - își au locul în acest capitol pentru că prind ce le scapă suprafețelor componentei principale, dar nu sunt ele însele suprafețe de configurare ale componentei principale. Tratarea în cinci straturi care urmează nu depinde de cum citești componenta principală - un pachet unitar sau cinci controale separate; ambele perspective duc la aceeași muncă de configurare.
Stratul unu: permisiunile.
E stratul pe care majoritatea echipelor îl cunosc deja, pentru că există de la primii coding agents încoace. Permisiunile răspund la întrebarea „are voie acest agent să execute această acțiune chiar acum?”.
În modelul mai vechi de permisiuni, declarai regulile explicit. Allow: citește orice fișier. Ask: scrie în orice fișier din afara directorului de lucru. Deny: șterge fișiere din ~/.ssh. Deny: scrie în fișiere .env. Deny: rulează orice comandă care conține rm -rf. Agentul consulta regulile înaintea fiecărui tool call. Dacă o regulă se potrivea, regula decidea ce urmează.
Modelul mai nou, pe care îl recomand ca default, este auto mode. Auto mode predă decizia per acțiune unui clasificator - de regulă un model mai mic și mai rapid - care hotărăște la fiecare tool call dacă permite, întreabă sau refuză, în funcție de risc și de context. Clasificatorul citește acțiunea propusă și contextul din jur, își aplică antrenamentul și emite o judecată. Majoritatea acțiunilor trec în liniște. Unele sunt scoase la suprafață pentru aprobarea utilizatorului. Puține sunt blocate de-a dreptul.
Auto mode e mai permisiv în cazurile ușoare (zero fricțiune pe acțiunile de rutină) și mai restrictiv în cazurile grele (întreabă acolo unde un reviewer uman ar întreba). Nu înlocuiește regulile declarative - lucrează împreună cu ele. Pattern-ul recomandat: auto mode ca default, plus un set mic de reguli explicite care suprascriu clasificatorul acolo unde acesta greșește sau unde conformitatea cere reguli declarative explicite.
Setul mic trebuie să rămână mic. Reperul meu: zece-cincisprezece override-uri per repository. Dacă lista ta de override-uri crește peste atât, AGENTS.md-ul tău (ajungem și la AGENTS.md) e prea subțire, nu lista de reguli prea scurtă. Lista de override-uri se reduce scriind un ghidaj mai bun la nivel de echipă, pe care clasificatorul din auto mode să-l poată folosi, nu scriind tot mai multe reguli fragile care încearcă să anticipeze fiecare situație.
Stratul unu e ce va configura orice echipă prima dată. Stratul unu e și ce cedează când reușește un prompt injection. Un atacator iscusit, care poate injecta conținut în contextul agentului, poate uneori convinge agentul să ocolească gate-ul de permisiuni - nu spărgând gate-ul, ci păcălind agentul să ceară acțiuni pe care gate-ul nu le-ar vedea în mod normal. Permisiunile sunt necesare. Permisiunile nu sunt suficiente.
Stratul doi: sandbox-ul.
Stratul doi prinde ce i-a scăpat stratului unu.
Sandbox-ul e izolare la nivel de sistem de operare. Kernelul însuși refuză să execute syscall-urile pe care agentul nu e autorizat să le facă. Citire din afara căilor permise? Refuzată. Conexiune de rețea către un host care nu e pe allowlist? Refuzată. Scriere într-un director pe care sandbox-ul nu-l include? Refuzată.
Proprietatea crucială a unui sandbox e că nu face parte din agent. Face parte din sistemul de operare. Prompt injection nu poate ocoli sandbox-ul, pentru că prompt injection funcționează prin manipularea raționamentului agentului, iar kernelul nu ascultă de raționamentul agentului. Kernelul ascultă de apeluri de sistem. Apelul de sistem fie e permis, fie nu e. Raționamentul e irelevant.
Coding agents moderni suportă sandbox-uri pe Linux (bubblewrap cu Landlock și seccomp), pe macOS (Seatbelt) și pe Windows (restricted tokens cu job objects). Sandbox-ul e opt-in. Configurezi allowlist-ul de căi și allowlist-ul de rețea, fie în fișierul de configurare al agentului, fie în AGENTS.md. Pentru majoritatea echipelor, default-ul corect e: citire pe tot repository-ul, scriere doar în worktree, rețea doar către host-urile permise explicit. Restul, blocat.
Sandbox-ul nu încetinește agentul în mod sesizabil. Doar refuză operațiunile care oricum ar fi trebuit refuzate. Dacă agentul tău se lovește regulat de limitele sandbox-ului în timpul muncii normale, limitele sunt greșite; lărgește-le. Dacă agentul tău nu se lovește niciodată de limitele sandbox-ului, probabil le-ai setat corect.
Configurarea sandbox-ului diferă de la agent la agent. Codex CLI impune sandbox-ul by default pe Linux și macOS; trebuie să renunți explicit la el, nu să-l activezi. În versiunile de Claude Code pe care le-am folosit în 2026, sandboxing-ul e disponibil, dar cere configurare explicită - trebuie să-l activezi tu, să configurezi allowlist-urile de căi și de rețea și să accepți micul cost administrativ. Tratează asta ca pe un detaliu de implementare legat de versiune, nu ca pe o proprietate universală a tool-ului. Majoritatea echipelor de Claude Code cu care am lucrat sar peste pasul ăsta, pentru că instalarea default merge și fără el. Instalarea default nu are însă nicio protecție împotriva prompt injection-ului sau a derapajelor agentului. PocketOS e exact cum arată o instalare default fără sandbox atunci când lucrurile merg prost. Sandbox-ul costă o după-amiază de configurare. Merită.
Stratul trei: secretele.
Stratul trei e protecția structurală a credențialelor.
Incidente de securitate a agenților pe care trebuie să le cunoști.
Trei clase de vulnerabilități documentate în 2025-2026 merită știute la acest strat:
- Auto-încărcarea de dot-env: agenții citesc secrete din fișierele .env aflate în directorul de lucru, la pornirea sesiunii.
- Injecția prin fișiere de configurare: fișiere de configurare de proiect care nu sunt de încredere (.claude/settings.json, .mcp.json) execută hook-uri înainte de dialogul de trust, deschizând calea către RCE sau exfiltrarea de API key-uri.
- Ocolirea parser-ului de permisiuni: reguli de deny sărite în tăcere când comenzile de shell se înlănțuie dincolo de un plafon de recunoaștere, sau când parser-ul nu recunoaște binarul (open() din Python, fs.readFile din Node).
A treia clasă merită o notă aparte, pentru că modul de eșec e ușor de citit greșit. Un check de securitate care scana comenzile de shell după potriviri cu regulile de deny retrograda în tăcere la un prompt generic de „ask” atunci când comanda înlănțuia mai mult de cincizeci de subcomenzi. Găsit de un red team extern la începutul lui 2026 și patch-uit într-o săptămână, dar clasa în sine merită reținută: un strat de guvernanță poate avea un mod de eșec silențios, a cărui existență nu e deloc evidentă din citirea configurației. Apărarea în adâncime înseamnă să presupui că orice strat luat singur poate avea un bug; celelalte straturi sunt cele care prind ce i-a scăpat acestuia.
Fiecare clasă a fost documentată și patch-uită sau mitigată. Clasa supraviețuiește; CVE-urile concrete, versiunile de patch și mitigările trăiesc în Anexa C, pentru că numerele de versiune îmbătrânesc mai repede decât pattern-ul de dedesubt.
O preocupare arhitecturală înrudită e injecția de conținut în fișierul de instrucțiuni al echipei printr-o dependență malițioasă sau printr-un contributor compromis, care poate schimba comportamentul agentului la fiecare pornire de sesiune; mitigarea e să tratezi fișierul de instrucțiuni al echipei (AGENTS.md sau echivalentul) drept cod versionat în repo: trecut prin review în PR, semnat de autor, parte din supply chain-ul tău.
Vulnerabilitățile astea sunt reale. Sunt însă și delimitate. Fiecare are un patch sau o mitigare documentată. Clasa de problemă - „gestionarea secretelor în sistemele agentice cere aceeași disciplină ca gestionarea secretelor oriunde altundeva” - e permanentă.
Recomandările mele: nu da commit la fișiere .env în git. Folosește un vault de secrete (HashiCorp Vault, AWS Secrets Manager, Doppler, ce folosește echipa ta) și trage secretele la runtime printr-un pas de fetch explicit, pe care agentul poate fi configurat să-l sară. Include căile sensibile în lista de deny-read a sandbox-ului - agentul pur și simplu nu le poate citi, indiferent ce spune system prompt-ul. Tratează fișierul de instrucțiuni al echipei (AGENTS.md sau echivalentul) drept cod versionat în repo: trecut prin review în PR, semnat de autor, parte din supply chain-ul tău.
Framing-ul pe care îl folosesc cu echipele: regulile de deny și configurația sunt apărare în adâncime. Sandbox-ul e granița dură. Vault-ul e alegerea structurală. Controale în straturi.
Vectorii de mai sus sunt cei cu nume. Mai există un vector care primește mai puțină atenție și lovește echipele mai des: injecția prin munca în sine. Ticket-ul de Jira ale cărui criterii de acceptare conțin un paragraf care începe cu „ignore all previous instructions and...”. Comentariul de PR de la un contributor extern, care strecoară o instrucțiune în ceva ce arată a notă de code review. Mesajul de eroare al unui test third-party instabil, pe care agentul îl citește și îl interpretează drept directivă. README-ul bibliotecii de la un vendor, adusă de agent în timpul research-ului. Oriunde agentul citește conținut în limbaj natural ca parte din munca lui e o potențială suprafață de injecție. Am văzut cu ochii mei un agent executând conștiincios o instrucțiune îngropată într-un fișier de log copiat și lipit, pentru că operatorul nu se gândise la un fișier de log ca la un input de neîncredere.
Mitigarea e aceeași postură ca în restul guvernanței: nu te baza pe raționamentul agentului ca să depisteze injecția. Constrânge ce poate face agentul indiferent de ce a citit. Sandbox-ul prinde acțiunea periculoasă chiar și atunci când agentul e convins că acțiunea e legitimă. Hook-ul prinde categoria periculoasă chiar și atunci când agentul e convins că „doar de data asta e în regulă”. Tratează orice input pe care îl citește agentul drept text de neîncredere - aceeași postură pe care un inginer cu experiență o are față de input-ul utilizatorului dintr-un formular web - și straturile tale de guvernanță vor prinde tentativa de injecție pe care designul promptului a ratat-o. Injecția care reușește e cea care găsește o acțiune pe care straturile de dedesubt nu au delimitat-o.
Stratul patru: hook-urile de securitate.
Stratul patru înseamnă reguli proprii, impuse la nivel de acțiune.
Un hook de securitate e cod care rulează înainte ca agentul să execute un anumit tip de acțiune. Hook-ul citește acțiunea propusă, o evaluează față de regulile echipei și fie o permite, fie cere confirmare, fie o blochează. Hook-urile se declanșează înainte de execuția tool-ului - pre-tool-use, în terminologia consacrată - așa că agentul nu poate duce la capăt o acțiune cu hook fără aprobarea hook-ului.
Pattern-ul cel mai des întâlnit e folosirea unui plugin (în ecosistemul Claude Code, plugin-ul security-guidance și altele asemenea) care vine din fabrică cu reguli pentru categoriile uzuale de vulnerabilități. Secrete scurse în diff-uri. Pattern-uri de SQL injection în codul propus. Credențiale hardcodate. Algoritmi criptografici nesiguri. Scrieri directe de fișiere pe căi cunoscute ca sensibile. Fiecare categorie e o regulă. Hook-ul verifică fiecare acțiune propusă față de fiecare regulă. La potrivire, hook-ul intervine.
Rostul hook-urilor e că sunt programabile. Cele opt sau zece categorii livrate de un plugin de-a gata sunt o bază bună. Echipa ta va avea propriile categorii pe deasupra - poate o regulă conform căreia orice schimbare în logica de conversie valutară cere aprobare explicită, sau una conform căreia orice commit care atinge tabela de clienți cere un reviewer de securitate, sau una conform căreia orice modificare a unui anumit modul relevant pentru conformitate e blocată complet în afara orelor de program. Adaugi regulile astea în hook, agentul le moștenește, fiecare sesiune le impune.
Hook-urile sunt instrumentul la care apelezi când stratul unu (permisiunile) e prea grosier, când stratul doi (sandbox-ul) e prea brutal, când stratul trei (secretele) e în regulă structural, dar tot vrei un gate per acțiune pe anumite operațiuni periculoase. Hook-urile sunt instrumentul de precizie.
Stratul cinci: telemetria.
Primele patru straturi sunt preventive. Opresc agentul să facă lucrul greșit de la bun început. Telemetria e detectivă: îți spune ce a făcut agentul, după ce a rulat, ca să poți audita și îmbunătăți.
Ce loghezi: fiecare tool call făcut de agent. Fiecare comandă de Bash. Fiecare scriere de fișier. Fiecare request către un API extern. Argumentele, rezultatele, timpii. Agentul vede că îl citești; agentul nu vede că îl loghezi. Logul e pentru tine.
Unde îl trimiți: într-un store central deținut de echipa de securitate. Splunk, Elasticsearch, SIEM-ul tău existent, un store custom - ce se potrivește stack-ului tău. Miza e durabilitatea și posibilitatea de interogare. Vrei să poți răspunde la „ce sesiuni au atins serviciul de plăți în ultimele treizeci de zile” fără să faci grep prin istoricele locale de agent ale celor optzeci de ingineri.
Ce urmărești: încălcări de scop (agentul a editat un fișier din afara task-ului asignat), apeluri externe neobișnuite (agentul a contactat un host care nu era pe allowlist-ul lui), refuzuri repetate de permisiuni (agentul a încercat ceva interzis de mai multe ori - fie un bug în setul de reguli, fie o tentativă de prompt injection), credențiale de producție în context (agentul a încărcat un fișier care conține ceva ce arată a secrete).
Incidentul PocketOS e și un eșec de Stratul 5. Apelul distructiv de Volume Delete a generat un audit log de API Railway pe partea de server. Dar PocketOS nu avea monitorizare detectivă a comportamentului propriului agent; nicio alertă nu s-a declanșat când o sesiune de agent a contactat Railway cu un token de producție. Primul semnal primit de echipă a fost baza de date devenită inaccesibilă.
Stratul 5 nu previne PocketOS. Straturile 1-4 previn PocketOS. Stratul 5 detectează momentul în care prevenția a eșuat, așa că timpul de reacție trece de la „două zile până ne dăm seama” la „două minute până primește alerta inginerul de on-call”. Diferența asta e diferența dintre un incident și o catastrofă.
Cinci straturi. Permisiuni, sandbox, secrete, hook-uri de securitate, telemetrie. Fiecare prinde ce le scapă celorlalte. Fiecare are alt mod de eșec. Fiecare e configurabil. Niciunul nu trebuie tratat drept opțional pentru o utilizare serioasă în producție.
Lecția PocketOS nu e „AI-ul e nesigur”. Lecția PocketOS e „un singur strat de apărare nu e de ajuns”. Două straturi sunt semnificativ mai sigure decât unul. Trei straturi sunt semnificativ mai sigure decât două. Patru straturi preventive plus telemetria ca al cincilea îți dau redundanța care face ca un singur eșec să nu devină dezastru, plus pista de audit din care înveți din incidentele evitate la mustață.
Configurează cele cinci straturi o singură dată. Întreține-le ca pe orice altă infrastructură. N-o să regreți în ziua în care ceva merge prost, pentru că ziua aia va veni.
Practici adiacente.
Cele cinci straturi de mai sus sunt controalele orientate către agent. Două practici adiacente țin de aceeași postură de guvernanță, pentru că prind ce nu prind straturile.
Separarea mediilor. Agentul nu deține credențiale de producție by default. Credențialele de staging și de development sunt limitate la ce e accesibil din acele medii. Acțiunile de producție trec printr-un gate de workflow separat - o aprobare umană, un pipeline de CI, un script de deploy - pe care agentul o declanșează, dar nu o execută cap-coadă. Incidentul PocketOS e, în parte, o poveste despre o sesiune de agent care deținea credențiale ce ar fi trebuit segregate.
Branch-uri protejate, CODEOWNERS, politică de CI. Agentul face commit și deschide pull request-uri, ca orice alt contributor. Regulile de protected branch, review-urile CODEOWNERS și politica de CI se aplică PR-urilor agentului exact cum se aplică PR-urilor unui om. Majoritatea echipelor le au deja. Asigură-te că PR-urile agentului trec prin ele, nu pe lângă ele.
Partea I se încheie aici. Ai arhitectura. Știi ce e un agent din punct de vedere anatomic, cum evaluezi unul când apare, ce straturi de guvernanță pui în funcțiune ca să-l ții sub control.
Partea a II-a e despre cum livrezi software cu agentul acum, că el există în mediul tău. Arhitectura răspunde la „ce e chestia asta”. Metoda răspunde la „cum facem treabă cu ea”. Ambele sunt necesare. Niciuna nu e suficientă de una singură.
Să-i dăm drumul.