{"record":{"id":"01a34eaafa0743ee","repo":"jdx/mise","slug":"python-locks-require-credential-free-http-artifact-urls","errorCode":null,"errorMessage":"Python locks require credential-free HTTP artifact URLs; configure authentication outside the lockfile","messagePattern":"Python locks require credential-free HTTP artifact URLs; configure authentication outside the lockfile","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/backend/pipx/lock.rs","lineNumber":635,"sourceCode":"    {\n        url.set_path(\"/simple/\");\n    } else {\n        let path = url.path().trim_end_matches('/').trim_end_matches(\"/simple\");\n        url.set_path(&format!(\"{path}/simple/\"));\n    }\n    Ok(url.into())\n}\n\nfn validate_portable_urls(value: &toml::Value) -> Result<()> {\n    match value {\n        toml::Value::String(s) if s.contains(\"://\") => {\n            let url = url::Url::parse(s)?;\n            if !matches!(url.scheme(), \"https\" | \"http\")\n                || !url.username().is_empty()\n                || url.password().is_some()\n                || url.query().is_some()\n            {\n                bail!(\n                    \"Python locks require credential-free HTTP artifact URLs; configure authentication outside the lockfile\"\n                );\n            }\n        }\n        toml::Value::Table(t) => {\n            for value in t.values() {\n                validate_portable_urls(value)?;\n            }\n        }\n        toml::Value::Array(a) => {\n            for value in a {\n                validate_portable_urls(value)?;\n            }\n        }\n        _ => (),\n    }\n    Ok(())\n}","sourceCodeStart":617,"sourceCodeEnd":653,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/backend/pipx/lock.rs#L617-L653","documentation":"validate_portable_urls enforces that every artifact URL recorded in a generated Python (uv) lockfile is an http/https URL with no embedded credentials (username/password) and no query string. Portable locks must work across machines, so credentials cannot be baked into the lockfile; this error signals a URL that would leak or bind authentication into the lock.","triggerScenarios":"Validating a uv lock (validate_uv_lock) or a lock entry's URL when the artifact URL contains userinfo (user:pass@), a password, or a query parameter, or uses a non-http(s) scheme.","commonSituations":"Pointing the lock at a private package index whose artifact URLs embed basic-auth credentials; using a mirror that appends tokens as query strings; hand-editing a lockfile with a credentialed internal registry URL.","solutions":["Remove credentials and query strings from the artifact URLs and configure authentication out-of-band (netrc, keyring, or env-based index auth)","Use a credential-free internal mirror/proxy URL for private artifacts","Regenerate the lock against an index that serves plain https URLs"],"exampleFix":"# before (lockfile entry)\nurl = \"https://user:token@pypi.example.com/pkg.whl\"\n# after\nurl = \"https://pypi.example.com/pkg.whl\" # auth via netrc/env","handlingStrategy":"validation","validationCode":"// validate a lockfile artifact URL before use\nconst u = new URL(url);\nconst ok = (u.protocol === 'https:' || u.protocol === 'http:') && !u.username && !u.password && u.search === '';","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never embed user:pass@ or token query params in lockfile URLs","Configure private index auth via netrc/keyring/env instead of URLs","Use a credential-free internal mirror for private packages"],"tags":["python","lockfile","security","url"],"backgroundTag":"invalid-url-format","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"}