Plan: W3+W4 — Pełne CI/CD i deployment compliance (bms-1)

Tracking issue: #3171 (closed 2026-07-09 — see reconciliation below, several gaps outlived the closure) Powiązane: #3172 (artnet elimination), #3178 (monitoring reorg) Architektura: docs/pinbox24-w3-w4-architecture-spec.md Ostatnia aktualizacja: 2026-07-11 Tracker post-sesji 2026-07-08: #3425


Status update — 2026-07-11 reconciliation

Issue #3171 was closed 2026-07-09, but that closure only covered Fazy 0/1/2 as originally scoped. A 2026-07-09 W3 cascading-outage incident (see docs/incidents/2026-07-09-w3-cascading-outage-postmortem.md) and subsequent sessions did substantial additional work not reflected in the phases below. Reconciled against live repo/issue state 2026-07-11:

Confirmed DONE (verified against current code/issues, not just assumed from the phase table):

  • Faza 1 (mailgun + s3-v2 GitLab CI) — done 2026-07-09, as the doc already states.
  • Faza 2 (secrets-sync full W3+W4+backends) — done, but in a different shape than originally proposed: instead of one sync-bms-1 job extension, three separate jobs now handle it (sync-pinbox24-w3, sync-pinbox24-w4, sync-pinbox24-backends in .github/workflows/secrets-sync.yml). Blocker #3400 (MAILGUN_AUTH_TOKEN parens breaking SSH heredoc) fixed via PR #3462, merged 2026-07-08.
  • #3407 (WSDL missing in v42-prod, GUS API ENOENT) — closed 2026-07-09.
  • Gap 1 (wkhtml-v42-prod DNS EAI_AGAIN) — resolved via dual-network isolation (#3193, #3228, MR !783), not a DNS fix per se. The Prometheus health-check follow-up was never done — see #3739.
  • Gap 10 (v42-notify-prod SOPS coverage) — confirmed zero gaps, 2026-07-08.
  • New work this session (2026-07-09/11), not in the original plan at all:
    • GitLab CI “autoheal” added to both W3 (p24-v-3.2) and W4 (p24-back-ts) — re-derives backend-environment.env/s3-environment.env from the bms-1 SOPS cache before deploy scripts run, so a GitLab git-clean no longer wipes untracked env files (root cause of the 2026-07-09 incident). MRs !68/!788.
    • v32-prod-reso/v32-prod-socket sidecars brought under secrets-sync (files-only, no force-recreate — see open question below) — PR #3694.
    • bms1-dr-plan.md rewritten with a full W3+W4 container/secrets inventory and off-host encrypted config backup (PR #3662, #3672).
    • mailgun-pipeline-exporter shipped and deployed to bms-1 — advances Faza 5 (monitoring) for the mailgun/W4 pipeline specifically (issue #3688, PR #3705, #3724).
    • s3-v2-v42-prod fully compose-managed + health-checked; v42-notify-prod/pdf-gen-v42-prod/ git-deploy-v42-prod added to secrets-sync (2026-07-11, #3704).

Corrected — was reported done, actually is NOT:

  • Issue #3542 (“W4 bms-1 — clean CI/CD run: docker-compose to GitLab + Phase 3A/B deploy scripts”) was believed closed by PR #3558 in an earlier session. This was wrong — PR #3558 only closed the issue’s five body verification goals (Wasabi/Redis/Mailgun/Mezmo checks); the issue title’s actual scope (committing docker-compose-w3.yml/docker-compose-w4.yml to git, Faza 3A/3B deploy script cleanup) was never done. #3542 has been re-scoped (see issue comment 2026-07-11) and re-queued rather than left believed-complete.

Decisions made 2026-07-11 (resolving open D#/Gap items below):

  • D5 (git-deploy-v42-prod keep/remove): audit first, before deciding — see #3734.
  • D6 (WebSocket restart strategy): Option A — nightly-only restart window (20:00–06:00 UTC), not nginx-upstream rolling. Document in the runbook once Faza 3C lands.
  • Gap 8 (persistent-patches bake-in vs volume-mount for W4): volume-mount, same pattern as W3.
  • reso/socket no-force-recreate policy (PR #3694): not yet finalized — user wants an actual code/usage analysis of what the WebSocket functionality does before accepting “never restart” as permanent policy, rather than assuming it. See #3740.

Follow-up issues filed 2026-07-11 (all queued to the remote worker, Triage milestone):

  • #3542 (re-scoped) — docker-compose-w3/w4.yml to git + deploy script cleanup + Gap 5 (redis-v42 depends_on/healthcheck) folded in
  • #3733 — rebuild v41-prod from source into ECR (untagged-image SPOF)
  • #3734 — audit git-deploy-v42-prod (D5)
  • #3735 — audit pdf-gen-v42-prod identity (D7/Gap 6)
  • #3736 — audit W3 frontend for the same untagged-image risk as v41-prod (D9/Gap 12)
  • #3737 — bring GOOGLE_APPLICATION_CREDENTIALS under SOPS management (Gap 7)
  • #3738 — fix + re-enable w3_app_mongodb_password/w4_app_mongodb_password rotation (rotate-schedule.yml, dormant since 2026-07-05 despite #2639’s closure) + dedicated w3_app MongoDB user for v42-prod’s mongojs connection (replacing RS0 admin credentials)
  • #3739 — wkhtml-v42-prod Prometheus health check (Faza 5 follow-up to the Gap 1 fix)
  • #3740 — analyze v32-prod-socket WebSocket usage before finalizing the reso/socket sync policy
  • #3741 — Faza 0 remainder: W3 MAILGUN_PASSWORD gap + remove 11 dead PayU/Przelewy24 keys
  • #3742 — Gap 11: resolve dead-credential verdict for Jabber/Twilio/OneSignal/ConvertAPI

Still genuinely blocked / not yet actionable:

  • Faza 3C (W4) — git-tracked artifact + runbook DONE (PR #3771). Applying it live to pinbox24/p24-back-ts (push branch + open MR) is blocked: GITLAB_ADMIN_PAT lost visibility into the pinbox24 GitLab group (404 on the group itself, empty membership list) — see #3775. The same #3775 blocker applies to applying Faza 3D (W3, p24-v-3.2) live; note Faza 3D’s git-tracked artifact is already merged (PR #3782) and its GitLab MR !70 was opened before this visibility regression — see the Faza 3D update below.
  • Gap 11 provider-dashboard checks may need human action (dashboard login access) — flagged in #3742.

Update 2026-07-11 (#3769) — Faza 3D done, pending MR review: docker-compose.yml + .gitlab-ci.yml in the pinbox24/p24-v-3.2 GitLab repo reconciled against docs/bms-1/docker-compose-w3.yml (source of truth): added prod-v-3-net network + restart: unless-stopped + the 6 persistent-patch bind mounts to the backend (v32-prod) service — volume-mounted, not baked into the image, per the Gap 8 decision. v32-prod-reso/v32-prod-socket are not defined in this GitLab-tracked compose file, so they are untouched here. #3740 is now resolved (closed 2026-07-11): its verdict is a nightly-window (20:00–06:00 UTC) force-recreate for those two sidecars — already encoded as the deploy:v32-prod-reso-socket:nightly job in the merged docs/bms-1/gitlab-ci-w3.yml (PR #3782). The live implementation of that policy on bms-1 is tracked separately in #3804 (gated on MR !70 landing first). GitLab MR: pinbox24/p24-v-3.2!70 — open, awaiting human review/merge (not merged by the agent, per process).


Cel — Definicja “compliant platform”

Platforma W3+W4 jest zgodna ze standardami gdy:

  1. SOPS = jedyne źródło prawdy — zero hardcoded credentials w deploy scripts
  2. secrets-sync.yml = jedyny mechanizm dostarczania — rotacja klucza → automatycznie do kontenera
  3. CI/CD = jedyna ścieżka wdrożenia kodu — wszystkie poprawki baked w obrazie przez GitLab CI, zero bind-montów dla kodu aplikacji
  4. Narażone klucze zrotowane — wszystkie credentials widoczne przed naprawą
  5. Docker-compose w git — zero konfiguracji istniejącej tylko w pamięci działających kontenerów
  6. Monitoring — PM2 restart alerting, endpoint health w Prometheus

Stan wejściowy (weryfikacja 2026-07-07)

Kontenery W4 (bms-1: 94.23.26.113)

ContainerImageSOPS coverageStatus
v42-prodECR v42-prod:merged-20260706-0512pinbox24-w4.env.sops — kompletny (65 kluczy)✅ działa, PM2 fork
v42-notify-prodECRpinbox24-w4.env.sops✅ zweryfikowane 2026-07-08 — zero gaps
s3-v42-prodECR v4-s3pinbox24-w4.env.sops✅ działa
s3-v2-v42-prodECR s3-v2pinbox24-backends.env.sopsPhase 1
mailgun-prodlocal/ECRpinbox24-backends.env.sopsPhase 1
redis-v42redis:7-alpinestatyczny — brak SOPS✅ local Redis, W4-only
wkhtml-v42-prodECR wkhtmltopdfbrak SOPS⚠️ DNS EAI_AGAIN — diagnoza w toku
pdf-gen-v42-prodlocalnieznany❓ niezidentyfikowany — audyt wymagany
git-deploy-v42-prodlocalnieznany❓ deploy trigger — zastąpić CI/CD?
v41-produntagged local (still running as-is; not cut over)brak✅ backup 2026-07-08 → Wasabi tar.gz; ✅ 2026-07-11 (#3733) GitLab CI build→ECR pipeline restored + running digest protected in ECR (v41-prod:pre-ci-fix-running-20260711) — see docs/playbooks/v41-prod-ecr-rebuild.md

Kontenery W3 (bms-1)

ContainerImageSOPS coverageStatus
v32-prod + 3 warianty (socket, reso)ECR v32-prodpinbox24-w3.env.sops — kompletny
s3-v32-prod + 3 wariantyECR old-s3pinbox24-w3.env.sops✅ (MAILGUN_PASSWORD gap zamknięty — #3778)
cron-v32-prod + 2 wariantylocalstatyczne env — brak SOPS needed

Fazy (plan zaakceptowany w #3171)

Prerequisite: PR #3163 (merge → main)

Fix nginx round-robin (VIRTUAL_HOST na s3-v42-prod) + PM2 fork mode. Wymagany przed wszystkim.

Prerequisite: #3172 zakończone przed Phase 3

#3172 usuwa referencje artnet.pl z deploy scripts. Phase 3 (#3171) czyści te same scripts — muszą się nie nakładać. Kolejność: #3172 → merge → #3171 Phase 3.


Faza 0 — SOPS gaps (secret-manager, parallel z Fazą 1)

AkcjaSOPS fileKlucze
Dodaj MAILGUN_MONGODB_URL, MAILGUN_AUTH_TOKENpinbox24-backends.env.sopsz mailgun-environment.env na bms-1
Dodaj brakujące W4 keys (PM2, Wasabi, MAILGUN_PASSWORD dla s3)pinbox24-w4.env.sopsz s3-environment.env na bms-1
Usuń 11 PayU/Przelewy24 kluczy (wyłączone)pinbox24-w4.env.sopsD4: PAYU_, przelewy24
MAILGUN_PASSWORD gap W3 — zamknięty (#3778)pinbox24-w3.env.sopsKlucz jest w SOPS + dostarczany do s3-environment.env na bms-1. Uwaga: s3-v32-prod czyta mailgun creds z hardcoded config/default.js (obraz old-s3), nie z env — patrz nota niżej. MAILGUN_USER_NAME niepotrzebny (owner potwierdził). Hardening allowlistu → PR #4497.
Zweryfikuj v42-notify-prod env — dodaj do SOPS jeśli brakujepinbox24-w4.env.sopsdocker inspect v42-notify-prod

Nota — W3 s3-v32-prod mailgun (#3778, zamknięte): kontener (obraz old-s3, biblioteka node-config) czyta config.get('mailgun.username'|'.password') z hardcoded /app/config/default.js. Brak custom-environment-variables.js, więc żaden MAILGUN_* z s3-environment.env nie jest mapowany do configu — MAILGUN_PASSWORD/MAILGUN_USER_NAME w env są czytane 0 razy. Wniosek: dodawanie MAILGUN_USER_NAME do SOPS/sync byłoby no-op (owner potwierdził — nie dodane). Sync MAILGUN_PASSWORD (obecnie na main) pozostaje jako hygiene; hardening allowlistu → PR #4497. Osobny follow-up (sys-security): default.js hardcode’uje prod credentials w obrazie old-s3.

Faza 1 — mailgun + s3-v2 CI/CD (GitLab) ✅ DONE 2026-07-09

Zrealizowane (sesja 73):

  • pinbox24/p24-ms-mailgun (master): .gitlab-ci.yml — runner mailgun-bms1-autodeploy (tag dodany do runner ID 53991640, shell executor na bms-1). Build+deploy SUCCESS. Kontener mailgun-v42-prod działa z obrazu mailgun-v42-prod:591bc43f (lokalnie zbudowany). Minimalne env (13 kluczy) przez printf/tmp/mailgun-deploy-${CI_PIPELINE_ID}.env. Stary ECR pipeline zastąpiony.
  • pinbox24/pinbox24-ms-s3-v2 (feature/scanque): .gitlab-ci.yml — runner s3-v2-bms1-autodeploy (tag dodany do runner ID 53991639). Build SUCCESS (77s). Deploy when: manual — czeka na Fazę 0 (brakuje s3-v2 credentials w pinbox24-backends.env.sops). Stary artnet.pl private registry pipeline zastąpiony. 5 persistent patches bind-mounted w docker run.
  • bms-1 env permissions: hotfix 0640 root:gitlab-runner zastosowany ręcznie + PR #3507 merged do main (commit 8a616eb3).
  • bash sourcegrep|cut: specjalne znaki w MAILGUN_AUTH_TOKEN i innych kluczach łamią source. Nowe CI używa grep "^KEY=" file | head -1 | cut -d= -f2- dla wyciągania wartości.

Co pozostaje z Fazy 1:

  • Faza 0: dodaj s3-v2 SOPS credentials → zmień s3-v2 CI deploy when: manualwhen: on_success
  • Usuń/zaktualizuj sync-mailgun-environment.env step w secrets-sync.yml (PR #3369) — teraz obsolete bo CI zarządza kontenerem bezpośrednio; sprawdź czy /root/mailgun-prod/ istnieje na bms-1

Faza 2 — secrets-sync pełny W3+W4 (sync-bms-1)

BLOKER FAZY 2 — #3400: sync-pinbox24-backends failuje bo MAILGUN_AUTH_TOKEN zawiera nawiasy () łamiące SSH heredoc arg passing. Job musi przejść zanim Faza 2 może być zakończona. Fix: quote lub base64-encode wartość przed SSH. Tracker: #3400#3425.

Rozszerzenie sync-bms-1 w secrets-sync.yml (target bms1-all) — deploy wszystkich SOPS plików na bms-1:

  • pinbox24-w3.env.sops/opt/p24-infra/bms-1/pinbox24-w3.env
  • pinbox24-w4.env.sops/opt/p24-infra/bms-1/pinbox24-w4.env
  • pinbox24-backends.env.sops/opt/p24-infra/bms-1/pinbox24-backends.env

UWAGA: W połączeniu z PR-D (#3178 Track B) — jeden PR dla wszystkich secrets-sync.yml zmian.

Faza 3A — Deploy scripts W4 cleanup

Usuń hardcoded credentials z /root/builds/7N4sbbrB/0/pinbox24/p24-back-ts/ scripts. Commituj docker-compose W4 do repo (docs/bms-1/docker-compose-w4.yml). Usuń git-deploy-v42-prod jeśli zdecydujemy zastąpić CI/CD (patrz P1 gap #4).

Faza 3B — Deploy scripts W3 cleanup

Usuń hardcoded credentials z /home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2/ scripts (autorytatywny, GitLab-runner; /root/builds/pn3C9eHo/... NIE jest katalogiem serwującym prod, ale NIE jest porzucony — audyt on-server 2026-08-01 wykazał, że to aktywne źródło mountów W3-staging, więc NIE usuwać go w całości — #4985, patrz docs/w3-w4-stack-operations.md §3). Commituj docker-compose W3 do repo.

Faza 3C — Image CI/CD W4 (GitLab)

GitLab CI pipeline dla v42-prod:

  • Build nowego obrazu — patches zostają volume-mounted, NIE baked in (Gap 8 decyzja 2026-07-11, odwraca wcześniejsze “baked persistent patches” założenie — patrz docker-compose-w4.yml)
  • depends_on: redis-v42 w compose — startup ordering
  • WebSocket graceful restart strategy (patrz P1 gap #6 / D6)
  • wkhtml-v42-prod — jeśli DNS fix gotowy, dodać health check (poza zakresem — #3739)

Status (2026-07-11):

  • DONE — git-tracked artifact + runbook merged via PR #3771 (issue #3768): docs/bms-1/gitlab-ci-w4.yml (proposed .gitlab-ci.yml, honors Gap 5/Gap 8/D6) + docs/playbooks/w4-gitlab-ci-image-pipeline.md (apply/rollback runbook). This was landed as a p24-infra-tracked source of truth first, same pattern as docker-compose-w4.yml (#3542).
  • 🚧 BLOCKED — applying the artifact to the live pinbox24/p24-back-ts GitLab repo (push branch + open MR, per the runbook’s single-file-PUT procedure) is blocked: GITLAB_ADMIN_PAT currently has zero visibility into the pinbox24 GitLab group (GET /groups/pinbox24404, membership list empty), a regression from the reachable state recorded in docs/pinbox24/gitlab-repo-locations.md (2026-07-09). Token identity itself is valid (GET /user200 as radieu). Tracked in #3775 — needs a human to check/restore GitLab group membership (or reissue the PAT) before the MR can be opened.

Faza 3D — Image CI/CD W3 (GitLab) ✅ MR OPEN 2026-07-11 (#3769)

GitLab CI pipeline dla v32-prod. Rollback: jeśli pipeline fail po 4+ latach → zostaw na obecnym obrazie, dokumentuj jako tech-debt.

Wykonane (2026-07-11, issue #3769): docker-compose.yml w repo pinbox24/p24-v-3.2 zweryfikowany i wyrównany z docs/bms-1/docker-compose-w3.yml (source of truth) — brakowało prod-v-3-net (parytet z reso/socket, #2826), restart: unless-stopped, oraz 6 volume-mountów persistent patches na v32-prod (zgodnie z decyzją Gap 8 — bind-mount, nie bake do obrazu). .gitlab-ci.yml dostał komentarz dokumentujący scope + rollback policy (bez automatycznego retry — zgodnie z wytyczną planu). v32-prod-reso/v32-prod-socket poza scope tego compose file (nie są w nim zdefiniowane). #3740 zamknięte (2026-07-11): werdykt to nocne okno force-recreate (20:00–06:00 UTC) — już zakodowane jako job deploy:v32-prod-reso-socket:nightly w zmergowanym docs/bms-1/gitlab-ci-w3.yml (PR #3782). Wdrożenie tej polityki na żywo na bms-1 śledzone osobno w #3804 (gated na merge MR !70). MR: pinbox24/p24-v-3.2!70 — otwarty, czeka na review/merge człowieka.

Faza 4 — Rotacje credentials

MAILGUN, JWT, Redis, Wasabi. Po weryfikacji Fazy 3.

Dodatkowe — w3_app MongoDB user (2026-07-08): V42_v3MongoUrl (mongojs legacy w v42-prod) używa RS0 admin credentials — każda rotacja MONGODB_RS0_ADMIN_PASSWORD wymaga ręcznej aktualizacji (wystąpiło w PR #3359 jako hotfix po PR #3241). W Fazie 4:

  1. sys-admin: stwórz usera w3_app na RS0 primary (bms-2) z dostępem tylko do kolekcji W3
  2. secret-manager: zaktualizuj V42_v3MongoUrl w pinbox24-w4.env.sops — podmień admin credentials na w3_app
  3. secrets-sync → restart v42-prod → potwierdź mongojs connected z dedykowanym userem Tracker: #3425

Faza 5 — Monitoring + SOPS minimalizacja

PM2 restart alerting (Prometheus). Endpoint health checks. Wkhtml health check.



Separacja W3/W4 — Analiza izolacji (2026-07-08)

Aktualny stan Docker (bms-1)

WymiarSeparacjaStanWymagana akcja
Sieci DockerW3 = prod-v-3-net, W4 = test-net⚠️ Częściowa — v32-prod NIE jest na prod-v-3-net (#2826)Fix Faza 3B
Kontenery W4v42-prod, v42-notify-prod, s3-v42-prod, s3-v2-v42-prod, mailgun-prod, redis-v42, wkhtml-v42-prod, pdf-gen-v42-prod✅ Osobne — bez overlap z W3
Kontenery W3v32-prod + socket/reso warianty, s3-v32-prod + warianty, cron-*✅ Osobne
Wspólnenginx-proxy (nginx-proxy kontener, port 80/443)⚠️ Shared reverse proxy — świadome współdzielenie, nie ryzykoDokumentować

Decyzja D10: mailgun-prod obsługuje tylko W4 (URL hardcoded v42-prod:3000). Nie ma shared mailgun między W3 i W4 — separacja kompletna dla mailguna.

Aktualny stan SOPS (separacja credentials)

SOPS fileZakresStanProblem
pinbox24-w4.env.sopsTYLKO W4 backend + s3✅ Dedykowany
pinbox24-w3.env.sopsTYLKO W3 backend + s3✅ DedykowanyMAILGUN_PASSWORD gap zamknięty (#3778)
pinbox24-backends.env.sopsmailgun + s3-v2 (W4-only)⚠️ Nazwa sugeruje “oba”, ale zawiera tylko W4Rename lub dokumentować
pinbox24-w4.env.sopspinbox24-w3.env.sopsMongoDB URI✅ Osobne usery (w4_app, w3_app — w3_app tbd)V42_v3MongoUrl używa admin (Faza 4)

Wniosek: SOPS separacja jest dobra strukturalnie. Główny problem: klucze współdzielą admin credentials zamiast dedykowanych userów per-stack.

Wymagana akcja — Faza 0: weryfikacja pełnej izolacji

Przed Fazą 2 (full secrets-sync) zweryfikować:

  1. Żaden klucz W3 nie jest w pinbox24-w4.env.sops i odwrotnie
  2. MongoDB: W3 i W4 używają osobnych userów MongoDB (w3_app, w4_app) — nie admin
  3. Wasabi: W3 i W4 mają osobne IAM keys (lub shared? — audit potrzebny)
  4. Mailgun: API key W3 i W4 — ten sam? (różny subdomain? audit #3271)

Pre-Deployment Checklist — Weryfikacja całego środowiska W3/W4

Policy (2026-07-08): przed każdym deployem (Faza 3C/3D i dalej) wymagana pełna weryfikacja.

1. Health check wszystkich mikroserwisów

# W4 — sprawdź czy WSZYSTKIE kontenery działają
docker ps --format "table {{.Names}}\t{{.Status}}" | grep -E "v42|mailgun|wkhtml|pdf-gen|redis"
 
# W3 — sprawdź czy WSZYSTKIE kontenery działają
docker ps --format "table {{.Names}}\t{{.Status}}" | grep -E "v32|cron"
 
# Endpoint check
curl -s -o /dev/null -w "%{http_code}" https://api.w4.pinbox24.com/api/i18n/langs  # 200
curl -s -o /dev/null -w "%{http_code}" https://api.w3.pinbox24.com/api/i18n/langs  # 200

2. MongoDB connectivity per-stack

# W4: mongoose connected, mongojs connected — sprawdź logi
docker logs v42-prod --since 2m | grep -i "mongoose\|mongojs\|connected\|auth"
 
# W3: mongoose connected
docker logs v32-prod --since 2m | grep -i "mongoose\|connected\|auth"

3. Każdy mikroserwis = własne hasło (pre-deploy audit)

Przed deployem Fazy 3C/4 zweryfikować że każdy kontener ma własny dedykowany zestaw credentials, nie współdzielony admin:

MikroserwisExpected userActual userStatus
v42-prod mongoosew4_appV42_NEW_MONGODB_URI userVerify
v42-prod mongojsw3_app (target)RS0 admin obecnie⚠️ Fix w Fazie 4
s3-v42-prodWasabi W4 IAM userV42_S3_WASABI_*Audit Faza 0
mailgun-prodMailgun API keyMAILGUN_AUTH_TOKENAudit #3271
v32-prod mongoosew3_app (target)V32_NEW_MONGODB_URI userVerify
s3-v32-prodWasabi W3 IAM userDB_URI userAudit Faza 0

4. Rotacja haseł przy deploymencie (policy decyzja)

Pytanie: Czy rotować wszystkie hasła W3/W4 przy każdym deployu Fazy 3C/3D?

Analiza:

  • Za rotacją: hardcoded credentials mogły być kompromitowane przed naprawą; “clean slate” po migracji do CI/CD
  • Przeciw rotacji przy deploymencie: rotacja powinna być osobnym, przetestowanym krokiem; deploy + rotacja naraz = dwa możliwe punkty awarii
  • Rekomendacja: Rotacja jako osobna Faza 4, nie wbudowana w deploy. Kolejność:
    1. Faza 3C/3D: deploy z istniejącymi credentials (testuj że środowisko działa)
    2. Faza 4: rotacja per-mikroserwis z weryfikacją po każdej rotacji

Wyjątek — rotacja OBOWIĄZKOWA przy deploymencie: jeśli credentials były widoczne w plaintext w logach CI/CD lub plikach na serwerze (issues #3216, #3333, #3428) → te konkretne klucze rotować w ramach Fazy 3A/3B, nie czekać na Fazę 4.


Zidentyfikowane luki (gap analysis 2026-07-07)

P0 — Blokujące Phase 3+ (muszą być rozwiązane PRZED fazami 3-5)

Gap 1: wkhtml-v42-prod DNS resolution failure

Problem: Error: getaddrinfo EAI_AGAIN wkhtml-v42-prod — v42-prod nie może rozwiązać nazwy PDF service. Diagnoza: W toku (inna sesja). Akcja przed Phase 3C:

  • Zidentyfikować root cause (container down / wrong network / Docker DNS cache)
  • Fix: upewnić się że wkhtml-v42-prod jest na test-net (ta sama sieć co v42-prod)
  • Dodać wkhtml-v42-prod do docker-compose W4 z restart: unless-stopped
  • Health check /healthz lub similar → Prometheus alert jeśli down

Gap 2: v41-prod untagged image — [DONE ✅ 2026-07-11, issue #3733]

Problem: Angular W4 frontend działa na lokalnym untagged image (v41-prod). Jeśli bms-1 się restartuje, image znika → W4 frontend niedostępny permanent. Krok 1 (2026-07-08):

# Na bms-1:
docker save v41-prod | gzip > /tmp/v41-prod-backup-$(date +%Y%m%d).tar.gz
# Upload do Wasabi p24-infra bucket:
aws s3 cp /tmp/v41-prod-backup-*.tar.gz s3://p24-infra/backups/v41-prod/ --endpoint-url https://s3.eu-central-1.wasabisys.com

Krok 2 (2026-07-11, #3733) — reproducible build path: Source zlokalizowany w GitLab pinbox24/pinbox24-version-4 (Angular, .gitlab-ci.yml już istniał z pełnym build → push-to-ECR → deploy pipeline — dokładnie ten sam wzorzec co v42-prod). Runner tagi (autodeploy, prod-deploy-p24) wskazywały na stare, offline runnery — żywy runner bms-1-autodeploy (id 54112450, te same tagi, już używany dla p24-back-ts/v42-prod) został dopisany do projektu v41. Deploy joby przełączone na when: manual żeby zielony pipeline nie podmieniał automatycznie działającego kontenera. Zweryfikowano też, że obraz aktualnie uruchomiony na bms-1 (digest sha256:6ad6ea86...) już istniał w ECR (untagged, z ostatniego udanego pipeline’u 2025-04-12) — otagowany teraz jako v41-prod:pre-ci-fix-running-20260711 dla jednoznacznego punktu odniesienia. Pełna procedura + cutover: docs/playbooks/v41-prod-ecr-rebuild.md. Aktualizacja 2026-08-02 (#3733 infra-task worker): MR pinbox24/pinbox24-version-4!409 (ten sam when: manual gate dla gałęzi development/staging, co był już na master) został scalony — obie gałęzie mają teraz spójny build→push-to-ECR + manual-deploy pipeline. Zielony pipeline master (2669817220) potwierdzony: front-end-build + docker-image-build = success, prod-front-end-deploy = manual (nie uruchomiony). Reproducible build path jest w pełni przywrócony na obu gałęziach. Nadal otwarte: secrets-sync.yml nie zarządza tym kontenerem (frontend nie ma runtime secrets, więc priorytet niższy niż dla backendów); live cutover na nowy ECR image jest świadomie odłożony jako human-action follow-up (deployuje NOWSZY bundle niż aktualnie działający — wymaga side-by-side weryfikacji + go/no-go człowieka; procedura w docs/playbooks/v41-prod-ecr-rebuild.md).

Gap 3: Docker-compose files nie w git

Problem: Konfiguracja wszystkich kontenerów istnieje tylko w pamięci działających procesów. Restart bms-1 = utrata stanu. Akcja w Phase 3A/3B:

  • docker inspect wszystkich kontenerów → wygeneruj docker-compose
  • Commit do docs/bms-1/docker-compose-w3.yml i docs/bms-1/docker-compose-w4.yml
  • Podstawa dla Phase 3C/3D (GitLab CI musi wiedzieć jak startować)

P1 — Ważne (adresować w Phase 3C/3D)

Gap 4: git-deploy-v42-prod — co to jest?

Problem: Container “git-based deploy trigger” — niejasna rola. W CI/CD świecie może być zbędny lub stanowić security risk (wykonuje git pull bez uwierzytelnienia?). Akcja: Audyt przed Phase 3C. Jeśli zastąpiony przez GitLab CI → wyłączyć. Jeśli aktywnie używany → udokumentować.

Gap 5: redis-v42 startup ordering

Problem: Jeśli bms-1 rebootuje i redis-v42 startuje PO v42-prod, RabbitMQ consumer crashuje przy inicjalizacji. Akcja w Phase 3C docker-compose:

services:
  v42-prod:
    depends_on:
      redis-v42:
        condition: service_healthy
  redis-v42:
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      retries: 5

Gap 6: pdf-gen-v42-prod — niezidentyfikowany kontener

Problem: Container istnieje na bms-1 ale nie ma go w mapie env vars ani SOPS coverage. Niejasna relacja z wkhtml-v42-prod. Akcja: docker inspect pdf-gen-v42-prod + sprawdź logi → określ czy duplikat wkhtml, wrapper, czy osobna funkcja.

Gap 7: GOOGLE_APPLICATION_CREDENTIALS — zarządzanie JSON credentials

Problem: v42-prod potrzebuje pliku JSON z Google Service Account credentials. Ścieżka jest env varem, ale sam plik musi być na serwerze. Nie ma go w SOPS (binary file). Akcja w Phase 3C:

  • Zidentyfikować obecną lokalizację pliku na bms-1
  • Decyzja: volume mount (keep) vs. baked in image (nie, secrets w obrazie = złe) vs. secret store
  • Rekomendacja: volume mount z /opt/p24-infra/bms-1/google-credentials.json → deploy przez secrets-sync analogicznie

Gap 8: Persistent patches — bake in image vs. volume

Problem: uploadAwsS3.helper.js i gus-api-regon-wsdl/ są volume-mounted jako persistent patches. W CI/CD świecie powinny być w obrazie. Akcja w Phase 3C:

  • Porównaj patch content z ECR image source
  • Jeśli różnice są małe i dobrze zrozumiane → bake into image w GitLab CI
  • Jeśli patches są zbyt ryzykowne do rederywacji → zostaw volume mount, dokumentuj

Update 2026-07-08 — WSDL brakuje w node_modules (#3407): @pobidowski/gus-api-regon/dist/wsdl/UslugaBIRzewnPubl-ver11-test.wsdl missing w kontenerze v42-prod — PM2 ENOENT errors. Root cause: paczka npm nie zawiera WSDL w buildzie (nie: volume-mount problem). Niezależne od gap 8 strategii, ale musi być naprawione w Phase 3C (postinstall skrypt lub fork paczki). Tracker: #3407#3425.

Gap 9: Zero-downtime WebSocket restart

Problem: Socket.IO połączenia droppują przy restart v42-prod (docker-compose up -d). Klienci dostają transport close. Opcje:

  • Opcja A (prosta): Restart w godzinach nocnych (20:00-06:00) — akceptowalne dla 7 klientów W4
  • Opcja B (lepsza): nginx upstream z 2 instancjami — jedno musi być alive, rolling deploy
  • Opcja C (idealna): Socket.IO sticky sessions + nginx upstream health — wymaga refactoru Rekomendacja dla Phase 3C: Opcja A — nocne deploye. Dokumentować w runbooku.

Gap 10: v42-notify-prod — brak w mapie SOPS ✅ DONE 2026-07-08

Problem: Kontener notification microservice nie ma zweryfikowanych env vars ani coverage w SOPS. Wynik audytu 2026-07-08: Zero gaps. Wszystkie env vars v42-notify-prod pokryte w pinbox24-w4.env.sops. Mikroservice Discord webhook — credentials przekazywane w request body, brak własnych SOPS kluczy do dodania.

P2 — Do weryfikacji (niskie ryzyko)

Gap 11: Dead credentials w SOPS

Aktywność do sprawdzenia przed Phase 4 (rotacje):

  • Jabber/XMPP (jabber_HOST, jabber_JID, jabber_PASSWORD) — #3449: INCONCLUSIVE, nie martwe. Najsilniejszy sygnał kodu z czterech — dedykowany jabber.helper.js + zadanie w kolejce (messaging_jabber.js) + 5 modułów XMPP. Zero logów w oknie 14–40h (za krótkie, po force-recreate #3060). Pozostaje w Tier 3 (manual).
  • Twilio (twilioAccountSid, twilioAuthToken) — #3449: INCONCLUSIVE, nie martwe. twilioService.js + pełny SDK w 3 wariantach backendu. Pozostaje w Tier 3.
  • OneSignal (onesignal_APP_ID, onesignal_APP_AUTH_KEY) — #3449: INCONCLUSIVE, nie martwe. Dedykowany controller+helper + SDK. Pozostaje w Tier 3.
  • Mailgun (V32_MAILGUN_API_KEY) — #3449: LIVE consumer w rodzinie s3-v32-prod (mailgun-js + src/tmpStorage/mailgun/); nieobecny tylko w v32-prod. Nie usuwać. Follow-up: potwierdzić domenę/konto (dashboard Mailgun EU → secret-manager); rozstrzyga D8/D10.
  • ConvertAPI (CONVERT_API) — używane? Alternatywa dla wkhtml? (poza zakresem #3449 — nadal do sprawdzenia)

#3449 usunięcia zero — żaden z 4 integracji nie dał czystego dowodu “martwe”; wszystkie zachowane w Tier 3 (manual) i wypisane w docs/sops-templates/pinbox24-w3.keys z notatką + follow-up. Realny werdykt live/dead wymaga: (a) sprawdzenia dashboardów providerów (secret-manager), lub (b) ponownego audytu logów po 72h+ stabilnego uptime (infra-task/sys-admin). Dopiero po tym: Jeśli nieaktywne → usunąć z SOPS (dead credentials = attack surface reduction).

Gap 12: W3 frontend — brak w planie

Angular frontend W3 — status nieznany. Czy jest lokalny untagged image jak v41-prod? Audyt wymagany.


Zaktualizowana kolejność wykonania

[DONE ✅ 2026-07-08]
  Gap 2: v41-prod image → Wasabi: s3://p24-infra/backups/docker-images/v41-prod-backup-20260708.tar.gz
  Gap 10: v42-notify-prod env audit → zero gaps, SOPS kompletny
  mongojs hotfix: V42_v3MongoUrl zaktualizowany (PR #3359) — hasło zsynchronizowane z MONGODB_RS0_ADMIN_PASSWORD

[PR-A]
  Merge PR #3163 → main (nginx fix + PM2 fork)

[RÓWNOLEGLE po PR-A]
  #3172: artnet.pl elimination + dane migration
  Gap 1: wkhtml DNS fix (inna sesja diagnozuje)
  Gap 6: pdf-gen-v42-prod audit
  #3400: MAILGUN_AUTH_TOKEN parens fix w secrets-sync.yml ← BLOKER FAZY 2, dispatch równolegle

[PR-B, po PR-A]
  Faza 0: SOPS gaps (secret-manager)

[PR-C]
  Faza 1: mailgun + s3-v2 GitLab CI

[PR-D — COMBINED z #3178, po #3400 DONE]
  secrets-sync.yml: sync-bms-1 extension + Track B jobs

[PR-E — po PR-D, po #3172 DONE]
  Faza 3A: W4 deploy scripts cleanup
    → Gap 3: docker-compose W4 do git
    → Gap 4: git-deploy-v42-prod decyzja
  Faza 3B: W3 deploy scripts cleanup
    → Gap 3: docker-compose W3 do git

[PR-F]
  Faza 3C: W4 image CI/CD
    → Gap 5: redis-v42 depends_on
    → Gap 7: GOOGLE_APPLICATION_CREDENTIALS → volume managed
    → Gap 8: persistent patches strategy
    → Gap 9: nocne-deploy policy (WebSocket)
    + Gap 1: wkhtml health check (jeśli fix gotowy)

[PR-G]
  Faza 3D: W3 image CI/CD

[PR-H]
  Faza 4: Credential rotations (po P2 Gap 11 audit)
    + w3_app MongoDB user → podmiana admin w V42_v3MongoUrl (patrz §Faza 4 powyżej)
    + #3407 WSDL fix → postinstall lub fork @pobidowski/gus-api-regon

[PR-I]
  Faza 5: PM2 monitoring + Prometheus health checks

[PR-L (Track B #3178)]
  Phase 2 service accounts

Playbooki do napisania (po wykonaniu)

  • docs/playbooks/pinbox24-wkhtml-troubleshooting.md — po diagnozie wkhtml DNS
  • docs/playbooks/bms-1-deployment-runbook.md — pełny runbook deploy W3+W4
  • docs/playbooks/pinbox24-cicd-rollback.md — procedura rollback dla każdej fazy

Decyzje wymagające odpowiedzi przed Phase 3

D#PytanieKto decydujeDeadline
D5git-deploy-v42-prod — wyłączyć czy zachować?Developer / audyt koduPrzed Phase 3A
D6WebSocket restart — Opcja A (nocne) czy B (nginx upstream)?Właściciel produktuPrzed Phase 3C
D7pdf-gen-v42-prod — co to jest i czy potrzebne?Audyt logi + kodPrzed Phase 3C
D8Jabber/Twilio/OneSignal/Mailgun — aktywne?#3449: bms-1 read-only audit INCONCLUSIVE (wszystkie wired, log-window za krótkie); Mailgun ma live consumer w s3-v32-prod. Zero usunięć, wszystkie w Tier 3. Ostateczny werdykt: dashboardy providerów (secret-manager) lub re-audyt logów po 72h+ (infra-task)Przed Phase 4
D9W3 frontend — lokalny untagged image jak v41-prod?Audyt bms-1Przed Phase 3D