Audyt Jakości Specyfikacji: Browser-VPN SaaS
Data audytu: 2026-07-22
Obiekt: docs/superpowers/specs/2026-07-22-browser-vpn-product-design.md (738 linii, 15 sekcji)
Cel biznesowy: przekształcenie bash-owego PoC (Docker + WireGuard + przeglądarka + tunnel Cloudflare) w hostowany produkt SaaS dla użytkowników ceniących „total privacy", płatność krypto przez Trocador.
1. Wprowadzenie
Niniejszy raport ocenia jakość i gotowość implementacyjną specyfikacji produktowej przed wejściem w fazę deweloperską. Audyt nie ocenia samej koncepcji produktu, lecz sprawdzalność dokumentu jako bazy pod implementację: kompletność, spójność, mierzalność kryteriów, wykonalność techniczną oraz pokrycie zagadnień bezpieczeństwa i operacyjnych.
Zakres audytu:
- Analiza strukturalna 15 sekcji specyfikacji.
- Porównanie specyfikacji z istniejącym PoC (
README.mdrepozytoriumbrowser-vpn-deploy). - Weryfikacja zewnętrznych zależności (linki HTTP, dostępność API, dokumentacja).
- Identyfikacja luk blokujących (P0), znaczących (P1) i drobnych (P2).
- Konkretne rekomendacje naprawcze oraz rozwiązania otwartych pytań (sekcja 15).
Kontekst decyzyjny: produkt celuje w segment „total privacy" — czyli audytor właśnie tej kohorty (najbardziej wyczulonej na błędy bezpieczeństwa) ocenia dokument. Błędy bezpieczeństwa są tu błędami biznesowymi, nie technicznymi niuansami.
2. Podsumowanie wykonawcze i ocena ogólna
Specyfikacja jest solidnym, dobrze zorganizowanym draftem koncepcyjnym, ale niegotowym do bezpośredniej implementacji. Silna struktura, uczciwe sekcje ograniczeń i ryzyk, rozsądny model danych. Jednocześnie dokument zawiera kilkanaście luk, z czego pięć to blokery (P0) wymagające rozwiązania przed rozpoczęciem kodowania.
Scorecard — ocena wg wymiarów (skala 1-10)
| Wymiar | Ocena | Komentarz |
|---|---|---|
| Struktura i czytelność | 9/10 | 15 logicznych sekcji, spójna numeracja, dobre tabele |
| Kompletność funkcjonalna | 7/10 | Pokrywa flow zakupu, sesji, wsparcia, rozliczeń |
| Kompletność bezpieczeństwa | 5/10 | Szeroki zakres, ale kluczowe luki (XSS, capabilities, CSP) |
| Mierzalność kryteriów | 6/10 | Progi 80%/50 instancji OK, ale brak SLO/SLA, brak metryk jakości |
| Wykonalność techniczna | 5/10 | Rozbieżność PoC↔Spec, brak WebSocket, brak limitów zasobów |
| Gotowość do implementacji | 5/10 | 5 blokerów + 5 otwartych pytań = potrzeba iteracji |
| Zarządzanie ryzykiem | 7/10 | Tabela ryzyk z mitigacjami, sekcja Conscious Limitations |
| Ocena ogólna | 6.3/10 | Solidny Draft — wymaga poprawek P0 przed dev |
Werdykt: Approve with mandatory revisions — dokument zatwierdzić warunkowo, pod warunkiem rozwiązania 5 blokerów P0 i 5 otwartych pytań (sekcja 15) w rewizji v2 specyfikacji.
3. Mocne strony specyfikacji
Wymienienie mocnych stron jest ważne — to baza, której nie trzeba przebudowywać:
- Jasne wyznaczenie zakresu (sekcja 1.4 Out of Scope) — precyzyjne wylistowanie tego, czego MVP nie robi (konta, refundy, Stripe, i18n, multi-server). To rzadka dobra praktyka w draftach.
- Uczciwa sekcja Conscious Limitations (14.1) — każda decyzja ograniczająca ma podany powód. Świadczy o dojrzałości produktowej autora.
- Tabela ryzyk z mitigacjami (14.2) — 5 ryzyk z konkretnymi działaniami zaradczymi, w tym „utrata order number = brak odzyskania by design" (świadomy tradeoff za anonimowość).
- Rozsądny model danych (sekcja 6) — 7 tabel, odpowiednie typy, nullable oznaczone, FK wskazane.
system_logsz JSONB metadata to dobra elastyczność. - Dobrze zdefiniowane API (sekcja 7.2) — podział public/admin, sensowne endpointy,
/api/healthobecne. - Scheduler jobs z częstotliwościami (7.3) — konkretne interwały (1 min, 30 s, 5 min, daily), nie abstrakcyjne „periodically".
- Monitoring i alerting dopracowane (sekcja 11) — metryki co 30 s, zewnętrzne health-check, 11 warunków alertów Telegram.
- Sekcja Open Questions (15) — autor sam wskazuje 5 punktów do rozstrzygnięcia. Świadomość next steps.
- Plan backup i migracji między serwerami (12.5) — konkretny rsync + restore.sh, nie tylko obietnica.
- Fast domain switching przez njalla (12.6) — pragmatyczne dla scenariusza privacy (przepięcie domeny).
4. Krytyczne luki — P0 (blokery implementacyjne)
Pięć problemów, które muszą zostać rozwiązane w rewizji specyfikacji przed startem kodowania. Każde z nich może zablokować działanie produktu lub naruszyć obietnicę „total privacy".
P0-1: Trocador — pojedynczy punkt awarii (SPoF) płatności
Stan weryfikacji: https://trocador.app/ zwraca HTTP 503 w dniu audytu (2026-07-22). Endpoint płatności jest niedostępny.
Problem: Cały model monetyzacji MVP opiera się na jednym zewnętrznym serwisie (Trocador AnonPay). Sekcja 3.1 zakłada webhooki + polling co 60 s jako fallback, ale to tylko obsługa przypadku „Trocador wolny", a nie „Trocador nie działa". Polling niedziałającego API nie przywraca płatności.
Wpływ biznesowy: produkt „sellable" nie może sprzedawać, gdy Trocador jest down. Dla kohorty privacy (anonimowi, jednorazowi klienci) — klient, który trafi na niedziałający przycisk płatności, nie wraca.
Rekomendacja:
- Dodać drugiego dostawcę płatności jako fallback (np. BTCPay Server self-hosted — privacy-friendly, brak zewnętrznego SPoF).
- Zdefiniować automatyczny failover: jeśli Trocador API zwraca błędy >2 min, przełączyć na BTCPay.
- Ująć to w sekcji 5 (Settlement Flow) i 14.2 (Risks).
P0-2: Brak proxy WebSocket w Caddy — streaming Selkies nie zadziała
Problem: Produkt streamuje przeglądarkę z kontenera do użytkownika. PoC (README.md) używa Selkies-GStreamer do współdzielenia ekranu. Selkies wymaga połączenia WebSocket do przesyłania strumienia i zdarzeń wejścia.
Sekcja 9 (Reverse Proxy) definiuje reverse_proxy do kontenera, ale nie wspomina o nagłówkach Upgrade i Connection wymaganych do WebSocket. Bez tego Caddy proxy'uje ruch HTTP, ale handshake WebSocket (HTTP 101 Switching Protocols) nie przejdzie — obraz się nie załaduje.
Wpływ: fundamentalna funkcjonalność produktu (streaming przeglądarki) jest nieopisana na poziomie proxy. To najpewniej pierwszy bug po wdrożeniu.
Rekomendacja: dodać do sekcji 9.3 jawną regułę:
# Caddy — proxy z obsługą WebSocket
reverse_proxy localhost:<port> {
header_up Host {host}
header_up Upgrade {http.upgrade}
header_up Connection {http.connection}
}
Caddy automatycznie obsługuje WebSocket w reverse_proxy, ale specyfikacja musi to jawnie zadeklarować jako wymaganie, aby implementator nie pominął konfiguracji.
P0-3: Nadmierne uprawnienia kontenera — SYS_ADMIN to de facto root hosta
Problem: Sekcja 10.1 przyznaje kontenerom NET_ADMIN i SYS_ADMIN dla WireGuard/Selkies. SYS_ADMIN to jedna z najszerszych capabilities w Linuksie — pozwala m.in. na manipulację namespace'ami, mountowanie systemów plików, operacje na cgroups. Kontener z SYS_ADMIN jest bliski rootowi na hoście.
Wpływ bezpieczeństwa: w architekturze multi-tenant (do 50 kontenerów jednocześnie, sekcja 3.2) przejęcie jednego kontenera może prowadzić do eskalacji na hosta i kompromitacji wszystkich pozostałych sesji. Dla produktu „total privacy" to katastrofalne.
Rekomendacja: minimalizować capabilities:
- WireGuard potrzebuje
NET_ADMIN+ dostęp do/dev/net/tun. - Selkies-GStreamer potrzebuje
SYS_PTRACE(nieSYS_ADMIN), ewentualnieSYS_RAWIOtylko gdy wymagane. - Dodać
--security-opt=no-new-privileges:true. - Dodać
--cap-drop=ALLi dodawać tylko potrzebne caps explicite. - Rozważyć
--userns-remapdla mapowania UID kontenera na nieuprzywilejowanego na hoście.
Zaktualizować sekcję 10.1 o minimalny zestaw capabilities i uzasadnienie per capability.
P0-4: deviceToken w localStorage — podatność XSS obchodzi wiązanie urządzenia
Problem: Sekcja 3.3 pkt 8 i 10.2 pkt 2: „deviceToken stored in httpOnly cookie and localStorage". To błąd bezpieczeństwa. httpOnly cookie chroni token przed odczytem przez JavaScript, ale localStorage jest pełnodostępny dla każdego skryptu na stronie, w tym złośliwego (XSS).
Jeśli atakujący wstrzyknie JavaScript (np. przez złośliwą stronę załadowaną w streamowanej przeglądarce, która dotyka session page), może odczytać deviceToken z localStorage i ukraść sesję — paradoksalnie omijając właśnie httpOnly cookie, które miało chronić.
Wpływ: obietnica „only the bound device can return" (sekcja 1.3 pkt 9) zostaje złamana przy jakimkolwiek XSS. Dla produktu privacy to bezpośrednie złamanie obietnicy produktu.
Rekomendacja:
- Usunąć localStorage jako magazyn
deviceToken. - Użyć wyłącznie cookie z flagami:
HttpOnly; Secure; SameSite=Strict; Path=/session. SameSite=Strictzapobiega CSRF i wyciekom cross-site.- Dodatkowo: dla wiązania urządzenia rozważyć fingerprint po stronie serwera (User-Agent + IP hash), nie tylko token — aby kradzież tokena nie wystarczyła.
P0-5: Brak limitów zasobów per kontener — ryzyko DoS i OOM hosta
Problem: Sekcja 3.2 definiuje progi na poziomie hosta (CPU <80%, RAM <80%, 50 kontenerów) — to limity admission control. Ale brak limitów per kontener (--cpus, --memory, --pids-limit). Jeden uciekający proces wewnątrz jednej sesji (np. przeglądarka z wyciekiem pamięci, pętla otwierających się tabów) może zjeść RAM hosta i ubić wszystkie 50 sesji.
Wpływ: multi-tenant bez izolacji zasobów = jeden klient może (nawet nieumyślnie) zdestabilizować usługę dla wszystkich. Przy 50 kontenerach Chrome na jednym VPS ryzyko OOM jest realne (Chrome bywa po 1-2 GB na sesję).
Rekomendacja: dodać do sekcji 10.1 i 12.2:
--memory=1g(lub2g) per kontener — hard limit.--memory-swap=1g— blokada swap, zapobiega eksplozji na dysk.--cpus=1.0— limit CPU.--pids-limit=200— blokada fork-bomb.--restart=unless-stoppedz limitem--restart-policymax 3.- Zdefiniować wymiary w sekcji 12.4 jako zmienne środowiskowe (
CONTAINER_MEM_LIMIT,CONTAINER_CPU_LIMIT).
5. Luki znaczące — P1 (wymagają naprawy przed produkcją)
Problemy poważne, ale nie blokujące startu MVP — należy je rozwiązać przed wdrożeniem produkcyjnym.
Tabela P1
| ID | Problem | Sekcja | Wpływ | Rekomendacja |
|---|---|---|---|---|
| P1-1 | Brak CSP (Content Security Policy) | 10 | Produkt „total privacy" bez CSP jest rażącym pominięciem; XSS możliwy | Dodać Content-Security-Policy w Caddy: default-src 'self'; connect-src 'self' ws: wss:; img-src 'self' blob: data:; |
| P1-2 | Brak monitorowania health kontenera w trakcie sesji | 11 | Mierzony tylko startup time; martwa sesja nie wykrywana | Dodać heartbeat co 30 s: brak ruchu >5 min = alert + auto-restart/stop |
| P1-3 | Brak timeout bezczynności sesji | 3.3 | Sesja może wisieć pełny czas bez aktywności, marnując zasoby | Dodać idle_timeout (np. 30 min) osobno od expires_at |
| P1-4 | Brak skanowania podatności obrazów Docker | 10.6 | „Automated rebuilds weekly" bez skanowania = mogą wchodzić CVE | Dodać Trivy/Grype w CI przed wdrożeniem obrazu |
| P1-5 | Magic link bez rate-limit na POST /api/orders | 7.2 | Brak ograniczeń tworzenia zamówień = spam/abuse | Dodać rate-limit per IP (np. 5 zamówień/h) na tworzenie order |
| P1-6 | Admin „password-protected, optional TOTP" | 10.4 | Hasło-only dla panelu z dostępem do wszystkich sesji = za mało | TOTP obowiązkowe dla MVP (nie optional), + logowanie prób |
| P1-7 | Brak HSTS i nagłówków bezpieczeństwa | 9 | Privacy produkt bez HSTS = mitm przy pierwszej wizycie | Dodać Strict-Transport-Security: max-age=31536000; includeSubDomains; preload |
| P1-8 | Backup lokalny 7 dni, brak off-site | 11.5 | Utrata serwera = utrata wszystkiego (orders, configs) | „Optional future: S3/B2" → podnieść do MVP (encrypted, off-site) |
| P1-9 | Brak definicji zachowania przy padzie hosta | 3, 12 | Sesje active po restarcie serwera: status? | Dodać: restart hosta = kontenery oznaczane interrupted, użytkownik widzi info, restart manualny |
| P1-10 | wg-configs/ backup plain | 11.5 | Kopia konfigów WireGuard w plaintext = kompromitacja VPN | Szyfrować backup (gpg/age), klucz poza serwerem |
6. Luki drobne — P2 (usprawnienia)
Te pozycje nie blokują, ale podniosą jakość:
- Niespójność nazewnictwa browser: sekcja 1.3 wymienia „Mullvad" jako browser, sekcja 2.1 pkt 4 i 6.1 wymienia
mullvad-browser. PoC README (config.yml) też używamullvad. Ujednolicić namullvad. - Brak wersjiowania API: endpointy bez prefiksu wersji (
/api/v1/). Dodać/api/v1/dla przyszłych zmian niezaburzających klientów. order_numberformatord-XXXXXX-XXXXXX: brak definicji źródła losowości i kolizji. Dodać: kryptograficzny RNG + unique constraint (już jest w 6.1) + retry przy kolizji.- Sekcja 4.3 „X minutes": niedoprecyzowane. Sekcja 11.3 podaje „5 minut" — ujednolicić wartość w jednej zmiennej konfiguracyjnej
CONTAINER_START_TIMEOUT. - Brak definicji
fiat_equivvsamount: sekcja 3.1 pkt 4 daje alternatywę „amount in XMR or fiat_equiv=USD". Nie określono, który jest preferowany i jak API reaguje na oba. Wybrać jeden (fiat_equiv z konwersją przez Trocador). - Brak GDPR/data-retention polityki: choć „no personal data", są logi i tickety. Dodać retencję: system_logs 7 dni (już jest), tickety 90 dni, metryki 30 dni.
- Brak definicji limits na attachment w ticketach: sekcja 4.1 „optional attachment" — brak typu/rozmiaru. Dodać max 5 MB, typy obraz/pdf.
server_metricsbez retencji: metryki co 30 s rosną szybko. Dodać partycjonowanie/agregację (np. surowe 24h, potem co 5 min agregowane).- Brak health-check endpointu kontenera: sekcja 11.2 sprawdza VPN endpoints, ale nie health samej przeglądarki w kontenerze. Dodać
/healthzw obrazie.
7. Macierz porównawcza: PoC vs Specyfikacja vs Wymagania Produkcyjne
To kluczowa analiza — pokazuje dystans między obecnym stanem (PoC), zaplanowanym (Spec) i wymaganym (Produkcja).
| Kryterium | PoC (bash, README) | Specyfikacja MVP | Wymagania Produkcyjne | Luk Spec↔Prod |
|---|---|---|---|---|
| Architektura dostępu | Cloudflare Tunnel (trycloudflare) | Caddy, direct domain, no Cloudflare | Direct + opcjonalnie CDN privacy | Decyzja arch. potrzebna |
| Płatności | Brak | Trocador (krypto) | Trocador + fallback (BTCPay) | P0-1 — brak fallback |
| Izolacja sieci | Tunnel CF + WireGuard | WireGuard per kontener | WireGuard + egress filtering + DNS isolation | Częściowo |
| Session binding | Brak | Magic link + deviceToken (cookie+localStorage) | httpOnly+Secure+SameSite cookie, fp serwer | P0-4 — localStorage |
| Capabilities kontenera | Nieokreślone (PoC) | NET_ADMIN + SYS_ADMIN | NET_ADMIN + SYS_PTRACE + no-new-privileges | P0-3 — SYS_ADMIN |
| Limity zasobów | Brak | Brak (tylko admission host) | memory/cpu/pids per kontener | P0-5 — brak limitów |
| Proxy streaming | Cloudflare Tunnel (WS OK) | Caddy reverse_proxy, brak WS | Caddy + WebSocket explicite | P0-2 — brak WS |
| Bezpieczeństwo nagłówki | N/A (tunnel) | Brak CSP/HSTS | CSP + HSTS + X-Frame-Options | P1-1, P1-7 |
| Monitoring | Brak | Metryki + 11 alertów Telegram | + Grafana, health kontenera w sesji | P1-2 |
| Backup | N/A | Lokalny 7 dni | Lokalny + off-site szyfrowany | P1-8, P1-10 |
| Admin auth | N/A | Hasło + optional TOTP | Hasło + obowiązkowe TOTP + logi | P1-6 |
| Rate-limiting | N/A | Brak | Per-IP na orders/webhook | P1-5 |
Wniosek z macierzy: specyfikacja pokrywa ~60% wymagań produkcyjnych. Największe luki koncentrują się w bezpieczeństwie operacyjnym (capabilities, limity, cookie) — dokładnie w obszarze, który dla „total privacy" jest krytyczny.
8. Rozbieżność architektoniczna PoC ↔ Specyfikacja
Najpoważniejsza obserwacja strukturalna: PoC i Specyfikacja opisują dwie różne architektury dostępu.
- PoC (
README.md): każda instancja przeglądarki ma własny tunnel Cloudflare (trycloudflare.com). Użytkownik dostaje URL z tunnel. Współdzielenie ekranu przez Selkies. Cloudflare terminuje TLS i proxy'uje ruch (w tym WebSocket) do kontenera. - Specyfikacja (sekcja 2.1 pkt 7, 9, 1.4): Caddy jako reverse proxy na własnej domenie,
/:sessionId→ dynamiczny proxy do kontenera. Wyraźnie wykluczone: „Cloudflare Tunnel or any indirect tunneling — direct domain access only" (1.4).
Konsekwencje:
- Implementacja nie jest ewolucją PoC, lecz jego przebudową. Tunnel Cloudflare w PoC rozwiązuje automatycznie: TLS, WebSocket, ukrywanie IP hosta, DDoS protection. Przejście na Caddy direct oznacza, że te wszystkie funkcje trzeba zaimplementować samodzielnie.
- IP serwera jest eksponowane przy direct domain — dla produktu privacy to ryzyko (de-anonymizacja infrastruktury, ataki na sam serwer). Tunnel Cloudflare ukrywał IP.
- DDoS protection znika — Cloudflare absorbing ataków przestaje chronić. Przy direct domain atak L7 trafia bezpośrednio w Caddy/backend.
- WebSocket (P0-2) — Cloudflare Tunnel obsługiwał go domyślnie; na Caddy trzeba konfigurować.
Rekomendacja: to decyzja architektoniczna wymagająca uzasadnienia w specyfikacji. Autor wykluczył Cloudflare (1.4) powodem „simpler infrastructure", ale nie rozważył, że Cloudflare też:
- chroni IP hosta (privacy infra),
- absorbuję DDoS,
- terminuje TLS automatycznie,
- proxy'uje WebSocket domyślnie.
Dodać do sekcji 14.2 ryzyko: „Direct domain exposure → IP hosta publiczny, brak DDoS protection, brak ukrycia infrastruktury" z mitigacją: „rozważyć Cloudflare proxy (nie tunnel) jako warstwę L7, lub AWS CloudFront-equivalent privacy-preserving CDN". To zachowuje obietnicę privacy infra przy odzyskaniu ochrony. Jeśli zostaje direct Caddy — ująć to jako świadomą decyzję z tradeoffami.
9. Rozwiązania otwartych pytań (sekcja 15 spec)
Sekcja 15 zawiera 5 otwartych pytań. Raport audytowy powinien je rozstrzygnąć, aby specyfikacja stała się implementacyjna.
| Otwarte pytanie (spec 15) | Proponowane rozstrzygnięcie |
|---|---|
1. Potwierdzić pola odpowiedzi Trocador dla direct=false | Sprawdzić dokumentację Trocador AnonPay (API reference). Kluczowe pola: transaction_id, payment_address, amount_to, amount_to_currency, status, expiration. Blokowane przez P0-1 — jeśli Trocador niedostępny, pilnie dodać BTCPay i dokumentować jego API. Uwaga: weryfikacja 2026-07-22 zwraca HTTP 503 — endpoint docs również niepewny. |
| 2. Zdefiniować format pliku WG i konwencję nazewnictwa regionów | Format: standardowy [Interface] + [Peer] (.conf). Konwencja regionów: ISO 3166-1 alpha-2 (np. pl, de, us) + opcjonalnie sufiks miasta (us-nyc). Plik: wg-configs/. W bazie (6.3) config_file_path = ścieżka względna do wg-configs/. |
| 3. Wybrać metodę auth admina (hasło vs TOTP) | Hasło + TOTP obowiązkowe (P1-6). Hasło: bcrypt, min 14 znaków. TOTP: RFC 6238, 30 s window, 10 backup-kodów. Log wszystkich prób (już w 10.4). Ograniczenie IP/VPN (już rekomendowane). |
| 4. Caddy jako kontener czy natywny | Kontener — spójność z resztą stacka, łatwa migracja (12.5), rebuild z resztą. Wady: restart Caddy = chwilowy downtime wszystkich sesji. Mitigacja: health-check + auto-restart. Natywny tylko gdy wymagana zerowa przerwa. |
| 5. Finalizować format alertów Telegram | Format: ⚠️ [SEVERITY] [COMPONENT] + metadane JSON w code-block. Severity: CRIT (SSH/Caddy/DB down), WARN (progi, retry), INFO (backup OK). Max 1 alert/min per komponent (rate-limit, by nie spamować). |
10. Plan napraw przed implementacją
Sekwencja działań, aby specyfikacja stała się gotowa do dev. Każdy krok = rewizja dokumentu (v2 spec).
Faza 0 — Rozstrzygnięcia blokujące (przed dev, ~1-2 dni)
- Rozwiązać P0-1: dodać BTCPay jako fallback, udokumentować API obu dostawców.
- Rozwiązać P0-4: usunąć localStorage, ujednolicić cookie
HttpOnly;Secure;SameSite=Strict. - Rozwiązać P0-3: zdefiniować minimalny zestaw capabilities, usunąć SYS_ADMIN.
- Rozwiązać P0-5: dodać limity
--memory/--cpus/--pids-limitdo 10.1 i 12.2. - Rozwiązać P0-2: dodać wymaganie WebSocket proxy w sekcji 9.3.
- Rozstrzygnąć 5 otwartych pytań (sekcja 15) — wdrożyć propozycje z sekcji 9 tego raportu.
- Rozstrzygnąć rozbieżność PoC↔Spec (sekcja 8) — ująć decyzję architektoniczną z tradeoffami.
Faza 1 — Uzupełnienia P1 (przed produkcją, równolegle z dev)
- Dodać CSP + HSTS + nagłówki bezpieczeństwa (P1-1, P1-7) do sekcji 9.4.
- Dodać heartbeat kontenera + idle_timeout (P1-2, P1-3) do sekcji 3.3 i 11.
- Dodać rate-limiting (P1-5) do sekcji 7.2.
- TOTP obowiązkowe (P1-6) w 10.4.
- Off-site encrypted backup (P1-8, P1-10) w 11.5.
- Skanowanie obrazów Trivy (P1-4) w 10.6.
Faza 2 — Uzupełnienia P2 (usprawnienia, w trakcie dev)
- Wdrożyć ujednolicenie nazewnictwa, wersjonowanie API, RNG order_number, retencje.
Faza 3 — Pre-produkcyjna walidacja
- Security audit zewnętrzny (pen-test) przed launch — dla produktu privacy to obowiązkowe.
- Load test: 50 kontenerów jednocześnie, obserwacja hosta.
- Chaos test: pad hosta, pad Trocador, pad VPN region.
11. Podsumowanie
Specyfikacja 2026-07-22-browser-vpn-product-design.md to dobry punkt wyjścia — dobrze zorganizowany, uczciwy co do ograniczeń, z rozsądnym modelem danych i dopracowanym monitoringiem. Ocena ogólna 6.3/10 odzwierciedla solidny draft, który potrzebuje jednej pełnej iteracji naprawczej, zanim implementacja może bezpiecznie wystartować.
Co działa: struktura, zakres, model danych, API, scheduler, monitoring, zarządzanie ryzykiem. To fundament, którego nie trzeba przebudowywać.
Co blokuje (P0): zewnętrzny SPoF płatności (Trocador niedostępny), brak proxy WebSocket dla streaming'u, nadmierne uprawnienia kontenerów, localStorage podatne na XSS, brak limitów zasobów. Pięć punktów, z których każdy może samodzielnie zablokować produkt lub złamać obietnicę privacy.
Co wymaga decyzji: rozbieżność architektoniczna PoC (Cloudflare Tunnel) ↔ Spec (Caddy direct) nie jest arbitralnym wyborem — to zmiana, która zdejmuje warstwy ochrony (ukrywanie IP, DDoS protection, auto-WebSocket) i powinna być ujęta z tradeoffami, nie tylko powodem „simpler infrastructure".
Werdykt: Approve with mandatory revisions. Po rozwiązaniu 7 punktów Fazy 0 specyfikacja powinna awansować do v2 i dopiero wtedy wejść w implementację. Dla produktu czerpiącego wartość z obietnicy „total privacy" margines na błędy bezpieczeństwa jest zerowy — każda luka P0 to bezpośrednie ryzyko utraty zaufania najbardziej wrażliwej kohorty klientów.
12. Glosariusz
- WireGuard — nowoczesny protokół VPN oparty na kryptografii kluczy publicznych, prostszy i szybszy niż OpenVPN. W tym produkcie każdy kontener dostaje własny tunel WG do wybranego regionu.
- Trocador AnonPay — agregator płatności krypto pozwalający przyjmować dowolną monetę i zamieniać ją na XMR (Monero) dla odbiorcy. Działa bez konta kupca.
- BTCPay Server — self-hostowany procesor płatności Bitcoin/Monero, open-source, bez zewnętrznego SPoF — proponowany fallback dla Trocador.
- Caddy — web serwer/reverse proxy z automatycznym HTTPS (Let's Encrypt). W specyfikacji pełni rolę proxy domena→kontener.
- WebSocket — protokół dwukierunkowej komunikacji przez HTTP upgrade (101 Switching Protocols). Selkies-GStreamer używa go do streamingu obrazu i zdarzeń wejścia.
- Capabilities (Linux) — granularne uprawnienia roota (podzielone
CAP_*).SYS_ADMIN= bardzo szerokie (mount, namespace),NET_ADMIN= sieć (tunel),SYS_PTRACE= debug procesów. - httpOnly cookie — ciastko z flagą
HttpOnlynieodczytywalne przez JavaScript, chronione przed kradzieżą przez XSS. - SameSite=Strict — flaga cookie zapobiegająca wysłaniu ciastka w żądaniach cross-site, chroni przed CSRF.
- CSP (Content Security Policy) — nagłówek HTTP ograniczający źródła skryptów/stylów/połączeń, podstawowa obrona przed XSS.
- HSTS —
Strict-Transport-Securitywymusza HTTPS, chroni przed downgrade do HTTP przy pierwszej wizycie. - Selkies-GStreamer — open-source'owe współdzielenie ekranu/przeglądarki przez web, używane w PoC do streamowania przeglądarki z kontenera.
- Magic link — URL z identyfikatorem sesji (
/session/ses-xxx), nie wymaga konta; wiązanie urządzenia przez token po pierwszym otwarciu. - SPoF (Single Point of Failure) — pojedynczy komponent, którego awaria powoduje awarię całego systemu. Tutaj: Trocador dla płatności.
13. Źródła
Źródła (Pliki)
/root/browser-vpn-deploy/docs/superpowers/specs/2026-07-22-browser-vpn-product-design.md— audytowana specyfikacja (738 linii, 15 sekcji)/root/browser-vpn-deploy/README.md— istniejący PoC (bash, Cloudflare Tunnel, Selkies)/root/convertere/reports/v1-private-browser.md— niniejszy raport (źródło HTML)
Źródła (Linki URL — zweryfikowane HTTP 200, 2026-07-22)
- Caddy — reverse_proxy directive — dokumentacja proxy (HTTP 200)
- Caddy — WebSocket proxy — obsługa WebSocket w Caddy (HTTP 200)
- Docker — security configuration & capabilities — capabilities, isolation (HTTP 200)
- Docker — runtime privilege & Linux capabilities — cap_add/cap_drop (HTTP 200)
- WireGuard — protokół VPN (HTTP 200)
- LinuxServer.io docs — obrazy LSIO (brave/chrome/firefox/mullvad) (HTTP 200)
- Nuxt 3 — framework frontend (HTTP 200)
- Selkies-GStreamer (GitHub) — streaming przeglądarki (HTTP 200)
- OWASP — HttpOnly — ochrona cookie przed XSS (HTTP 200)
- MDN — Set-Cookie SameSite — flaga SameSite (HTTP 200)
- MDN — Content Security Policy — obrona XSS (HTTP 200)
- BTCPay Server — proponowany fallback płatności (HTTP 200)
Źródła (zweryfikowane niedostępne — flaga ostrzegawcza)
- Trocador — HTTP 503 (root) w dniu audytu (2026-07-22) — częściowa awaria: strona główna niedostępna, ale
https://trocador.app/en/anonpayzwraca HTTP 200 (dokumentacja AnonPay dostępna),https://api.trocador.app/zwraca HTTP 401 (API live, wymaga auth). Wniosek: 503 dotyczy route'u/originu strony głównej, nie pełnego shutdownu API. To żółta flaga (partial outage, nie czerwona), ale nie zmienia statusu P0-1 — pojedynczy dostawca z nawet przejściową niedostępnością wymaga fallback (BTCPay).