can1357/oh-my-pi · error · HTTPException
invalid repo {repo!r}
Error message
invalid repo {repo!r} What it means
`_validate_repo_name` rejects repo identifiers that fail _GITHUB_REPO_RE (owner/name shape) or contain traversal fragments ('/..' or '../'). It guards every URL and path derived from the repo name, raising this HTTP 400 before any GitHub request or filesystem access.
Source
Thrown at python/robomp/src/proxy/server.py:260
"ROBOMP_GIT_HTTP_AUTH",
"GITHUB_TOKEN",
"GH_TOKEN",
"GITHUB_WEBHOOK_SECRET",
"ROBOMP_REPLAY_TOKEN",
"ROBOMP_GH_PROXY_HMAC_KEY",
)
@dataclass(slots=True, frozen=True)
class _RemoteAuth:
url: str
token: str | None
auth_url: str | None
def _validate_repo_name(repo: str) -> None:
if not _GITHUB_REPO_RE.fullmatch(repo) or "/.." in repo or "../" in repo:
raise HTTPException(400, f"invalid repo {repo!r}")
def _github_url_for_repo(repo: str) -> str:
_validate_repo_name(repo)
return f"https://github.com/{repo}.git"
def _git_probe_env(repo_dir: Path) -> dict[str, str]:
env = {**os.environ, "GIT_TERMINAL_PROMPT": "0", "GIT_ASKPASS": "", "SSH_ASKPASS": ""}
for key in _GIT_PROBE_SCRUBBED_ENV_KEYS:
env.pop(key, None)
env.update(_safe_directory_env(repo_dir))
return env
def _read_remote_urls(repo_dir: Path, slot_uid: int | None = None, *, push: bool = False) -> list[str]:
"""Read every configured fetch URL or push URL for `origin` without contacting it."""
env = _git_probe_env(repo_dir)View on GitHub (pinned to 9690622007)
Solutions
- Pass the fully qualified 'owner/repo' identifier exactly as it appears on GitHub (e.g. 'octocat/hello-world').
- Strip any '.git' suffix or URL prefix before sending — the regex expects the bare owner/name form.
- Sanitize path fragments: reject/normalize any value containing '..' or leading dots client-side.
- If the repo legitimately fails the regex (unusual characters in the name), confirm the exact casing/characters against the GitHub URL and use the canonical form.
Example fix
// before
await proxy.get("/workflows/runs", params={"repo": "hello-world"})
// after
await proxy.get("/workflows/runs", params={"repo": "octocat/hello-world"}) Defensive patterns
Strategy: validation
Validate before calling
import re
REPO_RE = re.compile(r"^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$")
def safe_repo(repo: str) -> str:
repo = repo.removesuffix(".git")
if not REPO_RE.fullmatch(repo) or "/.." in repo or "../" in repo:
raise ValueError(f"invalid repo {repo!r}; expected 'owner/name'")
return repo Type guard
def is_repo_name(v: object) -> TypeGuard[str]:
return (
isinstance(v, str)
and "/" in v
and not v.startswith("/")
and "/.." not in v
and "../" not in v
and all(p and not p.startswith(".") for p in v.split("/"))
) Try / catch
try:
resp = http.get(f"{base}/workflows/runs", params={"repo": repo})
resp.raise_for_status()
except httpx.HTTPStatusError as e:
if e.response.status_code == 400 and "invalid repo" in e.response.text:
raise ValueError(f"repo {repo!r} must be a clean 'owner/name' identifier") from e
raise Prevention
- Always send the full 'owner/name'; never a bare repo name or a URL
- Strip '.git' suffixes and URL prefixes before sending
- Reject any repo input containing '..' or leading dots at the CLI boundary
- Source repo names from validated config, not raw shell expansion
When it happens
Trigger: Calling any repo-taking endpoint (_pool_dir users, workflow run/job listing, job log tail, git URL builders) with values like 'owner', '../etc', 'owner/../repo', empty string, or names with illegal characters.
Common situations: Clients passing a bare repo name without the owner prefix; shell variables expanding to relative paths; trailing-dot or double-dot path fragments from misconfigured remotes; injection probing against the proxy.
Related errors
- invalid issue identifier: ${identifier}. Pass an issue numbe
- path must be repository-relative
- missing/invalid 'slot_uid'
- invalid '{field}': must be array of strings
- missing/invalid 'comments'
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/0aa395d8d003dff4.
Report an issue: GitHub.