# 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 применялся вручную в контейнере: ```bash 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`: ```bash 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` клона. - **Idempotent** — `git config --global url..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).