Skip to content

Commit 0994b92

Browse files
lovasoacursoragent
andauthored
Sqlpage port variable parsing (#1206)
* Ignore invalid SQLPAGE_PORT values from Kubernetes service environment variables Co-authored-by: contact <contact@ophir.dev> * Use custom visitor for port deserialization instead of serde_json::Value Co-authored-by: contact <contact@ophir.dev> * Fix clippy warnings about uninlined format args Co-authored-by: contact <contact@ophir.dev> * Add robust port deserialization for Kubernetes --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
1 parent 8b26827 commit 0994b92

1 file changed

Lines changed: 60 additions & 1 deletion

File tree

src/app_config.rs

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::cli::arguments::{parse_cli, Cli};
22
use crate::webserver::content_security_policy::ContentSecurityPolicyTemplate;
33
use crate::webserver::routing::RoutingConfig;
4+
use actix_web::http::Uri;
45
use anyhow::Context;
56
use config::Config;
67
use openidconnect::IssuerUrl;
@@ -9,6 +10,7 @@ use serde::de::Error;
910
use serde::{Deserialize, Deserializer, Serialize};
1011
use std::net::{SocketAddr, ToSocketAddrs};
1112
use std::path::{Path, PathBuf};
13+
use std::str::FromStr;
1214
use std::time::Duration;
1315

1416
#[cfg(not(feature = "lambda-web"))]
@@ -190,6 +192,7 @@ pub struct AppConfig {
190192

191193
#[serde(default, deserialize_with = "deserialize_socket_addr")]
192194
pub listen_on: Option<SocketAddr>,
195+
#[serde(default, deserialize_with = "deserialize_port")]
193196
pub port: Option<u16>,
194197
pub unix_socket: Option<PathBuf>,
195198

@@ -439,6 +442,36 @@ fn env_config() -> config::Environment {
439442
.with_list_parse_key("sqlite_extensions")
440443
}
441444

445+
fn deserialize_port<'de, D>(deserializer: D) -> Result<Option<u16>, D::Error>
446+
where
447+
D: Deserializer<'de>,
448+
{
449+
// deserializes both 8080 and "tcp://1.1.1.1:9090"
450+
#[derive(Deserialize)]
451+
#[serde(untagged)]
452+
enum PortOrUrl {
453+
Port(u16),
454+
Url(String),
455+
}
456+
let port_or_url: Option<PortOrUrl> = Deserialize::deserialize(deserializer)?;
457+
match port_or_url {
458+
Some(PortOrUrl::Port(p)) => Ok(Some(p)),
459+
Some(PortOrUrl::Url(u)) => {
460+
if let Ok(u) = Uri::from_str(&u) {
461+
log::warn!("{u} is not a valid value for the SQLPage port number. Ignoring this error since kubernetes may set the SQLPAGE_PORT env variable to a service URI when there is a service named sqlpage. Rename your service to avoid this warning.");
462+
Ok(None)
463+
} else {
464+
Err(D::Error::custom(format!(
465+
"Invalid port number: {u}. Expected a number between {} and {}",
466+
u16::MIN,
467+
u16::MAX
468+
)))
469+
}
470+
}
471+
None => Ok(None),
472+
}
473+
}
474+
442475
fn deserialize_socket_addr<'de, D: Deserializer<'de>>(
443476
deserializer: D,
444477
) -> Result<Option<SocketAddr>, D::Error> {
@@ -545,7 +578,7 @@ fn create_default_database(configuration_directory: &Path) -> String {
545578
);
546579
drop(tmp_file);
547580
if let Err(e) = std::fs::remove_file(&default_db_path) {
548-
log::debug!("Unable to remove temporary probe file. It might have already been removed by another instance started concurrently: {}", e);
581+
log::debug!("Unable to remove temporary probe file. It might have already been removed by another instance started concurrently: {e}");
549582
}
550583
return prefix + &encode_uri(&default_db_path) + "?mode=rwc";
551584
}
@@ -754,6 +787,32 @@ mod test {
754787
env::remove_var("SQLPAGE_CONFIGURATION_DIRECTORY");
755788
}
756789

790+
#[test]
791+
fn test_k8s_env_var_ignored() {
792+
let _lock = ENV_LOCK
793+
.lock()
794+
.expect("Another test panicked while holding the lock");
795+
env::set_var("SQLPAGE_PORT", "tcp://10.0.0.1:8080");
796+
797+
let config = load_from_env().unwrap();
798+
assert_eq!(config.port, None);
799+
800+
env::remove_var("SQLPAGE_PORT");
801+
}
802+
803+
#[test]
804+
fn test_valid_port_env_var() {
805+
let _lock = ENV_LOCK
806+
.lock()
807+
.expect("Another test panicked while holding the lock");
808+
env::set_var("SQLPAGE_PORT", "9000");
809+
810+
let config = load_from_env().unwrap();
811+
assert_eq!(config.port, Some(9000));
812+
813+
env::remove_var("SQLPAGE_PORT");
814+
}
815+
757816
#[test]
758817
fn test_config_priority() {
759818
let _lock = ENV_LOCK

0 commit comments

Comments
 (0)