Skip to content

Resolve native database TLS settings as PHP Server 2.9.10 does - #559

Merged
rmcdaniel merged 7 commits into
mainfrom
rust-325-database-tls
Oct 21, 2026
Merged

rmcdaniel merged 7 commits into
mainfrom
rust-325-database-tls

Conversation

@rmcdaniel

Copy link
Copy Markdown
Member

Part of #325 (operations gate: DW_*/DB_* configuration compatibility).

PHP Server 2.9.10 (#545) added explicit database TLS settings. With this change, native reads the same settings, applies the same rules, and refuses the same configurations. One deployment configuration now means the same thing to both servers.

Behavior. The new database_tls module follows PHP's DatabaseTlsConfiguration and config/database.php:

  • Inputs.

    • DB_SSLMODE, with the Helm chart's alias DB_SSL_MODE;
    • DB_SSLROOTCERT, with the alias DB_SSL_ROOT_CERT;
    • a DB_URL's sslmode/sslrootcert;
    • MySQL's legacy MYSQL_ATTR_SSL_CA.

    Laravel's env() reading applies (null, empty, explicitly empty values). Mode names are normalized (required, verify_identity, …), and PostgreSQL defaults to prefer.

  • Refusals (database_tls_configuration_invalid, with PHP's messages):

    • conflicting aliases;
    • a URL that contradicts DB_SSLMODE or DB_SSLROOTCERT;
    • unknown modes, and MySQL/MariaDB modes other than disable, require and verify-full;
    • verification without a readable CA bundle;
    • a CA without a mode;
    • required TLS over a Unix socket (including MySQL's localhost and DB_SOCKET);
    • MySQL CA conflicts, and disabled TLS combined with TLS options.
  • DB_URL. Native used to ignore DB_SSLMODE and DB_SSLROOTCERT whenever DB_URL was set. TLS now always comes from the resolved settings, and TLS spellings that only SQLx reads are removed from the URL before parsing.

  • Startup and readiness.

    • An invalid configuration stops native at startup.
    • A failed connection that required TLS stops it with database_tls_connection_failed.
    • PHP keeps serving and reports both cases as an unavailable readiness check.
    • When the database is reachable, /api/ready carries PHP's checks.database.tls snapshot (mode, encrypted, CA and hostname verification, evidence), scoped rust_to_configured_database_endpoint.
  • Known difference. With no configured mode, native MySQL uses TLS when the server offers it, while PHP sets no TLS options. Both report the mode as unset.

Qualification. scripts/conformance/native-database-tls.sh NATIVE_BINARY runs PHP's qualify-database-tls.sh cases on its fixtures (scripts/ci/database-tls-compose.yaml, pinned images):

  • TLS servers (PostgreSQL 17, MySQL 8.0, MariaDB 10.11). Each runs verified, encrypted-only, the chart aliases, wrong CA and wrong hostname.
  • PostgreSQL extras. Missing and unreadable CA, and a URL that verifies or tries to downgrade.
  • MySQL chain-only verification.
  • Plaintext servers. disable connects; require is refused.

The database side confirms the transport. PostgreSQL's pg_stat_ssl shows native's connections encrypted, and the MySQL/MariaDB fixture accounts accept only TLS.

Local run on this commit: all 24 cases passed, and the fixtures were retired afterwards.

Checks. The four database_tls unit tests mirror PHP's DatabaseTlsConfigurationTest cases. The native lib suite (124) and the SQLite execution suite (287) pass.

🤖 Generated with Claude Code

durable-workflow-ops and others added 4 commits October 20, 2026 23:04
Native now reads DB_SSLMODE/DB_SSL_MODE, DB_SSLROOTCERT/DB_SSL_ROOT_CERT,
a DB_URL's sslmode/sslrootcert and MYSQL_ATTR_SSL_CA with the rules of
PHP's DatabaseTlsConfiguration, and refuses the same configurations with
database_tls_configuration_invalid. TLS always comes from the resolved
settings, including when DB_URL is set, which native previously let
override DB_SSLMODE. A failed connection that required TLS refuses startup
with database_tls_connection_failed, and readiness reports PHP's TLS
snapshot. native-database-tls.sh runs PHP's TLS qualification cases on its
fixtures against the native binary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rmcdaniel

Copy link
Copy Markdown
Member Author

Sonar's security gate flagged two literal URL passwords in the database_tls URL-parsing tests (S6697). 76386e758 replaces them with password-free URLs. These still cover an encoded @ in the user name and an IPv6 host. 96f841fc3 merges main (#550). On the merged head, the native lib suite (128) and the SQLite execution suite (294) pass locally.

@rmcdaniel
rmcdaniel disabled auto-merge October 21, 2026 01:17
@rmcdaniel
rmcdaniel enabled auto-merge October 21, 2026 01:24
@rmcdaniel

Copy link
Copy Markdown
Member Author

10c29d7f0 merges main (#548). The first full SQLite run on this head had two failures: cooperative_child_independent_deadline_preserves_leased_parent and ..._reuses_ready_parent (child still pending when cancelled was expected). Both tests depend on a cooperative cancellation deadline. They passed twice when run alone, and a full rerun passed (lib 128, execution 295). This change does not touch that path, so I'm tracking it separately as a timing flake under load. Auto-merge is back on; parity run 39526376043 on this head is running.

durable-workflow-ops and others added 2 commits October 21, 2026 03:17
The PostgreSQL and MySQL fixture jobs check that a wrong CA and a wrong
hostname refuse native's schema check. With required TLS, native now names
that refusal database_tls_connection_failed, as PHP Server 2.9.10 does,
instead of storage_unavailable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@rmcdaniel

Copy link
Copy Markdown
Member Author

Updated with main after #523 merged (a454c62; main.rs merged cleanly, unit tests pass locally).

The earlier fixtures run 39526376043 on 10c29d7 failed two jobs:

  • postgres-storage TLS checks. The workflow still expected storage_unavailable for a wrong CA and a wrong hostname. This PR deliberately names that refusal database_tls_connection_failed, as PHP 2.9.10 does. 2185a87 updates both the PostgreSQL and MySQL checks.
  • execution-and-codec. Published PHP 2.5.14 answered HTTP 500 to the manual-lifecycle schedule trigger after resume. That is the reference server on SQLite, not native, and it is the only such failure in the last 30 fixtures runs. I'll add a guarded retry if it recurs.

I cancelled the superseded runs on 10c29d7 and a454c62. The run on 2185a87 is the qualifying one.

@sonarqubecloud

Copy link
Copy Markdown

@rmcdaniel
rmcdaniel merged commit 7e56e91 into main Oct 21, 2026
22 checks passed
@rmcdaniel
rmcdaniel deleted the rust-325-database-tls branch October 21, 2026 03:43
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