* fix(pipeline-status): handle git insteadOf userinfo in parse_remote_url * test(pipeline-status): add tests for URL with userinfo * docs(handoff): set PR number 55 in handoff + ADR-023 --------- Co-authored-by: opencode-agent <agent@slaid098.dev>
3.6 KiB
ADR-023: parse_remote_url strips git insteadOf userinfo from HTTPS URLs
Статус
Accepted (2026-07-24)
Контекст
PR#53 (ADR-022) добавил git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf https://github.com/ в setup-memory.sh для non-interactive HTTPS auth в Docker. После этого git remote get-url origin возвращает rewritten URL с встроенным userinfo:
https://x-access-token:github_pat_...@github.com/slaid098/opencode-config.git
parse_remote_url (в pipeline-status.py и spec-status.py) использовал regex https?://([^/]+)/([^/]+)/(.+?)(?:\.git)?$ — группа [^/]+ жадно матчит всё между :// и первым /, включая user:password@ (символ @ не исключён). В результате host = x-access-token:github_pat_...@github.com вместо github.com.
Это ломало get_memory_file_path() → путь repos/x-access-token:...@github.com/slaid098/opencode-config.md (не существует) → check_memory возвращал NOT_DONE для каждого PR после PR#53. get_repo_full_name() случайно не ломался (возвращает org/repo, host отбрасывается), но фикс применён в обоих файлах для консистентности.
CI на PR#53 не поймал regression — тесты test_parse_remote_url_* покрывали только plain URLs без userinfo.
Решение
Изменить HTTPS-regex в parse_remote_url (оба файла) на:
re.match(r"https?://(?:[^/@]*@)?([^/]+)/([^/]+)/(.+?)(?:\.git)?$", url)
(?:[^/@]*@)? — опциональная non-capturing группа, пропускающая user:password@ userinfo перед host:
- Для plain
https://github.com/...группа не матчится (нет@) → host =github.com. - Для
https://user:token@github.com/...группа матчитuser:token@и отбрасывается → host =github.com. [^/@]внутри userinfo не матчит ни/ни@, поэтому корректно останавливается на первом@(поддерживаетuser:pass,user,token@формы).
7 новых тестов: 4 в test_pipeline_status.py (parse + get_memory_file_path), 3 в test_spec_status.py (parse + get_repo_full_name).
Альтернативы
- Использовать
git config --get remote.origin.urlвместоgit remote get-url origin— bypasses insteadOf, возвращает raw URL. Отклонено: coupling с git internals, ломается если кто-то задаст remote URL с token напрямую (не через insteadOf). - Strip userinfo через
url.split("@")[-1]— хрупкий: ломается если path содержит@(legitimate в GitHub URLs для определённых refs/paths). - Рефакторинг
parse_remote_urlв shared module — оба файла дублируют функцию. Отклонено для этого PR: риск для ADR-010 cwd-aware_resolve_repo_rootlogic, выходит за рамки bugfix. - Не чинить, отключить insteadOf — отклонено: insteadOf нужен для non-interactive memory clone (PR#53/ADR-022), regression в pipeline_status — меньшее из зол.
Regex fix (выбран) — минимальный, root-cause, без env coupling, покрывает оба caller'а.