Compare commits

..

4 Commits

Author SHA1 Message Date
gitea 7e0a51878e feat(astroklient-demo): własny klucz podpisu sesji (LOG-34)
SESSION_SECRET w sekrecie astrololo-demo — WŁASNY, nie ten z pełnej aplikacji:
demo i produkcja nie mają powodu uznawać nawzajem swoich sesji.

W runbooku zapisana różnica wobec pełnej wersji: demo nie ma własnego wolumenu,
więc nie ma licznika sesji. Zdalne unieważnienie robi się przez DEMO_USERS —
usunięcie konta albo zmiana hasła natychmiast ubija jego otwarte sesje.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 00:21:52 +02:00
gitea a9ff6e1f68 refactor: astroklient → astroklient-demo
Nazwa `astroklient` zostaje zarezerwowana dla przyszłej wersji produkcyjnej;
obecna, demonstracyjna nazywa się od teraz `astroklient-demo`.

Zmiana obejmuje nazwy plików (astroklient-demo.yaml, astroklient-demo-stack.yaml,
README-astroklient-demo.md), Deployment i Service, etykiety selektorów, obraz
w rejestrze, alias w image-updaterze, wpisy w kustomization i odsyłacze w README.

`data-demo` i `logic-demo` zostają bez zmian — nie niosły starej nazwy.

Sprawdzone: `kubectl kustomize astrololo` składa komplet 27 zasobów, obraz to
astrololo-astroklient-demo, żadnego zdublowanego przyrostka ani gołego
`astroklient` nie zostało.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-20 23:36:57 +02:00
gitea e52284c88f feat(astroklient): własna warstwa danych i pule per konto (PRE-29)
Zmiana wobec pierwszej wersji: demo NIE pracuje już na produkcyjnej warstwie
danych. Ma własną logikę i własne dane, na osobnym udziale astrololo-demo,
pustym na starcie. Oryginalne bazy są dla demo nieosiągalne — nie przez
uprawnienia, tylko dlatego, że nie ma do nich drogi.

DLACZEGO OSOBNA JEST TEŻ WARSTWA LOGICZNA. Zna ona JEDEN adres warstwy danych,
więc astroklient korzystający z produkcyjnej logiki i tak trafiłby na produkcyjne
bazy. Izolacja musi sięgnąć obu warstw naraz, inaczej nie ma jej wcale. Jedyną
różnicą logic-demo wobec produkcyjnej jest DATA_URL — i to jest cała izolacja,
więc wpisanie tam „logic" cofnęłoby ją jednym słowem. Stąd komentarz przy tej
linii i sąsiedztwo obu plików.

PULE PER KONTO. Każde konto demo dostaje własny podkatalog na tym udziale,
niewidoczny dla pozostałych — w liście plików i w wynikach wyszukiwania. Konta
są listą `login:sekret` w sekrecie, bo jedno wspólne oznaczałoby wspólną pulę,
czyli klientów oglądających nawzajem swoje wgrania.

Ten sam OBRAZ co produkcja dla data i logic — różni je wyłącznie konfiguracja.
Osobny obraz to drugi kod do utrzymania i pewność, że kiedyś się rozjadą.

Logika demo nie dostaje kluczy do modeli językowych: astroklient nie umie o nie
prosić, więc nie ma powodu, żeby leżały w tym podzie.

Runbook opisuje IMPORT PULI KLIENTA do pełnej aplikacji — sedno całego układu,
bo klient przechodzący na pełną wersję nie może stracić wgrań. Jego pula to jeden
katalog: sprawdzenie kolizji nazw, kopiowanie z -n (nigdy nadpisania bazy
produkcyjnej), bez pliku stanu (produkcja ma własny), a na końcu świadome
włączenie w zakładce Pliki. Nie włączają się same, bo przeniesienie jest
czynnością techniczną, a decyzja o użyciu należy do właściciela.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 18:59:20 +02:00
gitea 82c73f6aa5 feat(astroklient): wdrożenie wersji demonstracyjnej (PRE-28)
Deployment + Service (ClusterIP), wpięcie w kustomization, obraz dopisany do
image-updatera i runbook.

Obraz na liście image-updatera CELOWO od razu: obraz, którego tam nie ma, nigdy
się nie podbije, choćby CI go budowało — tak przez chwilę wisiał render na :latest.

Token międzywarstwowy i klucz łącza brane z TYCH SAMYCH sekretów co prezentacja:
demo nie jest furtką omijającą ochronę warstwy logicznej. Hasło demo natomiast
z OSOBNEGO sekretu astrololo-demo — demo odcina się jego skasowaniem, bez ruszania
kont głównej aplikacji.

Limit żądań niższy niż w pełnej aplikacji (60/min): demo bywa udostępniane szerzej,
a każde zapytanie sięga do treści baz.

Runbook zaczyna się od ostrzeżenia, bo to jedyna rzecz, którą trzeba pamiętać za
każdym razem: demo pracuje na PRODUKCYJNEJ warstwie danych, więc kto dostaje adres,
czyta oryginalne bazy, a jego wgrania trafiają do produkcyjnego zbioru. Pełna
izolacja wymagałaby osobnej warstwy danych i nie jest dziś zrobiona.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 18:39:48 +02:00
12 changed files with 53 additions and 250 deletions
@@ -1,7 +1,7 @@
# astrodemo — wdrożenie wersji demo (PRE-28/29) # astroklient-demo — wdrożenie wersji demo (PRE-28/29)
Osobna usługa o dwóch funkcjach: **dodanie pliku bazy** i **zapytanie o Osobna usługa o dwóch funkcjach: **dodanie pliku bazy** i **zapytanie o
interpretację urodzeniową**. Opis aplikacji: `services/astrodemo/README.md` interpretację urodzeniową**. Opis aplikacji: `services/astroklient-demo/README.md`
w repo aplikacji. w repo aplikacji.
--- ---
@@ -9,7 +9,7 @@ w repo aplikacji.
## Jak to jest odizolowane ## Jak to jest odizolowane
``` ```
astrodemo → logic-demo → data-demo → /mnt/Tank1/astrololo-demo astroklient-demo → logic-demo → data-demo → /mnt/Tank1/astrololo-demo
└── klientA/ ← pula konta └── klientA/ ← pula konta
└── klientB/ ← pula konta └── klientB/ ← pula konta
``` ```
@@ -18,7 +18,7 @@ astrodemo → logic-demo → data-demo → /mnt/Tank1/astrololo-demo
własną warstwę danych, pracującą na osobnym udziale, pustym na starcie. własną warstwę danych, pracującą na osobnym udziale, pustym na starcie.
Dlaczego osobna jest też **warstwa logiczna**: zna ona jeden adres warstwy danych, Dlaczego osobna jest też **warstwa logiczna**: zna ona jeden adres warstwy danych,
więc astrodemo korzystający z produkcyjnej logiki i tak trafiłby na produkcyjne więc astroklient-demo korzystający z produkcyjnej logiki i tak trafiłby na produkcyjne
bazy. Izolacja musi sięgnąć obu warstw naraz, inaczej nie ma jej wcale. bazy. Izolacja musi sięgnąć obu warstw naraz, inaczej nie ma jej wcale.
**Każde konto ma własną pulę** — swój podkatalog na tym udziale. Konta nie widzą **Każde konto ma własną pulę** — swój podkatalog na tym udziale. Konta nie widzą
@@ -85,8 +85,8 @@ python scripts/make_user.py klientB
``` ```
```bash ```bash
kubectl -n astrololo create secret generic astrololo-astrodemo \ kubectl -n astrololo create secret generic astrololo-demo \
--from-literal=ASTRODEMO_USERS='klientA:scrypt$…,klientB:scrypt$…' \ --from-literal=DEMO_USERS='klientA:scrypt$…,klientB:scrypt$…' \
--from-literal=SESSION_SECRET="$(openssl rand -hex 32)" --from-literal=SESSION_SECRET="$(openssl rand -hex 32)"
``` ```
@@ -96,70 +96,43 @@ powodu uznawać nawzajem swoich sesji.
> **Zdalne unieważnienie w demo działa inaczej niż w pełnej wersji.** Demo nie ma > **Zdalne unieważnienie w demo działa inaczej niż w pełnej wersji.** Demo nie ma
> własnego wolumenu, więc nie ma gdzie trzymać licznika sesji. Zamiast tego: > własnego wolumenu, więc nie ma gdzie trzymać licznika sesji. Zamiast tego:
> usunięcie konta z `ASTRODEMO_USERS` albo zmiana jego hasła **natychmiast ubija jego > usunięcie konta z `DEMO_USERS` albo zmiana jego hasła **natychmiast ubija jego
> otwarte sesje** — bo odcisk poświadczenia wpisany w ciasteczko przestaje pasować. > otwarte sesje** — bo odcisk poświadczenia wpisany w ciasteczko przestaje pasować.
> Rotacja `SESSION_SECRET` wylogowuje wszystkich naraz. > Rotacja `SESSION_SECRET` wylogowuje wszystkich naraz.
### Dodanie konta później ### Dodanie konta później
```bash ```bash
STARE=$(kubectl -n astrololo get secret astrololo-astrodemo -o jsonpath='{.data.ASTRODEMO_USERS}' | base64 -d) STARE=$(kubectl -n astrololo get secret astrololo-demo -o jsonpath='{.data.DEMO_USERS}' | base64 -d)
kubectl -n astrololo create secret generic astrololo-astrodemo \ kubectl -n astrololo create secret generic astrololo-demo \
--from-literal=ASTRODEMO_USERS="${STARE},klientC:scrypt\$…" \ --from-literal=DEMO_USERS="${STARE},klientC:scrypt\$…" \
--dry-run=client -o yaml | kubectl apply -f - --dry-run=client -o yaml | kubectl apply -f -
kubectl -n astrololo rollout restart deploy/astrodemo kubectl -n astrololo rollout restart deploy/astroklient-demo
``` ```
### Odebranie dostępu ### Odebranie dostępu
Usuń wpis z `ASTRODEMO_USERS` tą samą drogą. **Pula zostaje na udziale** — pliki Usuń wpis z `DEMO_USERS` tą samą drogą. **Pula zostaje na udziale** — pliki
klienta nie znikają, tylko przestaje być komu je pokazywać. klienta nie znikają, tylko przestaje być komu je pokazywać.
--- ---
## Krok 3 — tag obrazu ## Krok 3 — wdrożenie
**Zanim wdrożysz.** CI pcha obrazy wyłącznie pod tagiem ośmioznakowym
(`TAG=${GITHUB_SHA::8}`) i **nigdy nie pcha `latest`**. Manifest z `newTag: latest`
zatrzyma się na `ImagePullBackOff`, co wygląda na problem z rejestrem albo siecią,
a jest zwykłym brakiem takiego tagu.
Po zmergowaniu zmian w repozytorium aplikacji i zbudowaniu obrazu:
```bash
TAG=$(git -C ~/git/astrololo rev-parse --short=8 master)
echo "$TAG" # ten sam ciąg musi być widoczny w logu zadania „build"
```
Wpisz go jako `newTag` przy `astrololo-astrodemo` w `kustomization.yaml`. Kolejne
wersje podbija już image-updater sam — pod warunkiem, że obraz jest na jego liście
(`image-updater.yaml`), co ten PR załatwia.
## Krok 4 — wdrożenie
```bash ```bash
kubectl apply -k astrololo kubectl apply -k astrololo
kubectl -n astrololo rollout status deploy/data-demo deploy/logic-demo deploy/astrodemo kubectl -n astrololo rollout status deploy/data-demo deploy/logic-demo deploy/astroklient-demo
``` ```
Sprawdzenie na czas jednej sesji, bez wystawiania na świat: Sprawdzenie na czas jednej sesji, bez wystawiania na świat:
```bash ```bash
kubectl -n astrololo port-forward deploy/astrodemo 8005:8005 kubectl -n astrololo port-forward deploy/astroklient-demo 8005:8005
``` ```
Wejście z zewnątrz jest już w `ingress.yaml`: host **astrodemo.czernobog.pl**, Wejście z zewnątrz wymaga reguły w `ingress.yaml` — osobny host albo ścieżka.
z przekierowaniem z http na https i tym samym certyfikatem co astrololo
(`tls.yaml` obejmuje 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.
Pozostaje wpis DNS: **astrodemo.czernobog.pl musi wskazywać na ten sam adres co
astrololo.czernobog.pl**. Bez tego Traefik nigdy nie zobaczy żądania.
**Celowo nie zakładam tego za Ciebie**: to decyzja, pod jakim adresem świat **Celowo nie zakładam tego za Ciebie**: to decyzja, pod jakim adresem świat
zobaczy demo. zobaczy demo.
@@ -208,8 +181,8 @@ techniczną, a decyzja, które bazy biorą udział w interpretacji, należy do C
## Odcięcie całego demo ## Odcięcie całego demo
```bash ```bash
kubectl -n astrololo scale deploy/astrodemo --replicas=0 kubectl -n astrololo scale deploy/astroklient-demo --replicas=0
``` ```
Pule i dane zostają. Skasowanie sekretu `astrololo-astrodemo` zatrzyma pod (nie wstanie Pule i dane zostają. Skasowanie sekretu `astrololo-demo` zatrzyma pod (nie wstanie
bez niego) i to też jest zachowanie zamierzone. bez niego) i to też jest zachowanie zamierzone.
+7 -98
View File
@@ -29,62 +29,14 @@ Runbook: **[README-pliki.md](README-pliki.md)**. Ekran „Pliki" wymaga zapisu d
udziału z bazami, więc znosi gwarancję z DAN-25, że baz nie da się zmienić przez udziału z bazami, więc znosi gwarancję z DAN-25, że baz nie da się zmienić przez
NFS. Co zostaje z zabezpieczeń i jak to wdrożyć — w runbooku. NFS. Co zostaje z zabezpieczeń i jak to wdrożyć — w runbooku.
## astrodemo — wersja demonstracyjna (PRE-28/29) ## astroklient-demo — wersja demo (PRE-28)
Osobna usługa o dwóch funkcjach: dodanie pliku i pytanie o interpretację Osobna usługa o dwóch funkcjach. Runbook: **[README-astroklient-demo.md](README-astroklient-demo.md)**.
urodzeniową. Runbook: **[README-astrodemo.md](README-astrodemo.md)**.
Ma **własną warstwę danych i logiki** (`astrodemo-stack.yaml`) oraz własny udział Ma **własną warstwę logiczną i własną warstwę danych** na osobnym udziale
NFS, a każde konto dostaje w nim odrębną, niewidoczną dla pozostałych pulę plików `astrololo-demo` — oryginalne bazy są dla demo nieosiągalne. Każde konto demo ma
(PRE-29). Nie sięga do produkcyjnych baz. własną, niewidoczną dla pozostałych pulę plików, a jego pulę da się później
przenieść do pełnej aplikacji jako jeden katalog.
Konta są osobne (sekret `astrololo-astrodemo`), więc usługę odcina się jedną
zmianą, bez ruszania kont głównej aplikacji. Wchodzi się przez własny host
`astrodemo.czernobog.pl` — nie przez ścieżkę pod adresem astrololo, bo wspólne
pochodzenie oznaczałoby wspólne ciasteczka i wzajemne wylogowywanie.
## ⚠️ Wymóg węzłów: klient NFS
Wszystkie warstwy montują udziały z NAS-a, więc **każdy węzeł, na którym może
wylądować pod, musi mieć klienta NFS**. Bez niego kubelet nie zamontuje wolumenu:
```
mount: ... bad option; for several filesystems (e.g. nfs, cifs) you might need
a /sbin/mount.<type> helper program
```
Ten komunikat **nie oznacza problemu z udziałem ani z uprawnieniami** — serwer
w ogóle nie został zapytany. Jądro nie znalazło programu pomocniczego
`/sbin/mount.nfs`.
### Sprawdzenie
```bash
for N in 192.168.1.73 192.168.1.80 192.168.1.81; do
printf "%-15s " "$N"
ssh hammer@$N 'test -x /sbin/mount.nfs && echo MA-KLIENTA || echo BRAK-KLIENTA'
done
```
### Instalacja
```bash
ssh hammer@<węzeł> 'sudo apt-get update && sudo apt-get install -y nfs-common'
```
> **Na WSZYSTKICH węzłach, nie tylko na tym, gdzie pod stoi teraz.** Braku na
> pozostałych nie widać, dopóki scheduler tam czegoś nie przeniesie — a wtedy
> awaria wygląda na nagłą, choć przyczyna leżała od dawna. Dokładnie tak wyszło
> za pierwszym razem: pody działały miesiącami na jednym węźle, aż zejście do
> zera replik przy innej naprawie przeplanowało je gdzie indziej.
### Skąd wiadomo, że to TO
| komunikat | co znaczy |
|---|---|
| `bad option ... mount.<type> helper program` | **brak `nfs-common` na węźle** — serwer niepytany |
| `access denied by server while mounting` | serwer odmawia: eksport nieprzeładowany, węzła nie ma na liście `hosts`, albo udział wyłączony |
| `Permission denied` przy zapisie | montowanie działa, brakuje praw — patrz `mapall_user` i właściciel katalogu |
## ⚠️ Sekret `astrololo-auth` — utwórz PRZED wdrożeniem ## ⚠️ Sekret `astrololo-auth` — utwórz PRZED wdrożeniem
@@ -104,54 +56,11 @@ read -rs -p "Hasło do aplikacji (APP_PASSWORD): " APP_PASSWORD; echo
kubectl -n astrololo create secret generic astrololo-auth \ kubectl -n astrololo create secret generic astrololo-auth \
--from-literal=APP_PASSWORD="$APP_PASSWORD" \ --from-literal=APP_PASSWORD="$APP_PASSWORD" \
--from-literal=INTERNAL_TOKEN="$(openssl rand -hex 32)" \ --from-literal=INTERNAL_TOKEN="$(openssl rand -hex 32)"
--from-literal=SESSION_SECRET="$(openssl rand -hex 32)"
unset APP_PASSWORD unset APP_PASSWORD
``` ```
`SESSION_SECRET` podpisuje ciasteczka sesji (LOG-34). **Pod bez niego celowo nie
wstanie**: usługa z kontami, ale bez klucza, nie odróżniłaby ważnej sesji od
podrobionej. Nikt go nigdy nie musi oglądać.
### ⚠️ Masz już sekret sprzed LOG-34? Dołóż klucz, nie twórz od nowa
Komenda wyżej zakłada sekret **od zera**. Jeśli `astrololo-auth` już istnieje,
merge manifestu sam klucza nie dołoży — pod zgłosi wtedy:
```
Error: couldn't find key SESSION_SECRET in Secret astrololo/astrololo-auth
```
Dokładamy klucz, nie ruszając pozostałych:
```bash
kubectl -n astrololo patch secret astrololo-auth --type=merge \
-p "{\"stringData\":{\"SESSION_SECRET\":\"$(openssl rand -hex 32)\"}}"
kubectl -n astrololo rollout restart deploy/presentation
```
Sprawdzenie, że komplet kluczy jest na miejscu (bez pokazywania wartości):
```bash
kubectl -n astrololo get secret astrololo-auth -o jsonpath='{.data}' \
| tr ',' '\n' | grep -o '"[A-Z_]*"'
```
Oczekiwane: `APP_PASSWORD`, `INTERNAL_TOKEN`, `SESSION_SECRET`.
> `--type=merge` ze `stringData` **dokłada albo nadpisuje** i nie wymaga, żeby
> klucz wcześniej istniał — w odróżnieniu od JSON Patch z `op: replace`, który
> na brakującej ścieżce po prostu odmawia. Ta sama komenda służy więc i do
> dołożenia, i do rotacji.
### Rotacja klucza sesji
**Wylogowuje WSZYSTKICH.** To nie usterka, tylko awaryjny wyłącznik: gdy
podejrzewasz, że ktoś przechwycił cudzą sesję, podmiana klucza unieważnia je
wszystkie naraz. Komenda ta sama, co dołożenie wyżej.
`INTERNAL_TOKEN` jest losowany i **nikt go nigdy nie musi oglądać** — służy tylko `INTERNAL_TOKEN` jest losowany i **nikt go nigdy nie musi oglądać** — służy tylko
usługom do rozmowy między sobą. `APP_PASSWORD` wpisujesz w przeglądarce usługom do rozmowy między sobą. `APP_PASSWORD` wpisujesz w przeglądarce
(użytkownik: `astrololo`, zmienny przez `APP_USER` w `presentation.yaml`). (użytkownik: `astrololo`, zmienny przez `APP_USER` w `presentation.yaml`).
@@ -1,11 +1,11 @@
# Warstwa danych i logiki WYŁĄCZNIE dla wersji demo (PRE-29). # Warstwa danych i logiki WYŁĄCZNIE dla wersji demo (PRE-29).
# #
# DLACZEGO OSOBNY KOMPLET, A NIE WSPÓŁDZIELONY. Warstwa logiczna zna JEDEN adres # DLACZEGO OSOBNY KOMPLET, A NIE WSPÓŁDZIELONY. Warstwa logiczna zna JEDEN adres
# warstwy danych, więc astrodemo korzystający z produkcyjnej logiki i tak trafiłby # warstwy danych, więc astroklient-demo korzystający z produkcyjnej logiki i tak trafiłby
# na produkcyjne bazy. Izolacja demo musi więc sięgnąć obu warstw naraz, inaczej # na produkcyjne bazy. Izolacja demo musi więc sięgnąć obu warstw naraz, inaczej
# nie ma jej wcale. # nie ma jej wcale.
# #
# Udział `astrololo-astrodemo` jest PUSTY na starcie i nigdy nie zawiera oryginalnych # Udział `astrololo-demo` jest PUSTY na starcie i nigdy nie zawiera oryginalnych
# baz. Każde konto demo dostaje w nim własny podkatalog (pulę) — patrz PRE-29. # baz. Każde konto demo dostaje w nim własny podkatalog (pulę) — patrz PRE-29.
--- ---
apiVersion: apps/v1 apiVersion: apps/v1
@@ -1,32 +1,32 @@
# astrodemo — wersja demonstracyjna (PRE-28). # astroklient-demo — wersja demonstracyjna (PRE-28).
# #
# Osobna usługa o DWÓCH funkcjach: dodanie pliku bazy i zapytanie o interpretację # Osobna usługa o DWÓCH funkcjach: dodanie pliku bazy i zapytanie o interpretację
# urodzeniową. Pozostałe funkcje nie są tu ukryte — nie ma ich w obrazie. # urodzeniową. Pozostałe funkcje nie są tu ukryte — nie ma ich w obrazie.
# #
# IZOLACJA (PRE-29): astrodemo ma WŁASNĄ warstwę logiczną i WŁASNĄ warstwę # IZOLACJA (PRE-29): astroklient-demo ma WŁASNĄ warstwę logiczną i WŁASNĄ warstwę
# danych (astrodemo-stack.yaml), pracujące na osobnym, pustym na starcie # danych (astroklient-demo-stack.yaml), pracujące na osobnym, pustym na starcie
# udziale. Oryginalne bazy interpretacyjne są dla demo NIEOSIĄGALNE. # udziale. Oryginalne bazy interpretacyjne są dla demo NIEOSIĄGALNE.
# #
# Wewnątrz demo każde konto ma własną pulę plików — swój podkatalog na tym # Wewnątrz demo każde konto ma własną pulę plików — swój podkatalog na tym
# udziale — niewidoczną dla pozostałych kont. Dzięki temu demo można rozdawać # udziale — niewidoczną dla pozostałych kont. Dzięki temu demo można rozdawać
# szeroko, a pliki jednego klienta da się później przenieść do pełnej aplikacji # szeroko, a pliki jednego klienta da się później przenieść do pełnej aplikacji
# jako jeden katalog (patrz README-astrodemo.md). # jako jeden katalog (patrz README-astroklient-demo.md).
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: astrodemo name: astroklient-demo
namespace: astrololo namespace: astrololo
spec: spec:
replicas: 1 replicas: 1
selector: selector:
matchLabels: { app: astrodemo } matchLabels: { app: astroklient-demo }
template: template:
metadata: metadata:
labels: { app: astrodemo } labels: { app: astroklient-demo }
spec: spec:
containers: containers:
- name: astrodemo - name: astroklient-demo
image: gitea.czernobog.pl/gitea/astrololo-astrodemo:latest image: gitea.czernobog.pl/gitea/astrololo-astroklient-demo:latest
ports: [{ containerPort: 8005 }] ports: [{ containerPort: 8005 }]
env: env:
# WŁASNA warstwa logiczna, wskazująca na WŁASNĄ warstwę danych. # WŁASNA warstwa logiczna, wskazująca na WŁASNĄ warstwę danych.
@@ -35,14 +35,14 @@ spec:
- name: LOGIC_URL - name: LOGIC_URL
value: "http://logic-demo:8001" value: "http://logic-demo:8001"
# Konto demo — WŁASNE, nie astrololo-auth. Sekret tworzony POZA repo # Konto demo — WŁASNE, nie astrololo-auth. Sekret tworzony POZA repo
# (jak pozostałe), patrz README-astrodemo.md. # (jak pozostałe), patrz README-astroklient-demo.md.
# KONTA DEMO — lista `login:sekret` po przecinku. Każde konto ma # KONTA DEMO — lista `login:sekret` po przecinku. Każde konto ma
# WŁASNĄ, niewidoczną dla pozostałych pulę baz (PRE-29), więc jedno # WŁASNĄ, niewidoczną dla pozostałych pulę baz (PRE-29), więc jedno
# wspólne konto oznaczałoby klientów oglądających swoje wgrania # wspólne konto oznaczałoby klientów oglądających swoje wgrania
# nawzajem. Sekrety najlepiej jako hash scrypt. # nawzajem. Sekrety najlepiej jako hash scrypt.
- name: ASTRODEMO_USERS - name: DEMO_USERS
valueFrom: valueFrom:
secretKeyRef: { name: astrololo-astrodemo, key: ASTRODEMO_USERS } secretKeyRef: { name: astrololo-demo, key: DEMO_USERS }
# Token międzywarstwowy i klucz łącza — TE SAME co prezentacja: # Token międzywarstwowy i klucz łącza — TE SAME co prezentacja:
# demo nie jest furtką omijającą ochronę warstwy logicznej. # demo nie jest furtką omijającą ochronę warstwy logicznej.
- name: INTERNAL_TOKEN - name: INTERNAL_TOKEN
@@ -59,7 +59,7 @@ spec:
# znaczyłby, że sesja z demo bywa ważna tam, gdzie nie powinna. # znaczyłby, że sesja z demo bywa ważna tam, gdzie nie powinna.
- name: SESSION_SECRET - name: SESSION_SECRET
valueFrom: valueFrom:
secretKeyRef: { name: astrololo-astrodemo, key: SESSION_SECRET } secretKeyRef: { name: astrololo-demo, key: SESSION_SECRET }
# Za Ingressem bezpośrednim rozmówcą jest pod Traefika. Bez tego limit # Za Ingressem bezpośrednim rozmówcą jest pod Traefika. Bez tego limit
# liczyłby WSZYSTKICH do jednego wiadra i pierwsza osoba, która go # liczyłby WSZYSTKICH do jednego wiadra i pierwsza osoba, która go
# wyklika, odcięłaby pozostałe. # wyklika, odcięłaby pozostałe.
@@ -76,11 +76,11 @@ spec:
apiVersion: v1 apiVersion: v1
kind: Service kind: Service
metadata: metadata:
name: astrodemo name: astroklient-demo
namespace: astrololo namespace: astrololo
spec: spec:
# ClusterIP — wejście z zewnątrz wyłącznie przez Ingress po https, tak samo # ClusterIP — wejście z zewnątrz wyłącznie przez Ingress po https, tak samo
# jak prezentacja. Druga, nieszyfrowana droga byłaby obejściem PRE-16. # jak prezentacja. Druga, nieszyfrowana droga byłaby obejściem PRE-16.
type: ClusterIP type: ClusterIP
selector: { app: astrodemo } selector: { app: astroklient-demo }
ports: [{ port: 8005, targetPort: 8005 }] ports: [{ port: 8005, targetPort: 8005 }]
+2 -2
View File
@@ -36,8 +36,8 @@ spec:
imageName: gitea.czernobog.pl/gitea/astrololo-render imageName: gitea.czernobog.pl/gitea/astrololo-render
# Wersja demo (PRE-28). Obraz, którego nie ma na tej liście, NIGDY się nie # Wersja demo (PRE-28). Obraz, którego nie ma na tej liście, NIGDY się nie
# podbije, choćby CI go budowało — tak przez chwilę wisiał render na :latest. # podbije, choćby CI go budowało — tak przez chwilę wisiał render na :latest.
- alias: astrodemo - alias: astroklient-demo
imageName: gitea.czernobog.pl/gitea/astrololo-astrodemo imageName: gitea.czernobog.pl/gitea/astrololo-astroklient-demo
commonUpdateSettings: commonUpdateSettings:
updateStrategy: newest-build updateStrategy: newest-build
writeBackConfig: writeBackConfig:
-43
View File
@@ -73,46 +73,3 @@ spec:
pathType: Prefix pathType: Prefix
backend: backend:
service: { name: presentation, port: { number: 8000 } } service: { name: presentation, port: { number: 8000 } }
---
# ── astrodemo ──────────────────────────────────────────────────────────────
# Osobny host, nie ścieżka pod astrololo.czernobog.pl. Ścieżka („/demo") dzieliłaby
# z pełną aplikacją pochodzenie w rozumieniu przeglądarki, czyli i ciasteczka:
# wejście do jednej ruszałoby sesję w drugiej. Osobny host trzyma je rozdzielnie.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: astrodemo
namespace: astrololo
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.middlewares: astrololo-security-headers@kubernetescrd
spec:
tls:
- hosts: [astrodemo.czernobog.pl]
secretName: astrololo-tls # ten sam certyfikat obejmuje oba hosty (tls.yaml)
rules:
- host: astrodemo.czernobog.pl
http:
paths:
- path: /
pathType: Prefix
backend:
service: { name: astrodemo, port: { number: 8005 } }
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: astrodemo-redirect
namespace: astrololo
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.middlewares: astrololo-redirect-https@kubernetescrd
spec:
rules:
- host: astrodemo.czernobog.pl
http:
paths:
- path: /
pathType: Prefix
backend:
service: { name: astrodemo, port: { number: 8005 } }
+7 -7
View File
@@ -5,20 +5,20 @@ resources:
- postgres.yaml # lustro baz Excela w SQL (DAN-28) — sekret astrololo-postgres POZA repo - postgres.yaml # lustro baz Excela w SQL (DAN-28) — sekret astrololo-postgres POZA repo
- data.yaml - data.yaml
- logic.yaml - logic.yaml
- astrodemo-stack.yaml # OSOBNA warstwa danych i logiki dla demo (PRE-29)
- astrodemo.yaml # wersja demo (PRE-28) — sekret astrololo-astrodemo POZA repo
- presentation.yaml - presentation.yaml
- astroklient-demo-stack.yaml # OSOBNA warstwa danych i logiki dla demo (PRE-29)
- astroklient-demo.yaml # wersja demo (PRE-28) — sekret astrololo-demo POZA repo
- render.yaml # składanie raportu PDF (PRE-24), osobny obraz z TeX Live - render.yaml # składanie raportu PDF (PRE-24), osobny obraz z TeX Live
- tls.yaml # certyfikat z własnego CA (wymaga cert-managera) - tls.yaml # certyfikat z własnego CA (wymaga cert-managera)
- ingress.yaml # wejście po https + przekierowanie z http - ingress.yaml # wejście po https + przekierowanie z http
images: images:
- name: gitea.czernobog.pl/gitea/astrololo-data - name: gitea.czernobog.pl/gitea/astrololo-data
newTag: 10ade555 newTag: ee3c515d
- name: gitea.czernobog.pl/gitea/astrololo-logic - name: gitea.czernobog.pl/gitea/astrololo-logic
newTag: 10ade555 newTag: ee3c515d
- name: gitea.czernobog.pl/gitea/astrololo-render - name: gitea.czernobog.pl/gitea/astrololo-render
newTag: latest newTag: latest
- name: gitea.czernobog.pl/gitea/astrololo-astroklient-demo
newTag: latest
- name: gitea.czernobog.pl/gitea/astrololo-presentation - name: gitea.czernobog.pl/gitea/astrololo-presentation
newTag: 10ade555 newTag: ee3c515d
- name: gitea.czernobog.pl/gitea/astrololo-astrodemo
newTag: fd79513c
-7
View File
@@ -32,13 +32,6 @@ spec:
secretKeyRef: { name: astrololo-auth, key: INTERNAL_TOKEN } secretKeyRef: { name: astrololo-auth, key: INTERNAL_TOKEN }
- name: APP_USER - name: APP_USER
value: "astrololo" value: "astrololo"
# Klucz podpisu ciasteczek sesji (LOG-34). WYMAGANY — pod bez niego
# celowo nie wstaje: usługa z kontami, ale bez klucza, nie umiałaby
# odróżnić ważnej sesji od podrobionej. Rotacja tego klucza WYLOGOWUJE
# WSZYSTKICH, i tak ma być — to jest awaryjny wyłącznik.
- name: SESSION_SECRET
valueFrom:
secretKeyRef: { name: astrololo-auth, key: SESSION_SECRET }
- name: RATE_LIMIT_PER_MIN - name: RATE_LIMIT_PER_MIN
value: "120" # 0 = bez limitu value: "120" # 0 = bez limitu
# Aplikacja stoi za Ingressem, więc bezpośrednim rozmówcą jest zawsze # Aplikacja stoi za Ingressem, więc bezpośrednim rozmówcą jest zawsze
-3
View File
@@ -59,9 +59,6 @@ spec:
commonName: astrololo.czernobog.pl commonName: astrololo.czernobog.pl
dnsNames: dnsNames:
- astrololo.czernobog.pl - astrololo.czernobog.pl
# Jeden certyfikat na oba hosty. Osobny wymagałby osobnego sekretu i osobnego
# odnawiania, a to ten sam klaster i ten sam wystawca.
- astrodemo.czernobog.pl
duration: 2160h # 90 dni duration: 2160h # 90 dni
renewBefore: 720h # 30 dni zapasu renewBefore: 720h # 30 dni zapasu
privateKey: { algorithm: ECDSA, size: 256, rotationPolicy: Always } privateKey: { algorithm: ECDSA, size: 256, rotationPolicy: Always }
-13
View File
@@ -31,19 +31,6 @@ spec:
# Where the librarian sends THIS bot's results/pongs back to (its own # Where the librarian sends THIS bot's results/pongs back to (its own
# NodePort). Lets one librarian serve both bots - see deploy-bot.yaml. # NodePort). Lets one librarian serve both bots - see deploy-bot.yaml.
- { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32442" } - { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32442" }
# Self-hosted models (Ollama). No API key - the endpoint IS the
# configuration, and the backend stays unselectable while unset.
# Pick a model at runtime with: $gadaj_teraz ollama <model>
# ($modele_ai lists what the server actually has pulled).
- { name: CONJURER_OLLAMA_URL, value: "http://192.168.1.72:11434" }
# The server currently has exactly one model pulled (verified via
# /v1/models): gemma4:e2b. Without this the built-in default
# (llama3.1:8b) would be requested and every reply would fail.
- { name: CONJURER_OLLAMA_MODEL, value: "gemma4:e2b" }
# Self-hosted generation is far slower than a hosted API, especially
# the first request after the model is evicted from VRAM. Applies to
# every backend, so keep it only as high as you actually need.
- { name: CONJURER_AI_TIMEOUT_SECONDS, value: "240" }
volumeMounts: volumeMounts:
- { name: data, mountPath: /data } - { name: data, mountPath: /data }
- { name: netrc, mountPath: /secrets, readOnly: true } - { name: netrc, mountPath: /secrets, readOnly: true }
-13
View File
@@ -51,19 +51,6 @@ spec:
# query and answers results/pongs HERE - so it serves this bot AND the # query and answers results/pongs HERE - so it serves this bot AND the
# test bot from one instance, no CONJURER_MAIN_BOT repointing needed. # test bot from one instance, no CONJURER_MAIN_BOT repointing needed.
- { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32443" } - { name: CONJURER_SELF_CALLBACK, value: "http://192.168.1.73:32443" }
# Self-hosted models (Ollama). No API key - the endpoint IS the
# configuration, and the backend stays unselectable while unset.
# Pick a model at runtime with: $gadaj_teraz ollama <model>
# ($modele_ai lists what the server actually has pulled).
- { name: CONJURER_OLLAMA_URL, value: "http://192.168.1.72:11434" }
# The server currently has exactly one model pulled (verified via
# /v1/models): gemma4:e2b. Without this the built-in default
# (llama3.1:8b) would be requested and every reply would fail.
- { name: CONJURER_OLLAMA_MODEL, value: "gemma4:e2b" }
# Self-hosted generation is far slower than a hosted API, especially
# the first request after the model is evicted from VRAM. Applies to
# every backend, so keep it only as high as you actually need.
- { name: CONJURER_AI_TIMEOUT_SECONDS, value: "240" }
volumeMounts: volumeMounts:
- { name: data, mountPath: /data } - { name: data, mountPath: /data }
- { name: netrc, mountPath: /secrets, readOnly: true } - { name: netrc, mountPath: /secrets, readOnly: true }
+2 -2
View File
@@ -8,9 +8,9 @@ resources:
- deploy-bot-backup.yaml - deploy-bot-backup.yaml
images: images:
- name: gitea.czernobog.pl/gitea/conjurer-librarian - name: gitea.czernobog.pl/gitea/conjurer-librarian
newTag: fdc1fa18 newTag: d0c7ab61
- name: gitea.czernobog.pl/gitea/conjurer-bot - name: gitea.czernobog.pl/gitea/conjurer-bot
newTag: fdc1fa18 newTag: d0c7ab61
# Production bot channel - only bumped when a [deploy]-tagged build appears. # Production bot channel - only bumped when a [deploy]-tagged build appears.
# Bootstrapped to fbd1ec9f: that's the image the first [deploy] build (merge # Bootstrapped to fbd1ec9f: that's the image the first [deploy] build (merge
# of conjurer#20) promoted to conjurer-bot-deploy. From here the image-updater # of conjurer#20) promoted to conjurer-bot-deploy. From here the image-updater