Przebudowa oryginalnej makiety (React + Vite, "AI Studio" export) na natywną aplikację desktopową: Tauri v2 (backend Rust) + Solid.js (frontend).
cybersec-mode/
├── Makefile # make dev / build / lint / icons / clean
├── scripts/ # setup.sh, dev.sh, build-release.sh
├── ipc/ # placeholder na wspólny kontrakt frontend<->backend (patrz ipc/README.md)
└── source-code/
├── frontend/ # Solid.js + Vite + Tailwind
│ ├── src/
│ │ ├── components/ # Terminal, ToolShop, Analytics, NetworkMonitor,
│ │ │ # DraggableScanner, PowerButton
│ │ ├── lib/tauri.ts # jedyne miejsce wołające @tauri-apps/api
│ │ ├── App.tsx
│ │ └── main.tsx
│ └── package.json
└── backend/ # src-tauri (Rust)
├── src/{main,lib}.rs
├── capabilities/default.json
├── icons/
├── Cargo.toml
└── tauri.conf.json
./scripts/setup.sh # albo: make install
make dev # tryb deweloperski (hot reload)
make build # bundle produkcyjny (.deb/.AppImage/.msi/.dmg zależnie od OS)Wymagania: Node.js 18+, Rust (rustup) i zależności systemowe Tauri dla Twojej platformy — https://tauri.app/start/prerequisites/.
- Migracja komponentów z React (hooks, JSX) na Solid.js (signals,
<For>,createEffect/onMount/onCleanup), bez zmiany warstwy wizualnej. framer-motionzastąpiony natywnymi transitions CSS + Pointer Events API (drag okna skanera) — jedna zależność mniej, brak odpowiednika 1:1 w ekosystemie Solid, więc lepiej nie ciągnąć dodatkowego pakietu tylko dla jednego elementu.lucide-react→lucide-solid.- Cały frontend spakowany jako natywna appka desktopowa przez Tauri (Rust webview), zamiast SPA serwowanego przez Express/Vite preview.
- Dodany przycisk zasilania (lewy dolny róg, zawsze na wierzchu, wymaga
dwukliku w oknie 4s) — wywołuje
exit(0)z@tauri-apps/plugin-process. - Wydzielona warstwa
src/lib/tauri.tsjako jedyny punkt styku z Tauri API, żeby komponenty UI nie znały nazw komend/pluginów bezpośrednio. - Struktura repo rozdzielona na
source-code/frontendisource-code/backendMakefile,scripts/,ipc/(placeholder) zgodnie z ustaloną konwencją.
Arsenal w górnej nawigacji (albo ikona warstw w lewym pasku) otwiera pełny
"software center" w stylu Discover/GNOME Software, ale nad prawdziwym
pacmanem BlackArch działającym w kontenerze podman:
- Backend (
source-code/backend/src/blackarch.rs) zakłada, że podman jest już zainstalowany w systemie hosta — sam go nie instaluje, tylko sprawdza (podman --version) i jasno komunikuje brak w UI. - Przy pierwszym otwarciu Store, jeśli kontener
blackarch-redteamnie istnieje, pokazuje ekran onboardingu z przyciskiem "Utwórz kontener BlackArch" →podman run -d --name blackarch-redteam ... blackarch/blackarch tail -f /dev/null, potempacman -Syw środku kontenera. - Kategorie w lewej kolumnie Store to realne grupy pakietów BlackArch
(
blackarch-recon,blackarch-scanner,blackarch-exploitation, itd.), pobierane przezpacman -Sg <grupa>+pacman -Sidla opisów/wersji. - Wyszukiwarka woła
pacman -Ss <fraza>wewnątrz kontenera. - Install/Usuń wołają odpowiednio
pacman -S --noconfirm <pkg>ipacman -R --noconfirm <pkg>w kontenerze — backend Rust jest jedynym miejscem, które faktycznie odpala procesy; frontend tylko woła komendy Tauri (src/lib/tauri.ts) i renderuje wynik. - W przeglądarce (poza Tauri,
npm run devbeztauri dev)lib/tauri.tsprzełącza się na dane mockowe, żeby dało się developować UI bez podmana.
To był i jest w dużej mierze mockup UI poza samym Store, który teraz faktycznie mówi do pacmana — reszta (terminal, wykres ruchu, lista "zagrożeń") to nadal dane zaszyte na sztywno. Do wersji, która faktycznie nadaje się dla zespołu red-team w środowisku korporacyjnym, potrzeba świadomie zaprojektowanej warstwy backendowej — to nie jest coś, co da się "dopisać" bezmyślnie w komponencie:
- Autentykacja i autoryzacja operatora — appka otwiera się od razu w trybie "root", bez logowania. W środowisku korporacyjnym potrzebny jest ekran logowania, integracja z SSO/LDAP firmy, oraz podział na role (operator / lead / audytor tylko-do-odczytu) — w tym kto w ogóle ma prawo instalować pakiety przez Store.
- Bezpieczeństwo kontenera Store — dziś
ensure_containertworzy kontener z domyślnymi ustawieniami sieci (pełny dostęp) i bez limitów zasobów. Do użytku firmowego: rootless podman, ograniczona sieć (proxy przez firmowy egress zamiast pełnego internetu), limity CPU/RAM, read-only rootfs poza katalogiem roboczym, oraz decyzja czy instalacja pakietów wymaga zatwierdzenia (np. allowlist pakietów zamiast pełnego dostępu do repo BlackArch). - Progres instalacji w czasie rzeczywistym —
install_packagedziś czeka na zakończeniepacman -Si dopiero wtedy zwraca wynik. Realny pasek postępu wymaga strumieniowania stdout pacmana do frontendu przez eventy Tauri (app.emit()+listen()po stronie Solid), nie tylko spinnera "instaluję...". - Prawdziwe źródło danych dla reszty appki — CVE, alerty, wykres ruchu sieciowego to dziś stałe wartości. Docelowo: backend Rust jako pośrednik do wewnętrznych systemów firmy (SIEM, EDR, wewnętrzna baza CVE) — nigdy bezpośrednio z frontendu do internetu.
- Kontrakt IPC (
ipc/) — wciąż pusty placeholder, mimo że Store już ma 9 komend Tauri z własnymi typami (Package,Category). Warto ustalić wspólne typy request/response między Solid.js a Rust (np. przezspecta), zanim liczba komend urośnie dalej. - Terminal — nadal symulacja z zaszytymi odpowiedziami, całkiem
niepodłączona do kontenera Store, który już naprawdę istnieje. Podłączenie
realnej powłoki w tym samym kontenerze podman (np. przez
portable-ptypo stronie Rust) to osobna decyzja bezpieczeństwa — sandboxing, logowanie każdej sesji, jasna polityka uprawnień. - Audyt i logowanie działań — w środowisku korpo każda akcja operatora (instalacja/usunięcie pakietu, skan, eksport raportu) powinna trafiać do logu z timestampem i tożsamością operatora, najlepiej po stronie backendu (żeby log nie dało się podmienić z poziomu frontendu).
- Podpisywanie i dystrybucja buildów —
tauri.conf.jsonnie ma konfiguracji code-signing. Do dystrybucji w firmie potrzebny jest certyfikat (macOS notarization, Windows Authenticode) oraz pipeline CI/CD budujący i podpisujący binarki dla wszystkich platform. - Aktualizacje — brak
tauri-plugin-updater. Warto dodać, żeby appka (i lista dostępnych kategorii/pakietów) mogła się aktualizować bez ręcznej redystrybucji. - Testy — zero testów, teraz już przy realnej logice (parsowanie
wyjścia
pacman -Ss/-Siwblackarch.rs, stany instalacji wStore.tsx) to nie jest opcjonalne. Parsery tekstowe pacmana są szczególnie kruche na zmiany formatu między wersjami — potrzebują testów jednostkowych z przykładowym wyjściem.
Chętnie wejdę głębiej w którykolwiek z powyższych punktów — powiedz, od którego zacząć (np. streaming postępu instalacji, bo widać go najszybciej w UI, albo bezpieczeństwo kontenera, bo to fundament dla reszty).
Wszystkie 9 punktów z listy wyżej zaadresowane. Tauri v2 (bez zmian —
tauri = "2" w Cargo.toml, @tauri-apps/api v2 we frontendzie).
- Terminal → prawdziwy PTY (
source-code/backend/src/pty.rs) —portable-ptyspawnujepodman exec -it blackarch-redteam bash, stdout/stderr strumieniowane do frontendu eventempty://output, wejście operatora idzie przez komendępty_write.Terminal.tsxprzepisany na konsumenta tego strumienia zamiast zaszytych odpowiedzi. - Audit log (
src/audit.rs) — append-only JSONL w katalogu danych appki (~/.local/share/cybersecurity-mode/audit.jsonlna Linuksie). Każda mutująca akcja (login/logout, tworzenie kontenera, instalacja/ usunięcie/odrzucenie pakietu, zmiana allowlisty) loguje operatora, timestamp i szczegóły. Podgląd ostatnich wpisów w panelu Analytics. - Code-signing i dystrybucja —
tauri.conf.jsonma teraz sekcjebundle.macOS/bundle.windowsz polami na certyfikat orazplugins.updaterz endpointem i kluczem publicznym (placeholdery do podmiany). Pełny przepis krok-po-kroku (generowanie klucza, notarization, Authenticode) wSIGNING.md. Szkielet pipeline'u w.github/workflows/release.yml. - Aktualizacje —
tauri-plugin-updaterdodany po stronie Rust (lib.rs) i JS (@tauri-apps/plugin-updater).lib/tauri.tseksportujecheckForUpdate()/downloadAndInstallUpdate(); header appki pokazuje przycisk "Aktualizacja X.Y.Z", gdy nowa wersja jest dostępna. - Testy — Rust:
#[cfg(test)]wblackarch.rsz przykładowym wyjściempacman -Ss/-Si(w tym przypadek pustego/uszkodzonego wejścia) —cargo test. Frontend: vitest skonfigurowany (npm run test), przykład na wyodrębnionej czystej funkcji (lib/networkScale.ts+lib/__tests__/networkScale.test.ts). - Auth / role (
src/auth.rs) — appka nie startuje już w trybie "root", tylko pokazuje ekran logowania (Login.tsx), dopókicurrent_session()nie zwróci sesji. Logowanie idzie przez systemowy PAM — dokładnie to samo konto i hasło co dosu/konsoli na tym hoście (modułpam_unix, weryfikacja hasła przez setuid-rootunix_chkpwd, appka NIE musi być rootem). Jeśli host ma PAM/NSS podpięte pod firmowe LDAP/SSSD/Kerberos, appka loguje przez to źródło automatycznie — nie ma już własnej bazy loginów do zarządzania. Rola (Operator/Lead/Auditor) wynika z przynależności do grup uniksowych (redteam-lead/redteam-operator, nazwy nadpisywalne zmiennymi środowiskowymi — patrz komentarz modułu). - Bezpieczeństwo kontenera Store —
ensure_containertworzy teraz kontener z--cap-drop=ALL,--security-opt no-new-privileges, twardym limitem--memory 2g --cpus 2. Dodana allowlist pakietów (get_allowlist/set_allowlist, zarządzana przez rolę Lead) — domyślnieallow_all: true(żeby Store działał od razu), ale gotowa do zawężenia do zatwierdzonego zestawu narzędzi. Rootless podman i ograniczenie sieci do firmowego egress proxy zostają jako kolejny krok — patrz pkt niżej. - Progres instalacji w czasie rzeczywistym —
install_package,remove_packageiensure_containerstrumieniują teraz stdout/stderr procesu przez eventstore://progresszamiast czekać w ciszy;Store.tsxrenderuje log na żywo (ekran onboardingu + pasek podczas instalacji/usuwania). - Prawdziwe źródła danych (
src/threat_feed.rs) —NetworkMonitorczyta teraz realne I/O kontenera przezpodman stats --format jsonzamiast losowych słupków.Analyticswołaget_threat_feed(), które uczciwie zwraca pustą listę / błąd zamiast zmyślonych CVE, dopóki nikt nie skonfigurujethreat_feed.json/source_url— podpięcie realnego SIEM/CVE API to świadomie zostawiony, oznaczonyTODOkrok (wymaga dodania klienta HTTP, np.reqwest).
- Uruchamiaj
tauri(CLI) tylko przeznpm run tauri ...zsource-code/frontend— skrypt wpackage.jsonsam robicd ../backendprzed odpaleniem CLI. Jeśli wywołasztauri/npx tauribezpośrednio z innego katalogu, dostaniesz błąd "Couldn't recognize the current folder as a Tauri project" — to ograniczenie samego Tauri CLI (szuka configu tylko w podkatalogach bieżącego katalogu), nie bug w tym repo.make dev/make buildużywają tej samej ścieżki. beforeDevCommand/beforeBuildCommandużywają jawnej formy obiektowej{ "cwd": "../frontend", "script": "..." }, nie samego stringa z--prefix. Tauri CLI ma udokumentowaną, mylącą zasadę ustalania cwd dla wersji string-owej (liczy je względem najbliższegopackage.jsonod strony CLI, nie względemtauri.conf.json) — patrz tauri-apps/tauri#3551. Efekt uboczny:npm run build --prefix ../frontendpotrafi rozwiązać się o katalog za wysoko (np.cybersec-mode/frontendzamiastcybersec-mode/source-code/frontend) i wywalić się z ENOENT. Forma obiektowa zcwdjest liczona względem lokalizacjitauri.conf.json(czylisource-code/backend), więc"cwd": "../frontend"jednoznacznie wskazujesource-code/frontend— bez zgadywania.- Logowanie = konto systemowe tego hosta (PAM), nie osobna baza. Zaloguj
się loginem/hasłem dowolnego użytkownika Linuksa, który już istnieje na
maszynie uruchamiającej appkę. Domyślnie appka odwołuje się do usługi PAM
login(nadpisywalne zmiennąCYBERSEC_MODE_PAM_SERVICE, np. na Fedorze warto ustawićsystem-auth). Żeby ktoś dostał rolęOperatoralboLeadzamiast domyślnegoAuditor(tylko podgląd), dodaj go do grupy:sudo usermod -aG redteam-operator <użytkownik>(alboredteam-lead) — nazwy grup też nadpisywalne (CYBERSEC_MODE_OPERATOR_GROUP,CYBERSEC_MODE_LEAD_GROUP). Kompilacja wymaga nagłówków PAM w systemie: Debian/Ubuntusudo apt install libpam0g-dev, Fedora/RHELsudo dnf install pam-devel, Arch zwykle ma je już z pakietupam. plugins.updater.pubkeyiendpointswtauri.conf.jsonto placeholdery — appka nie znajdzie aktualizacji, dopóki nie wygenerujesz klucza i nie podepniesz prawdziwego endpointu (patrzSIGNING.md).threat_feed.jsonnie istnieje domyślnie — panel Analytics uczciwie pokaże "brak podpiętego źródła", dopóki go nie skonfigurujesz.
- Rootless podman + ograniczenie sieci kontenera do firmowego egress proxy.
- Realny klient HTTP w
threat_feed.rs(dziś tylko kontrakt +TODO). - Pełne nagrywanie sesji terminala do audit logu (dziś logujemy tylko start/koniec sesji, nie treść — to świadoma decyzja do podjęcia osobno, bo dotyczy prywatności operatora i wolumenu logów).
- Realna integracja OIDC/LDAP na poziomie appki, jeśli PAM+SSSD na hoście kiedyś przestanie wystarczać (dziś: PAM już pośrednio to ogarnia, jeśli host ma SSSD/LDAP skonfigurowane — patrz punkt 6 wyżej).
- Kontrakt w
ipc/— wciąż pusty, a komend Tauri przybyło (auth, audit, pty, threat_feed) — coraz bardziej warto to ustandaryzować.
- Zła nazwa obrazu kontenera —
blackarch/blackarchnie istnieje; poprawny, oficjalny obraz toblackarchlinux/blackarch(publikowany przez BlackArch/blackarch-docker). To był najpewniejszy powód błędu "Procespodmanzakończył się kodem Some(125)" przy pierwszym tworzeniu kontenera (manifest unknownprzy próbie ściągnięcia nieistniejącego obrazu). ensure_containerużywa terazpodman run --replace, więc nieudana poprzednia próba (zawieszony/martwy kontener o tej samej nazwie) już nie blokuje kolejnej próby błędem "name already in use".run_streamingzbiera teraz ostatnie linie stdout/stderr i dołącza je do zwracanego błędu — kolejne awarie tego typu pokażą realny komunikat podmana/pacmana, nie tylko gołą liczbę kodu wyjścia.- Auth przepisany na PAM (
src/auth.rs) — appka nie ma już własnej bazy loginów (operators.json, Argon2, seedadmin/changeme— to wszystko usunięte). Logowanie idzie przez systemowy PAM, czyli realne konto systemowe tego hosta; patrz punkt 6 w "Runda 2" wyżej (zaktualizowany) po szczegóły i zmienne środowiskowe do konfiguracji grup/usługi PAM.