{"record":{"id":"ff428679f3e497d5","repo":"can1357/oh-my-pi","slug":"remote-url-must-be-https-github-com-expected-re","errorCode":null,"errorMessage":"remote url must be https://github.com/{expected_repo}[.git]","messagePattern":"remote url must be https://github\\.com/(.+?)\\[\\.git\\]","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"python/robomp/src/proxy/server.py","lineNumber":318,"sourceCode":"\n\ndef _read_single_remote_url(repo_dir: Path, expected_repo: str, *, push: bool, slot_uid: int | None = None) -> str:\n    urls = list(dict.fromkeys(_read_remote_urls(repo_dir, slot_uid=slot_uid, push=push)))\n    if len(urls) != 1:\n        kind = \"push\" if push else \"fetch\"\n        log.warning(\n            \"gh-proxy: refusing git op — origin has ambiguous remote urls\",\n            extra={\"expected_repo\": expected_repo, \"kind\": kind, \"count\": len(urls)},\n        )\n        raise HTTPException(400, f\"origin must have exactly one {kind} url\")\n    return urls[0]\n\n\ndef _normalized_github_https_url(url: str, expected_repo: str) -> str:\n    _validate_repo_name(expected_repo)\n    parsed = urlparse(url)\n    if (parsed.scheme or \"\").lower() != \"https\":\n        raise HTTPException(400, f\"remote url must be https://github.com/{expected_repo}[.git]\")\n    if parsed.username or parsed.password:\n        raise HTTPException(400, \"remote url must not contain embedded credentials\")\n    try:\n        port = parsed.port\n    except ValueError as exc:\n        raise HTTPException(400, \"remote url has invalid port\") from exc\n    if port is not None:\n        raise HTTPException(400, \"remote url must not specify a port\")\n    if (parsed.hostname or \"\").lower() != \"github.com\":\n        raise HTTPException(400, f\"remote url host must be github.com for repo {expected_repo!r}\")\n    if parsed.params or parsed.query or parsed.fragment:\n        raise HTTPException(400, \"remote url must not contain params, query, or fragment\")\n    path = parsed.path.strip(\"/\")\n    if path.endswith(\".git\"):\n        path = path[:-4]\n    if path.lower() != expected_repo.lower():\n        raise HTTPException(400, f\"remote url does not match repo {expected_repo!r}\")\n    return _github_url_for_repo(expected_repo)","sourceCodeStart":300,"sourceCodeEnd":336,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/robomp/src/proxy/server.py#L300-L336","documentation":"Raised by _normalized_github_https_url when the worktree's origin URL is not HTTPS (e.g. ssh://, git@..., git://, file://). The proxy only authenticates and forwards git operations against https://github.com URLs, because it injects a bearer token over HTTPS; SSH URLs would bypass or break that auth model.","triggerScenarios":"Any proxied git op where the repo's origin (fetch or push) scheme is not 'https' — e.g. origin set to git@github.com:acme/repo.git or https replaced by http/ssh/file after cloning.","commonSituations":"Cloning via SSH locally and letting the proxy reuse that worktree; http:// (cleartext) URLs from internal tooling; local path or file:// remotes from offline setups; insteadOf rewrites changing the effective URL.","solutions":["Convert origin to HTTPS: `git remote set-url origin https://github.com/<owner>/<repo>.git`","Strip insteadOf rewrites affecting the URL (`git config --get-all url.*.insteadOf`) if a rewrite is mutating your https URL into ssh","Re-clone the worktree with the HTTPS URL","If you require SSH, do not route those repos through this proxy"],"exampleFix":"// before\n$ git remote set-url origin git@github.com:acme/repo.git\n// after\n$ git remote set-url origin https://github.com/acme/repo.git","handlingStrategy":"validation","validationCode":"from urllib.parse import urlparse\n\ndef origin_is_https(url: str) -> bool:\n    return (urlparse(url).scheme or \"\").lower() == \"https\"","typeGuard":null,"tryCatchPattern":"from fastapi import HTTPException\n\ntry:\n    result = client.post(\"/git/op\", json={\"repo\": \"acme/repo\"})\nexcept HTTPException as e:\n    if e.status_code == 400 and \"must be https\" in e.detail:\n        set_origin_https(worktree_dir, \"acme/repo\")\n    else:\n        raise","preventionTips":["Clone with HTTPS URLs when the worktree will be proxied","Check for and remove `url.*.insteadOf` rewrites that turn https into ssh","Standardize on https://github.com/<owner>/<repo>.git in provisioning scripts"],"tags":["git","https","remote-url","proxy","authentication"],"backgroundTag":"non-https-git-remote","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}