Репозиторий вендора#
Репозиторий Flatpak - это каталог формата OSTree, доступный по HTTP. Отдельного серверного ПО он не требует: достаточно раздать каталог любым веб-сервером. Инструменты сборки кладут результат прямо в такой каталог, поэтому репозиторий получается побочным продуктом сборки.
Весь путь ниже показан на одном примере: домен flatpak.example.ru,
репозиторий в /srv/flatpak/repo, приложение ru.example.Hello.
Ключ подписи#
Ключ создаётся один раз и переиспользуется для всех сборок. Отдельный ключ только для подписи репозитория удобнее личного: его проще передать сборочной машине и отозвать:
gpg --batch --quick-generate-key "Example Repo Signing <repo@example.ru>" \
rsa3072 sign never
Отпечаток понадобится и при сборке, и при подготовке файла подключения:
gpg --list-secret-keys --with-colons | awk -F: '/^fpr:/{print $10; exit}'
ED26FA18B97CF57F1169B0DB653C2A83A443C168
Публичная часть выгружается в файл: он пойдёт в файл подключения и пользователям:
gpg --export ED26FA18B97CF57F1169B0DB653C2A83A443C168 > repo-key.gpg
Закрытая часть остаётся на сборочной машине. Если ключ защищён паролем, для сборки без запроса пароль кладут в файл и передают его механизмом секретов конвейера.
Сборка с подписью#
Для aft-app подпись и каталог репозитория задаются секцией export
манифеста:
export:
repository: /srv/flatpak/repo
gpgSign: ED26FA18B97CF57F1169B0DB653C2A83A443C168
gpgHomedir: ~/.gnupg
stable: true
collection-id: ru.example.Apps
generate-static-deltas: true
prune: false
Сборка:
sudo aft-app build ru.example.Hello.yaml
Для flatpak-builder то же самое задаётся флагами:
flatpak-builder --force-clean --repo=/srv/flatpak/repo \
--default-branch=stable \
--gpg-sign=ED26FA18B97CF57F1169B0DB653C2A83A443C168 \
build-dir ru.example.Hello.yml
Оба инструмента после экспорта сами обновляют сводку репозитория. Отдельно
вызывать flatpak build-update-repo нужно только тогда, когда репозиторий
наполняется вручную командами flatpak build-export.
Поле generate-static-deltas включает генерацию двоичных дельт между
версиями: пользователь при обновлении скачивает разницу, а не приложение
целиком, но репозиторий занимает больше места. Поле prune удаляет объекты,
на которые больше не ссылается ни одна ветка. Поле collection-id задаёт
идентификатор набора: он записывается в репозиторий и в сборки, и клиент
проверяет, что ветка пришла из того же набора, что и заявлено.
Что получилось#
После сборки в каталоге репозитория лежит примерно это:
/srv/flatpak/repo/
|-- config
|-- extensions/
|-- objects/
|-- refs/
|-- state/
|-- summaries/
|-- summary
|-- summary.idx
|-- summary.idx.sig
|-- summary.sig
`-- tmp/
Файлы summary.sig и summary.idx.sig появляются только у подписанного
репозитория. Если их нет, подпись не отработала, и подключить репозиторий с
проверкой не получится.
Посмотреть, что внутри:
ostree --repo=/srv/flatpak/repo refs
app/ru.example.Hello/x86_64/stable
appstream/x86_64
appstream2/x86_64
Ветки appstream собираются автоматически: из них центры приложений берут
описания и иконки.
Публикация#
Каталог раздаётся веб-сервером как есть, без обработки:
server {
listen 80;
server_name flatpak.example.ru;
root /srv/flatpak;
autoindex off;
}
При такой настройке репозиторий доступен по http://flatpak.example.ru/repo/,
а файл подключения ляжет рядом, в /srv/flatpak.
Проверить, что снаружи всё читается, можно обычным curl:
curl -o /dev/null -w '%{http_code}\n' http://flatpak.example.ru/repo/summary
200
Каталог обновляется сборкой напрямую, поэтому во время экспорта клиент может поймать несогласованное состояние. Если сборки идут часто, репозиторий собирают в стороне и переносят на веб-сервер готовым.
Файл подключения#
Чтобы пользователю не пришлось вводить адрес и импортировать ключ руками, рядом
с репозиторием выкладывается файл .flatpakrepo. Значение GPGKey - это
выгруженный публичный ключ, закодированный base64 в одну строку:
base64 -w0 repo-key.gpg
Готовый файл /srv/flatpak/example.flatpakrepo:
[Flatpak Repo]
Title=Приложения Example
Url=http://flatpak.example.ru/repo/
Homepage=https://example.ru
Comment=Репозиторий приложений Example
Description=Приложения Example для Astra Linux
GPGKey=mQGNBGqeptABDADJK/7d9J8CGpsOaT97TEjrUJsCyiWvbNlyslInjF1ZOEnDnqC...
Обязательны только Title и Url. Ключ GPGKey не обязателен
формально, но без него пользователю придётся подключать репозиторий с
отключённой проверкой подписи. Полный разбор полей - в блоке
Отладка и подготовка репозиториев.
Значение Url заканчивается косой чертой и указывает на каталог
репозитория, а не на сам файл подключения.
Проверка со стороны пользователя#
Перед выдачей стоит пройти путь пользователя целиком, лучше на другой машине или хотя бы в отдельной пользовательской установке:
flatpak --user remote-add --if-not-exists --from example \
http://flatpak.example.ru/example.flatpakrepo
flatpak --user remote-ls example
flatpak --user install -y example ru.example.Hello
flatpak run ru.example.Hello
Убрать за собой после проверки:
flatpak --user uninstall -y ru.example.Hello
flatpak --user remote-delete example
Если файла подключения нет, репозиторий подключается по адресу каталога, и тогда ключ указывается отдельно:
flatpak --user remote-add --if-not-exists example \
http://flatpak.example.ru/repo/ --gpg-import=repo-key.gpg
Вариант без подписи существует, но годится только для проверки у себя:
flatpak --user remote-add --if-not-exists --no-gpg-verify example \
http://flatpak.example.ru/repo/
Выпуск новой версии#
Новая версия кладётся в тот же каталог той же командой сборки. Она становится
новым коммитом в той же ветке, а старые объекты остаются, пока их не удалит
очистка. Пользователь получает её обычным flatpak update.
Ветка задаётся полем metadata.branch в манифесте aft-app или флагом
--default-branch у flatpak-builder. Разные ветки живут в репозитории
параллельно, поэтому под тестовые сборки удобно завести отдельную ветку и не
трогать ту, что стоит у пользователей.
Со временем репозиторий растёт за счёт старых объектов. Удалить то, на что уже никто не ссылается:
flatpak build-update-repo --prune --prune-depth=1 \
--gpg-sign=ED26FA18B97CF57F1169B0DB653C2A83A443C168 /srv/flatpak/repo
Значение --prune-depth задаёт, сколько прошлых версий оставить в каждой
ветке. Ноль оставляет только текущую, и откатиться на предыдущую версию после
этого будет нельзя.
Что проверить перед выдачей#
Приложение ставится и запускается на чистой системе, где нет ни сборочного окружения, ни исходных пакетов. Проверка на машине сборки этого не показывает: там нужные файлы могут оказаться в системе, а не в сборке.
Среда выполнения, указанная в манифесте приложения, доступна пользователю из репозиториев Astra, а её версия указана точным номером ветки. Приложение, собранное на одной версии среды, на другой может не запуститься.
Разрешения песочницы сведены к минимуму. Что попало в готовую сборку, разберёт
aft-analyzer: он сообщает о лишних разрешениях, битых метаданных и
неразрешённых зависимостях:
aft-analyzer ru.example.Hello --report=./report
Известные уязвимости по составу ПО проверяет aft-scanner:
aft-scanner scan ru.example.Hello --fail-on=high