147 lines
12 KiB
Markdown
147 lines
12 KiB
Markdown
# Who Need Help — local hardening completion plan
|
|
|
|
This plan deliberately excludes buying a domain, renting another server, and
|
|
real third-party credentials. The existing local Docker/kind environments and
|
|
the temporary `whoneedhelp.imalto.site` staging origin are sufficient for every
|
|
item below unless the evidence column explicitly describes a local mock.
|
|
|
|
| Area | Observed baseline | Local completion evidence |
|
|
| --- | --- | --- |
|
|
| Browser E2E | Manual headed-Chrome scenarios exist; no committed browser suite | A fresh uniquely named Compose project runs two-user urgent help, Activity, moderation, privacy, and error paths; traces are retained on failure; its exact volume is removed |
|
|
| Android UI | Two JVM unit-test files; no `androidTest` source set | Emulator instrumentation covers deep links, permissions, foreground tracking, notification Stop, lifecycle, and network failure |
|
|
| CI and quality | No tracked CI workflow or static/security analysis dependencies | The same containerized gates pass locally and are represented in a validated CI workflow |
|
|
| Localization and accessibility | Completed locally: product copy and custom validation messages are extracted; EN/UK/RU catalogs and localized category descriptions/structured values are implemented | 508 default and 40 error messages are current; RU/UK have no empty/fuzzy entries; 171 backend tests and all 8 browser specs pass, including locale persistence, keyboard, axe, themes, responsive widths, and reconnect |
|
|
| Database scale | Core discovery/chat/moderation lists call unbounded `Repo.all()` | Cursor-bounded queries pass behavior tests and measured `EXPLAIN ANALYZE` checks on an isolated generated dataset |
|
|
| Load and resilience | Public/readiness/heartbeat k6 profile exists | Authenticated writes, chat, tracking, reconnect, rolling replacement, and worker retry profiles pass without touching staging data |
|
|
| Observability | Completed locally: protected per-process metrics feed a pinned Prometheus/Grafana/Alertmanager profile | All 3 direct web targets are up before/after the drill; a verified replica stop delivers firing and resolved webhooks; Grafana datasource/dashboard and an empty DB-count diff are retained |
|
|
| Backup | Completed locally: a plaintext-free Restic stream is retained in pinned local MinIO | The encrypted repository passes full-data checking and fresh-database restore; corrupted configuration and an interrupted upload fail closed, leave no snapshot, and their temporary buckets are removed |
|
|
| External boundaries | Completed locally: real Assent/Req, Swoosh/gen_smtp, and the provider-neutral push adapter run against an internal protocol mock | Success, rejection, retry, replay, timeout, PKCE/state, one-time-code, and idempotency paths pass without host ports or retained secrets; acceptance/chat product events pass through an ephemeral PostGIS database and two Oban workers |
|
|
| Final regression | 167 Phoenix tests plus reproducible browser and Android device suites | Browser, Android, API, DB, WebSocket, backup, monitoring, failure, cleanup, docs, and clean Git are verified from the final commits |
|
|
|
|
The goal remains open while any row lacks reproducible local evidence.
|
|
|
|
## Verified progress
|
|
|
|
- The isolated browser harness now generates independent local secrets, starts
|
|
two web and two worker replicas behind Traefik, and removes only its uniquely
|
|
named Compose project and PostGIS volume.
|
|
- The browser suite passes public/authentication boundaries and the complete
|
|
two-user medicine flow: Mailpit confirmation, category-driven request,
|
|
matching, bidirectional realtime chat, handover verification, bilateral
|
|
completion, and double-blind review reveal.
|
|
- A separate browser scenario passes Activity creation, participant approval,
|
|
bidirectional private group chat, a report scoped to the selected message,
|
|
block/unblock, inherited location privacy, manual social-link removal,
|
|
category-proposal rejection, report resolution, account restriction, and
|
|
enforcement of that restriction. Its administrator is created in the
|
|
isolated database through the existing audited one-time bootstrap command.
|
|
- Browser console errors, page errors, and unexpected failed requests are
|
|
test failures. Playwright traces, screenshots, video, JSON/HTML reports, and
|
|
Compose logs are retained in ignored output on failure.
|
|
- The browser gate also passes axe checks on the home, safety, login, and
|
|
registration pages in both light and dark themes, keyboard skip navigation,
|
|
and 360/768/1440-pixel overflow checks. Its local raster-tile endpoint exists
|
|
only in the E2E-compiled image, and map scenarios wait for MapLibre `idle`
|
|
before navigation.
|
|
- A forced LiveSocket transport loss while Chromium is offline exposes the
|
|
reconnect alert, and restoring the network clears it and reconnects the
|
|
authenticated LiveView.
|
|
- The isolated API 30/34/37 Android matrix passes seven device tests per API:
|
|
missing and granted location permission, same-origin deep-link routing across
|
|
Activity recreation, native foreground location upload, notification Stop
|
|
with remote cleanup, a disconnected Stop request with visible retry state,
|
|
continued uploads after Home and Activity destruction, and a forced
|
|
main-frame disconnect followed by native Retry and a rendered DOM. A separate probe
|
|
externally kills the instrumentation process and verifies that the
|
|
`START_NOT_STICKY` service and notification do not return. The suite uses an
|
|
in-process loopback fixture, runs each emulator without external networking,
|
|
retains diagnostics on failure, and removes its exact container and image.
|
|
- The containerized `scripts/quality.sh` gate passes ShellCheck, Hadolint,
|
|
actionlint, all Compose renders, Helm lint, a Trivy scan of tracked source and
|
|
the rendered Kubernetes manifest, compiler/xref/Credo/Sobelow/Dialyzer/Hex
|
|
checks, 167 Phoenix tests, both npm audits, and Trivy scans of the backup,
|
|
MinIO server/client, external-mock, and production release images. It creates
|
|
random one-run database credentials and removes its exact volume, networks,
|
|
images, and source snapshot.
|
|
- The checked-in GitHub Actions workflow runs the same isolated backend/security
|
|
gate, browser E2E suite, and Android unit/lint/APK build. The workflow itself
|
|
passes actionlint and uses a commit-pinned checkout action without persisted
|
|
credentials.
|
|
- The hardened local kind manifests also passed a runtime rollout: PostGIS,
|
|
Mailpit, both web replicas, and both worker replicas became Ready as non-root
|
|
containers with read-only root filesystems, dropped capabilities, and
|
|
RuntimeDefault seccomp where configured. The cross-node PubSub probe passed.
|
|
- EN/UK/RU extraction and catalogs are now complete for current product UI and
|
|
custom validation messages. Locale selection persists for public pages and
|
|
authenticated LiveViews; category descriptions and structured values follow
|
|
that browser locale. The localization browser specs run in the same isolated
|
|
two-web/two-worker gate as the accessibility checks.
|
|
- The isolated three-web/two-worker load profile now uses real password login,
|
|
authenticated LiveView joins, tracking start, HTTP position writes, private
|
|
chat writes, and explicit tracking stop. A measured 30-second run completed
|
|
all 1,888 authenticated chains and 240 heartbeat sockets with no functional
|
|
failure, retained no current positions after stop, passed cross-node PubSub
|
|
and readiness, and restored every tracked table count after exact fixture
|
|
cleanup.
|
|
- The same isolated profile now passes deliberate web/worker BEAM crashes,
|
|
sequential replacement of every replica, exact five-node cluster/PubSub
|
|
checks, and an Oban job that records one failure before succeeding on its
|
|
second attempt. A 758-sample readiness probe observed no final HTTP failure
|
|
and the probe job/domain fixtures were absent afterward.
|
|
- The project-owned kind cluster also passes a full web/worker rolling restart:
|
|
all four pod UIDs changed, all replacements became Ready with zero restarts,
|
|
the four-node cluster/PubSub probe passed, and database counts were unchanged.
|
|
The local single-node NodePort needed two reconnect attempts across 362
|
|
ultimately successful samples; this is recorded rather than presented as
|
|
raw transport continuity.
|
|
- The isolated observability profile scrapes all three web containers by direct
|
|
target with a file-based Bearer credential, provisions a four-panel Grafana
|
|
dashboard, and routes the `up == 0` rule through Alertmanager. The canonical
|
|
drill observed both firing and resolved webhooks for the exact stopped
|
|
replica, restored all three targets, and left database counts unchanged.
|
|
- The encrypted backup profile streams PostgreSQL custom format through Restic
|
|
directly into local MinIO without a host plaintext archive. The canonical
|
|
drill restored 23 public tables with all 10 migrations and PostGIS 3.6.4,
|
|
rejected an intentionally corrupted repository, stopped a scoped upload
|
|
after an encrypted object reached MinIO, published no interrupted snapshot,
|
|
pruned the unreferenced packs, removed both temporary buckets and the
|
|
temporary restore database, and left source table counts unchanged.
|
|
- The isolated external-service drill uses the release's configured Assent/Req
|
|
and Swoosh/gen_smtp clients against an internal-only protocol mock. Its
|
|
latest run passed OAuth success, PKCE/state rejection, provider denial,
|
|
one-time-code replay, temporary failure and timeout; SMTP success, permanent
|
|
rejection, one temporary retry, timeout and repeated submission; and the HTTP
|
|
push boundary's disabled default, retry, rejection, replay, and ambiguous
|
|
timeout paths. An ephemeral PostGIS database plus two worker replicas also
|
|
delivered real acceptance and chat events, observed an Oban retry on attempt
|
|
2, rejected replay before transport, and excluded private chat content. It
|
|
retained no credentials, published no host ports, and removed its exact
|
|
project, volume, network, and one-run images. FCM/APNs device registration is
|
|
not claimed.
|
|
- The final regression repeated the 174-test quality/security gate, isolated
|
|
browser 1/1 bootstrap plus 30/30 application scenarios across Chromium,
|
|
Firefox and WebKit, the public 3/3 full workflow replay and 1/1 PWA replay,
|
|
Android debug/staging builds and 7/7 device tests on API 30, 34, and 37, the
|
|
50,000-row database benchmark, authenticated HTTP/LiveView/WebSocket/tracking
|
|
load, Compose crash/replacement and kind rolling drills, alert
|
|
firing/resolution, encrypted backup/restore failure paths, and the external
|
|
protocol boundary. Scoped fixtures and one-run projects were removed,
|
|
retained evidence is ignored and non-secret, and Git was clean at the tested
|
|
application commit before this documentation update.
|
|
- The public-facing database backup also passes a full isolated upgrade
|
|
rehearsal against application commit `af9018f`: the restored copy advanced
|
|
from 8 to all 10 migrations, exposed all 11 valid cursor indexes, ran two web
|
|
and two worker replicas in a four-node cluster, passed cross-node PubSub,
|
|
production HTTPS redirects, trusted-proxy pages, and both health endpoints,
|
|
and retained an empty application-table count diff. The scoped project,
|
|
volume, networks, and one-run image were removed; the ordinary Compose
|
|
project stayed on its original image and migration level.
|
|
- After explicit approval for the development rollout, a fresh backup passed
|
|
its restore drill and the ordinary Compose project was upgraded from 8 to all
|
|
10 migrations at application commit `143e159`. Its full application-table
|
|
snapshot had an empty before/after diff. The current two-web/two-worker
|
|
release then passed local health, four-node cluster/PubSub, public HTTPS/TLS,
|
|
WebSocket Upgrade, post-rollout log scanning, and headed-Chrome Russian
|
|
localization and authorization-boundary checks. Evidence is retained under
|
|
ignored `output/staging-rollout/20260719093528-3223196/`.
|