From 2329213337748252aca01ce21bc7bfdf17195926 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 23 May 2026 22:05:37 +0000 Subject: [PATCH] fix(projects): strip ephemeral proxy prefix from project_id In a sandbox whose git remotes are rewritten by an HTTP proxy to local_proxy@127.0.0.1:/git//, the port is ephemeral (new each session) and leaked into the project_id, so issues created in one session became unresolvable in the next and every write-path command aborted with "Cannot find project path". Normalize by stripping the local_proxy@:/git/ prefix to a stable /. Co-Authored-By: Claude --- tests/test_proxy_project_id.py | 43 ++++++++++++++++++++++++++++++++++ trace_core/projects.py | 8 +++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/test_proxy_project_id.py diff --git a/tests/test_proxy_project_id.py b/tests/test_proxy_project_id.py new file mode 100644 index 0000000..be9cdc7 --- /dev/null +++ b/tests/test_proxy_project_id.py @@ -0,0 +1,43 @@ +"""Cloud-sandbox egress-proxy project-id stability. + +Anthropics cloud sandbox rewrites every git remote to +local_proxy@127.0.0.1:/git//, where is ephemeral +(new each sandbox). Without normalization the port leaks into the project_id, +so issues created in one sandbox become unresolvable in the next and every +trc write aborts with "Cannot find project path". +""" +import tempfile +from pathlib import Path + +from trace_core.projects import _extract_project_id_from_git_remote + + +def _git_dir_with_url(tmp: Path, url: str) -> Path: + gd = tmp / ".git" + gd.mkdir() + (gd / "config").write_text( + "[remote \"origin\"]\n\turl = %s\n\tfetch = +refs/heads/*:refs/remotes/origin/*\n" % url + ) + return gd + + +def test_proxy_port_stripped_and_stable(): + with tempfile.TemporaryDirectory() as d: + tmp = Path(d) + a = _extract_project_id_from_git_remote( + _git_dir_with_url(tmp / "a", "http://local_proxy@127.0.0.1:37849/git/GetsEclectic/claude-cloud-bootstrap") + ) + b = _extract_project_id_from_git_remote( + _git_dir_with_url(tmp / "b", "http://local_proxy@127.0.0.1:38291/git/GetsEclectic/claude-cloud-bootstrap") + ) + assert a == "GetsEclectic/claude-cloud-bootstrap" + assert a == b # stable across ephemeral ports + + +def test_ordinary_remotes_unchanged(): + with tempfile.TemporaryDirectory() as d: + tmp = Path(d) + https = _extract_project_id_from_git_remote(_git_dir_with_url(tmp / "h", "https://github.com/user/repo.git")) + ssh = _extract_project_id_from_git_remote(_git_dir_with_url(tmp / "s", "git@github.com:user/repo.git")) + assert https == "github.com/user/repo" + assert ssh == "github.com/user/repo" diff --git a/trace_core/projects.py b/trace_core/projects.py index 19e0fbd..e4d7a12 100644 --- a/trace_core/projects.py +++ b/trace_core/projects.py @@ -280,6 +280,14 @@ def _extract_project_id_from_git_remote(git_dir: Path) -> Optional[str]: # Unknown format return None + # Cloud-sandbox egress proxy rewrites every remote to + # local_proxy@127.0.0.1:/git//, where is + # ephemeral (new each sandbox). Strip the proxy prefix so the + # project_id is stable across sandboxes -> /. + proxy = re.match(r"^local_proxy@[^/]+/git/(.+)$", url) + if proxy: + url = proxy.group(1) + return url if url else None except Exception: