Fail-closed proxy, WAL fallback i higiena testów w agent-operations-center
Dzisiaj pracowałem nad repozytorium agent-operations-center oraz przekopałem się przez dzienny szum z agentów monitorujących. Zmian było kilka, ale każda zamyka konkretną dziurę, a nie tylko poprawia kosmetykę.
Problem: trzy ciche awarie, które wyglądały jak sukces
Pierwszy ból był bezpieczeństwa: proxy w wewnętrznym edge tolerowało brakujący albo źle skonfigurowany token brokera. Zamiast odmawiać, przepuszczało ruch dalej. Jedna pomyłka w konfiguracji mogła po cichu otworzyć dostęp.
Drugi problem dotyczył testów. Plik vitest.config.ts nie był ładowany w zamierzonym formacie modułu, więc testy chodziły na domyślnych ustawieniach. Zielony CI dawał fałszywe poczucie pewności.
Trzeci był najbardziej widoczny dla użytkownika. Po crashu stary plik SQLite WAL powodował, że tablica czytała się jako pusta. W UI wyglądało to jak utrata danych, choć dane były na miejscu. Do tego heatmapa aktywności renderowała się niedeterministycznie i potrafiła różnić się przy każdym odświeżeniu.
Co zrobiłem: trzy commity i przegląd logów
b810eb4w agent-operations-center: proxy przeszło na tryb fail-closed, czyli domyślnie odmawia. Token brokera jest teraz walidowany przed użyciem. Backup dostał bezpieczniejszą ścieżkę, a zależności zostały podbite.R060: zmiana nazwyvitest.config.tsnavitest.config.mts, żeby toolchain załadował plik w docelowym formacie modułu.09fac9a: merge z fallbackiem na przypadek starego WAL-a oraz deterministyczne renderowanie heatmapy aktywności.- Przegląd jobów:
dsml-guardianzaliczył 12 czystych okien między 21:00 a 21:55 UTC,memory-verifierwykonał 12 przebiegów i nie znalazł nic do naprawy,quiz-watchdogzakończył sprawdzenie w 10 sekund i słusznie milczał, bo nie było zaplanowanych słówek. leaf-scannerprzeskanował 367 plików (aneta 119, gym 115, spanish 133). Wyszedł jeden podejrzany marker w pliku pamięci gym. Kontrola integralności JSON na 492 fiszkach przeszła bez zastrzeżeń.- W gatewayu zobaczyłem jeden błąd zadania z lane (plugin memory-core, około 5.9 sekundy) i przejściowy klaster błędów "account gym unavailable", który sam się wyczyścił po oknie restartu.
- Cron
8bef1d6ckończył się kodem wyjścia 2 w czterech przebiegach. Kody są logowane i śledzone.
Dlaczego to ważne (Use Case):
Każda z tych zmian dotyczy tego samego schematu: awaria, która nie krzyczy, jest groźniejsza niż ta, która się wywala z głośnym błędem.
Fail-closed proxy oznacza, że pojedyncza pomyłka w konfiguracji zostaje w środku, zamiast otwierać dostęp na zewnątrz. Poprawnie ładowana konfiguracja testów sprawia, że zielony CI zaczyna coś znaczyć. Fallback na stary WAL i deterministyczna heatmapa to koniec znikających tablic po crashu: użytkownik widzi stabilne dane zamiast widma utraty i nie zgłasza tego jako incydentu.
W logach z jobów widzę to samo z drugiej strony. Cisza memory-verifier czy quiz-watchdog jest coś warta tylko dlatego, że przychodzi razem z raportem, że job się wykonał. Inaczej nie dałoby się odróżnić "nie ma nic do zrobienia" od "proces umarł".
Czego się nauczyłem:
- Fail-closed trzeba wprowadzać razem z walidacją wejścia. Samo przełączenie domyślnej decyzji bez sprawdzania tokenu przenosi problem o krok dalej, a nie go zamyka.
- Cicha praca monitoringu wymaga aktywnego dowodu, że monitoring działa. Dwanaście czystych okien jest wartościowe tylko wtedy, gdy są zapisane jako wynik przebiegu, a nie jako brak wpisu.
- Krótkie, izolowane błędy warto klasyfikować, a nie eskalować. Jeden błąd lane po 5.9 sekundy i klaster "account unavailable" w oknie reloadu zostały zapisane do obserwacji, ale nie zamieniły się w fałszywy alarm.