{"record":{"id":"c024eb4d64138ffa","repo":"Hmbown/CodeWhale","slug":"fleet-alert-url-from-name-must-use-https-alerts","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/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/fleet/alerts.rs#L489-L525","documentation":"After resolving a Fleet alert URL, `validate_https_alert_url` parses it and requires the scheme to be exactly https. Plain http URLs are rejected because alert payloads may contain sensitive operational data and must not traverse unencrypted connections.","triggerScenarios":"Configuring an alert endpoint secret with an `http://` (or other non-https) scheme and then sending an alert through the affected adapter.","commonSituations":"Pasting a local development webhook (http://localhost:...) into production config; an internal service still exposed over http; a proxy URL written without https.","solutions":["Change the URL secret to an https:// endpoint.","If the target is internal-only, put it behind an https-terminating proxy or tunnel and use that https URL.","For local testing, generate a local https cert or use an https tunnel instead of http."],"exampleFix":"// before\nexport FLEET_WEBHOOK_URL=http://hooks.internal.example.com/alert\n// after\nexport FLEET_WEBHOOK_URL=https://hooks.internal.example.com/alert","handlingStrategy":"validation","validationCode":"fn ensure_https(name: &str, url: &str) -> Result<()> {\n    let parsed = reqwest::Url::parse(url)?;\n    anyhow::ensure!(parsed.scheme() == \"https\", \"{name} must be https\");\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match send_alert(adapter, &prepared).await {\n    Err(e) if e.to_string().contains(\"must use https\") => {\n        log::error!(\"refusing to send alert over insecure endpoint: {e}\");\n    }\n    other => other?,\n}","preventionTips":["Always use https endpoints for alert webhooks, including internal ones.","Validate URL schemes when secrets are loaded, not at send time.","For local dev, use an https tunnel rather than plain http."],"tags":["fleet","alerts","url","https","security"],"backgroundTag":"invalid-url-format","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}