6.5 KiB
Gitea pull-mirror из GitVerse — сессия 2026-08-30
Цель: зеркалировать репозиторий с gitverse.ru в локальный Gitea для катастрофоустойчивости (на случай поломки bigbox).
Контекст
- Gitea 1.26.2 (docker, /opt/gitea.nixg.ru), API http://127.0.0.1:3000/api/v1, домен gitea.nixg.ru.
- GitVerse: только SSH (
git@gitverse.ru:kpa39l/<repo>.git), REST-API не открыт анонимно, https-клон требует PAT (которого нет). SSH-ключ ~/.ssh/gitverse аутентифицирует как kpa39l. - Стек gitea: gitea-db (postgres), gitea-redis, gitea, act-runner.
Что РАБОТАЕТ (проверено)
1. Токен Gitea API без пароля (CLI от имени git)
Gitea в docker НЕ запускается от root: docker exec gitea gitea ... падает с
"Gitea is not supposed to be run as root". Но есть системный пользователь git (uid 1000):
docker exec -u 1000 gitea gitea admin user list
docker exec -u 1000 gitea gitea admin user generate-access-token \
--username estorozhenko --token-name monitoring-mirror \
--scopes "read:repository,write:repository,read:user,write:user"
# → "Access token was successfully created: <token>"
Это обходит неизвестный пароль пользователя целиком.
2. Дать контейнеру gitea SSH-ключ для внешнего git-хоста
Volume gitea: /opt/gitea.nixg.ru/gitea -> /data. Ключ кладётся в home пользователя git:
mkdir -p /opt/gitea.nixg.ru/gitea/git/.ssh
cp ~/.ssh/gitverse /opt/gitea.nixg.ru/gitea/git/.ssh/id_rsa
chown -R 1000:1000 /opt/gitea.nixg.ru/gitea/git/.ssh && chmod 600 .../id_rsa
docker exec -u 1000 gitea ssh -o BatchMode=yes -T git@gitverse.ru
# → "Hi there, kpa39l! You've successfully authenticated..."
Gitea зеркалит от имени владельца SSH-ключа (kpa39l).
3. Разрешить SSH-протокол для миграций
По умолчанию Gitea отклоняет SSH в migrate. В docker-compose gitea добавить:
- GITEA__service__MIGRATIONS_ALLOWED_PROTOCOLS=ssh,git,http,https
Затем пересоздать КОНТЕЙНЕР (env-переменные пишутся в app.ini при старте):
docker compose up -d --force-recreate gitea (простой restart/up -d может не перечитать).
РАБОЧИЙ РЕЦЕПТ: HTTPS + oauth2 PAT (проверено 2026-08-30, 13 репо мигрировано)
Штатный migrate API работает, если clone_addr — https с PAT gitverse:
git ls-remote "https://oauth2:<PAT>@gitverse.ru/kpa39l/<repo>.git" HEAD # тест PAT
curl -X POST http://127.0.0.1:3000/api/v1/repos/migrate \
-H "Authorization: token <GITEA_TOKEN>" -H "Content-Type: application/json" \
-d '{"clone_addr":"https://oauth2:<PAT>@gitverse.ru/kpa39l/<repo>.git",
"repo_name":"<repo>","repo_owner":"estorozhenko","service":"git",
"mirror":true,"mirror_interval":"8h"}'
# 201 = создан; затем POST /api/v1/repos/<owner>/<repo>/mirror-sync (200 = принято)
- PAT gitverse лежит в URL уже существующего mirror:
docker exec gitea cat /data/git/repositories/estorozhenko/monitoring.git/config→https://oauth2:<GITVERSE_PAT>@gitverse.ru/kpa39l/monitoring.git(значение — из/opt/hermes/.hermes/secrets/git-tokens.env) - Проверка синхронизации:
git ls-remote git@gitverse.ru:kpa39l/<repo>.git HEADvsdocker exec gitea git --git-dir=/data/git/repositories/estorozhenko/<repo>.git rev-parse HEAD. - PAT gitverse в URL уже существующего mirror:
docker exec gitea cat /data/git/repositories/estorozhenko/<существующий-repo>.git/config→https://oauth2:<GITVERSE_PAT>@gitverse.ru/kpa39l/<repo>.git(токен в secrets) - Gitea-токен без пароля:
docker exec -u 1000 gitea gitea admin user generate-access-token --username estorozhenko --token-name X --scopes "read:repository,write:repository,read:user,write:user" --raw
НЕ РАБОТАЕТ / НЕ РЕШЕНО (проверено, потрачено много шагов)
POST /api/v1/repos/migrateсclone_addr: "git@host:path"→ 422 "the provided url is invalid".POST /api/v1/repos/migrateсclone_addr: "ssh://git@host/path"→ 422 "the provided url protocol is not allowed" — даже после добавления ssh в MIGRATIONS_ALLOWED_PROTOCOLS и --force-recreate. Это РАСХОЖДЕНИЕ: конфиг в app.ini показываетssh,git,http,https, но migrate всё равно режет. Дальнейшее копание в бинаре (strings), swagger, UI-форме/repo/migrate(требует сессионную cookie, не токен) успеха не дало. ВАЖНО: признать тупик и не листать это заново вслепую. Вывод: для pull-mirror использовать HTTPS+PAT (см. выше), ssh:// не трогать.POST /user/reposс полями mirror/clone_addr — НЕ создаёт пулл-миро: CreateRepoOption таких полей не имеет, репозиторий создаётся обычным (mirror=False, empty=True).- Пароль пользователя gitea неизвестен — Basic auth в API не работает.
Обходные пути, проверенные частично
- Локальная копия через git-remote: создать обычный repo в gitea, добавить в его bare
remote на gitverse и гонять
git fetchпо cron (вместо штатного mirror-механизма). Надёжный, уродливый, но не требует migrate API. НЕ доведён до конца в сессии. - PAT GitVerse по https — если у пользователя появится, migrate с
https://<token>@gitverse.ru/...должен сработать штатно.
Правило для агента
Если POST /repos/migrate с ssh:// вернул 422 протокол — НЕ перезапускать gitea ещё раз
и не копать strings: сообщить о блокаде и предложить обходной путь (локальный remote+cron
или PAT). Повторение уже проверенных тупиков — потеря времени.