use crate::errors::ProxyError;
const MAX_YAML_BYTES: usize = 4_194_304;
const MAX_EXPANDED_BYTES: usize = 16_777_216;
pub(crate) fn check_yaml_safety(raw: &str) -> Result<(), ProxyError> {
check_yaml_size(raw)?;
check_yaml_expansion(raw, MAX_EXPANDED_BYTES)
}
fn check_yaml_size(raw: &str) -> Result<(), ProxyError> {
if raw.len() > MAX_YAML_BYTES {
return Err(ProxyError::Config(format!(
"YAML input too large ({} bytes, max {MAX_YAML_BYTES})",
raw.len()
)));
}
Ok(())
}
fn check_yaml_expansion(raw: &str, threshold: usize) -> Result<(), ProxyError> {
if let Ok(value) = serde_yaml::from_str::<serde_yaml::Value>(raw)
&& let Ok(expanded) = serde_yaml::to_string(&value)
&& expanded.len() > threshold
{
return Err(ProxyError::Config(format!(
"YAML alias expansion too large ({} bytes expanded from {} bytes raw, \
max {threshold})",
expanded.len(),
raw.len()
)));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reject_oversized_yaml() {
let huge = "x".repeat(5 * 1024 * 1024);
let err = check_yaml_size(&huge).unwrap_err();
assert!(err.to_string().contains("too large"), "should reject oversized YAML");
}
#[test]
fn accept_small_yaml() {
check_yaml_size("a: 1\n").expect("small YAML should pass size check");
}
#[test]
fn reject_yaml_alias_bomb() {
let err = check_yaml_expansion("a: &a x\nb: &b [*a,*a,*a]\nlisteners: []\n", 5);
assert!(err.is_err(), "should reject expansion exceeding threshold");
assert!(
err.unwrap_err().to_string().contains("alias expansion too large"),
"error message should mention alias expansion"
);
}
#[test]
fn accept_yaml_within_expansion_threshold() {
check_yaml_expansion("a: &a x\nb: *a\nlisteners: []\n", 1_000_000)
.expect("small expansion within threshold should pass");
}
#[test]
fn safety_check_rejects_oversized() {
let huge = "x".repeat(5 * 1024 * 1024);
let err = check_yaml_safety(&huge).unwrap_err();
assert!(err.to_string().contains("too large"), "should reject oversized YAML");
}
#[test]
fn safety_check_passes_valid_yaml() {
check_yaml_safety("a: 1\n").expect("valid small YAML should pass all safety checks");
}
}