{"record":{"id":"cbf4163796520e08","repo":"jdx/mise","slug":"setup-repository-url-must-be-nonempty-and-must-not","errorCode":null,"errorMessage":"setup repository URL must be nonempty and must not start with '-'","messagePattern":"setup repository URL must be nonempty and must not start with '-'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/history/sync/network.rs","lineNumber":23,"sourceCode":"\nuse eyre::{Result, bail};\n\nuse crate::system::history::shadow::HistoryRepo;\n\n/// The fetched setup branch head.\npub(crate) const UPSTREAM_REF: &str = \"refs/remotes/origin/setup\";\n\n/// A Git transport failed, as distinct from an invalid local configuration,\n/// encryption policy, or reconciliation plan.\n#[derive(Debug, thiserror::Error)]\n#[error(\"{0}\")]\npub(crate) struct NetworkError(pub String);\n\n/// Authentication belongs in a credential helper or SSH agent, never in\n/// persisted connection URLs or the errors recorded in history health.\npub(crate) fn validate_url(value: &str) -> Result<()> {\n    if value.trim().is_empty() || value.trim_start().starts_with('-') {\n        bail!(\"setup repository URL must be nonempty and must not start with '-'\");\n    }\n    let http_like = value\n        .trim_start()\n        .get(..5)\n        .is_some_and(|prefix| prefix.eq_ignore_ascii_case(\"http:\"))\n        || value\n            .trim_start()\n            .get(..6)\n            .is_some_and(|prefix| prefix.eq_ignore_ascii_case(\"https:\"));\n    if http_like && url::Url::parse(value).is_err() {\n        bail!(\"invalid HTTP setup repository URL; use a Git credential helper for authentication\");\n    }\n    if let Ok(url) = url::Url::parse(value) {\n        let http = matches!(url.scheme(), \"http\" | \"https\");\n        if url.password().is_some()\n            || (http\n                && (!url.username().is_empty()\n                    || url.query().is_some()","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/history/sync/network.rs#L5-L41","documentation":"validate_url checks the setup repository URL before any git network command is built with it. An empty URL, or one beginning with '-' after leading whitespace, is rejected: the empty case is meaningless, and a leading dash would be interpreted by git as a command-line flag, enabling argument injection. This guard runs before every fetch/push/ls-remote against the remote.","triggerScenarios":"Calling Network::fetch_with_depth, push, symbolic_head, or ls_remote — or the malformed_http_remotes_fail_without_echoing_credentials path — with a URL that is empty/whitespace-only or starts with '-' (e.g. from an unexpanded template or a config value like \"--upload-pack=...\").","commonSituations":"A placeholder URL left unfilled in configuration; an environment variable interpolating to an empty string; a crafted or copy-pasted remote string attempting option injection into the git invocation.","solutions":["Provide a nonempty repository URL (e.g. https://host/org/repo.git or git@host:org/repo.git)","Remove any leading dash or stray characters from the configured URL","Check where the URL is sourced (env var, template, config) and ensure it expands to a real URL"],"exampleFix":"// before\nlet url = std::env::var(\"HISTORY_REMOTE\").unwrap_or_default(); // \"\"\nRemote::new(&repo, &url).ls_remote()?; // bails\n// after\nlet url = std::env::var(\"HISTORY_REMOTE\")?;\nanyhow::ensure!(!url.trim().is_empty(), \"HISTORY_REMOTE must be set\");\nRemote::new(&repo, &url).ls_remote()?;","handlingStrategy":"validation","validationCode":"fn url_ok(v: &str) -> bool {\n    let t = v.trim();\n    !t.is_empty() && !t.starts_with('-')\n}","typeGuard":"function isValidRemoteUrl(v: unknown): v is string {\n  return typeof v === \"string\" && v.trim().length > 0 && !v.trim().startsWith(\"-\");\n}","tryCatchPattern":"match validate_url(&raw) {\n    Ok(()) => { /* proceed with network call */ }\n    Err(e) => {\n        log::error(\"rejecting setup repository URL: {e}\");\n        return Err(e);\n    }\n}","preventionTips":["Never build git command lines with unvalidated remote strings from user input","Expand and check env-var/template placeholders before they reach the remote field","Treat a leading '-' in any CLI-passed value as hostile and reject it early"],"tags":["git","security","validation","argument-injection"],"backgroundTag":"invalid-url","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}