---
pr: 53
title: persist git insteadOf helper for GITHUB_TOKEN in setup-memory.sh
---

# PR 53: persist git insteadOf helper for GITHUB_TOKEN in setup-memory.sh

## Что сделано
- `.opencode/scripts/setup-memory.sh:29-33` — перед `git clone` добавлен guarded блок `git config --global url."https://x-access-token:${GITHUB_TOKEN}@github.com/".insteadOf https://github.com/`. Срабатывает только если `GITHUB_TOKEN` непустой (`if [ -n "${GITHUB_TOKEN:-}" ]`), иначе пропускается без ошибки. Расположен ВНУТРИ ветки clone (`if [ ! -d "$MEMORY_DIR/.git" ]`), т.к. insteadOf нужен только при первом клонировании remote — pull на существующем репо уже авторизован через `origin` URL.
- `tests/test_setup_memory.py` — 4 новых теста:
  - `test_script_contains_git_insteadof` — grep check: скрипт содержит `git config --global url.` + `.insteadOf https://github.com/`, и блок стоит ДО `git clone --origin` (позиционная проверка `insteadof_pos < clone_pos`).
  - `test_script_contains_github_token_check` — grep check: скрипт содержит `GITHUB_TOKEN` и это guarded check (`-n "${GITHUB_TOKEN:-}"`), а не hard-fail.
  - `test_insteadof_idempotent` — функциональный тест: запускает скрипт 2x с fake `GITHUB_TOKEN` против mock remote (isolated `HOME`), проверяет что `~/.gitconfig` содержит ровно 1 `insteadOf` entry (не дублируется). `git config --global` перезаписывает значение, idempotent by git semantics.
  - `test_no_github_token_skips_insteadof` — когда `GITHUB_TOKEN` unset, `~/.gitconfig` либо не создаётся, либо не содержит `insteadOf` (skip без ошибки).
- ADR-022 + этот handoff.

## Почему
При миграции opencode-config на linux-1 `setup-memory.sh` падал с `could not read Username for 'https://github.com'` при клонировании memory repo — git не подставляет `GITHUB_TOKEN` автоматически для HTTPS, и в non-interactive контексте (container, нет tty) prompts блокируют clone. Временный fix (`git config --global url.insteadOf`) применялся вручную, но `~/.gitconfig` живёт в overlay container filesystem и теряется при `docker compose restart` — после рестарта memory-clone снова падал.

Решение: встроить insteadOf helper в сам `setup-memory.sh` (детерминированный flow, вызывается через memory-setup tool при старте opencode). Скрипт idempotent — `git config --global` перезаписывает значение, не дублирует. Guarded check на `GITHUB_TOKEN` — если token отсутствует (локальная dev-среда), скрипт не падает, клон идёт как обычно (для mock/file remotes).

Альтернатива (Dockerfile ENTRYPOINT / `.bashrc` hack) отклонена — `setup-memory.sh` вызывается детерминированно через tool, а `.bashrc` требует interactive shell (non-interactive container его не читает).

## Pending
— (нет)

## Watch out
- **insteadOf внутри clone-ветки** — helper стоит внутри `if [ ! -d "$MEMORY_DIR/.git" ]`, т.е. срабатывает только при первом клонировании. На последующих запусках (pull path) вместо него не выполняется — это намеренно: `origin` URL уже сохранён в `.git/config` клона, pull идёт через него. Если remote URL не содержит token (HTTPS без auth), pull упадёт — но это уже проблема конфигурации remote, а не скрипта. Для fresh clone вместоOf переписывает `https://github.com/` на `https://x-access-token:TOKEN@github.com/` в момент clone.
- **Isolated HOME в тестах** — `test_insteadof_idempotent` и `test_no_github_token_skips_insteadof` используют `HOME=$tmp_path/home`, чтобы `git config --global` не писал в реальный `~/.gitconfig` CI-раннера. Без этого тест загрязнил бы глобальный gitconfig.
- **ADR number = 022** (sequential, следующий после 021), НЕ PR number.
- Существующие 358 тестов не сломаны — полный suite: 362 passed (358 + 4 новых).