{"record":{"id":"fc96fd2e2fd63003","repo":"Hmbown/CodeWhale","slug":"remote-url-is-not-a-supported-forge","errorCode":null,"errorMessage":"remote url is not a supported forge","messagePattern":"remote url is not a supported forge","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/cloud_dispatch.rs","lineNumber":420,"sourceCode":"\n/// Classify and validate `job.remote_url` before any `git clone` or\n/// sandbox clone. Returns the trimmed URL on success.\npub fn validate_git_remote_url(raw: &str) -> Result<String> {\n    let url = raw.trim();\n    if url.is_empty() || url.len() > MAX_REMOTE_BYTES {\n        bail!(\"remote url is empty or oversized\");\n    }\n    if url.starts_with('-') {\n        bail!(\"remote url must not start with '-'\");\n    }\n    if url.chars().any(char::is_control) {\n        bail!(\"remote url contains control characters\");\n    }\n    if remote_has_userinfo(url) {\n        bail!(\"remote url must not embed userinfo\");\n    }\n    if looks_like_network_git_url(url) && classify_url(url).is_none() {\n        bail!(\"remote url is not a supported forge\");\n    }\n    Ok(url.to_string())\n}\n\n/// Display form of a remote: userinfo is never printed.\npub fn redact_remote_url(raw: &str) -> String {\n    redact_url_userinfo(raw)\n}\n\nfn remote_has_userinfo(url: &str) -> bool {\n    if let Ok(parsed) = reqwest::Url::parse(url) {\n        return !parsed.username().is_empty() || parsed.password().is_some();\n    }\n    // scp-style `user:token@host:path` (plain `git@host:path` is identity, not a secret).\n    if let Some((userinfo, _host)) = url.split_once('@') {\n        return userinfo.contains(':') && !userinfo.eq_ignore_ascii_case(\"git\");\n    }\n    false","sourceCodeStart":402,"sourceCodeEnd":438,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/cloud_dispatch.rs#L402-L438","documentation":"When a URL looks like a network-based git URL (looks_like_network_git_url) but classify_url cannot map it to a known forge (github / cnb / gitee), validation fails. The dispatcher only supports cloning from the forges it knows how to classify and sandbox.","triggerScenarios":"Calling validate_git_remote_url / safe_git_remote_url / clone_repository with a URL whose host is not a recognized forge — e.g. a self-hosted GitLab, Bitbucket, a raw IP, or a typo'd hostname like github.com.evil.io.","commonSituations":"Pointing the tool at an internal/enterprise forge it does not support; host typos or spoofed lookalike domains; mirrors hosted on generic domains; protocol forms (ssh:// with odd ports) the classifier does not recognize.","solutions":["Use a hosted URL on a supported forge: github.com, cnb, or gitee (named hosts win over URL classification).","Fix the hostname typo and re-run; check that the scheme/host match the forge's canonical form.","If you need another forge, that requires extending classify_url — not a caller-side workaround.","Mirror the repository to a supported forge if the original host cannot change."],"exampleFix":"// before\nlet url = \"https://gitlab.internal.corp/team/repo.git\";\nvalidate_git_remote_url(url)?;\n// after\nlet url = \"https://github.com/org/repo.git\";\nvalidate_git_remote_url(url)?;","handlingStrategy":"validation","validationCode":"fn supported_forge_host(url: &str) -> bool {\n    [\"github.com\", \"cnb.cool\", \"gitee.com\"].iter()\n        .any(|h| url.contains(h))\n}","typeGuard":null,"tryCatchPattern":"match validate_git_remote_url(raw) {\n    Err(e) if e.to_string().contains(\"supported forge\") => {\n        eprintln!(\"only github / cnb / gitee remotes are supported; got: {raw}\");\n    }\n    other => { /* ... */ }\n}","preventionTips":["Restrict remote inputs to the supported forge hosts in your product's UI.","Document the supported forges next to the remote URL field.","Watch for lookalike/typo domains; validate the host, not a substring.","Extend classify_url (in the library) when adding forge support — do not bypass validation."],"tags":["validation","git","url","unsupported"],"backgroundTag":"unsupported-operation","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"}