Работа с RPM

CodeScoring.Save реализует RPM-репозиторий (формат createrepo) с префиксом /rpm/<project>/<repository>/. Совместим со стандартными клиентами dnf и yum на RHEL, Rocky Linux, AlmaLinux, Fedora, CentOS и производных дистрибутивах.

Proxy-репозиторий

curl -X POST https://save.example.com/api/v1/repos \
  -H "Content-Type: application/json" \
  -u "<username>:<password>" \
  -d '{
    "project": "infra",
    "name": "rocky-proxy",
    "format": "rpm",
    "repository_type": "proxy",
    "remote_url": "https://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/os",
    "cache_ttl": 3600
  }'
remote_url — это baseurl

В remote_url указывается тот же URL, который был бы baseurl в .repo-файле, — каталог, внутри которого лежит repodata/repomd.xml.

Proxy отдаёт repodata upstream как есть

Proxy-репозиторий не генерирует собственные индексыrepomd.xml, hash-именованные файлы repodata и repomd.xml.asc проксируются с upstream побайтно, чтобы подписи и контрольные суммы оставались валидными. Пакеты кэшируются как неизменяемые артефакты; метаданные ревалидируются по истечении cache_ttl. Если upstream недоступен, Save отдаёт последнюю закэшированную копию метаданных. Загрузка пакетов в proxy-репозиторий запрещена — он read-only.

Hosted-репозиторий

curl -X POST https://save.example.com/api/v1/repos \
  -H "Content-Type: application/json" \
  -u "<username>:<password>" \
  -d '{
    "project": "infra",
    "name": "rpm-hosted",
    "format": "rpm",
    "repository_type": "hosted"
  }'

При создании hosted-репозитория Save сразу публикует пустой repodata/repomd.xml, поэтому dnf makecache работает ещё до загрузки первого пакета. Индексы (primary, filelists, other) перегенерируются автоматически после каждой загрузки или удаления пакета.

URL-схема

https://save.example.com/rpm/<project>/<repository>/repodata/repomd.xml   # индекс индексов
https://save.example.com/rpm/<project>/<repository>/Packages/<буква>/...  # пакеты
https://save.example.com/rpm/<project>/<repository>/repository.key        # публичный GPG-ключ

Настройка клиента

dnf / yum

Создайте /etc/yum.repos.d/codescoring.repo:

[codescoring]
name=CodeScoring Save
baseurl=https://save.example.com/rpm/<project>/rpm-hosted
enabled=1
username=<username>
password=<password>
gpgcheck=0
repo_gpgcheck=0
dnf makecache --repo=codescoring
dnf install <package>

dnf / yum с проверкой подписи метаданных

Если на сервере включена подпись метаданных (METADATA_SIGNING_ENABLED), Save публикует детачированную подпись repodata/repomd.xml.asc, а публичный ключ — по адресу <repo>/repository.key. Включите repo_gpgcheck=1:

[codescoring]
name=CodeScoring Save
baseurl=https://save.example.com/rpm/<project>/rpm-hosted
enabled=1
username=<username>
password=<password>
gpgcheck=0
repo_gpgcheck=1
gpgkey=https://save.example.com/rpm/<project>/rpm-hosted/repository.key
gpgcheck vs repo_gpgcheck

repo_gpgcheck=1 включает проверку подписи метаданных репозитория (repomd.xml.asc) — это аналог apt'шного signed-by, и именно эту подпись создаёт Save. gpgcheck=1 проверяет подписи самих пакетов: Save их не создаёт и не изменяет — включайте gpgcheck=1 только если загружаемые пакеты подписаны на этапе сборки.

Robot-аккаунты в CI

Для CI/CD используйте robot-аккаунт: username = sa$<robot-name>, password = <api-key> в .repo-файле. Структура файла не меняется — отличаются только значения. Подробнее — в общем разделе Аутентификация.

Публикация пакетов (hosted)

Загрузка выполняется PUT-запросом в канонический путь Packages/<первая-буква-имени>/:

curl -u "<username>:<password>" \
  -T mypackage-1.0.0-1.x86_64.rpm \
  https://save.example.com/rpm/<project>/rpm-hosted/Packages/m/mypackage-1.0.0-1.x86_64.rpm

Имя файла должно соответствовать схеме <name>-<version>-<release>.<arch>.rpm. Save валидирует заголовки пакета и приводит путь к каноническому виду — фактический путь возвращается в ответе.

Альтернатива — multipart POST на корень репозитория:

curl -u "<username>:<password>" \
  -F "file=@mypackage-1.0.0-1.x86_64.rpm" \
  https://save.example.com/rpm/<project>/rpm-hosted

Принудительная перегенерация repodata

curl -u "<username>:<password>" \
  -X POST https://save.example.com/rpm/<project>/rpm-hosted/rebuild-index

Rebuild также удаляет устаревшие hash-именованные файлы repodata, оставшиеся от предыдущих публикаций.

Миграция URL репозитория

Сценарий использования: миграция RPM-репозитория с Nexus / Artifactory на CodeScoring.Save.

Источникbaseurl до миграцииbaseurl после миграции
Nexushttps://nexus.host.ru/repository/yum-hostedhttps://save.example.com/rpm/<project>/rpm-hosted
Artifactoryhttps://jfrog.host.ru/artifactory/rpm-localhttps://save.example.com/rpm/<project>/rpm-hosted
Официальное зеркалоhttps://dl.rockylinux.org/pub/rocky/9/BaseOS/x86_64/oshttps://save.example.com/rpm/<project>/rocky-proxy

Параметры аутентификации (username / password) в .repo-файле сохраняются без изменений. Для proxy-репозитория Save отдаёт repomd.xml.asc upstream как есть, поэтому существующие gpgkey-ключи дистрибутива продолжают работать с repo_gpgcheck=1.

Устранение неполадок

Проверка repomd.xml

curl -u "<username>:<password>" \
  https://save.example.com/rpm/<project>/rpm-hosted/repodata/repomd.xml

В ответе — XML с секциями data type="primary", filelists, other и hash-именованными href-ссылками.

Проверка наличия пакета в primary-индексе

# href primary-индекса берётся из repomd.xml
curl -s -u "<username>:<password>" \
  https://save.example.com/rpm/<project>/rpm-hosted/repodata/<hash>-primary.xml.gz \
  | gunzip | grep '<location'

Если пакет загружен, но отсутствует в индексе — подождите несколько секунд (индексация асинхронная) либо выполните rebuild-index.

Проверка публичного ключа

curl -u "<username>:<password>" \
  https://save.example.com/rpm/<project>/rpm-hosted/repository.key
# Ожидается: -----BEGIN PGP PUBLIC KEY BLOCK-----
# 404 означает, что подпись метаданных не включена на сервере

Состояние сервиса

curl https://save.example.com/health

Аудит по репозиторию

curl -u "<username>:<password>" \
  "https://save.example.com/api/v1/admin/audit?resource_type=repository&q=rpm-hosted&limit=50"
Страница была полезна?