{"record":{"id":"aab209b97c6be56a","repo":"Hmbown/CodeWhale","slug":"fleet-alert-url-from-name-must-use-https","errorCode":null,"errorMessage":"fleet alert URL from {name} must use https","messagePattern":"fleet alert URL from (.+?) must use https","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/fleet/alerts.rs","lineNumber":507,"sourceCode":"        .ok_or_else(|| anyhow!(\"fleet alert secret {name} is not configured\"))\n}\n\nfn required_https_url<R>(resolver: &R, name: &str) -> Result<String>\nwhere\n    R: FleetAlertSecretResolver,\n{\n    let url = resolver\n        .resolve(name)\n        .ok_or_else(|| anyhow!(\"fleet alert URL {name} is not configured\"))?;\n    validate_https_alert_url(name, &url)?;\n    Ok(url)\n}\n\nfn validate_https_alert_url(name: &str, url: &str) -> Result<()> {\n    let parsed = reqwest::Url::parse(url)\n        .with_context(|| format!(\"fleet alert URL from {name} is not a valid URL\"))?;\n    if parsed.scheme() != \"https\" {\n        return Err(anyhow!(\"fleet alert URL from {name} must use https\"));\n    }\n    Ok(())\n}\n\nfn short_reason(reason: &str) -> String {\n    let trimmed = reason.trim();\n    if trimmed.len() <= 240 {\n        return trimmed.to_string();\n    }\n    let prefix: String = trimmed.chars().take(237).collect();\n    format!(\"{prefix}...\")\n}\n\nfn default_pagerduty_severity() -> String {\n    \"error\".to_string()\n}\n\n#[cfg(test)]","sourceCodeStart":489,"sourceCodeEnd":525,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/fleet/alerts.rs#L489-L525","documentation":"After a URL secret resolves, `validate_https_alert_url` parses it and requires scheme `https` (fleet/alerts.rs:507). http:// and every other scheme are rejected so alert payloads never travel in cleartext.","triggerScenarios":"The URL variable contains an `http://` endpoint because the internal receiver has no TLS; a localhost test URL; a scheme typo that fails parsing or a non-http scheme that fails the check.","commonSituations":"Local testing endpoints; internal relays without TLS; proxies that terminate TLS while config points at the plain internal port.","solutions":["Use an https:// URL — terminate TLS at a reverse proxy if the backend speaks plain HTTP","Or point at an https relay that forwards to the internal endpoint","Fix scheme typos in the URL variable"],"exampleFix":"# before\nexport FLEET_ALERT_WEBHOOK_URL=http://10.0.0.5:9090/hook\n# after\nexport FLEET_ALERT_WEBHOOK_URL=https://alerts.internal/hook","handlingStrategy":"validation","validationCode":"let raw = std::env::var(&adapter.url_env).context(\"URL not configured\")?;\nlet parsed = reqwest::Url::parse(&raw)?;\nanyhow::ensure!(parsed.scheme() == \"https\", \"alert URL must be https: {raw}\");","typeGuard":"fn is_https_url(raw: &str) -> bool {\n    reqwest::Url::parse(raw)\n        .map(|u| u.scheme() == \"https\")\n        .unwrap_or(false)\n}","tryCatchPattern":null,"preventionTips":["Provision only https endpoints for alert delivery","Front plain-HTTP receivers with a TLS-terminating proxy","Validate the scheme at config load, not at dispatch time"],"tags":["alerts","fleet","security","url","tls"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}