Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
## [Unreleased]

### Security
- Unsupported database URL errors no longer echo the full connection URL,
preventing embedded credentials from being disclosed in diagnostics.
- **WFL package publishing now keeps credentials registry-scoped.** A
project-controlled `registry` setting can no longer redirect a saved token to
another origin; registry URLs are canonicalized and must use HTTPS without
Expand Down
22 changes: 19 additions & 3 deletions src/interpreter/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,10 @@ pub async fn connect(url: &str) -> Result<DbPool, String> {
.map(DbPool::MySql)
.map_err(|e| format!("Failed to connect to MariaDB/MySQL database: {e}"))
} else {
Err(format!(
"Unsupported database URL '{url}'. Supported schemes: sqlite://, postgres://, postgresql://, mysql://, mariadb://"
))
Err(
"Unsupported database URL scheme. Supported schemes: sqlite://, postgres://, postgresql://, mysql://, mariadb://"
.to_string(),
)
Comment on lines +126 to +129
}
}

Expand Down Expand Up @@ -419,6 +420,21 @@ row_to_value!(mysql_row_to_value, MySqlRow, mysql_int);
mod tests {
use super::*;

#[tokio::test]
async fn unsupported_database_url_does_not_echo_credentials() {
const SECRET: &str = "WFL_TEST_SECRET_unsupported_password_d5e0ec";
let url = format!("oracle://wfl:{SECRET}@database.example/app");

let error = match connect(&url).await {
Ok(_) => panic!("unsupported database URL unexpectedly connected"),
Err(error) => error,
};

assert!(error.contains("Unsupported database URL scheme"));
assert!(!error.contains(SECRET));
assert!(!error.contains(url.as_str()));
}

#[test]
fn whole_numbers_bind_as_integers() {
assert!(matches!(
Expand Down
Loading