From 4ee94865619fab3134d8a8dd3a93741c5db5f48e Mon Sep 17 00:00:00 2001 From: "glm-5.1" Date: Fri, 12 Jun 2026 14:33:48 +0000 Subject: [PATCH] feat(upstream-host-validation): validate host part of upstream address in config Add host part validation to is_valid_upstream: IPv4/IPv6 addresses must parse as valid IpAddr, bracket-enclosed hosts must parse as IPv6, DNS names must pass is_valid_hostname. Previously, values like '!!!bad!!!:3000' would pass. --- src/config/validation.rs | 55 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/src/config/validation.rs b/src/config/validation.rs index 2f40404..4eb643c 100644 --- a/src/config/validation.rs +++ b/src/config/validation.rs @@ -317,7 +317,15 @@ fn is_valid_upstream(upstream: &str) -> bool { Ok(p) => p, Err(_) => return false, }; - port != 0 + if port == 0 { + return false; + } + if host_part.starts_with('[') && host_part.ends_with(']') { + let inner = &host_part[1..host_part.len() - 1]; + inner.parse::().is_ok() + } else { + host_part.parse::().is_ok() || is_valid_hostname(host_part) + } } else { false } @@ -1136,4 +1144,49 @@ mod tests { .iter() .any(|e| matches!(e, ValidationError::KeyPathNotReadable { .. }))); } + + #[test] + fn rule17_upstream_valid_hostname() { + assert!(is_valid_upstream("gitea:3000")); + } + + #[test] + fn rule17_upstream_valid_ipv4() { + assert!(is_valid_upstream("127.0.0.1:3000")); + } + + #[test] + fn rule17_upstream_valid_ipv6_bracket() { + assert!(is_valid_upstream("[::1]:3000")); + } + + #[test] + fn rule17_upstream_valid_ipv6_bracket_full() { + assert!(is_valid_upstream("[2001:db8::1]:8080")); + } + + #[test] + fn rule17_upstream_invalid_hostname_chars() { + assert!(!is_valid_upstream("!!!bad!!!:3000")); + } + + #[test] + fn rule17_upstream_invalid_special_chars() { + assert!(!is_valid_upstream("@#$%:8080")); + } + + #[test] + fn rule17_upstream_empty_host() { + assert!(!is_valid_upstream(":3000")); + } + + #[test] + fn rule17_upstream_invalid_ipv6_bracket() { + assert!(!is_valid_upstream("[notipv6]:3000")); + } + + #[test] + fn rule17_upstream_hostname_with_dots() { + assert!(is_valid_upstream("app.example.com:8080")); + } }