Конвейер CI перестал клонировать репозиторий, который вчера работал: ключ развёртывания отозван или перевыпущен

Что было. Сборки проекта внезапно падают на шаге получения кода с git@…: Permission denied (publickey). Никто ничего не менял, репозиторий тот же, вчера всё собиралось.

Причина и решение (подтверждено). Ключ развёртывания, который CI использует для доступа к репозиторию, перестал быть действительным: его удалили в настройках репозитория, отозвали при ротации, либо он был привязан к другому репозиторию. Решение: в настройках проекта в CI удалить старый ключ, создать новый (сервис сам генерирует пару и добавляет публичную часть в репозиторий) и убедиться, что ключ появился в списке ключей развёртывания на стороне хостинга кода. Следующая сборка прошла.

Почему это случается «само».

  • Плановая ротация или чистка ключей в организации (политика «ключи старше N дней удаляются»).
  • Хостинг кода прекратил поддержку слабых алгоритмов (например, подписи RSA/SHA-1 для старых ключей): ключ есть, но сервер его больше не принимает. Лечится перевыпуском ключа в ed25519.
  • Репозиторий перенесли или переименовали: ключ привязан к старому пути.
  • Ключ развёртывания разрешён только на чтение, а конвейер начал делать push (теги версий, обновление документации).
  • Кто-то использовал один ключ для нескольких репозиториев: хостинг кода запрещает это для deploy keys, и при добавлении во второй репозиторий он отваливается от первого.

Диагностика.

  1. В логе шага checkout включить подробность: ssh -vT git@host в отдельном шаге покажет, какой ключ предлагается и принимается ли.
  2. На стороне хостинга кода: настройки репозитория → ключи развёртывания: есть ли ключ с тем же отпечатком, дата последнего использования, права.
  3. Журнал аудита организации: кто и когда удалил ключ.

Как устроить надёжно.

  • Один ключ на пару «репозиторий + конвейер», ed25519, права только чтение, если запись не нужна.
  • Хранить приватную часть только в секретах CI, никогда в репозитории.
  • Для нескольких репозиториев одного проекта: «машинный пользователь» с ограниченным членством вместо десятка deploy keys, либо токены установленного приложения хостинга, которые CI-сервис выпускает сам.
  • Мониторинг: сборка, падающая на checkout, должна оповещать иначе, чем падающие тесты.

Ключи развёртывания описаны в документации GitHub.