Другой способ, также основанный на подписанном gpg, состоит в том, чтобы подписать саму операцию push (а не объект , такой как тег или коммит)
Это то, что предлагает Git 2.2 (ноябрь 2014), с commit a85b377 , Junio C Hamano (gitster
) :
push
: начало "git push --signed
"
Хотя подписанные теги и коммиты утверждают, что подписанные таким образом объекты пришли от вас, подписавших эти объекты, нет хорошего способа утверждать, что вы хотите иметь конкретный объект на кончике определенной ветви.
Мой подписывающий тег v2.0.1 только означает, что я хочу вызвать версию v2.0.1, и это не означает, что я хочу отправить его в мою ветку 'master
' - скорее всего, я хочу только в ' maint
', поэтому подписи на одном объекте недостаточно.
Единственное заверение для вас, что 'maint' указывает на то, что я хотел разместить там, зависит от вашего доверия к хостинг-сайту и моей аутентификации на нем, что не может быть легко проверено позже.
Представьте механизм, который позволяет вам подписывать «push-сертификат» (из-за отсутствия более подходящего имени) каждый раз, когда вы нажимаете, утверждая, что какой объект вы нажимаете для обновления, какой ref, который раньше указывал на какой-либо объект .
Думайте об этом как о криптографической защите обновлений ссылок, аналогично подписанным тегам / фиксациям, но работающим по ортогональной оси.
Основной поток, основанный на этом механизме, выглядит так:
Вы выдвигаете свою работу с помощью "git push --signed
".
Отправляющая сторона узнает, где находятся удаленные ссылки, как обычно, и какое расширение протокола поддерживает принимающая сторона.
Если принимающая сторона не объявляет расширение протокола "push-cert
", попытка "git push --signed
" завершается неудачей.
В противном случае в основном готовится текстовый файл, который выглядит следующим образом:
certificate version 0.1
pusher Junio C Hamano <gitster@pobox.com> 1315427886 -0700
7339ca65... 21580ecb... refs/heads/master
3793ac5... 12850be... refs/heads/next
Файл начинается с нескольких строк заголовка, которые могут увеличиваться по мере накопления опыта.
Заголовок 'pusher
' записывает имя подписавшего (значение переменной конфигурации user.signingkey
, возвращаясь к GIT_COMMITTER_{NAME|EMAIL}
) и время генерации сертификата.
После заголовка следует пустая строка, за которой следует копия строк протокольного сообщения.
Каждая строка показывает старое и новое имя объекта в конце ссылки, которую этот push пытается обновить, способом, идентичным тому, как базовый протокол обмена "git push
" сообщает обновлению ссылки принимающей стороне ( записывая «старое» имя объекта, push-сертификат также защищает от повторного воспроизведения).
Ожидается, что новые типы пакетов команд, отличные от вида old-new-refname
, будут включены в push-сертификат таким же образом, как и в обычных пакетах команд в виде беззнаковых нажатий.
Затем пользователя просят подписать этот push-сертификат, используя GPG, отформатированный способом, аналогичным тому, как подписываются объекты подписанного тега, и результат отправляется на другую сторону (т.е. receive-pack
).
При обмене протоколами этот шаг происходит непосредственно перед тем, как отправитель сообщает, каким должен быть результат отправки, что, в свою очередь, происходит до того, как он отправляет данные пакета.
- Когда принимающая сторона видит push-сертификат, сертификат
записано как капля Крюк предварительного получения может узнать о
сертификат путем проверки переменной среды GIT_PUSH_CERT,
который, если присутствует, сообщает имя объекта этого BLOB-объекта и делает
решение разрешить или отклонить этот толчок. Кроме того,
Хук post-receive также может посмотреть на сертификат, который может быть
хорошее место для регистрации всех полученных сертификатов на потом
проверок.
Поскольку push-сертификат содержит ту же информацию, что и обычные командные пакеты при обмене протоколами, мы можем опустить последний, когда используется push-сертификат, и сократить издержки протокола.