apex-advisory / upkeep-agent
Agent za Upkeep — šalje činjenice o sajtu centralnoj aplikaciji za održavanje.
Requires
- php: ^8.1
- ext-curl: *
- ext-json: *
- illuminate/console: ^9.0|^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^9.6|^10.5|^11.0|^12.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Agent za Upkeep. Instalira se na klijentski Laravel sajt i šalje činjenice o njegovom stanju centralnoj aplikaciji.
Instalacija
Na hubu izdaj kod:
php artisan agent:code
Na klijentskom sajtu:
composer require apex-advisory/upkeep-agent
php artisan upkeep:install --hub=https://hub.apex-advisory.me --claim=UPKEEP-XXXX-XXXX
To je sve. Komanda upisuje ključeve u .env (uz snimak .env.upkeep.bak), prijavljuje
sajt, pošalje probni potpisan izvještaj i pokrene dijagnostiku.
Raspored se registruje sam, iz booted() hooka service providera. Ne diraj
Kernel.php ni routes/console.php — radi identično od Laravela 9 do 13.
Ako sajt još nema cron, upkeep:doctor ispiše tačan red za copy-paste.
Komande
| Komanda | Šta radi |
|---|---|
upkeep:install | prijava sajta i podešavanje |
upkeep:report | šalje izvještaj (--dry ispiše bez slanja, --deep uključi skupe provjere) |
upkeep:doctor | provjerava sve i kaže šta je pokvareno |
Šta agent šalje
Verzije PHP-a i Laravela, SAPI, deployed commit (čitanjem .git/HEAD, ne kroz git),
veličinu baze i pet najvećih tabela, broj migracija u redu, neuspjele poslove i zaostatak
u redu, slobodan disk, otkucaj crona, brojače grešaka iz loga, sanity provjere okruženja,
i spisak paketa iz composer.lock kao parove ime+verzija.
Uz --deep (podrazumijevano na svakih 6h) dodaje obilazak storage/app i sonde
web-izloženosti.
Šta agent NIKAD ne šalje
- Cijeli
composer.lock— sadrži URL-ove privatnih repoa i nagovještaje autentifikacije. Šalju se samo parovi ime+verzija. - Pune stack traceove — redovno sadrže tokene, mejlove i vezivanja upita. Šalju se
potpisi grešaka i, samo ako se eksplicitno uključi
UPKEEP_LOG_SAMPLES=true, skraćene poruke. - Kredencijale baze,
APP_KEY, sadržaj.env-a.
Načela
- Agent šalje činjenice, hub drži mišljenja. Nigdje u ovom paketu nema EOL tabele, praga ni uparivanja CVE-ova. Sve to je na hubu, jer se mijenja — a novu EOL tabelu ne možeš progurati na 40 sajtova svaki put kad Laravel izda verziju. Zato se tanak prenosilac činjenica rijetko i mijenja.
- Goli cURL, bez Guzzlea i bez
Httpfasade. Guzzle pravi sukobe verzija kroz šest Laravel majora, aHttpfasada ne postoji prije Laravela 7. composer.lockse čita kao fajl. Shared hosting rijetko imacomposerna PATH-u, acomposer audittraži Composer 2.4+ — što stari sajtovi nemaju. Zato CVE uparivanje radi hub, pa dobijaš audit i tamo gdje Composer ne možeš ni pokrenuti.- Nikad
file_get_contentsnad logom.laravel.logod dva gigabajta nije rijetkost. Čita se samo rep, sa tvrdim budžetom vremena. - Neuspio push ne obara scheduler. Izvještaj ide u lokalni red i šalje se uz sljedeći uspješan, pa ispad huba ne pravi rupu u podacima.
- Agent se NIKAD ne ažurira sam. Kod koji sam sebe mijenja je botnet C2 i jedinstvena tačka kompromisa kroz cijeli portfelj. Ponašanje se mijenja kroz konfiguraciju koju hub vraća u odgovoru na push — samo allowlistovani ključevi, nikad putanje ni komande.
Potpis
Isti u oba smjera. Kanonski string:
v1\n{METOD}\n{HOST}\n{PUTANJA}\n{VRIJEME}\n{NONCE}\n{SHA256_TIJELA}
Potpisuje se heš tijela, ne tijelo: string ostaje ograničen bez obzira na veličinu payloada. Metod, host i putanja su uvezani, pa presretnut zahtjev ne može da se ponovi ni na drugom endpointu ni za drugi sajt.
Prozor je 300 sekundi, namjerno velikodušan — shared hostovi imaju stvarno loše satove.
Odstupanje se umjesto toga mjeri i prijavljuje (upkeep:doctor ga ispisuje u sekundama).
Pull endpoint (/_upkeep/{token}/report) vraća 404 na nepotpisan zahtjev, nikad 401 —
nikad ne potvrđuj da endpoint postoji. Payload je gotova lista meta za napadača.
Ista logika potpisa postoji i u hubu. Ne mogu da dijele kod, pa obje strane provjeravaju
isti fiksni vektor u SignerVectorTest — ako neko promijeni kanonski string na jednoj
strani, pukne test, a ne 40 sajtova u produkciji.
Shared hosting
Radi, ali jedna stvar se mora podesiti.
Cron na shared hostingu je često ograničen. HostGator, na primjer, dozvoljava cron najviše svakih 15 minuta. Ako agent misli da javlja svakih 5 minuta a stvarno javlja svakih 15, hub bi ga trajno vidio kao „ćuti".
Zato interval nije pretpostavka nego podatak: agent ga javlja u izvještaju, a hub iz njega izvodi prag za tišinu (tri puta interval, minimum 15 minuta).
php artisan upkeep:install --hub=… --claim=… --interval=900
Cron red tada:
*/15 * * * * cd /home/korisnik/sajt && php artisan schedule:run >/dev/null 2>&1
upkeep:doctor ispisuje koji je backup motor stvarno dostupan — na shared
hostingu mysqldump i proc_open često nisu, pa se ide na čist PHP dumper.
Podrška po verzijama
Laravel 9–13, PHP 8.1+.
Za starije sajtove (Laravel 5.8–8) ovaj paket se namjerno ne koristi: composer require
bi na njima povukao razrješavanje sukoba kroz Guzzle 6 i Symfony 4 na sajtu koji se niko
ne usuđuje da dira. Za njih je predviđen zaseban jednofajlni drop-in.
Testovi
composer install
vendor/bin/phpunit