{"record":{"id":"6fa096a2b179b9a9","repo":"gitbutlerapp/gitbutler","slug":"url-type-must-use-https-url","errorCode":null,"errorMessage":"{url_type} must use HTTPS: {url}","messagePattern":"(.+?) must use HTTPS: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-installer/src/release.rs","lineNumber":104,"sourceCode":"            release.version,\n            requested\n        );\n    }\n\n    Ok(release)\n}\n\n/// Common URL validation logic for GitButler domains.\n///\n/// Validates HTTPS protocol, parses URL, and checks the host against a predicate.\nfn validate_gitbutler_url(\n    url: &str,\n    url_type: &str,\n    is_host_valid: impl Fn(&str) -> bool,\n) -> Result<()> {\n    // Only allow HTTPS URLs\n    if !url.starts_with(\"https://\") {\n        bail!(\"{url_type} must use HTTPS: {url}\");\n    }\n\n    // Extract host from URL\n    let url_parsed =\n        url::Url::parse(url).with_context(|| format!(\"Invalid {} URL\", url_type.to_lowercase()))?;\n    let host = url_parsed\n        .host_str()\n        .ok_or_else(|| anyhow!(\"No host in {} URL\", url_type.to_lowercase()))?;\n\n    // Validate host using the provided predicate\n    if !is_host_valid(host) {\n        bail!(\"{url_type} is not from a trusted GitButler domain: {url}\");\n    }\n\n    Ok(())\n}\n\n/// Validates that an API URL is from the trusted API domain.","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/58e5313667b857ef39a730e380af31816a7b1768/crates/but-installer/src/release.rs#L86-L122","documentation":"validate_gitbutler_url enforces that all API/download URLs use HTTPS before further host checks. This error is thrown when a URL passed to validate_api_url or validate_download_url does not start with https://, protecting against plaintext downloads that could be tampered with.","triggerScenarios":"A constructed or configured URL uses http:// (or another scheme), typically from custom config, a hardcoded http endpoint, or building the URL with the wrong scheme.","commonSituations":"User-supplied mirror/config with http://, internal testing endpoint left in config, code concatenating \"http://\" by mistake, redirect source handing back an insecure URL.","solutions":["Change the URL scheme to https://","Fix the code/config that builds the URL to always use https","If testing locally, use a local HTTPS endpoint or bypass the validator in a test-only path","Update any custom mirror configuration to an HTTPS mirror"],"exampleFix":"// before\nlet url = format!(\"http://releases.gitbutler.com/{version}\");\n// after\nlet url = format!(\"https://releases.gitbutler.com/{version}\");","handlingStrategy":"validation","validationCode":"fn is_https(url: &str) -> bool { url.starts_with(\"https://\") }","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"must use HTTPS\") => {\n        // upgrade the URL scheme to https and retry\n    }\n    other => other?,\n}","preventionTips":["Always build URLs with https:// constants, not user-supplied schemes","Normalize/validate any user-configured mirror URLs at startup","Never downgrade to http for 'testing' in production paths"],"tags":["security","https","url","validation"],"backgroundTag":"invalid-url-format","analyzedSha":"58e5313667b857ef39a730e380af31816a7b1768","analyzedAt":"2026-09-18T06:50:32.052Z","contentChangedAt":"2026-09-18T06:50:32.052Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}