Commit Graph

13 Commits

Author SHA1 Message Date
gitea eff9d206ac data: wymagaj węzła z x86-64-v2; runbook maskowania CPU i lista czterech węzłów
data-demo wpadał w pętlę restartów na k3s-agent3:

  RuntimeError: NumPy was built with baseline optimizations:
  (X86_V2) but your machine doesn't support: (X86_V2).

DIAGNOZA — to NIE jest różnica sprzętu. Wszystkie cztery węzły to maszyny
wirtualne. Trzy widzą procesor jako „QEMU Virtual CPU 2.5+" i mają komplet
rozszerzeń x86-64-v2; agent3 widzi „Common KVM processor" (kvm64) i nie ma
popcnt, ssse3, sse4_1 ani sse4_2. Fizyczny i7-3770 pod spodem obsługuje nawet
x86-64-v3 — te flagi są MASKOWANE przez domyślny model CPU w Proxmoksie.

agent3 ma 14 dni, pozostałe 52. Został dołożony później i pominięto przy nim
krok `--cpu host`, odnotowany w pamięci projektu 2 sierpnia. Nikt tego nie
zauważył, dopóki scheduler nie postawił tam akurat warstwy danych — jedynej,
która ciągnie pandas, a przez nią NumPy.

ZABEZPIECZENIE: data i data-demo wymagają etykiety
`astrololo.czernobog.pl/cpu-x86-64-v2`. Świadomie ETYKIETA, a nie wykluczenie
agent3 po nazwie: wykluczanie po nazwie znaczyłoby, że każdy KOLEJNY źle
postawiony węzeł znów zbiera się przez awarię. Nowy węzeł jest domyślnie
nieoznaczony, więc nie dostanie tych podów, dopóki ktoś go nie sprawdzi
i nie oznaczy. Pending z czytelnym powodem bije pętlę restartów z komunikatem
o „baseline optimizations".

KOLEJNOŚĆ: węzły trzeba oznaczyć PRZED wdrożeniem tej zmiany. Dziś etykietę ma
zero węzłów, więc samo zmergowanie posłałoby data w Pending.

RUNBOOK: skrypt sprawdzający węzły, naprawa u źródła (`qm set --cpu host` plus
pełne wyłączenie i włączenie maszyny — sam restart z gościa nie wystarcza),
oraz zastrzeżenie, że `--cpu host` blokuje migrację na żywo między hostami
o różnych procesorach.

PUŁAPKA PRZY CZYTANIU FLAG, udokumentowana bo kosztowała fałszywą diagnozę:
Linux raportuje SSE3 jako „pni", nie „sse3". Pierwsza wersja kontroli wskazała
przez to trzy zdrowe węzły jako niesprawne.

Przy okazji: lista węzłów w eksportach NFS obejmuje wszystkie cztery. Runbooki
wymieniały trzy, a klaster ma cztery — ten sam mechanizm, ta sama przyczyna.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 21:44:02 +02:00
gitea 1d5bd27cdc astrodemo: wdrożenie wersji demonstracyjnej (PRE-28/29)
Zastępuje gałąź feat/astroklient. Tamta była odbita od mastera sprzed jedenastu
commitów i miała przypięte obrazy `ee3c515d`, podczas gdy master stoi na
`320a0ab2` — merge w tamtej postaci COFNĄŁBY klaster o kilka wersji. Zamiast
przepychać cztery commity przez rebase (każdy konfliktował na README), gałąź
jest odtworzona jednym commitem na aktualnym masterze, z zachowanymi tagami.

ZMIANA NAZWY. astroklient-demo → astrodemo, wraz z nazwą obrazu, zmiennymi
(ASTRODEMO_USERS) i sekretem (astrololo-astrodemo). Nazwa „astroklient" jest
zarezerwowana dla warstwy pośredniej: pełne funkcje astrologiczne, bez
generowania tekstu i bez administracji.

BRAKOWAŁO WEJŚCIA Z ZEWNĄTRZ. Manifesty tworzyły Deployment i Service, ale żadnej
reguły w Ingressie — usługa wstałaby i nie dałoby się do niej wejść. Dołożony
host astrodemo.czernobog.pl z przekierowaniem z http, a certyfikat obejmuje teraz
oba hosty.

Osobny host, a nie ścieżka `/demo` pod adresem astrololo, CELOWO: ścieżka
dzieliłaby z pełną aplikacją pochodzenie w rozumieniu przeglądarki, czyli
i ciasteczka — wejście do jednej ruszałoby sesję w drugiej.

OBRAZ NA LIŚCIE OBSERWOWANYCH. Bez wpisu w image-updater.yaml obraz nigdy się nie
podbije, choćby CI go budowało. Tak przez chwilę wisiał render na :latest.

POPRAWKI W RUNBOOKU. Opis twierdził, że demo pracuje na produkcyjnej warstwie
danych — nieprawda od PRE-29, ma własny stos i własny udział. Ponadto zmiana nazw
rozjechała ścieżkę udziału: `zfs create Tank1/astrololo-astrodemo` przy manifeście
montującym `/mnt/Tank1/astrololo-demo` utworzyłby inny zbiór niż ten, którego pod
szuka. Ścieżka jest stanem na dysku, nie nazwą w kodzie — zostaje jak była.

Sprawdzone: `kubectl kustomize astrololo/` buduje 29 obiektów, tagi obrazów
pozostają na 320a0ab2.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 19:49:43 +02:00
gitea 47544d1769 docs(sekrety): dołożenie klucza do ISTNIEJĄCEGO sekretu, nie tylko tworzenie
Po zmergowaniu LOG-34 pody prezentacji nie wstały:
  Error: couldn't find key SESSION_SECRET in Secret astrololo/astrololo-auth

Runbook opisywał wyłącznie ścieżkę instalacji OD ZERA — SESSION_SECRET pojawiał
się tylko w komendzie `create secret`. Na działającym wdrożeniu sekret już
istnieje, a merge manifestu kluczy do niego nie dokłada; każe ich tylko szukać.

Gorzej: opisana rotacja też by tam nie zadziałała. Używała JSON Patch z
`op: replace` na /data/SESSION_SECRET, a `replace` wymaga, żeby ścieżka już
istniała — czyli jedyna komenda, po którą sięgnąłby ktoś w tej sytuacji, też
odmawia.

Teraz obie potrzeby obsługuje JEDNA komenda: `--type=merge` ze `stringData`
dokłada albo nadpisuje i nie wymaga wcześniejszego istnienia klucza. Dopisane
sprawdzenie kompletu kluczy bez pokazywania wartości oraz to samo ostrzeżenie
w runbooku demo, gdzie czeka dokładnie ta sama pułapka.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-26 09:05:28 +00:00
gitea f754831f54 feat(prezentacja): klucz podpisu sesji (LOG-34)
SESSION_SECRET w sekrecie astrololo-auth. Pod bez niego CELOWO nie wstaje:
usługa z kontami, ale bez klucza, nie odróżniłaby ważnej sesji od podrobionej.

W README dopisana rotacja klucza jako awaryjny wyłącznik — podmiana unieważnia
wszystkie sesje naraz, co jest właściwą reakcją na podejrzenie przechwycenia
cudzej sesji.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 10:47:46 +00:00
gitea ff0a1c8256 docs(węzły): klient NFS jako jawny wymóg wdrożenia
Pody przestały wstawać z komunikatem „bad option ... you might need
a /sbin/mount.<type> helper program". To NIE jest problem z udziałem ani
z uprawnieniami — serwer w ogóle nie został zapytany; jądro nie znalazło programu
pomocniczego, bo na węźle brakowało nfs-common.

Wymogu klienta NFS nie było w żadnym runbooku, choć wszystkie trzy warstwy
montują udziały z NAS-a. Luka była uśpiona: wszystko stało na jednym węźle, który
klienta miał, więc braku na pozostałych nie było jak zauważyć. Ujawniło się
dopiero, gdy zejście do zera replik — przy zupełnie innej naprawie —
przeplanowało pody gdzie indziej.

Dopisana tabela odróżniająca trzy komunikaty, które łatwo pomylić, bo wszystkie
kończą się niewstającym podem: brak klienta na węźle, odmowa serwera i brak praw
do zapisu. Każdy ma inną przyczynę i inne miejsce naprawy.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 12:40:24 +02:00
gitea 94f059d090 docs(pliki): runbook otwarcia udziału z bazami na zapis (zgubiony przy merge'u)
Treść powstała jako commit na gałęzi feat/pliki-zapis JUŻ PO zmergowaniu jej
PR-a, więc nigdy nie trafiła na master — został tam wyłącznie manifest.
Sam manifest jest w porządku (readOnly zdjęte), brakowało tylko opisu, co z tym
zrobić po stronie NAS-a.

Runbook zawiera: komendy midclt otwierające udział z bazami na zapis, sprawdzenie
przez exportfs (bo konfiguracja udziału i stan eksportu to dwie różne rzeczy),
ostrzeżenie, że przeładowanie musi iść przez zero replik zamiast rollout restart,
oraz listę kontrolną po wdrożeniu — z wyszukiwaniem jako punktem NAJWAŻNIEJSZYM,
bo to jedyne miejsce, w którym ta zmiana mogłaby przejść niezauważona.

Osobno wyliczone, co świadomie tracimy: DAN-25 dawał gwarancję, że baz nie da się
zmienić przez NFS, i tych dwóch rzeczy nie da się mieć naraz.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 12:22:49 +02:00
gitea 99b9a0426f feat(astrololo): Postgres jako lustro baz w SQL + runbook (DAN-28)
Manifest, wpięcie w kustomization i runbook krok po kroku.

DECYZJE ZAPISANE W MANIFEŚCIE, ŻEBY NIE TRZEBA ICH BYŁO ODTWARZAĆ Z GŁOWY:

local-path, NIE NFS. Postgres zakłada semantykę blokad i fsync, której NFS nie
gwarantuje — to klasyczne źródło uszkodzenia bazy przy nagłym restarcie. Ceną
jest przywiązanie do węzła; przy luście odtwarzalnym z Excela to akceptowalne.

strategy: Recreate. Wolumen jest ReadWriteOnce, a dwa procesy Postgresa na jednym
katalogu danych to uszkodzona baza — rolling próbowałby wstać z nowym podem,
zanim stary zejdzie.

PGDATA w PODKATALOGU wolumenu: katalog główny potrafi zawierać wpisy systemu
plików, a initdb odmawia pracy w niepustym katalogu.

Wersja PRZYPIĘTA i poza image-updaterem: podbicie majora wymaga migracji katalogu
danych, więc nie może się zdarzyć samo, w nocy, przy okazji builda aplikacji.

C.UTF-8 zamiast pl_PL.UTF-8: dopasowanie tekstu robimy przez unaccent i pg_trgm,
nie przez collation, a pl_PL wymagałby obrazu z wygenerowanymi lokalizacjami.

DATA_PROVIDER zostaje na `excel`. Postgres można wdrożyć i obejrzeć BEZ ryzyka
dla działającego wyszukiwania; przełączenie to osobna, późniejsza decyzja.

SPRAWDZONE PRZED ODDANIEM: `kubectl kustomize astrololo` składa komplet 21
zasobów bez błędu, YAML parsuje się poprawnie, audyt odwołań potwierdza, że
jedynym brakującym sekretem jest astrololo-postgres (oba klucze), a DSN
postgresql+psycopg:// jest rozpoznawany przez SQLAlchemy z psycopg 3.

NIE SPRAWDZONE: skrypt inicjalizujący nie biegł przeciwko prawdziwemu Postgresowi
— na maszynie, na której to powstawało, nie ma Dockera. Zapisane wprost
w runbooku; krok 4 jest tam prawdziwym testem.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 12:06:10 +02:00
gitea aff4de4e49 fix(prezentacja): osobny udział na stan zamiast subPath na udziale z bazami
Pod presentation nie wstawał: CreateContainerConfigError, „failed to create
subPath directory for volumeMount state".

MÓJ BŁĄD, NIE ZAGADKA. Udział z bazami jest wyeksportowany `ro: true`
z `root_squash` — ustawiłem to runbookiem DAN-25 i sam tam napisałem ostrzeżenie,
że po tej zmianie nikt nic nie wgra. Dokładając wolumen na konta zmieniłem
`readOnly` przy MONTOWANIU w podzie i uznałem sprawę za załatwioną, nie sprawdzając
eksportu po stronie serwera.

Przyczyna była zresztą podwójna i za każdym razem ta sama:
  1. kubelet nie mógł utworzyć podkatalogu, bo udział jest tylko do odczytu,
  2. a gdyby nawet mógł — kontenery działają jako root, a root_squash mapuje
     roota na nobody, więc aplikacja i tak nie zapisałaby tam pliku kont.

ROZWIĄZANIE BEZ RUSZANIA DAN-25: osobny, mały udział /mnt/Tank1/astrololo-state,
zapisywalny, zawężony do tych samych trzech węzłów, z mapall_user na
nieuprzywilejowanego użytkownika (bezpieczniejsze niż no_root_squash, bo nie
oddaje roota). Udział z bazami ZOSTAJE tylko do odczytu.

Przy okazji znika subPath, czyli znika potrzeba, żeby kubelet cokolwiek zakładał —
katalog istnieje, bo jest korzeniem udziału.

Runbook README-stan-prezentacji.md zawiera test zapisu Z WĘZŁA do wykonania PRZED
wdrożeniem — dokładnie ten, którego zabrakło za pierwszym razem.

UWAGA: DAN-27 (zarządzanie plikami baz) uderzy w tę samą ścianę, bo wymaga zapisu
do udziału z BAZAMI. Ten commit tego nie rozwiązuje i celowo nie rusza DAN-25 —
to osobna decyzja, opisana na końcu runbooka.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 17:46:12 +02:00
gitea 3df1170f5d chore(astrololo): manifest CRD image-updater w repo (ślad tego, co śledzimy)
Konfiguracja argocd-image-updater istniała tylko w klastrze (ręczne `kubectl
apply`, brak w git). Skutkiem był PRE-24: `render` zbudował się i zdeployował raz,
ale kolejne buildy nie schodziły — bo nie było go na JAWNEJ liście obserwowanych
obrazów CRD, a nigdzie nie dało się tego podejrzeć ani odtworzyć.

Zrzucam manifest (z `render` już w środku, 4 obrazy: data/logic/presentation/
render) do `astrololo/image-updater.yaml` + opis w README.

Plik CELOWO nie jest w kustomization.yaml: resource stoi w ns `argocd` (poza
namespace docelowym aplikacji), a to konfiguracja kontrolera wdrażającego tę
aplikację — nakładany ręcznie (`kubectl apply -f astrololo/image-updater.yaml`),
w repo dla odtwarzalności i historii. Dodanie nowej usługi = dopisanie wpisu tutaj.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 00:02:53 +02:00
gitea a075f9555f feat(astrololo): klucze szyfrowania lacz miedzy warstwami (PRE-16)
Domyka PRE-16 po stronie manifestow. Kod (astrololo#21) potrafi juz szyfrowac
ruch miedzy warstwami AES-256-GCM; tu dokladamy klucze i wymuszenie.

- astrololo-link: nowy sekret z dwoma kluczami (LINK_KEY_PRESENTATION_LOGIC,
  LINK_KEY_LOGIC_DATA), tworzony POZA repo jak pozostale. Osobny klucz na pare
  rozmowcow: przejecie klucza prezentacji nie otwiera warstwy danych. Logika
  bierze oba, prezentacja i dane wylacznie swoj (secretKeyRef).
- LINK_ENCRYPTION_REQUIRED=true we wszystkich trzech: bez klucza pod NIE wstaje,
  a klient nie wysyla niczego. Fail-closed w obie strony jest celowy — usluga,
  ktora wstala i po cichu nie szyfruje, jest gorsza niz CrashLoop, bo awarii
  nie widac.

README: sekcja o sekrecie astrololo-link (tworzenie, wymiana, restart calej
trojki naraz) oraz uczciwa nota, ze szyfrowane sa ciala, nie naglowki — sciezka
i token jada czytelnie, ale sam token bez klucza nic nie daje.

Sprawdzone: kubectl kustomize + apply --dry-run=server przechodza dla obu
profili. Pelna instrukcja wdrozenia: docs/wdrozenie-pre16.md w repo astrololo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:40:43 +00:00
gitea 2d30d9a84d feat(astrololo): wejscie po https z wlasnym CA (PRE-16)
Do tej pory aplikacja chodzila po zwyklym http, a logowanie szlo przez HTTP
Basic — czyli haslo leciało siecia w postaci trywialnej do podsluchania.

Poza bezpieczenstwem TLS naprawia DWIE funkcje zepsute dzis z tego samego
powodu: geolokalizacja przegladarki („Tu i teraz") i kopiowanie promptu do
schowka dzialaja wylacznie w secure context, wiec po http po prostu odmawialy.

Wlasne CA, nie Let's Encrypt — klaster stoi w LAN (traefik trzyma LoadBalancera
na 192.168.1.x), wiec walidacja HTTP-01 nie ma jak dojsc z internetu, a DNS-01
wymagalby trzymania w klastrze tokena API do domeny.

Co dochodzi:
- tls.yaml — Issuer selfSigned -> korzen CA (10 lat, importowany raz do
  przegladarki) -> Issuer CA -> certyfikat serwera (90 dni, odnawiany sam).
  Krotki termin certyfikatu serwera jest CELOWY: odnawianie sprawdza sie wtedy
  co kwartal, a nie dopiero za dekade.
- ingress.yaml — wejscie po https + naglowki (HSTS rok, nosniff, frameDeny)
  oraz osobny Ingress na porcie 80 robiacy przekierowanie. Rozdzielone
  swiadomie: gdyby redirect wisial na tym samym routerze co wejscie po https,
  odsylalby sam do siebie w kolko.
- presentation: Service NodePort -> ClusterIP. NodePort byl druga,
  nieszyfrowana droga do aplikacji, czyli obejsciem calego PRE-16.

Zmiana wymagajaca uwagi: TRUST_PROXY=true. Za Ingressem bezposrednim rozmowca
jest zawsze pod Traefika, wiec bez tego limit zadan liczylby WSZYSTKICH do
jednego wiadra i pierwsza osoba, ktora go wyklika, odcielaby pozostalych.

Sprawdzone: Ingress i Middleware przechodza `kubectl apply --dry-run=server`
na zywym klastrze (CRD traefik.io/v1alpha1 sa, entrypointy web/websecure sa).
Obiekty cert-managera zwalidowane offline wobec oficjalnego schematu z CRD
v1.21.0 z additionalProperties=false — literowka w nazwie pola zostalaby
zlapana. `kubectl kustomize` przechodzi dla obu profili (bazowego i swisseph).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 16:40:43 +00:00
gitea 90bfff18df feat(astrololo): klucze do modeli w chmurze + konfiguracja modelu lokalnego
Domyslnie dziala model LOKALNY i nic nie opuszcza sieci. Zeby dalo sie wybrac
w UI OpenAI albo Anthropic, logika potrzebuje ich kluczy.

- LLM_PROVIDER=local, LOCAL_BASE_URL, LOCAL_MODEL, LLM_TIMEOUT, LLM_MAX_TOKENS
  jawnie (nie sa tajne),
- OPENAI_API_KEY i ANTHROPIC_API_KEY z osobnego sekretu `astrololo-llm`.

Sekret jest OPCJONALNY (optional: true) — inaczej niz `astrololo-auth`. Auth to
zabezpieczenie i ma zatrzymac pody, gdy go brak; klucze do chmury to funkcja,
wiec ich brak nie moze wywracac wdrozenia. Bez nich pody startuja normalnie,
tylko chmura jest niedostepna.

Osobny sekret, a nie doklejenie do astrololo-auth, zeby klucze LLM dalo sie
wymieniac bez dotykania hasla i tokenu miedzywarstwowego.

Zwalidowane kubectl kustomize; w wyniku nadal zadnego `kind: Secret`.
Instrukcja tworzenia i podmiany kluczy w astrololo/README.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-22 15:34:57 +00:00
gitea 66d174703e feat(astrololo): sekrety logowania i tokenu miedzywarstwowego (LOG-32)
Domyka od strony wdrozenia ochrone dodana w aplikacji (PR #10 w repo astrololo).
Bez tych zmiennych aplikacja startuje OTWARTA, a wystawia tresc oryginalnych
baz interpretacyjnych.

- presentation: APP_PASSWORD + INTERNAL_TOKEN z sekretu, APP_USER i
  RATE_LIMIT_PER_MIN jawnie (nie sa tajne).
- logic, data: INTERNAL_TOKEN z sekretu — bez niego da sie ominac logowanie,
  uderzajac wprost w warstwe nizej. Warstwa danych oddaje SUROWE wiersze,
  wiec to najwrazliwszy punkt.

WARTOSCI SEKRETOW CELOWO NIE TRAFIAJA DO REPO — to GitOps, wiec zostalyby
w historii gita na zawsze i przekreslily caly sens tej zmiany. Manifesty
tylko odwoluja sie do sekretu `astrololo-auth`, tworzonego poza repo — ta sama
konwencja co istniejacy `gitea-registry`.

UWAGA: sekret jest WYMAGANY (bez `optional: true`), wiec pody nie wstana,
dopoki go nie utworzysz. To swiadome: lepsza widoczna awaria niz cichy start
bez ochrony. Instrukcja tworzenia i zmiany hasla w astrololo/README.md.

Przy okazji: poprawiony mylacy komentarz przy EXCEL_DIR — pliki baz ida
z NFS, nie z obrazu (montaz je nadpisuje).

Zwalidowane `kubectl kustomize` dla bazy i profilu swisseph: sekrety trafiaja
do wlasciwych uslug, a w wyniku nie ma zadnego `kind: Secret`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 17:06:16 +00:00