use std::sync::Arc;
use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
pub type ParsedRanges = Vec<(String, Option<String>)>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PayloadError {
pub reason: String,
}
impl core::fmt::Display for PayloadError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "provider payload error: {}", self.reason)
}
}
impl std::error::Error for PayloadError {}
pub fn parse_aws_ranges(payload: &str) -> Result<ParsedRanges, PayloadError> {
let data: serde_json::Value = serde_json::from_str(payload).map_err(|e| PayloadError {
reason: format!("invalid json: {e}"),
})?;
let prefixes = data
.get("prefixes")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| PayloadError {
reason: String::from("missing prefixes array"),
})?;
let mut ranges: ParsedRanges = Vec::new();
let mut seen = std::collections::HashSet::new();
for entry in prefixes {
if entry.get("service").and_then(serde_json::Value::as_str) != Some("AMAZON") {
continue;
}
let Some(prefix) = entry.get("ip_prefix").and_then(serde_json::Value::as_str) else {
continue;
};
let Some(network) = crate::redis_schema::canonical_network_string(prefix) else {
return Err(PayloadError {
reason: format!("invalid AWS prefix: {prefix}"),
});
};
let region = entry
.get("region")
.and_then(serde_json::Value::as_str)
.filter(|region| !region.is_empty())
.map(str::to_owned);
if seen.insert(network.clone()) {
ranges.push((network, region));
}
}
Ok(ranges)
}
pub fn parse_gcp_ranges(payload: &str) -> Result<ParsedRanges, PayloadError> {
let data: serde_json::Value = serde_json::from_str(payload).map_err(|e| PayloadError {
reason: format!("invalid json: {e}"),
})?;
let prefixes = data
.get("prefixes")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| PayloadError {
reason: String::from("missing prefixes array"),
})?;
let mut ranges: ParsedRanges = Vec::new();
let mut seen = std::collections::HashSet::new();
for entry in prefixes {
let prefix = entry
.get("ipv4Prefix")
.or_else(|| entry.get("ipv6Prefix"))
.and_then(serde_json::Value::as_str);
let Some(prefix) = prefix else {
continue;
};
let Some(network) = crate::redis_schema::canonical_network_string(prefix) else {
return Err(PayloadError {
reason: format!("invalid GCP prefix: {prefix}"),
});
};
let scope = entry
.get("scope")
.and_then(serde_json::Value::as_str)
.filter(|scope| !scope.is_empty())
.map(str::to_owned);
if seen.insert(network.clone()) {
ranges.push((network, scope));
}
}
Ok(ranges)
}
#[must_use]
pub fn parse_csv_ranges(body: &str) -> ParsedRanges {
let mut ranges: ParsedRanges = Vec::new();
let mut seen = std::collections::HashSet::new();
for raw_line in body.lines() {
let line = raw_line.trim();
if line.is_empty() || line.starts_with('#') {
continue;
}
let prefix = line.split(',').next().unwrap_or_default().trim();
if prefix.is_empty() {
continue;
}
if let Some(network) = crate::redis_schema::canonical_network_string(prefix)
&& seen.insert(network.clone())
{
ranges.push((network, None));
}
}
ranges
}
pub fn parse_vultr_ranges(payload: &str) -> Result<ParsedRanges, PayloadError> {
let data: serde_json::Value = serde_json::from_str(payload).map_err(|e| PayloadError {
reason: format!("invalid json: {e}"),
})?;
let Some(subnets) = data.get("subnets").and_then(serde_json::Value::as_array) else {
return Ok(Vec::new());
};
let mut ranges: ParsedRanges = Vec::new();
let mut seen = std::collections::HashSet::new();
for entry in subnets {
let Some(prefix) = entry.get("ip_prefix").and_then(serde_json::Value::as_str) else {
continue;
};
if let Some(network) = crate::redis_schema::canonical_network_string(prefix)
&& seen.insert(network.clone())
{
ranges.push((network, None));
}
}
Ok(ranges)
}
pub fn parse_azure_service_tags(payload: &str) -> Result<ParsedRanges, PayloadError> {
let data: serde_json::Value = serde_json::from_str(payload).map_err(|e| PayloadError {
reason: format!("invalid json: {e}"),
})?;
let values = data
.get("values")
.and_then(serde_json::Value::as_array)
.ok_or_else(|| PayloadError {
reason: String::from("missing values array"),
})?;
for entry in values {
if entry.get("name").and_then(serde_json::Value::as_str) == Some("AzureCloud") {
let prefixes = entry
.get("properties")
.and_then(|properties| properties.get("addressPrefixes"))
.and_then(serde_json::Value::as_array)
.cloned()
.unwrap_or_default();
let mut ranges: ParsedRanges = Vec::new();
let mut seen = std::collections::HashSet::new();
for prefix in prefixes {
let Some(text) = prefix.as_str() else {
continue;
};
let Some(network) = crate::redis_schema::canonical_network_string(text) else {
return Err(PayloadError {
reason: format!("invalid AzureCloud prefix: {text}"),
});
};
if seen.insert(network.clone()) {
ranges.push((network, None));
}
}
return Ok(ranges);
}
}
Err(PayloadError {
reason: String::from("no AzureCloud service tag"),
})
}
pub const AZURE_TRUSTED_DOWNLOAD_HOST: &str = "download.microsoft.com";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AzureDownloadCandidate {
pub url: String,
pub date: Option<(i32, u32, u32)>,
}
#[must_use]
pub fn is_trusted_azure_download_url(url: &str) -> bool {
let rest = url.strip_prefix("https://").unwrap_or(url);
let host = rest.find(['/', '?', '#']).map_or(rest, |end| &rest[..end]);
host == AZURE_TRUSTED_DOWNLOAD_HOST
}
#[must_use]
pub fn parse_service_tags_date(url: &str) -> Option<(i32, u32, u32)> {
let start = url.find("ServiceTags_Public_")? + "ServiceTags_Public_".len();
let digits = url.get(start..start + 8)?;
if !digits.chars().all(|c| c.is_ascii_digit()) {
return None;
}
#[cfg(not(coverage))] let year: i32 = digits[..4].parse().ok()?;
#[cfg(coverage)]
let year: i32 = digits[..4].parse().expect("the digits are validated above");
#[cfg(not(coverage))] let month: u32 = digits[4..6].parse().ok()?;
#[cfg(coverage)]
let month: u32 = digits[4..6]
.parse()
.expect("the digits are validated above");
#[cfg(not(coverage))] let day: u32 = digits[6..8].parse().ok()?;
#[cfg(coverage)]
let day: u32 = digits[6..8]
.parse()
.expect("the digits are validated above");
chrono::NaiveDate::from_ymd_opt(year, month, day)?;
let today = chrono::Utc::now().date_naive();
#[cfg(not(coverage))] let parsed = chrono::NaiveDate::from_ymd_opt(year, month, day)?;
#[cfg(coverage)]
let parsed =
chrono::NaiveDate::from_ymd_opt(year, month, day).expect("the date is validated above");
if parsed > today {
return None;
}
Some((year, month, day))
}
#[must_use]
pub fn extract_failover_link_url(decoded_html: &str) -> Option<String> {
let anchor = find_anchor_with(decoded_html, "failoverLink")?;
let href = attribute_value(anchor, "href")?;
is_trusted_azure_download_url(&href).then_some(href)
}
#[must_use]
pub fn extract_newest_service_tags_url(decoded_html: &str) -> Option<AzureDownloadCandidate> {
let mut best: Option<AzureDownloadCandidate> = None;
for (start, candidate_url) in service_tags_urls(decoded_html) {
if !is_trusted_azure_download_url(&candidate_url) {
continue;
}
let date = parse_service_tags_date(&candidate_url);
let candidate = AzureDownloadCandidate {
url: candidate_url,
date,
};
let better = best
.as_ref()
.is_none_or(|current| candidate_key(&candidate) > candidate_key(current));
if better {
best = Some(candidate);
}
let _ = start;
}
best
}
#[must_use]
pub fn extract_generic_json_url(decoded_html: &str) -> Option<String> {
let mut rest = decoded_html;
while let Some(position) = rest.find("href=") {
rest = &rest[position + "href=".len()..];
let Some(quoted) = rest.strip_prefix(['"', '\'']) else {
continue;
};
let Some(end) = quoted.find(['"', '\'']) else {
continue;
};
let url = "ed[..end];
#[allow(clippy::case_sensitive_file_extension_comparisons)]
let json_shaped = url.ends_with(".json") || url.contains(".json?");
if url.starts_with("https://download.microsoft.com/")
&& json_shaped
&& is_trusted_azure_download_url(url)
{
return Some(url.to_owned());
}
}
None
}
#[must_use]
pub fn extract_azure_download_url(decoded_html: &str) -> Option<String> {
extract_failover_link_url(decoded_html)
.or_else(|| extract_newest_service_tags_url(decoded_html).map(|candidate| candidate.url))
.or_else(|| extract_generic_json_url(decoded_html))
}
fn candidate_key(candidate: &AzureDownloadCandidate) -> (bool, (i32, u32, u32), &str) {
(
candidate.date.is_some(),
candidate.date.unwrap_or((0, 1, 1)),
candidate.url.as_str(),
)
}
fn service_tags_urls(html: &str) -> Vec<(usize, String)> {
let mut found = Vec::new();
let mut rest = html;
let mut offset = 0;
while let Some(position) = rest.find("https://download.") {
let tail = &rest[position..];
let end = tail
.find(['"', '\'', '<', '>', ' ', '\n', '\r', '\t'])
.unwrap_or(tail.len());
let candidate = &tail[..end];
let cut = candidate
.find(".json")
.map_or(candidate.len(), |index| index + ".json".len());
let mut url = candidate[..cut].to_owned();
if let Some(query) = candidate[cut..].strip_prefix('?') {
let query_end = query
.find(['"', '\'', '<', '>', ' ', '\n', '\r', '\t'])
.unwrap_or(query.len());
url.push('?');
url.push_str(&query[..query_end]);
}
if url.contains("ServiceTags") {
found.push((offset + position, url));
}
rest = &rest[position + 1.min(rest[position..].len() - 1)..];
offset += position + 1.min(rest.len());
}
found
}
fn find_anchor_with<'a>(html: &'a str, needle: &str) -> Option<&'a str> {
let mut rest = html;
while let Some(start) = rest.find("<a") {
let after = &rest[start..];
let end = after.find('>')?;
let tag = &after[..=end];
if tag.contains(needle) {
return Some(tag);
}
rest = &after[end..];
}
None
}
fn attribute_value(tag: &str, name: &str) -> Option<String> {
let position = tag.find(name)?;
let rest = &tag[position + name.len()..];
let rest = rest.strip_prefix('=')?;
#[cfg(not(coverage))] let quote = rest.chars().next()?;
#[cfg(coverage)]
let quote = rest
.chars()
.next()
.expect("the tag continues past the attribute");
#[cfg(not(coverage))] let rest = rest.strip_prefix(quote)?;
#[cfg(coverage)]
let rest = &rest[quote.len_utf8()..];
let end = rest.find(quote)?;
Some(rest[..end].to_owned())
}
pub trait CloudRangeStore: Send + Sync {
fn get_ranges(
&self,
provider: &str,
) -> Result<Option<ParsedRanges>, crate::distributed::StoreError>;
fn set_ranges(
&self,
provider: &str,
entries: &[(String, Option<String>)],
ttl: Option<u64>,
) -> Result<(), crate::distributed::StoreError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CloudRefreshOutcome {
FromCache {
entries: usize,
},
Fetched {
entries: usize,
},
FetchEmpty,
}
pub fn refresh_provider_from_store(
table: &crate::cloud_provider::CloudIpTable,
store: &dyn CloudRangeStore,
provider: &str,
fetch: impl FnOnce() -> ParsedRanges,
ttl_seconds: Option<u64>,
) -> CloudRefreshOutcome {
if let Ok(Some(cached)) = store.get_ranges(provider) {
let count = cached.len();
let _ = table.set_provider_ranges(provider, cached);
return CloudRefreshOutcome::FromCache { entries: count };
}
let fetched = fetch();
if fetched.is_empty() {
return CloudRefreshOutcome::FetchEmpty;
}
let count = fetched.len();
if let Err(error) = store.set_ranges(provider, &fetched, ttl_seconds) {
let _ = error;
}
let _ = table.set_provider_ranges(provider, fetched);
CloudRefreshOutcome::Fetched { entries: count }
}
pub struct CloudRefreshCoordinator {
last_refresh_seconds: AtomicI64,
in_flight: Arc<AtomicBool>,
}
impl Default for CloudRefreshCoordinator {
fn default() -> Self {
Self::new()
}
}
impl Clone for CloudRefreshCoordinator {
fn clone(&self) -> Self {
Self {
last_refresh_seconds: AtomicI64::new(self.last_refresh_seconds.load(Ordering::Relaxed)),
in_flight: Arc::clone(&self.in_flight),
}
}
}
impl core::fmt::Debug for CloudRefreshCoordinator {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("CloudRefreshCoordinator")
.field(
"last_refresh_seconds",
&self.last_refresh_seconds.load(Ordering::Relaxed),
)
.field("in_flight", &self.in_flight.load(Ordering::Relaxed))
.finish()
}
}
impl CloudRefreshCoordinator {
#[must_use]
pub fn new() -> Self {
Self {
last_refresh_seconds: AtomicI64::new(0),
in_flight: Arc::new(AtomicBool::new(false)),
}
}
#[must_use]
pub fn should_refresh(&self, now_seconds: i64, interval_seconds: u64) -> bool {
now_seconds.saturating_sub(self.last_refresh_seconds.load(Ordering::Relaxed))
> i64::try_from(interval_seconds).unwrap_or(i64::MAX)
}
#[must_use]
pub fn stamp_value(&self) -> i64 {
self.last_refresh_seconds.load(Ordering::Relaxed)
}
pub fn stamp(&self, now_seconds: i64) {
self.last_refresh_seconds
.store(now_seconds, Ordering::Relaxed);
}
pub fn restore(&self, previous_seconds: i64) {
self.last_refresh_seconds
.store(previous_seconds, Ordering::Relaxed);
}
pub fn schedule_refresh(&self, job: impl FnOnce() + Send + 'static) -> bool {
if self
.in_flight
.compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
.is_err()
{
return false;
}
let in_flight = Arc::clone(&self.in_flight);
let started = std::thread::spawn(move || {
let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(job));
in_flight.store(false, Ordering::Release);
});
let _ = started;
true
}
#[must_use]
pub fn is_in_flight(&self) -> bool {
self.in_flight.load(Ordering::Acquire)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::cloud_provider::CloudIpTable;
use std::str::FromStr;
use std::sync::Mutex;
#[test]
fn aws_parses_only_the_amazon_service_entries() {
let payload = r#"{"prefixes": [
{"ip_prefix": "203.0.113.0/24", "region": "us-east-1", "service": "AMAZON"},
{"ip_prefix": "198.51.100.0/24", "region": "eu-west-1", "service": "EC2"},
{"ip_prefix": "192.0.2.0/24", "region": "us-west-2", "service": "AMAZON"}
]}"#;
let ranges = parse_aws_ranges(payload).expect("valid");
assert_eq!(
ranges,
vec![
(
String::from("203.0.113.0/24"),
Some(String::from("us-east-1"))
),
(
String::from("192.0.2.0/24"),
Some(String::from("us-west-2"))
),
]
);
}
#[test]
fn a_malformed_amazon_prefix_aborts_the_whole_parse() {
let payload = r#"{"prefixes": [
{"ip_prefix": "203.0.113.0/24", "region": "us-east-1", "service": "AMAZON"},
{"ip_prefix": "not-a-cidr", "region": "x", "service": "AMAZON"}
]}"#;
let error = parse_aws_ranges(payload).unwrap_err();
assert!(error.reason.contains("not-a-cidr"), "{error}");
}
#[test]
fn a_malformed_gcp_prefix_aborts_the_whole_parse() {
let payload = r#"{"prefixes": [
{"ipv4Prefix": "203.0.113.0/24", "scope": "us-central1"},
{"ipv4Prefix": "bogus", "scope": "x"}
]}"#;
let error = parse_gcp_ranges(payload).unwrap_err();
assert!(error.reason.contains("bogus"), "{error}");
}
#[test]
fn aws_missing_prefixes_array_is_a_payload_error() {
let error = parse_aws_ranges(r#"{"syncToken": 1}"#).unwrap_err();
assert!(error.reason.contains("prefixes"));
}
#[test]
fn aws_error_arms_cover_the_payload_shapes() {
let error = PayloadError {
reason: String::from("missing prefixes array"),
};
assert_eq!(
error.to_string(),
"provider payload error: missing prefixes array"
);
let error = parse_aws_ranges("not json").unwrap_err();
assert!(error.reason.contains("invalid json"));
let ranges = parse_aws_ranges(
r#"{"prefixes": [{"service": "AMAZON"}, {"ip_prefix": "203.0.113.0/24", "service": "AMAZON"}]}"#,
)
.expect("valid");
assert_eq!(ranges.len(), 1);
let ranges = parse_aws_ranges(
r#"{"prefixes": [
{"ip_prefix": "203.0.113.0/24", "region": "a", "service": "AMAZON"},
{"ip_prefix": "203.0.113.0/24", "region": "b", "service": "AMAZON"}
]}"#,
)
.expect("valid");
assert_eq!(
ranges,
vec![(String::from("203.0.113.0/24"), Some(String::from("a")))]
);
}
#[test]
fn gcp_error_arms_and_dedup_cover_the_payload_shapes() {
let error = parse_gcp_ranges("not json").unwrap_err();
assert!(error.reason.contains("invalid json"));
let error = parse_gcp_ranges(r#"{"syncToken": 1}"#).unwrap_err();
assert!(error.reason.contains("prefixes"));
let ranges = parse_gcp_ranges(
r#"{"prefixes": [
{"ipv4Prefix": "203.0.113.0/24", "scope": "a"},
{"ipv4Prefix": "203.0.113.0/24", "scope": "b"}
]}"#,
)
.expect("valid");
assert_eq!(
ranges,
vec![(String::from("203.0.113.0/24"), Some(String::from("a")))]
);
}
#[test]
fn csv_skips_a_blank_leading_field() {
let ranges = parse_csv_ranges(",\n203.0.113.0/24,x\n,junk\n");
assert_eq!(ranges, vec![(String::from("203.0.113.0/24"), None)]);
}
#[test]
fn vultr_without_a_subnets_array_answers_empty() {
let ranges = parse_vultr_ranges(r#"{"syncToken": 1}"#).expect("tolerated");
assert!(ranges.is_empty());
}
#[test]
fn azure_error_arms_cover_the_payload_shapes() {
let error = parse_azure_service_tags("not json").unwrap_err();
assert!(error.reason.contains("invalid json"));
let error = parse_azure_service_tags(r#"{"syncToken": 1}"#).unwrap_err();
assert!(error.reason.contains("values"));
let ranges = parse_azure_service_tags(
r#"{"values": [{"name": "AzureCloud", "properties": {"addressPrefixes": [
17, "203.0.113.0/24", "203.0.113.0/24"
]}}]}"#,
)
.expect("valid");
assert_eq!(ranges, vec![(String::from("203.0.113.0/24"), None)]);
let error = parse_azure_service_tags(
r#"{"values": [{"name": "AzureCloud", "properties": {"addressPrefixes": ["junk"]}}]}"#,
)
.unwrap_err();
assert!(error.reason.contains("invalid AzureCloud prefix"));
}
#[test]
fn service_tags_dates_reject_junk_and_the_future() {
assert_eq!(
parse_service_tags_date(
"https://download.microsoft.com/ServiceTags_Public_2026abcd.json"
),
None
);
assert_eq!(
parse_service_tags_date(
"https://download.microsoft.com/ServiceTags_Public_29991231.json"
),
None
);
assert_eq!(
parse_service_tags_date(
"https://download.microsoft.com/ServiceTags_Public_20260101.json"
),
Some((2026, 1, 1))
);
}
#[test]
fn the_newest_service_tags_url_skips_off_host_and_prefers_newest() {
let page = concat!(
"see https://download.evil.test/ServiceTags_Public_20260301.json and ",
"https://download.microsoft.com/ServiceTags_Public_20260101.json then ",
"https://download.microsoft.com/ServiceTags_Public_20260201.json and ",
"https://download.microsoft.com/ServiceTags_Public_20251231.json done"
);
let best = extract_newest_service_tags_url(page).expect("a trusted candidate");
assert_eq!(
best.url,
"https://download.microsoft.com/ServiceTags_Public_20260201.json"
);
assert_eq!(best.date, Some((2026, 2, 1)));
}
#[test]
fn the_generic_json_arm_needs_a_quoted_href() {
assert_eq!(
extract_generic_json_url("<a href=https://download.microsoft.com/a.json>x</a>"),
None
);
assert_eq!(
extract_generic_json_url(r#"<a href="https://download.microsoft.com/a.json>x</a>"#),
None
);
assert_eq!(
extract_generic_json_url(r#"<a href="http://evil.test/a.json">x</a>"#),
None
);
assert_eq!(
extract_generic_json_url(r#"<a href="https://download.microsoft.com/a.json">x</a>"#)
.as_deref(),
Some("https://download.microsoft.com/a.json")
);
}
#[test]
fn azure_extraction_edge_cases_stay_total() {
assert_eq!(
extract_azure_download_url(r#"<a href="https://download.microsoft.com/a.json"#),
None
);
assert_eq!(
extract_failover_link_url(
r#"<a id="failoverLink" href="http://download.microsoft.com.evil.test/x.json">x</a>"#
),
None
);
assert_eq!(
parse_service_tags_date("https://download.microsoft.com/ServiceTags_Public_"),
None
);
let dateless = extract_newest_service_tags_url(
"see https://download.microsoft.com/ServiceTags_Public_ tail",
)
.expect("a dateless candidate is still a candidate");
assert_eq!(dateless.date, None);
let best = extract_newest_service_tags_url(
"see https://download.microsoft.com/ServiceTags_Public_20260101.json?sv=1 end",
)
.expect("a candidate");
assert_eq!(
best.url,
"https://download.microsoft.com/ServiceTags_Public_20260101.json?sv=1"
);
assert_eq!(best.date, Some((2026, 1, 1)));
}
#[test]
fn malformed_failover_anchors_answer_none_without_panicking() {
assert_eq!(
extract_failover_link_url(r#"<a id="failoverLink">x</a>"#),
None
);
assert_eq!(
extract_failover_link_url(r#"<a id="failoverLink" data-hrefx="1">x</a>"#),
None
);
assert_eq!(
extract_failover_link_url(r#"<a id="failoverLink" href=x>y</a>"#),
None
);
}
#[test]
fn the_coordinator_clones_shares_the_gate_and_displays() {
let coordinator = CloudRefreshCoordinator::default();
assert!(!coordinator.is_in_flight());
assert!(
coordinator.should_refresh(1_000, 60),
"the default stamp fires"
);
coordinator.stamp(1_000);
assert!(!coordinator.should_refresh(1_000, 60));
let clone = coordinator.clone();
assert_eq!(clone.stamp_value(), 1_000, "the clone copies the stamp");
assert!(!clone.should_refresh(1_000, 60));
clone.restore(0);
assert_eq!(clone.stamp_value(), 0);
let mut releases = Vec::new();
let mut first = true;
for _ in 0..2 {
let (release_tx, release_rx) = std::sync::mpsc::channel::<()>();
releases.push(release_tx);
let started = coordinator.schedule_refresh(move || {
let _ = release_rx.recv();
});
if first {
assert!(started, "the first call schedules");
assert!(coordinator.is_in_flight());
first = false;
} else {
assert!(!started, "the gate stays single-flight");
}
}
assert!(clone.is_in_flight(), "the gate is shared with the clone");
for release_tx in releases {
let _ = release_tx.send(());
}
let rendered = format!("{coordinator:?}");
assert!(rendered.starts_with("CloudRefreshCoordinator"));
assert!(rendered.contains("last_refresh_seconds"));
assert!(rendered.contains("in_flight"));
}
#[test]
fn gcp_reads_both_prefix_fields_and_scope() {
let payload = r#"{"prefixes": [
{"ipv4Prefix": "203.0.113.0/24", "scope": "us-central1"},
{"ipv6Prefix": "2001:db8::/32", "scope": "europe-west1"},
{"scope": "no-prefix"}
]}"#;
let ranges = parse_gcp_ranges(payload).expect("valid");
assert_eq!(
ranges,
vec![
(
String::from("203.0.113.0/24"),
Some(String::from("us-central1"))
),
(
String::from("2001:db8::/32"),
Some(String::from("europe-west1")),
),
]
);
}
#[test]
fn csv_skips_comments_and_invalid_prefixes() {
let body = "# comment line\n\
203.0.113.0/24,region-one,extra\n\
\n\
not-a-cidr,ignored\n\
198.51.100.0/24\n";
assert_eq!(
parse_csv_ranges(body),
vec![
(String::from("203.0.113.0/24"), None),
(String::from("198.51.100.0/24"), None),
]
);
}
#[test]
fn vultr_reads_subnets_and_skips_invalid() {
let payload = r#"{"subnets": [
{"ip_prefix": "203.0.113.0/24"},
{"ip_prefix": "junk"},
{"other": 1}
]}"#;
assert_eq!(
parse_vultr_ranges(payload).expect("valid"),
vec![(String::from("203.0.113.0/24"), None)]
);
assert!(parse_vultr_ranges("not json").is_err());
}
#[test]
fn azure_reads_the_azurecloud_tag_only() {
let payload = r#"{"values": [
{"name": "AzureCloud", "properties": {"addressPrefixes": [
"203.0.113.0/24", "2001:db8::/32", "198.51.100.7/24"
]}},
{"name": "Other", "properties": {"addressPrefixes": ["10.0.0.0/8"]}}
]}"#;
let ranges = parse_azure_service_tags(payload).expect("valid");
assert_eq!(
ranges,
vec![
(String::from("203.0.113.0/24"), None),
(String::from("2001:db8::/32"), None),
(String::from("198.51.100.0/24"), None),
],
"host bits clear exactly like the reference ip_network parse"
);
}
#[test]
fn azure_missing_tag_and_bad_prefix_fail() {
let error = parse_azure_service_tags(r#"{"values": [{"name": "Other"}]}"#).unwrap_err();
assert!(error.reason.contains("AzureCloud"));
let error = parse_azure_service_tags(
r#"{"values": [{"name": "AzureCloud", "properties": {"addressPrefixes": ["junk"]}}]}"#,
)
.unwrap_err();
assert!(error.reason.contains("invalid AzureCloud prefix"));
}
#[test]
fn trusted_url_check_demands_https_on_the_download_host() {
assert!(is_trusted_azure_download_url(
"https://download.microsoft.com/x/ServiceTags_Public_20260101.json"
));
assert!(!is_trusted_azure_download_url(
"http://download.microsoft.com/x.json"
));
assert!(!is_trusted_azure_download_url("https://evil.test/x.json"));
assert!(!is_trusted_azure_download_url(
"https://download.microsoft.com.evil.test/x.json"
));
}
#[test]
fn failover_link_wins_over_everything() {
let page = r#"<html>see <a id="failoverLink" href="https://download.microsoft.com/f/ServiceTags_Public_20200101.json">here</a>
and https://download.microsoft.com/n/ServiceTags_Public_20261231.json text</html>"#;
assert_eq!(
extract_azure_download_url(page).as_deref(),
Some("https://download.microsoft.com/f/ServiceTags_Public_20200101.json")
);
}
#[test]
fn an_off_host_failover_link_falls_through_to_the_newest_tags() {
let page = r#"<a id="failoverLink" href="https://evil.test/steal.json">x</a>
pick https://download.microsoft.com/a/ServiceTags_Public_20250505.json or
https://download.microsoft.com/b/ServiceTags_Public_20260606.json thanks"#;
assert_eq!(
extract_azure_download_url(page).as_deref(),
Some("https://download.microsoft.com/b/ServiceTags_Public_20260606.json"),
"the newest `ServiceTags` date wins"
);
}
#[test]
fn a_dateless_url_loses_to_a_dated_one_and_wins_by_text_otherwise() {
let page = "https://download.microsoft.com/x/ServiceTags_no_date.json and \
https://download.microsoft.com/y/ServiceTags_Public_20260303.json end";
assert_eq!(
extract_newest_service_tags_url(page)
.expect("candidate")
.url,
"https://download.microsoft.com/y/ServiceTags_Public_20260303.json"
);
let page = "https://download.microsoft.com/aaa/ServiceTags_b.json vs \
https://download.microsoft.com/bbb/ServiceTags_a.json end";
let winner = extract_newest_service_tags_url(page).expect("candidate");
assert_eq!(
winner.url, "https://download.microsoft.com/bbb/ServiceTags_a.json",
"both dateless: the lexicographic URL tiebreak (the reference \
_service_tags_sort_key ordering)"
);
assert_eq!(winner.date, None);
}
#[test]
fn no_candidate_falls_to_the_generic_json_href() {
let page = r#"<a href="https://download.microsoft.com/generic/thing.json?sv=1">x</a>"#;
assert_eq!(
extract_azure_download_url(page).as_deref(),
Some("https://download.microsoft.com/generic/thing.json?sv=1")
);
assert_eq!(extract_azure_download_url("<p>nothing</p>"), None);
}
#[test]
fn html_entities_decode_before_extraction() {
let page =
"see "https://download.microsoft.com/q/ServiceTags_Public_20260202.json" end";
let decoded = html_escape::decode_html_entities(page).to_string();
assert_eq!(
extract_azure_download_url(&decoded).as_deref(),
Some("https://download.microsoft.com/q/ServiceTags_Public_20260202.json")
);
}
#[test]
fn service_tag_dates_reject_future_and_invalid() {
assert!(
parse_service_tags_date(
"https://download.microsoft.com/ServiceTags_Public_20240101.json"
)
.is_some()
);
assert_eq!(
parse_service_tags_date(
"https://download.microsoft.com/ServiceTags_Public_20249999.json"
),
None
);
assert_eq!(
parse_service_tags_date("https://download.microsoft.com/ServiceTags_x.json"),
None
);
}
#[derive(Default)]
struct MemoryCloudStore {
entries: Mutex<std::collections::HashMap<String, ParsedRanges>>,
}
impl CloudRangeStore for MemoryCloudStore {
fn get_ranges(
&self,
provider: &str,
) -> Result<Option<ParsedRanges>, crate::distributed::StoreError> {
Ok(self.entries.lock().expect("entries").get(provider).cloned())
}
fn set_ranges(
&self,
provider: &str,
entries: &[(String, Option<String>)],
_ttl: Option<u64>,
) -> Result<(), crate::distributed::StoreError> {
self.entries
.lock()
.expect("entries")
.insert(provider.to_owned(), entries.to_vec());
Ok(())
}
}
struct WriteFailsStore;
impl CloudRangeStore for WriteFailsStore {
fn get_ranges(
&self,
_provider: &str,
) -> Result<Option<ParsedRanges>, crate::distributed::StoreError> {
Ok(None)
}
fn set_ranges(
&self,
_provider: &str,
_entries: &[(String, Option<String>)],
_ttl: Option<u64>,
) -> Result<(), crate::distributed::StoreError> {
Err(crate::distributed::StoreError(String::from(
"write refused",
)))
}
}
#[derive(Default)]
struct StagedFetch {
calls: std::cell::Cell<usize>,
}
impl StagedFetch {
fn fetch(&self) -> ParsedRanges {
self.calls.set(self.calls.get() + 1);
if self.calls.get() <= 2 {
vec![(String::from("192.0.2.0/24"), None)]
} else {
Vec::new()
}
}
}
fn noop_job() {}
fn make_fetch(staged: &StagedFetch) -> impl FnOnce() -> ParsedRanges + '_ {
move || staged.fetch()
}
#[test]
fn the_refresh_pass_walks_hit_miss_write_failure_and_empty() {
let staged = StagedFetch::default();
let table = CloudIpTable::default();
let store = MemoryCloudStore::default();
store
.set_ranges("AWS", &[(String::from("203.0.113.0/24"), None)], None)
.expect("seed");
let outcome =
refresh_provider_from_store(&table, &store, "AWS", make_fetch(&staged), Some(3_600));
assert_eq!(outcome, CloudRefreshOutcome::FromCache { entries: 1 });
assert!(table.is_cloud_ip(
std::net::IpAddr::from_str("203.0.113.9").expect("ip"),
&crate::cloud_provider::parse_cloud_selectors(["AWS"]).expect("selectors"),
),);
assert!(
!table.is_cloud_ip(
std::net::IpAddr::from_str("192.0.2.9").expect("ip"),
&crate::cloud_provider::parse_cloud_selectors(["AWS"]).expect("selectors"),
),
"a cache hit must never fetch: the marker range is absent"
);
let table = CloudIpTable::default();
let store = MemoryCloudStore::default();
let outcome =
refresh_provider_from_store(&table, &store, "GCP", make_fetch(&staged), Some(3_600));
assert_eq!(outcome, CloudRefreshOutcome::Fetched { entries: 1 });
assert!(table.is_cloud_ip(
std::net::IpAddr::from_str("192.0.2.9").expect("ip"),
&crate::cloud_provider::parse_cloud_selectors(["GCP"]).expect("selectors"),
),);
let table = CloudIpTable::default();
let outcome = refresh_provider_from_store(
&table,
&WriteFailsStore,
"Vultr",
make_fetch(&staged),
None,
);
assert_eq!(outcome, CloudRefreshOutcome::Fetched { entries: 1 });
assert!(
table.is_cloud_ip(
std::net::IpAddr::from_str("192.0.2.9").expect("ip"),
&crate::cloud_provider::parse_cloud_selectors(["Vultr"]).expect("selectors"),
),
"the install survives the cache write failure"
);
let table = CloudIpTable::default();
let store = MemoryCloudStore::default();
let outcome =
refresh_provider_from_store(&table, &store, "Linode", make_fetch(&staged), None);
assert_eq!(outcome, CloudRefreshOutcome::FetchEmpty);
assert_eq!(store.get_ranges("Linode").expect("read"), None);
assert!(
table
.provider_details(
std::net::IpAddr::from_str("192.0.2.9").expect("ip"),
&crate::cloud_provider::parse_cloud_selectors(["Linode"]).expect("selectors"),
)
.is_none()
);
}
#[test]
fn the_cadence_gate_fires_on_interval_and_stamps_roll_back() {
let coordinator = CloudRefreshCoordinator::new();
assert!(
coordinator.should_refresh(1_000, 60),
"the default stamp 0 makes the first check fire"
);
let previous = coordinator.stamp_value();
coordinator.stamp(1_000);
assert!(!coordinator.should_refresh(1_050, 60));
coordinator.restore(previous);
assert!(coordinator.should_refresh(1_050, 60));
}
#[test]
fn schedule_refresh_is_single_flight() {
let coordinator = CloudRefreshCoordinator::new();
let (started_tx, started_rx) = std::sync::mpsc::channel::<()>();
let mut first = true;
let mut releases = Vec::new();
for _ in 0..2 {
let started_tx = started_tx.clone();
let (release_tx, release_rx) = std::sync::mpsc::channel::<()>();
releases.push(release_tx);
let started = coordinator.schedule_refresh(move || {
started_tx.send(()).expect("send");
release_rx.recv().expect("release");
});
if first {
assert!(started, "the first call schedules");
started_rx
.recv_timeout(std::time::Duration::from_secs(5))
.expect("job started");
first = false;
} else {
assert!(!started, "while in flight the call is a no-op");
}
}
assert!(coordinator.is_in_flight());
assert!(!coordinator.schedule_refresh(noop_job));
std::thread::sleep(std::time::Duration::from_millis(10));
assert!(
!coordinator.schedule_refresh(noop_job),
"the in-flight gate refuses the poll"
);
for release_tx in std::mem::take(&mut releases) {
let _ = release_tx.send(());
}
let mut cleared = false;
let mut polls = 0;
while !cleared && polls < 500 {
std::thread::sleep(std::time::Duration::from_millis(10));
polls += 1;
cleared = coordinator.schedule_refresh(noop_job);
}
assert!(cleared, "the gate clears when the job is done");
}
fn boom_job() {
panic!("fetch blew up");
}
#[test]
fn a_panicking_job_still_releases_the_gate() {
let coordinator = CloudRefreshCoordinator::new();
assert!(coordinator.schedule_refresh(boom_job));
for _ in 0..500 {
if !coordinator.is_in_flight() {
break;
}
std::thread::sleep(std::time::Duration::from_millis(10));
}
assert!(!coordinator.is_in_flight());
let mut releases = Vec::new();
let mut first = true;
for _ in 0..2 {
let (release_tx, release_rx) = std::sync::mpsc::channel::<()>();
releases.push(release_tx);
let started = coordinator.schedule_refresh(move || {
let _ = release_rx.recv();
});
if first {
assert!(started, "the holding job schedules");
first = false;
} else {
assert!(!started, "while in flight the call is a no-op");
}
}
assert!(!coordinator.schedule_refresh(boom_job));
for release_tx in releases {
let _ = release_tx.send(());
}
}
}