git-ssb — децентрализованный хостинг git-репозиториев

SSB (Secure Scuttlebutt) - это децентрализованная социальная сеть и протокол, на основе которого она работает. git-ssb заворачивает обычные git-репозитории в этот протокол. SSB хочет заменить собой Facebook, а git-ssb - GitHub. Под катом - краткое руководство по git-ssb. Актуально для тех, кому дискомфортна сама идея использования централизованных сервисов в качестве посредника. Своеобразная красная таблетка с полагающимися в этом случае неожиданными последствиями.

Secure Scuttlebutt

Протокол SSB описывает правила синхронизации ваших данных между заинтересованными в них узлами сети. Ваши данные - это история ваших действий в сети, связный список json-объектов. Связь задаётся hash-суммой предыдущего объекта (как в блокчейне). Таким образом, однажды опубликованные объекты неизменяемы и неудаляемы. Добавлять можно только в конец списка. Типичный use case предполагает, что каждый объект в списке - это пост или комментарий в блоге. Картинки и другие тяжёлые объекты хранятся вне списка в виде blob-ов и реплицируются отдельно. Объекты в списке могут на них ссылаться.

Большинство пользователей сети ведут блоги в приложениях Patchwork и Manyverse. Приложений для ведения блогов около десятка, они, в основном, совместимы друг с другом и отличаются интерфейсом. Кроме этого есть шахматы, чат, менеджер пакетов (ssb-npm) и git (git-ssb). Некоторые разработчики SSB используют git-ssb как основной сервис для управления версиями исходников. Мы тоже попробуем.

Установите ssb-server и git-ssb

ssb-server нужен для синхронизации с другими узлами в p2p сети. Он должен быть запущен, когда вы делаете push, pull, fetch, создаёте pull-request или форкаете репозиторий.

Пакет git-ssb включает:

  • программу для управления репозиториями (git-ssb)

  • git-remote-helper, который понимает адреса, начинающиеся с ssb://

  • web-интерфейс, отдалённо напоминающий GitHub

Все три компонента взаимодействуют с запущенным на вашей машине ssb-server.

$ sudo apt install git nodejs npm
$ npm install ssb-server git-ssb

ssb-server и git-ssb установятся в папку $HOME/node_modules. Чтобы было удобнее их вызывать, добавьте в конец файла ~/.profile стоки:

if [ -d "$HOME/node_modules/.bin/" ] ; then
    PATH="$HOME/node_modules/.bin/:$PATH"
fi

Чтобы переменная $PATH обновилась в текущей сессии, наберите

$ source ~/.profile

При логине файл ~/.profile должен исполниться автоматически. Некоторые среды рабочего стола (например, Xfce) этого не делают. Если после перезагрузки переменная $PATH не обновилась, то добавьте в .xsessionrc явный вызов ~/.profile:

. ~/.profile

Запустите ssb-server и оставьте его работающим на время экспериментов.

$ ssb-server start

При первом запуске он создаст identity по умолчанию в папке ~/.ssb.

Получите инвайт и примите его

Инвайт нужен для того, чтобы другие узлы сети узнали о вашем существовании. Узел, который выдаст вам инвайт, подпишется на вас и будет реплицировать ваши данные. Через него это смогут сделать и другие пользователи. Без инвайта можно, но сложнее.

У каждого узла могут быть свои правила выдачи инвайта. На данный момент большинство узлов ничего не спрашивают и просто дают строку, которую нужно скопировать. Список выдающих инвайты узлов. Примите инвайт, подставив полученную строку в следующую команду.

$ ssb-server invite.accept <ваш-инвайт-код>

Теперь вы с тем узлом взаимные друзья: вы начинаете копировать себе данные его и его друзей, а он - ваши.

Подпишитесь на @cel

@cel - это разработчик git-ssb.

$ ssb-server publish --type contact --contact "@f/6sQ6d2CMxRUhLpspgGIulDxDCwYD7DzFzPNr7u5AU=.ed25519" --following

Сейчас в папку ~/.ssb скачается около 1Gb данных - это его история (там и его git-репозитории) и истории тех пользователей, на которых он подписан. Эта подписка нужна, чтобы последующие примеры у всех работали примерно одинаково.

Установка и настройка завершены. Теперь вы многое можете:

Запустить web-интерфейс

$ git-ssb-web

Перейдя по напечатанной в консоли ссылке вы увидите хронологический список коммитов, issue и других действий в видимых репозиториях. Это, разумеется, не всё, а только то, что скачалось после подписки на предыдущем шаге. Нажав на имя пользователя вы увидите его activity log, нажав на репозиторий - интерфейс, похожий на GitHub.

Репозиторий git-ssb в git-ssb
Репозиторий git-ssb в git-ssb

Все ваши действия в web-интерфейсе (например, комментарий, создание issue или форка) запишутся в вашу историю и уйдут вашим подписчикам при синхронизации. Если вы в данный момент отключены от сети, то этот интерфейс будет продолжать работать: репозитории будут форкаться, issue создаваться и т.д.. ssb-server работает (вы же его ещё не выключили) и отправит все ваши изменения как только сеть появится.

Создать репозиторий

$ mkdir my-new-repo
$ cd my-new-repo
$ git init
Initialized empty Git repository in /tmp/my-new-repo/.git/

$ git-ssb create ssb my-new-repo
Created repo: ssb://<hash-code>.sha256 (my-new-repo)
Added remote: ssb

$ git remote -v
ssb    ssb://<hash-code>.sha256 (fetch)
ssb    ssb://<hash-code>.sha256 (push)

К привычному git init добавилась команда git-ssb create ssb my-new-repo, которая запишет в вашу историю факт создания нового репозитория с именем my-new-repo и добавит его URL в качестве remote с именем ssb. Аналогичным образом можно добавить такой remote к любому существующему репозиторию.

Запушить существующий репозиторий

Вы добавили ssb ссылку в качестве дополнительного remote к вашему репозиторию. Теперь можно пушить.

Важно: невозможно удалить что-то из SSB. Не ставьте эксперименты на чувствительных данных.

$ git push ssb master

Если репозиторий большой, то может не получиться. В git-ssb допустимый размер pack-файла зависит от максимального размера blob, а он ограничен 5Mb. Больший размер сеть не примет. Но закоммитить, тем не менее, возможно:

$ git push ssb master -o allow-big

Это не сделает вашу историю невалидной (blob синхронизируются отдельно от истории), но скачать большой pack-файл другие пользователи не смогут, пока не увеличат у себя в настройках максимальный размер blob.

Альтернативный способ вписаться в ограничение на размер pack-файла - это пушить небольшими порциями так, чтобы создаваемые git-ом pack-файлы не превышали 5Mb.

Клонировать репозиторий

Будем ставить эксперименты с git-ssb на репозитории git-ssb. В SSB нет DNS и красивых названий чего бы то ни было. Ссылку на репозиторий ssb://%n92DiQh7ietE+R+X/I403LQoyf2DtR3WQfCkDKlheQU=.sha256 я скопировал из web-интерфейса.

$ git clone ssb://%n92DiQh7ietE+R+X/I403LQoyf2DtR3WQfCkDKlheQU=.sha256 git-ssb
$ cd git-ssb
$ git remote -v
origin    ssb://%n92DiQh7ietE+R+X/I403LQoyf2DtR3WQfCkDKlheQU=.sha256 (fetch)
origin    ssb://%n92DiQh7ietE+R+X/I403LQoyf2DtR3WQfCkDKlheQU=.sha256 (push)

В этом репозитории у нас единственный remote, и он из SSB.

Форкнуть репозиторий

$ git-ssb fork my-fork
Created repo: ssb://<new-hash-code>.sha256 (git-ssb)
Added remote: my-fork
$ git remote -v
my-fork    ssb://<new-hash-code>.sha256 (fetch)
my-fork    ssb://<new-hash-code>.sha256 (push)
origin    ssb://%n92DiQh7ietE+R+X/I403LQoyf2DtR3WQfCkDKlheQU=.sha256 (fetch)
origin    ssb://%n92DiQh7ietE+R+X/I403LQoyf2DtR3WQfCkDKlheQU=.sha256 (push)

В вашей истории появится запись о создании нового репозитория, а в текущей папке добавится новый remote.

Сделать пулл-реквест

Вы внесли изменения и сделали коммит.

$ git-ssb pull-request

Откроется текстовый редактор, вы напишете описание ваших изменений. После сохранения распечатается новый объект, добавленный в вашу историю.

Пушить в чужой репозиторий

Это не баг, а фича. Согласно документации (git-ssb-intro), это одна из принятых моделей совместной работы. Вы создаёте в чужом репозитории ветку с именем @ваш-юзернейм/master (git checkout -b @ваш-юзернейм/master), пушите в неё (git push ssb), а после делаете пулл-реквест (git ssb pull-request). Но ничто не помешает вам запушить прямо в master без всяких пулл-реквестов.

Возможность асинхронного внесения изменений в одну ветку может привести к конфликту, если при помощи двух разных identity (про identity - см. ниже) были созданы два конкурирующих коммита. Когда git-ssb встречает такие ситуации, он просит пользователя сделать слияние этих альтернативных версий. Всё это происходит локально на вашем компьютере. Если вы не подписаны на ту другую identity, которая пушит в ваш репозиторий, то вы не увидите никакого конфликта. Другие же пользователи, которые на неё подписаны, увидят. Таким образом, один и тот же репозиторий будет выглядеть по-разному в зависимости от того, чьи обновления вы получаете.

Identity задаётся закрытым ключом в файле ~/.$ssb_appname/secret. Если переменная ssb_appname не задана, то будет использована identity по умолчанию (~/.ssb). Если в указанном месте нет файла secret, то ssb-server его создаст со случайным ключом.

Положительная сторона этой вседозволенности permissionless модели в том, что вы можете работать с одним репозиторием с нескольких устройств, на которых установлены разные identity.

С другой стороны, это может привести к распространению вредоносного кода: вы делаете что-то полезное, все об этом знают, клонируют и делают sudo make install не глядя в историю коммитов. У одних пользователей установится ваше приложение, а у других - ваше приложение с добавлением зловреда. Возможно, что даже вы сами не увидите, что после очередного git pull у вас появились чужие коммиты. Тогда зловред придёт к каждому, в том числе и к вам.

Обсуждение этой возможности внутри SSB.

Что ещё почитать?

git-ssb-intro: a guide to hacking together on the distributed web

Другие способы децентрализации git:

  • GitTorrent (на основе BitTorrent)

  • HyperGit (на основе Dat)

  • igis-remote (на основе IPFS)

  • ipld-remote (на основе IPFS)

  • GitCenter (на основе ZeroNet)

  • Mango (Ethereum + IPFS)

  • Radicle

  • Gitopia

Первые четыре подробно проанализированы в статье Daniel Aleksandersen "Four P2P distribution tools for Git repositories compared". К ней есть комментарии разработчиков SSB.

Спасибо за внимание. Надеюсь, что было не очень скучно. Хорошей децентрализации тем, кому это важно.

Картинка в шапке сгенерирована при помощи сервиса myoctocat.com.

Комментарии 8

    +3

    Зачем пытаться сделать децентрализованный git, если он изначально создавался децентрализованным? Или из-за гитхаба никто уже не помнит, как добавлять несколько origin-ов?

      +1

      В данном случае децентрализуется скорее аналог гитхаба/гитлаба, а не гит.
      Децентрализации самого гита на практике мешает исключительно то, что доступ к репо на стороннем сервере нужно как-то присобачивать ручками, при этом есть много вариантов как это сделать, и в результате обычно никто этого не делает вообще, потому что всем удобнее работать через центральный сервер гитхаба/гитлаба.


      P.S. Если нужна не столько децентрализация, сколько по-настоящему приватные репо для команды, которые никто другой не может посмотреть и/или заблокировать — в Keybase есть поддержка гита.

        0
        Да. Децентрализация помогает сохранять доступ вне зависимости от точки зрения хостера (см. удаление youtube-dl). В некотором смысле это противоположность приватности.

        P.S. Если нужна не столько децентрализация, сколько по-настоящему приватные репо для команды, которые никто другой не может посмотреть и/или заблокировать — в Keybase есть поддержка гита.

        Спасибо. Это интересно.
        0
        Поддерживаю.
        1. Берём децентрализованный гит.
        2. Насаживаем его на блокчейн.
        3. Получаем неконтролируемый запрет на правку/удаление файлов в репозитории.
        4. Бюджет освоен? Прибыль получена?

        p.s.
        Очень интересная тема, хотел почитать про git-ssb, но прочитал про ssb (очень понравились картинки и детальное описание), т.к.
        git-ssb заворачивает обычные git-репозитории в этот протокол.

        Также хотелось бы спросить у автора, зачем вдруг разработчикам приобретать такие нюансы:
        If a user loses their secret key or has it stolen they will need to generate a new identity and tell people to use their new one instead.

        Т.е. случилась беда с ключом — пересоздавай репозиторий??
        Pubs serve as a gathering point for new users to find other people and for existing users to welcome people who have just joined.
        Pubs have a stable IP address and allow incoming TCP connections, which enables users to connect even if their internet service provider lacks dedicated IP addresses or refuses incoming connections.

        Децентрализованная сеть с центрами централизации, ретрансляции и библиотекой пользователей с их ключами+адресами… Не, конечно можно каждому контрибьютеру выделить по белому ip, но тогда это ничем не отличается от гита.
        The connection begins with a 4-step handshake to authenticate each peer and set up an encrypted channel.
        Handshake is verifiable using Network key.
        Network key — most clients use well-known key to join the main network.

        Опаньки, главная подсеть в децентрализованной сети, которая ещё и за шифрование отвечает. Ну… это полный провал всей задумки децентрализации.
        When a user attaches an image to their post, that image is stored as a blob and the message contains a link to it.
        Blobs can handle much larger amounts of data than feeds or messages, which is why they are stored separately.

        А вот и вся фишка протокола — обмениваемся sha256 файлов вместо самих файлов, а файлы качаем отдельно. Идея неплохая, если компы всех контрибьютеров будут доступны или если каким-то образом совпадёт, что все по-цепочке скачают копию себе в момент коммита. Конечно можно было и файловый сервер поставить, но это же не гит.
          0
          Т.е. случилась беда с ключом — пересоздавай репозиторий??

          Если утрачен закрытый ключ, то утрачен и контроль над identity.

          Но с репозиторием это не так: там permissionless модель, т.е. любая identity может пушить в любой репозиторий. Потеряв ключ вы создаёте новый и продолжаете с тем же репозиторием.

          Децентрализованная сеть с центрами централизации, ретрансляции и библиотекой пользователей с их ключами+адресами…

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

          Это немного децентрализованнее, чем e-mail и Mastodon (там у вас есть «домашний» узел), но не настолько, как cjdns, где все узлы равны.

          Network key — most clients use well-known key to join the main network.

          Это константа, зашитая чуть ли не в код. Можно поменять, если хочется, чтобы узел не соединился ни с кем из основной сети.

          … если компы всех контрибьютеров будут доступны или если каким-то образом совпадёт, что все по-цепочке скачают копию себе в момент коммита.

          Пабы хранят и блобы тоже. Поэтому pull получается, когда в онлайне нет никого из тех, кто коммитил.
        +3
        Но ничто не помешает вам запушить прямо в master без всяких пулл-реквестов.

        То есть ситуация со «сторис для программистов» никого ничем не научила?
        Человеческая сущность такова, что нельзя давать всем доступ к ресурсу — чисто из вредности найдутся люди, которые захотят поднасрать.
          +2
          Пушить в чужой репозиторий
          Это не баг, а фича.

          Да нет, это именно баг, хотя и в голове. Конечно, если расчёт на то, что ssb никогда не выйдет из узких кругов, то это может быть и работоспособно
            0
            если расчёт на то, что ssb никогда не выйдет из узких кругов

            Судя по статистике, пока не выходит:
            image
            (Источник)
            Пик справа — это, похоже, как-то связано с блокировкой Parler.

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое