0045. Только нативный API без совместимости с внешними протоколами
Статус: accepted. Дата: 2026-09-30. Заменяет ADR 0010.
Контекст
Arkvory развивается как самостоятельное хранилище артефактов с собственным API /api/v1, SDK и CLI arkvoryctl. Кроме него сервер публиковал поднабор скачиваний в формате внешнего протокола: три семейства маршрутов вне /api/v1, catch-all пути, отдельный пакет адаптеров и две дополнительные схемы аутентификации, действовавшие только для этих маршрутов. Поднабор не проверялся на реальных клиентах, ошибки оставались native, а поддержка требовала отдельных правил CORS, inventory и документации ограничений.
Владелец продукта решил отказаться от совместимости со сторонними протоколами и развивать только собственный API.
Решение
- Удалить пакет адаптеров внешнего протокола и маршруты
/api/packages/{repository}/download,/upack/{repository}/download/...,/endpoints/{repository}/content/.... Тег OpenAPILegacyи областьcompatibilityкаталога операций удаляются. - Удалить аутентификацию заголовком
X-ApiKeyиAuthorization: Basicс именемapi. Все защищённые операции принимают толькоAuthorization: Bearer: managed и file-based сервисные ключи, пользовательские сессии. - Перенести сценарии скачивания по идентичности в нативный API:
GET|HEAD /api/v1/repositories/{repository}/packages/content?group=&name=&version=— точная версия UPack; безversion— старшая SemVer-версия (после ADR 0047 — старшая стабильная, prerelease только явно). operationIddownloadPackageContent.GET|HEAD /api/v1/repositories/{repository}/asset/content?path=— текущая ревизия файла по пути. operationIddownloadAssetContent.
- Оба маршрута на каждом запросе разрешают один неизменяемый артефакт и далее используют тот же путь выдачи, что
GET|HEAD .../artifacts/{id}/content: правоcontent.read(для file keys и групп — coarseread), admission, bandwidth, content pins, Range/ETag/If-Range, 304/416. Операции относятся к областиtransfersи, как остальные GET/HEAD, доступны на reader. - Публичный контракт
/api/v1, OpenAPI и SDK далее меняются аддитивно либо через ADR; поддержка проверяется собственными SDK/CLI и фикстурами с известным происхождением.
Альтернативы
- Сохранить поднабор: остаются непроверенная поверхность, дополнительные схемы аутентификации и обязательство следовать чужому контракту.
- Расширить совместимость до публикации и каталога: большой объём работы без подтверждённого сценария и стенда, противоречит позиционированию самостоятельного продукта.
- Оставить прежние адреса как псевдонимы нативных маршрутов: сохраняет catch-all пути и дополнительные схемы аутентификации без пользы для новых клиентов.
Последствия
- Безопасность: одна схема аутентификации вместо трёх; ключ больше не передаётся в Basic или отдельном заголовке; нет маршрутов вне
/api/v1и/healthи исключений из CORS-контракта. Поверхность атаки и объём проверок уменьшаются. - Клиенты внешнего протокола больше не поддерживаются; интеграции используют native API, SDK или
arkvoryctl. Переходный период не предусмотрен: продукт ещё не используется в установках (ADR 0040). - Схема БД, данные, ACL и permissions не меняются. Число операций и версия OpenAPI меняются; snapshot inventory обновляется вместе с кодом.
latestи путь файла разрешаются заново на каждом запросе, поэтому URL не закрепляет объект. Для докачки клиент использует If-Range с полученным ETag либо скачивание по artifact ID.- Импорт подготовленного каталога сохраняется (MIGRATION). Инструменты миграции из внешних репозиториев артефактов могут быть добавлены позднее отдельным решением, без возврата совместимости протокола.
Проверка
- Contract guard и snapshot
tests/fixtures/api-operations.json: удалённые маршруты отсутствуют, новые операции описаны с правами, retry и gateway metadata. - PostgreSQL/HTTP: exact и latest при каталоге более 1000 версий, отсутствующие версия или путь, те же байты и ETag, что у
artifacts/{id}/content, Range/If-Range,content.readбез права перечисления, reader, общий bandwidth, обрыв при усечении blob. - Прежние схемы аутентификации не принимаются: запрос без Bearer получает 401.