Kontrola měří něco jiného, než si myslíš
Špatná odpověď se většinou pozná. Číslo nesedí, test spadne, něco svítí červeně. Horší je odpověď na jinou otázku, než jakou jste položili. Vypadá úplně stejně jako ta správná: má správný tvar, přišla ze správného příkazu a nikde nic nehlásí. Jen neměří to, co si myslíte.
Stavím s pomocí AI, takže spoustu věcí ověřuju skripty, kontrolami a audity. O to víc mě zajímá, kdy kontrola lže. Tady jsou tři případy z jediného dne a pravidla, která mi z nich zůstala.
Padesát dva commitů s klíčem, který tam nebyl
V poznámkách, které držím v gitu, se našlo pár API klíčů. Stává se. Vyčistil jsem je z historie přes git filter-branch a pak spustil kontrolu: projdi všechny commity a hledej ten klíč.
Výsledek: klíč je pořád v 52 commitech. Takže čištění nefungovalo? Fungovalo. filter-branch si původní historii pro jistotu odkládá stranou, do refs/original/. A přepínač --all bere všechny reference, tedy i tuhle zálohu. Kontrola poctivě našla klíč v záloze, kterou jsem si před chvílí sám vyrobil.
Zrádné je to oběma směry. Kdo číslu věří, čistí donekonečna něco, co je dávno čisté. A kdo mávne rukou, že je to jen záloha, a pošle na server všechno, pošle tam i tu zálohu. I s klíči.
git rev-list main # jen to, co se opravdu odesílá
git update-ref -d refs/original/refs/heads/main
git rev-list --all # teprve teď má --all smysl
Sedmdesát osm nálezů, které byly jeden
Jiný repozitář, týž den. Sken na klíče k API (začínají sk-ant-) hlásil 78 zásahů. A to už bylo po pushi, takže studený pot.
Ve skutečnosti šlo o jediný nález, a ani ten nebyl klíč. V README stálo ANTHROPIC_API_KEY=sk-ant-..., tedy ukázka formátu s tečkami místo tajemství. Sedmdesát osm vyšlo proto, že git grep -c vypsal řádek za každý commit, ve kterém ta věta byla, a wc -l ty řádky poslušně sečetl. Počítal jsem commity, ne nálezy.
Plynou z toho dvě věci. Vzor musí být přísný: ne holý prefix, ale prefix a za ním dost dalších znaků, aby to vůbec mohl být skutečný klíč. A nález si musí někdo přečíst očima, protože číslo neřekne, co počítalo.
Odpověď byla na druhém řádku
Třetí případ mě stál hodinu. Zkoumal jsem, jestli proxy před jednou službou propouští WebSocket. Zkouška byla jednoduchá: poslat požadavek na upgrade a podívat se na první řádek odpovědi.
curl -sS -i -N --http1.1 ... 2>&1 | head -1
curl: (28) Operation timed out ... with 0 bytes received
Timeout, nula bajtů. Proxy upgrade zahazuje, jasná věc. Hodinu jsem ji pak ladil. Jenže upgrade prošel a 101 Switching Protocols leželo na druhém řádku. Curl WebSocketem dál mluvit neumí, takže i po úspěšném upgradu skončí timeoutem. Jeho hláška jde na stderr, který jsem si přes 2>&1 vmíchal do výstupu, a do roury dorazila dřív než hlavičky ze stdout. head -1 pak vybral přesně tu jednu větu, která nic neříkala.
Chyba nebyla v proxy. Byla v mé zkoušce.
Co si z toho beru
Všechny tři příkazy fungovaly správně. Odpověděly přesně na to, na co jsem se zeptal. Jen jsem se ptal na něco jiného, než jsem chtěl vědět. Proto si teď u každé kontroly kladu pár otázek:
- Co přesně ten příkaz vidí?
--allvidí i skryté reference,2>&1míchá dva proudy,-cpočítá řádky, ne shody. - Nula i velké číslo jsou podezřelé. Nula může znamenat „čisto" i „hledal jsem špatně". Sto může znamenat průšvih i „počítám commity".
- Aspoň jeden nález si přečtu celý. Číslo je shrnutí. Než mu uvěřím, chci vidět, z čeho vzniklo.
- Kontrolu, která nikdy nic nenašla, zkusím na případu, kde nález být musí. Jinak nevím, jestli vůbec hledá.
- Ověřuju výsledek, ne cestu. Že příkaz doběhl, ještě neznamená, že se stalo, co jsem chtěl.
Totéž platí u AI. Když mi asistent napíše „hotovo, ověřeno", ptám se, čím to ověřil. A jestli ta kontrola nenašla sama sebe. Hledání slova v souboru, kde to slovo stojí v komentáři vysvětlujícím, co se hledá, projde pokaždé.
Proto taky kontrola webu tady na webu nevrací jen jedno číslo. Ukáže sedm oblastí a u každého nálezu napíše, co přesně nesedí.