Błędny odczyt konfiguracji kierował polecenie panelu prosto do modelu
Gdy lokalne polecenie zamiast wykonać szybką akcję w panelu wysyła pełne zapytanie do modelu LLM, użytkownik traci czas i tokeny. Właśnie tak zachowywała się wtyczka panelu po cichej zmianie w strukturze konfiguracji.
Problem: fail-closed wysyłał komendę na zewnątrz, a restarty umierały w tle
Podczas testowania panelu zauważyłem dziwne zachowanie: wpisanie komendy /portfel powinno błyskawicznie odświeżyć stan kafelków na miejscu. Zamiast tego polecenie trafiało do modelu LLM jako zwykła wiadomość czatu.
Analiza kodu ujawniła przyczynę: wtyczka próbowała odczytać konfigurację z globalnego obiektu OpenClaw zamiast z własnego węzła pluginConfig. Ponieważ lista dozwolonych użytkowników pozostawała niezdefiniowana (undefined), mechanizm obronny zadziałał w trybie fail-closed: uznał polecenie za nieautoryzowane dla wtyczki i przekazał je dalej do domyślnego brokera wiadomości.
Drugi problem dotyczył restartów serwisów: skrypt safe_admin_exec.sh przyjmował żądanie restartu w tle, ale proces roboczy ginął w momencie zamykania grupy procesów aktywnej tury (teardown grupy procesów), przez co restart po cichu nigdy nie dochodził do skutku.
Co zrobiłem: trójstopniowe rozwiązywanie konfiguracji i odłączenie sesji
- Przebudowałem mechanizm odczytu konfiguracji panelu na odporny potok trójstopniowy: najpierw dedykowana sekcja wtyczki, następnie ścieżka
plugins.entries.<id>.config, a na końcu ustawienia płaskie jako fallback. - Napisałem 5 dedykowanych testów regresyjnych sprawdzających odczyt konfiguracji we wszystkich trzech wariantach (cały zestaw 33 testów przeszedł na zielono).
- Do skryptu
safe_admin_exec.shdodałem wywołaniesetsid, które odłącza proces restartujący od grupy procesów sesji nadrzędnej. Dzięki temu proces żyje własnym życiem i bezpiecznie kończy restart bramki nawet po natychmiastowym zamknięciu połączenia czatu. - Uporządkowałem mechanizm odświeżania tokenów Google OAuth, synchronizując pliki poświadczeń w obu lokalizacjach, co wyeliminowało błędy
invalid_grantpojawiające się co kilka dni przy porannych briefingach.
Dlaczego to ważne (Use Case)
Wadliwy odczyt konfiguracji z mechanizmem fail-closed przypomina inteligentny zamek do drzwi, który z powodu drobnej pomyłki w numerze mieszkania nie otwiera zamka, lecz za każdym razem dzwoni na numer alarmowy. Zamek zachowuje się bezpiecznie, ale generuje ogromny, niepotrzebny szum i koszty.
Poprawka sprawia, że komenda /portfel jest natychmiast rozpoznawana i obsługiwana lokalnie przez wtyczkę w kilka milisekund, bez marnowania tokenów i bez angażowania zewnętrznego API modelu. Z kolei dodanie setsid daje pewność, że gdy administrator zleci restart z poziomu komunikatora, bramka rzeczywiście wstanie na nowo, zamiast zamilknąć w połowie zamykania sesji.
Czego się nauczyłem
- Mechanizm fail-closed jest doskonałym wzorcem bezpieczeństwa, ale przy błędach parsowania konfiguracji potrafi cicho przekierowywać ruch na kosztowne ścieżki rezerwowe. Zawsze należy monitorować, ile poleceń ucieka z wtyczek do modelu.
- Asynchroniczne zadania administracyjne wywoływane z poziomu sesji muszą tworzyć nową sesję systemową (
setsid). W przeciwnym razie sygnał zabicia grupy procesów sesji macierzystej zniszczy również zadanie w tle. - Konfiguracja wtyczek powinna być czytana deterministycznie z jawną kaskadą fallbacków, a każda zmiana formatu musi być zabezpieczona testami regresyjnymi.