Skip to content

Harden deployment: configurable Postgres TLS, auth logging, multi-audience verify - #14

Merged
akumar-99 merged 2 commits into
mainfrom
fix/deployment-hardening
Jun 30, 2026
Merged

Harden deployment: configurable Postgres TLS, auth logging, multi-audience verify#14
akumar-99 merged 2 commits into
mainfrom
fix/deployment-hardening

Conversation

@akumar-99

Copy link
Copy Markdown
Contributor

Fixes surfaced by a real self-hosted production deployment (RDS + Cloudflare mTLS + Google Chat). See the three highest-impact issues from that setup.

Fix 1 — Postgres TLS is configurable, libpq-compatible by default 🔴

The driver now resolves the ssl option itself instead of letting node-pg interpret sslmode. Recent pg treats sslmode=require as verify-full, which rejects managed databases (RDS/Cloud SQL/Neon/Supabase) using a private CA → SELF_SIGNED_CERT_IN_CHAIN crash-loop on first boot.

  • Default: require = encrypt-without-verify (what libpq/psycopg/JDBC/pgx all do)
  • DB_SSL=verify-full + DB_SSL_CA=/path/ca.pem for strict verification
  • DB_SSL=disable to turn TLS off
  • A cert error now prints the exact fix instead of crash-looping

Fix 2 — request + auth-failure logging 🔴

/chat/events was a black box: a bad token returned a bare 401 and logged nothing, so "app not responding" was undebuggable. Now it logs every arrival (type=…) and, on rejection, the concrete reason — missing header / aud mismatch: got X, expected Y / issuer mismatch / signature — from decoded claims, never the token.

Fix 3 — verifier accepts project number or app URL audience 🟡

Google Chat's "Audience" can be the project number or the app URL. The verifier hard-coded project-number-only, so an app-URL token was rejected even when correctly configured. It now accepts a list; the dashboard audience field takes a number and/or an https URL (space-separated).

Testing

  • New unit tests: SSL resolver mapping, JWT claim decode + failure classification, multi-audience verifier, 401-reason logging.
  • Real TLS repro against a self-signed-cert Postgres: old raw sslmode=require fails (DEPTH_ZERO_SELF_SIGNED_CERT), new default connects, verify-full rejects without a CA and connects with DB_SSL_CA.
  • Full suite 111 passed on SQLite and over TLS via Repo.postgres.
  • Docs updated (.env.example, configuration, server-setup).

Not in this PR

  • Fix 4 (GHCR public): there is no REST endpoint to flip container-package visibility — it's a one-time UI toggle by an org owner (asyncup-dev → Packages → asyncup → Package settings → Change visibility → Public).

…ience verify

Fixes from a real self-hosted production setup (RDS + Cloudflare + Google Chat):

- Postgres TLS is now configurable and libpq-compatible by default. The
  driver resolves `ssl` itself instead of letting node-pg treat
  sslmode=require as verify-full (which crash-loops on RDS/Cloud SQL/Neon
  with SELF_SIGNED_CERT_IN_CHAIN). Default: require = encrypt-without-verify;
  DB_SSL=verify-full + DB_SSL_CA for strict; DB_SSL=disable to turn off.
  A cert error now prints the exact fix instead of crash-looping.
- /chat/events logs every arrival and the concrete 401 reason
  (missing header / aud mismatch / issuer mismatch / signature) using
  decoded claims only — never the token. Self-hosting is now debuggable.
- The request verifier accepts multiple audiences, so a token whose aud is
  the app URL (Chat API "Audience" = App URL) is accepted as well as the
  project number; the dashboard field accepts a number and/or https URL.

Tested against a real self-signed-cert Postgres: old raw sslmode=require
fails (DEPTH_ZERO_SELF_SIGNED_CERT), new default connects, verify-full
rejects without a CA and connects with DB_SSL_CA. Full suite (111) passes
on SQLite and over TLS via Repo.postgres.
Comment thread src/server.ts Fixed
Comment thread src/server.ts Fixed
Comment thread src/server.ts
Comment thread src/server.ts
@akumar-99
akumar-99 merged commit 6966fec into main Jun 30, 2026
5 checks passed
@akumar-99
akumar-99 deleted the fix/deployment-hardening branch June 30, 2026 05:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants