Context
nexus-postgres (the #213 contract-validation adapter) ships with sqlx features runtime-tokio, postgres, macros — no TLS backend. That was a deliberate scoping decision for the validation skeleton:
- The skeleton's tests connect to a local / unix-socket Postgres (the
nixosTest VM and local DATABASE_URL), so TLS is never exercised.
runtime-tokio-rustls pulls webpki-roots, whose license CDLA-Permissive-2.0 is not in our deny.toml allow-list (gate failure).
runtime-tokio-native-tls pulls openssl-sys / system TLS, which fights our Nix-reproducible builds and IoT cross-compilation values.
So the smallest, policy-change-free, reproducibility-preserving choice for validation was no TLS.
What's needed
Add a TLS-capable connection path so the adapter can reach managed Postgres (RDS, Cloud SQL, Supabase, Neon, …), all of which require TLS. This is production hardening, additive and non-breaking.
Decisions to make when picking this up
- TLS backend:
rustls (pure-Rust, cross-compiles cleanly, aligns with our values) vs native-tls. Leaning rustls — which means adding CDLA-Permissive-2.0 to deny.toml's allow-list (benign permissive data license for the CA-cert bundle).
- Feature-gate it? Consider exposing TLS behind a
tls cargo feature so the default build stays minimal/TLS-free, and only consumers who need managed-server connections opt in.
- Connection-string
sslmode handling + cert verification config surface.
Out of scope
mTLS / client-cert auth, custom CA bundles — separate follow-ups if needed.
Deferred from #213. See docs/plans/2026-06-30-postgres-adapter-plan.md ("Out of scope: production hardening").
Context
nexus-postgres(the #213 contract-validation adapter) ships withsqlxfeaturesruntime-tokio, postgres, macros— no TLS backend. That was a deliberate scoping decision for the validation skeleton:nixosTestVM and localDATABASE_URL), so TLS is never exercised.runtime-tokio-rustlspullswebpki-roots, whose licenseCDLA-Permissive-2.0is not in ourdeny.tomlallow-list (gate failure).runtime-tokio-native-tlspullsopenssl-sys/ system TLS, which fights our Nix-reproducible builds and IoT cross-compilation values.So the smallest, policy-change-free, reproducibility-preserving choice for validation was no TLS.
What's needed
Add a TLS-capable connection path so the adapter can reach managed Postgres (RDS, Cloud SQL, Supabase, Neon, …), all of which require TLS. This is production hardening, additive and non-breaking.
Decisions to make when picking this up
rustls(pure-Rust, cross-compiles cleanly, aligns with our values) vsnative-tls. Leaning rustls — which means addingCDLA-Permissive-2.0todeny.toml's allow-list (benign permissive data license for the CA-cert bundle).tlscargo feature so the default build stays minimal/TLS-free, and only consumers who need managed-server connections opt in.sslmodehandling + cert verification config surface.Out of scope
mTLS / client-cert auth, custom CA bundles — separate follow-ups if needed.
Deferred from #213. See
docs/plans/2026-06-30-postgres-adapter-plan.md("Out of scope: production hardening").