"""Zapora słownikowa: czego konto NIE MOŻE zobaczyć w żadnej swojej odpowiedzi. Poprzednie testy pilnowały pojedynczych miejsc — tego przycisku, tamtego bloku. Wyciek prawie nigdy nie siedzi w miejscu, o którym się pamięta: katalog modeli jechał blokiem JSON, nazwy ekranów komentarzem w arkuszu stylów, mechanizm kwarantanny zdaniem po polsku w komentarzu CSS, a nazwa gałęzi rozwojowej w komunikacie o błędzie. Wspólne mają jedno — pewne SŁOWA nie mają prawa paść. Więc test nie sprawdza miejsc, tylko przechodzi WSZYSTKO, co dane konto może pobrać (strony i zasoby), i szuka słów zakazanych. Nowy ekran, nowy skrypt, nowy komunikat wchodzą pod tę samą zaporę bez dopisywania czegokolwiek. Dwie z trzech list biorą się wprost z katalogu funkcji, więc nie rozjadą się z programem: dopisanie funkcji automatycznie dopisuje jej nazwę i jej adres do tego, czego konto bez niej nie ma prawa zobaczyć. """ import re import pytest from app import accounts as store from app import features # ── persona ────────────────────────────────────────────────────────────── # Osoba zatrudniona wyłącznie do wgrywania plików. Ma widzieć swój ekran i nic # poza nim — ani co program robi, ani co będzie robił, ani że ktoś widzi więcej. WGRYWACZ = ["files", "files_input"] # ── słowa zakazane, których NIE DA SIĘ wyprowadzić z katalogu ──────────── # Katalog zna nazwy funkcji, ale nie zna dziedziny programu ani słownictwa jego # mechanizmów. Te trzeba wypisać, i każde ma tu swój powód. DZIEDZINA = [ # (c) po co są wgrywane pliki "astrolog", "horoskop", "kosmogram", "zodiak", "efemeryd", "sygnifikator", "interpretacyjn", "aspektarian", "antyscj", "deklinacj", # „baza" mówi, że to nie są zwykłe pliki, tylko zbiory czegoś. Na ekranie # wgrywającego wszystko nazywa się plikiem; w częściach administracyjnych # słowo zostaje, bo tam jest właściwe (i tam ten test nie zagląda). "baz", # (b) że tekst pisze model językowy i u kogo "LLM", "anthropic", "openai", "gpt", "claude", "prompt", "token", # (e)/(f) mechanizmy i to, że istnieje ktoś, kto widzi więcej "administrator", "uprawnieni", "walidacj", "kwarantann", "wstrzyman", "zatwierdzi", "przypisan", "zakłada", "zakładał", # „konto" w obu przypadkach: pierwsza wersja listy miała samo „konto", # więc przepuszczała zdanie „Nie masz konta" — literówka, która kosztowałaby # cały sens testu, gdyby nie wyszła przy oglądaniu strony. "konto", "konta", "kontem", # (d) że produkt jest w budowie i ma ponumerowany backlog "roadmap", "przyszł", "planowan", "w budowie", "widok testowy", # topologia: gdzie pukać, żeby ominąć logowanie "warstwa logiczna", "warstwie logicznej", "openapi", "swagger", # architektura: „to jedna z warstw" mówi, że warstw jest więcej "layer", "presentation", "prezentacj", "localhost", "http://logic", "8001", "8002", "8003", ] WZORCE = [ (r"(?i)\b(PRE|LOG|DAN)-\d+\b", "identyfikator wymagania (ujawnia backlog)"), (r"(?i)\bfeat/[\w-]+", "nazwa gałęzi rozwojowej"), (r"(?i)\bmodel(u|em|e|i|ach|owi)?\b", "generowanie tekstu przez model"), (r"(?i)\bAI\b", "generowanie tekstu przez model"), ] def _zakazane_dla(perms: set[str]) -> list[tuple[str, str]]: """(igła, powód) — wyprowadzone z katalogu plus lista dziedzinowa.""" out = [(s, "słownik dziedziny/mechanizmu") for s in DZIEDZINA] for f in features.ALL: if f.key in perms: continue out.append((f.label, f"nazwa funkcji, której to konto nie ma ({f.key})")) if f.href and f.href != "/": out.append((f.href, f"adres ekranu, którego to konto nie ma ({f.key})")) # Nazwa zasobu też jest wyciekiem: `