fix: keep connection string query parameters under token auth (#10859)

* fix: keep connection string query parameters under token auth

* refactor: fold the database url parsing into one connect-options helper

* docs: state the narrower invariant on base_connect_options

* chore: update ee-repo-ref to 212cc7d61ec38580d4a70d9ac38d7a2cc9daf409

This commit updates the EE repository reference after PR #746 was merged in windmill-ee-private.

Previous ee-repo-ref: a15d08345d7e42526c28382079ad1f575a2d1674

New ee-repo-ref: 212cc7d61ec38580d4a70d9ac38d7a2cc9daf409

Automated by sync-ee-ref workflow.

---------

Co-authored-by: windmill-internal-app[bot] <windmill-internal-app[bot]@users.noreply.github.com>
This commit is contained in:
Ruben Fiszel
2026-08-26 23:08:36 +02:00
committed by GitHub
co-authored by windmill-internal-app[bot]
parent af15a73b8b
commit f131c3920f
3 changed files with 15 additions and 51 deletions
+1 -1
View File
@@ -1 +1 @@
d6aef91c0f7ba556befbf4addeb7674d4a9dd819
212cc7d61ec38580d4a70d9ac38d7a2cc9daf409
-45
View File
@@ -1,45 +0,0 @@
use anyhow::Result;
/// Parsed database connection parameters, shared across DB auth providers (IAM RDS, Entra ID, etc.)
#[derive(Debug, Clone)]
pub struct DatabaseParams {
pub hostname: String,
pub port: u64,
pub username: String,
pub database: String,
}
/// Extract database connection parameters from a PostgreSQL URL
pub fn extract_database_params(database_url: &str) -> Result<DatabaseParams> {
let url = url::Url::parse(database_url)
.map_err(|e| anyhow::anyhow!("Failed to parse database URL: {}", e))?;
let hostname = url
.host_str()
.ok_or_else(|| anyhow::anyhow!("Database URL missing hostname"))?
.to_string();
let port = url.port().unwrap_or(5432) as u64;
let username = if url.username().is_empty() {
return Err(anyhow::anyhow!("Database URL missing username"));
} else {
urlencoding::decode(url.username())?.to_string()
};
let database = url
.path()
.trim_start_matches('/')
.split('/')
.next()
.filter(|s| !s.is_empty())
.ok_or_else(|| anyhow::anyhow!("Database URL missing database name"))?
.to_string();
Ok(DatabaseParams {
hostname,
port,
username,
database: urlencoding::decode(&database)?.to_string(),
})
}
+14 -5
View File
@@ -42,7 +42,6 @@ pub mod db;
mod db_entra_ee;
#[cfg(all(feature = "enterprise", feature = "private"))]
mod db_iam_ee;
pub mod db_params;
pub mod dbt_manifest;
pub mod deploy_origin;
#[cfg(feature = "private")]
@@ -1479,6 +1478,17 @@ pub async fn create_custom_instance_database(
Ok(())
}
/// Connection options parsed from a database URL.
///
/// The only place a database URL becomes `PgConnectOptions`. Providers that mint the password
/// themselves override it on these and keep the rest: options assembled field by field instead
/// would drop every query parameter, `sslmode` and `sslrootcert` above all, leaving the
/// connection on sqlx's default TLS policy rather than the operator's.
pub fn base_connect_options(database_url: &str) -> Result<sqlx::postgres::PgConnectOptions, Error> {
sqlx::postgres::PgConnectOptions::from_str(database_url)
.map_err(|e| Error::InternalErr(format!("Failed to parse database URL: {}", e)))
}
#[derive(Clone)]
pub enum DatabaseUrl {
#[cfg(all(feature = "enterprise", feature = "private"))]
@@ -1509,8 +1519,8 @@ impl DatabaseUrl {
}
/// Get PgConnectOptions for this database URL.
/// For token-based auth (IAM RDS, Entra ID), this returns options built directly from the
/// token to avoid double-encoding issues with temporary credentials.
/// For token-based auth (IAM RDS, Entra ID), this returns options carrying the current
/// token, set on the builder to avoid double-encoding temporary credentials.
/// For static URLs, this parses the URL string.
pub async fn connect_options(&self) -> Result<sqlx::postgres::PgConnectOptions, Error> {
match self {
@@ -1524,8 +1534,7 @@ impl DatabaseUrl {
let guard = entra_url.read().await;
Ok(guard.connect_options())
}
DatabaseUrl::Static(url) => sqlx::postgres::PgConnectOptions::from_str(url)
.map_err(|e| Error::InternalErr(format!("Failed to parse database URL: {}", e))),
DatabaseUrl::Static(url) => base_connect_options(url),
}
}