use autumn_web::aeo::dns_aid::{DnsAidInput, records, valid_mcp_path};
pub fn dns(base_url: Option<String>, mcp_path: Option<&str>, ttl: u32, profile: Option<&str>) {
let base_url = base_url.or_else(|| {
let profile = crate::migrate::effective_profile(profile);
configured_base_url(
crate::migrate::read_autumn_toml_table_with_profile_from_config_dir(Some(&profile))
.as_ref(),
)
});
match render(base_url.as_deref(), mcp_path, ttl) {
Ok(zone) => print!("{zone}"),
Err(err) => {
eprintln!("error: {err}");
std::process::exit(1);
}
}
}
fn configured_base_url(table: Option<&toml::Table>) -> Option<String> {
table?
.get("seo")?
.get("base_url")?
.as_str()
.map(str::to_owned)
}
fn render(base_url: Option<&str>, mcp_path: Option<&str>, ttl: u32) -> Result<String, String> {
let base_url = base_url.ok_or_else(|| {
"no base URL: pass --base-url or set [seo] base_url in autumn.toml".to_owned()
})?;
if let Some(path) = mcp_path.filter(|p| !valid_mcp_path(p)) {
return Err(format!(
"--mcp-path {path:?} is not an absolute path without a query, fragment, \
quote or whitespace"
));
}
let lines = records(&DnsAidInput::new(base_url, mcp_path).ttl(ttl));
if lines.is_empty() {
return Err(format!(
"{base_url:?} is not an http(s) URL with a DNS host name and no credentials, \
query or fragment"
));
}
let mut zone = String::from(
"; DNS-AID records (draft-mozleywilliams-dnsop-dnsaid).\n\
; Sign the zone with DNSSEC so validating resolvers trust them.\n",
);
for line in lines {
zone.push_str(&line);
zone.push('\n');
}
Ok(zone)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn renders_records_with_a_dnssec_note() {
let zone = render(Some("https://example.com"), Some("/mcp"), 600).unwrap();
assert!(zone.starts_with("; DNS-AID records"), "{zone}");
assert!(
zone.contains("_mcp._agents.example.com. 600 IN SVCB 1 example.com."),
"{zone}"
);
assert!(
zone.contains("_catalog._agents.example.com. 600 IN TXT"),
"{zone}"
);
}
#[test]
fn base_url_comes_from_the_seo_table() {
let table: toml::Table =
toml::from_str("[seo]\nbase_url = \"https://example.com\"\n").unwrap();
assert_eq!(
configured_base_url(Some(&table)).as_deref(),
Some("https://example.com")
);
assert_eq!(configured_base_url(None), None);
}
#[test]
fn needs_an_absolute_base_url() {
assert!(render(None, None, 3600).unwrap_err().contains("--base-url"));
assert!(render(Some("example.com"), None, 3600).is_err());
}
#[test]
fn needs_an_absolute_mcp_path() {
let err = render(Some("https://example.com"), Some("mcp"), 3600).unwrap_err();
assert!(err.contains("--mcp-path"), "{err}");
assert!(render(Some("https://example.com"), Some("/mcp?tenant=a"), 3600).is_err());
}
}