PRE-27: generowanie tekstu przez model znika bez uprawnienia
Testy / Testy warstwy logicznej (silnik) (pull_request) Successful in 10m20s
Testy / Testy warstwy prezentacji (dostęp do baz) (pull_request) Successful in 9m29s
Testy / Testy warstwy bazodanowej (ochrona baz) (pull_request) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (pull_request) Successful in 5s
Testy / Kontrola składni wszystkich warstw (pull_request) Successful in 5s
build / build (push) Successful in 1m39s
Testy / Testy warstwy logicznej (silnik) (push) Failing after 4m45s
Testy / Testy warstwy prezentacji (dostęp do baz) (push) Successful in 9m32s
Testy / Testy warstwy bazodanowej (ochrona baz) (push) Successful in 9m25s
Testy / Build obrazu silnika B (swisseph) (push) Successful in 7s
Testy / Kontrola składni wszystkich warstw (push) Successful in 6s

Wymaganie było mocniejsze niż schowanie przycisku: po niedostępnej funkcji nie
może zostać śladu w źródle strony. Największy wyciek nie był przyciskiem —
_prompt_block wstrzykiwał w stronę CAŁY katalog modeli jako JSON (dostawcy,
nazwy modeli, rozmiary okien kontekstu), na każdym ekranie z generowaniem,
niezależnie od uprawnień konta.

Druga dziura była głębsza: handlery nie sprawdzały nic. Trasa /interpret musi
być dostępna dla konta z Interpretacjami, więc granica przebiega WEWNĄTRZ niej,
po polu `action` — spreparowany formularz z action=prompt generował tekst, a
action=export pobierał arkusz, mimo że szablon chował oba przyciski.

Akcja bez uprawnienia wraca do akcji domyślnej ekranu zamiast dawać błąd:
komunikat „brak uprawnień do generowania" sam w sobie mówiłby, że taka funkcja
istnieje.

Ślady wycięte także tam, gdzie nie były kontrolką: znaczniki natalNote/
reportNatal, pliki models.js/progress.js/natal.js/predictions.js oraz podtytuł
ekranu Skompiluj, który wymieniał interpretację od AI z nazwy.

12 testów; 9 z nich pada na kodzie sprzed poprawki (sprawdzone przez cofnięcie
zmian w app/). Kontrola pozytywna pilnuje, żeby nie przechodziły dlatego, że
generowanie jest zepsute dla wszystkich.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit was merged in pull request #77.
This commit is contained in:
2026-08-21 13:10:16 +02:00
parent f0d07ee8c3
commit 1d0ff2f72e
6 changed files with 243 additions and 8 deletions
+29
View File
@@ -64,6 +64,35 @@ jest niewidoczna do chwili, gdy ktoś ją znajdzie. Trasa bez wpisu w mapie wyma
uprawnień administracyjnych: **przeoczenie ma zamykać, nie otwierać**. Test
przechodzi po wszystkich trasach aplikacji i wymaga, by każda była opisana.
### Gdy jedna trasa robi kilka rzeczy
Mapa tras nie wystarcza tam, gdzie jedna trasa obsługuje kilka funkcji naraz.
`POST /interpret` liczy horoskop, ale to samo pole `action` prosi o wygenerowanie
promptu, napisanie horoskopu przez model albo eksport arkusza. Konto, które ma
mieć Interpretacje bez generowania, musi dostać tę trasę — więc granica przebiega
wewnątrz niej, po akcjach: `_AKCJE_POD_UPRAWNIENIEM` przypisuje akcji uprawnienie,
a `_dozwolona_akcja()` sprowadza żądanie bez uprawnienia do akcji domyślnej ekranu.
Sprowadza — nie odrzuca. Komunikat „brak uprawnień do generowania" sam w sobie
mówiłby, że taka funkcja istnieje, czyli łamałby zasadę drugą po to, żeby
wyegzekwować pierwszą. Akcja bez uprawnienia ma wyglądać na literówkę w formularzu.
### Ślad to nie tylko przycisk
Wymaganie brzmi „nie może być śladu", i to jest mocniejsze niż schowanie kontrolki.
Największym wyciekiem po stronie generowania nie był przycisk, tylko **katalog
modeli** — nazwy dostawców, nazwy modeli i rozmiary okien kontekstu — wstrzykiwany
w stronę blokiem JSON na każdym ekranie z generowaniem, niezależnie od uprawnień.
Dlatego `_llm_catalog_for()` oddaje pusty katalog kontu bez uprawnienia, a szablony
trzymają pod bramką także znaczniki (`natalNote`, `reportNatal`), pliki skryptów
(`models.js`, `progress.js`, `natal.js`, `predictions.js`) i **zdania opisujące
funkcję** — podtytuł ekranu Skompiluj wymieniał interpretację od AI z nazwy.
Testu na to nie da się napisać przez „sprawdź, czy przycisku nie ma": trzeba
sprawdzić, że w źródle strony nie ma żadnego z tych śladów, i mieć kontrolę
pozytywną, że przy uprawnieniu wszystkie są. Inaczej test przechodzi także wtedy,
gdy generowanie jest zepsute dla wszystkich.
## Gdzie leżą konta
Plik JSON wskazany przez `ACCOUNTS_FILE` (domyślnie `/app/state/accounts.json`),