homelab-codex-ws/kb/incidents/2026-08-26-mail-sync-20-dni-ciszy.md
oskar 4fa10f0a72 docs(kb): incydent 20 dni ciszy kb-mail-sync + session log
Dwa niezalezne root cause: PermissionError na save_eml (archiwum
root:root po sudo-runach 06.08) + fleet-prometheus nigdy nie dostal
/-/reload po dodaniu regul kb-mail-sync.yml/kb-ingest.yml (zylo tylko
fleet-liveness). Naprawa: chown archiwum + 2 tick recovery (548 kopert,
0 bledow) + reload Prometheusa z weryfikacja lancucha alertowego
end-to-end (brain-watchdog->Telegram wpiety poprawnie).
2026-08-26 20:39:45 +02:00

153 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
okf: "0.1"
type: incident
visibility: private
status: active
updated: 2026-08-26
links:
- ../audits/mail-sync-2026-08-06.md
- ../services/job-mail-imap-sync.md
- ../runbooks/mail-sync-run.md
- ../../docs/sessions/2026-08-06-kb-mail-sync-live.md
- ../../docs/sessions/2026-08-26-kb-incydent-mailsync.md
---
# Incydent: `kb-mail-sync` bez zapisu przez 20 dni, niewykryty — 2026-08-26
**Status:** oba root cause ustalone i naprawione. Przyrostówka odzyskana, alerting po raz
pierwszy realnie wpięty (wcześniej istniał tylko w repo, nie w runtime).
**Dotknięty serwis:** `mail-imap-sync` (job) @ PIHA + `fleet-prometheus` @ VPS.
**Klasa:** dwa niezależne błędy nakładające się w czasie — awaria zapisu (uprawnienia) +
martwy monitoring (config nigdy nie przeładowany). Osobno każdy byłby wykrywalny; razem
dały 20 dni ciszy bez żadnego sygnału.
---
## 1. TL;DR
`kb-mail-sync.timer` tykał godzinowo od uruchomienia (2026-08-06 18:01, patrz
[docs/sessions/2026-08-06-kb-mail-sync-live.md](../../docs/sessions/2026-08-06-kb-mail-sync-live.md))
bez ani jednego kolejnego udanego zapisu koperty aż do 2026-08-26. Poller "żył" — proces
startował, łączył się z IMAP, kursor w `mail_sync_state` się nie ruszał, bo `save_eml` dostawał
`PermissionError` na każdej próbie zapisu. Kursor nie przeskoczył niezapisanej wiadomości — to
zadziałało zgodnie z projektem (zero utraty poczty), ale oznaczało też, że failure był cichy: bez
crasha, bez zmiany stanu widocznej z zewnątrz poza rosnącym opóźnieniem.
Powinien to złapać alert `KbMailSyncStale` (reguła w repo od 2026-08-06) — ale nie złapał, bo
`fleet-prometheus` na VPS nigdy nie dostał `/-/reload` po dodaniu tego pliku reguł. Przez cały
czas żyła wyłącznie grupa `fleet-liveness` sprzed czerwca. Wykryto ręcznie, przy sanity checku po
3 tygodniach przerwy operatorskiej — nie przez monitoring.
---
## 2. Root cause #1 — uprawnienia katalogów archiwum
`~/kb/mail/archive/{gmail,fastmail}/2026/08/` powstały jako `root:root` — utworzone przez
ręczne `sudo`-runy z 2026-08-06 (pierwsze uruchomienia przed włączeniem timera, patrz runbook
[mail-sync-run.md](../runbooks/mail-sync-run.md), sekcja o `sudo` do odczytu `.env`). Timer
uruchamia job jako `User=oskar` (po zrzuceniu uprawnień z jednostki systemd) — `save_eml` w
`packages/kb-mail` dostawał `PermissionError` przy próbie zapisu `.eml` do katalogu należącego do
roota, na każdym z 480 ticków od 2026-08-06 18:01 do naprawy.
Design "kursor nie przeskakuje niezapisanej wiadomości" ([pkg-kb-mail.md](../services/pkg-kb-mail.md))
zadziałał dokładnie tak jak zamierzono: zero utraty poczty, folder stał w miejscu zamiast
przeskoczyć błąd i zostawić dziurę w korpusie. Cena tego bezpieczeństwa: bez monitoringu wygląda
identycznie jak "brak nowej poczty" — legalny stan mailboxa, którego runbook świadomie **nie**
traktuje jako alarmowy (patrz decyzja w [kb-mail-sync.yml](../../services/fleet-prometheus/rules/kb-mail-sync.yml)
o odrzuceniu progu na "brak nowej poczty").
## 3. Root cause #2 — dlaczego 20 dni ciszy, nie 6 godzin
Reguła `KbMailSyncStale` (próg 6h, `for: 5m`) i `kb-ingest.yml` leżały w repo od 2026-08-06.
Scrape config PIHA (`fleet-node`/`piha` → `100.108.208.3:9100`) był poprawny od czerwca — target
node_exportera PIHA już był zdefiniowany. Ale `fleet-prometheus` na VPS nigdy nie dostał
`POST /-/reload` po tym, jak te dwa pliki reguł wylądowały w bind mouncie `rules/`. W runtime
żyła wyłącznie grupa `fleet-liveness`, załadowana przy ostatnim restarcie kontenera (czerwiec).
Alert `KbMailSyncStale` nie istniał operacyjnie — mógł mieć idealną logikę i wciąż nic by nie
wysłał, bo Prometheus nie wiedział o jego istnieniu.
Dwa błędy nałożyły się: gdyby monitoring żył, alert wystrzeliłby po ~6h od pierwszego
`PermissionError` (2026-08-07 ok. 00:00), nie po 20 dniach. Gdyby zapis działał, martwy
monitoring nie miałby czego przegapić.
---
## 4. Naprawa
**Zapis (2026-08-26, przez CC z SOLARII, worktree recon+fix na PIHA):**
1. `chown -R oskar:oskar ~/kb/mail/archive/{gmail,fastmail}/2026/08` na PIHA.
2. Ręczny tick #1: `170 inserted / 379 perm-errors` — perm-errors to zaległe próby sprzed
chowna w tej samej partii (kolejka nie czyściła się między nieudanymi próbami).
3. Ręczny tick #2: `378 inserted / 155 archive_exists, errors=0` — pełne odzyskanie, kursor
dogonił IMAP. Łącznie 548 zaległych kopert wchłonięte bez strat.
**Monitoring (2026-08-26, przez CC z SOLARII, SSH na VPS):**
1. `promtool check rules` na `kb-mail-sync.yml` w kontenerze `fleet-prometheus` — OK,
plik był już poprawny składniowo (potwierdzenie, że problem był czysto operacyjny, nie
błąd w regule).
2. `POST http://100.95.58.48:9090/-/reload` — 200, `/api/v1/rules` od razu pokazał wszystkie
trzy grupy: `fleet-liveness`, `kb-ingest`, `kb-mail-sync`.
3. Weryfikacja łańcucha end-to-end:
- `kb_mail_sync_last_success_timestamp{node="piha"}` — scrape'owana, świeża (~5,8 min).
- `/api/v1/alerts` — pusto; reguła `KbMailSyncStale` w stanie `inactive`/`health: ok`
(nigdy nie zdążyła nic zaalarmować na starych danych — pierwsza ewaluacja po reloadzie
zastała już świeżą metrykę).
- `brain-watchdog` @ PIHA — `PROMETHEUS_URL` w `.env` poprawnie wskazuje na
`http://100.95.58.48:9090`, kontener `healthy` od 2 tygodni, brak wpisów o poll-failure
w logach → droga do Telegrama wpięta.
Żadna zmiana w repo nie była potrzebna dla naprawy monitoringu — config `rules/*.yml` i
`scrape_configs` były poprawne od dawna, brakowało wyłącznie `/-/reload` w runtime.
---
## 5. Rekomendacje
**R1 (proces, do CC) — utwardzić własność katalogów po ręcznym `sudo`-runie.** Po każdym
ręcznym uruchomieniu `mail-imap-sync` przez `sudo` (np. do odczytu `.env` 600 root:root, patrz
runbook): albo `chown -R oskar:oskar` na `archive/` od razu po runie, albo wariant `sudo`
zachowujący ownera docelowych katalogów. Docelowo `save_eml`/definicja jednostki systemd
powinny wymuszać poprawnego ownera tworzonych katalogów niezależnie od tego, kto je stworzył
(np. `umask`/`chown` przy starcie joba, albo katalogi tworzone z wyprzedzeniem z właściwymi
uprawnieniami zamiast `mkdir -p` przy pierwszym zapisie).
**R2 (proces, do CC) — dopisać `/-/reload` do procedury deployu reguł Prometheusa.** Dodanie
pliku reguł do `services/fleet-prometheus/rules/` bez reloadu jest w tej chwili niewidoczne —
`git diff` pokazuje zmianę, deploy przechodzi zielono, a Prometheus i tak jej nie widzi aż do
następnego restartu kontenera. Brakujący krok reload trzeba dopisać do runbooka deployu
fleet-prometheus (do zlokalizowania/utworzenia: `fleet-prometheus-deploy.md`), najlepiej jako
automatyczny krok w `scripts/deploy/deploy.sh` dla tego serwisu, nie tylko jako notatka w
dokumentacji.
**R3 (bezpieczeństwo, pilne) — rotacja sekretów po wycieku w transkrypcie.** `TG_TOKEN`
brain-watchdoga wypłynął w outpucie sesji 2026-08-26 (`cat .env` przez SSH w celach
diagnostycznych) — **czwarty udokumentowany przypadek tej klasy** (poprzedni: hasło
`kb-postgres`, 2026-08-05/06, patrz [docs/sessions/2026-08-06-kb-mail-sync-live.md](../../docs/sessions/2026-08-06-kb-mail-sync-live.md)
sekcja "Otwarte"). Do rotacji łącznie: `TG_TOKEN` (brain-watchdog) + hasło `kb-postgres`
(WISI) — oba są zaległe z poprzednich incydentów tej samej klasy i warto zrobić je w jednej
sesji zamiast kolejnych osobnych.
---
## 6. Nie w zakresie tej naprawy (follow-upy niezmienione z 2026-08-06)
Bez zmian względem stanu z poprzedniej sesji — patrz
[docs/sessions/2026-08-06-kb-mail-sync-live.md](../../docs/sessions/2026-08-06-kb-mail-sync-live.md)
"Otwarte":
- Fix `UID SEARCH ALL` na duże foldery (crash na kontach >`_MAXLINE`).
- Załączniki PDF z maili.
- Charset/mojibake w co najmniej 12 kopertach.
- NUL w nagłówkach `jsonb` (`gmail-header-backfill`/`bulk-import`).
---
## 7. Stan końcowy
- Kursor `mail_sync_state` dogonił IMAP na obu kontach, 548 zaległych kopert wchłonięte,
0 błędów w ostatnim ticku.
- `fleet-prometheus` ma żywe wszystkie trzy grupy reguł; `KbMailSyncStale` faktycznie
monitoruje po raz pierwszy od wdrożenia 2026-08-06.
- Łańcuch metryka → reguła → alert → `brain-watchdog` → Telegram zweryfikowany end-to-end,
bez dziur.
- Otwarte: R1R3 powyżej (poza zakresem tej sesji, do osobnych tasków).