* fix(memory): add git insteadOf helper for GITHUB_TOKEN in setup-memory.sh * test(memory): add tests for git insteadOf helper * docs(handoff): add handoff + ADR-022 for git insteadOf helper * docs(handoff): set PR number 53 in handoff + ADR-022 * style: ruff format test_setup_memory.py --------- Co-authored-by: opencode-agent <agent@slaid098.dev>
4.1 KiB
ADR-022 (PR 53): Persist git insteadOf helper for GITHUB_TOKEN in setup-memory.sh
Статус
Accepted (2026-07-24)
Контекст
При миграции opencode-config на linux-1 setup-memory.sh падал с could not read Username for 'https://github.com' при клонировании memory repo (OPENCODE_MEMORY_REMOTE = HTTPS GitHub URL). Git не подставляет GITHUB_TOKEN автоматически для HTTPS-remote — в non-interactive контексте (Docker container, нет tty) prompt блокирует clone, скрипт висит или падает.
Временный fix применялся вручную в контейнере:
git config --global url."https://x-access-token:$GITHUB_TOKEN@github.com/".insteadOf https://github.com/
Но ~/.gitconfig живёт в overlay container filesystem (Docker) и теряется при docker compose restart. После рестарта memory-clone снова падал — manual fix не persistent.
Нужен детерминированный механизм, который гарантированно применяет insteadOf при каждом запуске setup-memory.sh (вызывается через memory-setup tool при старте opencode).
Решение
Встроить guarded git config --global url.insteadOf блок в .opencode/scripts/setup-memory.sh, перед git clone:
if [ -n "${GITHUB_TOKEN:-}" ]; then
git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf https://github.com/
fi
- Guarded check — если
GITHUB_TOKENпуст/unset, блок пропускается без ошибки (локальная dev-среда с file-based mock remote не падает). - Inside clone-branch — helper стоит внутри
if [ ! -d "$MEMORY_DIR/.git" ], срабатывает только при первом клонировании. На pull-path не нужен:originURL уже сохранён в.git/configклона. - Idempotent —
git config --global url.<prefix>.insteadOfперезаписывает значение при повторном вызове, не дублирует entry. - 4 теста в
tests/test_setup_memory.py: grep check (insteadOf presence + ordering before clone), grep check (GITHUB_TOKEN guarded), functional idempotency (2x run → 1 insteadOf entry in isolated HOME), functional skip (no token → no insteadOf).
Альтернативы
-
Dockerfile ENTRYPOINT /
.bashrchack (RUN echo 'git config ...' >> /root/.bashrc) — отклонено:.bashrcчитается только interactive shell'ом, non-interactive container (opencode spawn) его не читает. ENTRYPOINT hack смешивает git-config с container lifecycle, менее детерминированно чем скрипт, вызываемый через tool. -
Hard-fail если
GITHUB_TOKENunset — отклонено: ломает локальную dev-среду (mock file-remote, offline tests). Guarded check (if [ -n ... ]) позволяет скрипту работать с любым remote — HTTPS GitHub (нужен token) или file-based mock (token не нужен). -
Применять insteadOf на каждом запуске (вне clone-ветки) — отклонено: на pull-path
originURL уже сохранён в.git/config, insteadOf не нужен. Дублирование вызоваgit config --globalна каждом запуске — лишняя запись в gitconfig без пользы (хоть и idempotent). Clone-ветка — единственное место, где remote URL впервые передаётся git.
Альтернативы
См. блок «Альтернативы» выше. Кратко: отклонены — Dockerfile/.bashrc hack (non-interactive), hard-fail on missing token (ломает dev), insteadOf на каждом запуске (лишнее). Выбран guarded insteadOf внутри clone-ветки (детерминированно, idempotent, dev-safe).