opencode-config/docs/decisions/022-pr-53-git-insteadof.md
Sergey 02f0863a24
fix(memory): persist git insteadOf helper for GITHUB_TOKEN in setup-memory.sh (#53)
* 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>
2026-07-24 21:28:06 +03:00

4.1 KiB
Raw Permalink Blame History

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 не нужен: origin URL уже сохранён в .git/config клона.
  • Idempotentgit 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 / .bashrc hack (RUN echo 'git config ...' >> /root/.bashrc) — отклонено: .bashrc читается только interactive shell'ом, non-interactive container (opencode spawn) его не читает. ENTRYPOINT hack смешивает git-config с container lifecycle, менее детерминированно чем скрипт, вызываемый через tool.

  • Hard-fail если GITHUB_TOKEN unset — отклонено: ломает локальную dev-среду (mock file-remote, offline tests). Guarded check (if [ -n ... ]) позволяет скрипту работать с любым remote — HTTPS GitHub (нужен token) или file-based mock (token не нужен).

  • Применять insteadOf на каждом запуске (вне clone-ветки) — отклонено: на pull-path origin URL уже сохранён в .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).