can1357/oh-my-pi · error · HTTPException

remote url must not contain embedded credentials

Error message

remote url must not contain embedded credentials

What it means

Raised when the origin HTTPS URL embeds credentials (username or password in the URL, e.g. https://user:token@github.com/...). The proxy forbids this because it injects its own token; embedded credentials would leak secrets into git's stored remote config and conflict with proxy-managed auth.

Source

Thrown at python/robomp/src/proxy/server.py:320

def _read_single_remote_url(repo_dir: Path, expected_repo: str, *, push: bool, slot_uid: int | None = None) -> str:
    urls = list(dict.fromkeys(_read_remote_urls(repo_dir, slot_uid=slot_uid, push=push)))
    if len(urls) != 1:
        kind = "push" if push else "fetch"
        log.warning(
            "gh-proxy: refusing git op — origin has ambiguous remote urls",
            extra={"expected_repo": expected_repo, "kind": kind, "count": len(urls)},
        )
        raise HTTPException(400, f"origin must have exactly one {kind} url")
    return urls[0]


def _normalized_github_https_url(url: str, expected_repo: str) -> str:
    _validate_repo_name(expected_repo)
    parsed = urlparse(url)
    if (parsed.scheme or "").lower() != "https":
        raise HTTPException(400, f"remote url must be https://github.com/{expected_repo}[.git]")
    if parsed.username or parsed.password:
        raise HTTPException(400, "remote url must not contain embedded credentials")
    try:
        port = parsed.port
    except ValueError as exc:
        raise HTTPException(400, "remote url has invalid port") from exc
    if port is not None:
        raise HTTPException(400, "remote url must not specify a port")
    if (parsed.hostname or "").lower() != "github.com":
        raise HTTPException(400, f"remote url host must be github.com for repo {expected_repo!r}")
    if parsed.params or parsed.query or parsed.fragment:
        raise HTTPException(400, "remote url must not contain params, query, or fragment")
    path = parsed.path.strip("/")
    if path.endswith(".git"):
        path = path[:-4]
    if path.lower() != expected_repo.lower():
        raise HTTPException(400, f"remote url does not match repo {expected_repo!r}")
    return _github_url_for_repo(expected_repo)

View on GitHub (pinned to 9690622007)

Solutions

  1. Strip credentials: `git remote set-url origin https://github.com/<owner>/<repo>.git`
  2. Check for insteadOf rewrites (`git config --get-regexp url\..*\.insteadof`) that inject credentials, and remove them
  3. Rotate any token that was stored in the remote URL — it is persisted in .git/config in cleartext
  4. Let the proxy supply auth (it injects its own token) rather than embedding credentials

Example fix

// before
$ git remote set-url origin https://x-access-token:ghp_SECRET@github.com/acme/repo.git
// after
$ git remote set-url origin https://github.com/acme/repo.git
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

def origin_has_no_embedded_credentials(url: str) -> bool:
    p = urlparse(url)
    return not (p.username or p.password)

Try / catch

from fastapi import HTTPException

try:
    result = client.post("/git/op", json={"repo": "acme/repo"})
except HTTPException as e:
    if e.status_code == 400 and "embedded credentials" in e.detail:
        rotate_token_from_url(worktree_dir)  # strip creds AND rotate the leaked token
    else:
        raise

Prevention

When it happens

Trigger: Any proxied git op where urlparse(url) shows a username or password component in the origin URL — typically after someone baked a PAT into the remote during setup, or a credential-carrying URL was pasted from CI tooling.

Common situations: CI-generated remotes like https://x-access-token:ghp_...@github.com/... left in the worktree; copy-pasted URLs including basic-auth; secret managers rewriting URLs with tokens.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/3f3418b61681eafd. Report an issue: GitHub.