Commit Graph

3 Commits

Author SHA1 Message Date
xarmian 5fffee2b9e fix(docker): bind to 127.0.0.1 + require POSTGRES_PASSWORD (TASK-661) (#174)
* fix(docker): bind to 127.0.0.1 + require POSTGRES_PASSWORD (TASK-661)

A fresh Docker install previously published 7777 on 0.0.0.0 with a
hardcoded pad:pad Postgres credential. The bootstrap endpoint is
reachable until the first admin is created, so this combination lets
anyone who can route to the host claim the instance — and with M5's
X-Forwarded-For spoof (fixed in TASK-660) chained with the loopback
bootstrap check, it became a full takeover.

Changes:
- docker-compose.yml: publish "127.0.0.1:7777:7777" by default, with a
  PAD_BIND_ADDR override for operators who intentionally want LAN
  access. Require POSTGRES_PASSWORD via ${VAR:?err} so docker compose
  refuses to start when it's unset — can't silently inherit a weak
  default credential.
- docker-compose.prod.yml: drop the "change-me-in-production"
  placeholder; require the same env var as the base file.
- .env.example: new file documenting POSTGRES_PASSWORD (required),
  PAD_BIND_ADDR, REDIS_PASSWORD, PAD_CLOUD_SECRET, PAD_ENCRYPTION_KEY,
  PAD_TRUSTED_PROXIES with generation instructions.
- README.md: add a Docker Compose section covering the .env workflow
  and the loopback-default → LAN override.

Parent: PLAN-643 (OSS Security Hardening).

* fix(docker): use libpq keyword=value DSN to avoid URI-encoding the Postgres password per Codex P1

Passwords produced by 'openssl rand -base64' often include '/', '+', or ':'
which are reserved in URI userinfo. Injecting them into postgres://user:PASS@...
breaks sql.Open. Switch PAD_DATABASE_URL to the libpq keyword=value form
(host=... password=... dbname=...) where the password is parsed as a single
token regardless of special characters.

Also teach pgDbnameFromURL to parse both DSN shapes so 'pad db backup/restore'
still shows the correct database name in its confirmation prompt.
2026-04-21 19:14:15 -04:00
xarmian 34ebf31fdf fix: resolve Codex review findings across SSE, audit, metrics, and deployment
- Make SSE limit checks atomic with subscription via SubscribeIfAllowed to
  prevent TOCTOU races where concurrent requests bypass connection caps
- Replace fmt.Sprintf JSON assembly with json.Marshal (auditMeta helper) in
  all audit log call sites to prevent silent JSONB insert failures on
  PostgreSQL when metadata contains special characters
- Pass database credentials via PGDATABASE env var instead of pg_dump/psql
  command-line args to avoid leaking passwords in ps/proc output
- Fix audit-log query builder to rebind placeholders once after all filters
  are appended, preventing duplicate $1 placeholders on PostgreSQL
- Replace per-workspace SSE GaugeVec with a single Gauge to avoid unbounded
  Prometheus label cardinality in multi-tenant deployments
- Fix prod Docker Compose: override PAD_REDIS_URL with password and add
  authenticated Redis healthcheck when REDIS_PASSWORD is set
2026-04-07 01:13:44 +00:00
xarmian af2755d5af docs: add deployment documentation, Docker Compose, and K8s manifests
Provide production-ready deployment configurations:
- docker-compose.yml: Pad + PostgreSQL + Redis single-command setup
- docker-compose.prod.yml: production overlay with resource limits
- deploy/k8s/: Kubernetes manifests (deployment, service, ingress, HPA)
- deploy/Caddyfile: Caddy reverse proxy with auto-TLS
- deploy/nginx.conf: nginx config with SSE-friendly proxy settings
- docs/deployment.md: environment variable reference, architecture
  diagram, quick start, production checklist
2026-04-06 01:58:04 +00:00