10 poprawek po code review — bezpieczeństwo, niezawodność i porządki w kodzie
Wersja v0.16.1 przechodzi gruntowny audyt kodu przez narzędzie app.devin.ai. W efekcie wprowadzamy 10 poprawek, które zwiększają bezpieczeństwo publicznego API, poprawiają niezawodność pipeline'u monitoringu i usuwają zaległy martwy kod. To nie są zmiany wizualne — to wzmocnienie fundamentów, na których działa cyberapis.pl.
Bezpieczeństwo
Rate limiting publicznego API
Endpoint /api/monitorings nie miał żadnego ograniczenia liczby zapytań ani walidacji parametrów. Atakujący mógł wysyłać nieograniczoną liczbę requestów i skanować dane przez dowolnie długie stringi w filtrze LIKE. Dodaliśmy throttle:60,1 (60 zapytań na minutę) oraz walidację max:255 na parametrach url i site_name. 61. request w ciągu minuty dostaje HTTP 429.
Zaufanie do proxy tylko na produkcji
trustProxies(at: '*') ufało wszystkim adresom IP jako proxy. Za Cloudflare to bezpieczne, ale gdyby aplikacja kiedykolwiek działała poza Cloudflare (staging, dev, bezpośredni dostęp po IPv6), nagłówki X-Forwarded-For mogły być sfałszowane. Ograniczyliśmy zaufanie tylko do środowiska produkcyjnego.
Autoryzacja przez Gate zamiast inline
Endpoint /monitoring/{monitoring}/status miał 10 linii logiki autoryzacyjnej bezpośrednio w closure routy — sprawdzanie właściciela, roli publicznej, locale. Ta logika trafiła do dedykowanego Gate'a view-monitoring-status w AppServiceProvider. Route skrócił się do jednej linii abort_unless(Gate::allows(...), 404). Czytelniej, testowalniej, bez rozsypanej logiki.
Niezawodność
Propagacja wyjątków z joba monitoringu
RunMonitoringCheck wywoływał Artisan::call('monitor:check-websites'), który łapał wyjątki wewnątrz komendy i zwracał exit code. Queue worker widział udany job nawet gdy monitoring się wysypał — zero retry, zero alertów. Teraz job wstrzykuje MonitoringService i MonitoringEmailService bezpośrednio, a wyjątki propagują się naturalnie do queue. Failed job = retry, logi, monitoring.
Izolacja profilu Chrome przy sprawdzaniu tekstu
findTextWithBrowsershot() używało hardcoded /tmp/chrome-browsershot jako katalogu profilu Chromium. Przy dwóch równoległych sprawdzeniach ten sam --user-data-dir powodował konflikt ("browser is already running"). Teraz każdy bieg dostaje unikalny katalog /tmp/cyberapis-browsershot-{uniqid} z pełnym cleanupem po zakończeniu — dokładnie tak samo jak render probe.
Dynamiczny SHA256 digest dla agent skills
AgentSkillsController miał hardcoded hash SHA256 pliku SKILL.md. Zmiana pliku = nieaktualny digest = klienci AI odrzucają skilla. Teraz digest jest liczony dynamicznie przez hash_file('sha256', $path) — zawsze zgodny z rzeczywistą zawartością.
Deduplikacja generacji sitemapy
Post i DocsPage wywoływały Artisan::call('sitemap:generate') synchronicznie przy każdym saved/deleted evencie. Przy masowym imporcie 100 stron — 100 osobnych przebudowań sitemapy. Nowy job RegenerateSitemap z ShouldBeUnique i 10-sekundowym delayem kolejkuje tylko jedną generację niezależnie od liczby zapisów. Kolejne dispatchowanie są ignorowane dopóki job nie zostanie przetworzony.
Czystość kodu
Usunięty duplikat trasy /
W routes/web.php istniały dwie definicje trasy / — pierwsza z anonimową funkcją, druga przez HomeController::index. Laravel używał drugiej, pierwsza była martwym kodem. Usunięta.
Pliki backupowe poza repozytorium
Sześć plików (MonitoringService.php.#1, .gemini, .przedwdrozeniem-spatie-browsershot, MonitoringResource.php.#1, Post.php.back, PostController.php.back) zalegało w katalogach app/Services/, app/Filament/Resources/, app/Models/ i app/Http/Controllers/. Usunięte z repo. Dodane wzorce *.back, *.#*, *.gemini, *.przedwdrozeniem* do .gitignore.
Usunięty martwy komponent MonitorWebsite
Livewire'owy MonitorWebsite był porzuconym prototypem — brak widoku, błędny model (MonitoringResult::first() zamiast Monitoring), sync HTTP w mount(), zero autoryzacji. Nigdy nie był nigdzie renderowany. Usunięty w całości.
Wszystkie 10 poprawek jest już na produkcji. Kolejny krok: wdrożenie rekomendacji z pełnego audytu bezpieczeństwa.