* 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>
43 lines
No EOL
4.1 KiB
Markdown
43 lines
No EOL
4.1 KiB
Markdown
# 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.<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). |