Управление репозиториями и артефактами¶
Контекст¶
CodeScoring.Save хранит и раздаёт артефакты для команды разработки: сборщик публикует пакет, а IDE, CI-агенты и пользователи скачивают его по тому же URL, не выходя за периметр компании.
Все артефакты лежат в репозиториях, репозитории сгруппированы в проекты. Это та же иерархия, что и в интерфейсе:
Project (например, backend-team)
└── Repository (например, maven-central)
└── Artifact (например, commons-lang3:3.12.0)
Проект — это контейнер, в котором живут репозитории команды. Репозиторий — конкретное хранилище одного формата (Maven, npm, Docker и т.д.) одного из двух типов. Артефакт — то, что в нём лежит и что качают клиенты.
Два типа репозиториев¶
CodeScoring.Save поддерживает только два типа репозиториев, и каждый решает свою задачу.
Proxy-репозиторий — кэширующий прокси к внешнему источнику (например, Maven Central или npmjs.com). Когда клиент впервые запрашивает артефакт, Save качает его из upstream, кэширует и отдаёт. Все последующие запросы идут уже из кэша — это ускоряет сборки и снижает зависимость от внешних сервисов. На proxy-репозитории дополнительно работают политики безопасности OSA Proxy (если он настроен), которые могут заблокировать скачивание небезопасных компонентов.
Hosted-репозиторий — собственное хранилище, в которое команда публикует свои артефакты. Сюда попадают внутренние библиотеки, проверенные сторонние компоненты и build-artifacts.
В одном проекте может быть произвольное количество репозиториев обоих типов.
URL-схема доступа¶
Внешний клиент (Maven, npm, Docker и т.д.) обращается к репозиторию по URL вида:
| Формат | Шаблон |
|---|---|
| Maven | https://save.example.com/maven/<project>/<repository>/<group>/<artifact>/<version>/<file> |
| npm | https://save.example.com/npm/<project>/<repository>/<package> |
| NuGet | https://save.example.com/nuget/<project>/<repository>/v3/index.json |
| PyPI | https://save.example.com/pypi/<project>/<repository>/simple/ |
| Go | https://save.example.com/go/<project>/<repository> (как GOPROXY) |
| Raw | https://save.example.com/raw/<project>/<repository>/<filepath> |
| OCI / Docker | https://save.example.com/v2/<project>/<repository>/<image>/... |
Для OCI / Docker используется стандартный префикс /v2/, как требует OCI Distribution Spec. Дополнительно поддерживается Nexus-совместимая маршрутизация плоских URL — см. Работа с OCI / docker.
Структура веб-интерфейса¶
Слева расположена вертикальная навигация со следующими разделами:
- Projects — основной раздел: список проектов, внутри каждого — список репозиториев, внутри каждого репозитория — дерево артефактов;
- Cleanup — политики автоматической очистки ненужных артефактов;
- Settings — управление учётными записями, ролями, сервисными аккаунтами, конфигурацией и журналом аудита.
В верхней части интерфейса находится глобальный поиск — открывается по клавише / и ищет одновременно по проектам, репозиториям и артефактам с подсказками в реальном времени.
Базовый сценарий: подключить свой первый репозиторий¶
Шаг 1. Создайте проект¶
Проект — это контейнер, в котором будут жить репозитории. Удобно делить проекты по командам, продуктам или окружениям.
- В боковом меню выберите Projects.
- Нажмите кнопку Create project в правом верхнем углу.
- Заполните форму:
- Name — человеко-читаемое название проекта (например,
Backend Team); - Color — цвет для визуального различения проектов в списке;
- Key — URL-safe идентификатор проекта (например,
backend-team). Если оставить пустым, будет сгенерирован автоматически из Name, даже если Name не использует латиницу. Изменить Key после создания нельзя; - Description — необязательное описание проекта;
- Cleanup policy — раздел двухпанельного селектора с уже созданными политиками очистки. Можно оставить пустым и привязать политики позже.
- Name — человеко-читаемое название проекта (например,
- Нажмите Create project.
После создания откроется страница проекта со списком репозиториев (пока пустым) и его метаданными в шапке.
Key и Name
Name отображается в интерфейсе и может быть изменено в любой момент. Key участвует во всех URL и API-путях, поэтому его смена потребовала бы переподписки клиентов.
Шаг 2. Создайте репозиторий в проекте¶
Внутри проекта создаётся репозиторий — конкретное хранилище для артефактов одного формата.
- Откройте только что созданный проект.
- Нажмите Create repository в правом верхнем углу страницы проекта.
- Заполните общие поля:
- Name — человеко-читаемое название (например,
Maven Central (proxy)); - Color — цвет для удобства;
- Key — URL-safe идентификатор (например,
maven-central). Изменить после создания нельзя; - Description — необязательное описание.
- Name — человеко-читаемое название (например,
- Выберите Format — один из поддерживаемых пакетных форматов:
maven,npm,docker(OCI),nuget,pypi,go,raw. После создания формат поменять нельзя. - Выберите Type:
- Proxy — для проксирования внешнего реестра;
- Hosted — для собственного хранилища.
- Если выбран тип Proxy, появятся дополнительные поля:
- Proxy URL — адрес upstream-репозитория (например,
https://repo1.maven.org/maven2/); - Cache TTL, seconds — время жизни кэша метаданных в секундах. Для типичных внешних реестров достаточно
86400(сутки).
- Proxy URL — адрес upstream-репозитория (например,
- При необходимости привяжите Cleanup policy — список уже созданных политик автоматической очистки.
- Нажмите Create repository.
После создания откроется страница репозитория. В шапке отображается статус (Enabled/Disabled), формат, тип, даты создания и обновления, а для proxy-репозитория — кликабельная ссылка Remote URL, ведущая на upstream.
Изменение статуса репозитория
Статус (Enabled/Disabled) задаётся на форме редактирования: откройте репозиторий, нажмите Edit repository в шапке, переключите верхний радио-переключатель Status, нажмите Save. Disabled-репозиторий не отдаёт и не принимает запросы, но не удаляется и не теряет своих артефактов.
Шаг 3. Получите готовые сниппеты для подключения клиентов¶
На странице репозитория в правой части шапки находится кнопка со значком «звено цепи». По клику она открывает popover Useful snippets — набор готовых фрагментов конфигурации и команд, который зависит от формата репозитория.
- Нажмите кнопку звено цепи в шапке репозитория.
- В появившейся карточке прокрутите список сниппетов:
- каждый сниппет состоит из заголовка (например,
settings.xml,.npmrc,pip.conf,docker login), блока кода с подсветкой синтаксиса и краткого описания; - набор сниппетов формируется на стороне сервера по формату и типу репозитория. Для Maven обычно показывается фрагмент
<mirror>дляsettings.xmlи<repository>дляpom.xml; для Docker —docker loginиdocker pull; для npm — строка для.npmrc; и так далее.
- каждый сниппет состоит из заголовка (например,
- Нажмите кнопку Copy справа от нужного сниппета — он скопируется в буфер обмена.
- Вставьте сниппет в конфигурационный файл клиента или выполните команду в терминале.
Шаг 4. Опубликуйте и скачайте первый артефакт¶
Дальше всё происходит уже на стороне клиента — Save принимает стандартные запросы пакетного менеджера. Для hosted-репозитория обычный путь — публикация через mvn deploy, npm publish, twine upload или docker push. Для proxy-репозитория — обычный pull, после которого артефакт окажется в кэше Save.
При первой загрузке может потребоваться аутентификация — см. раздел Подключение клиентов и аутентификация.
После того, как клиент впервые что-то загрузит или скачает, артефакт появится в дереве на странице репозитория.
Работа с артефактами в репозитории¶
Страница репозитория состоит из двух колонок: слева — дерево артефактов с поиском и сортировкой, справа — детали выбранного артефакта.
Просмотр дерева¶
Дерево показывает структуру репозитория: папки и файлы с иконками. Файлы со значком «замок» — это «защищённые» (locked/release) артефакты, которые нельзя удалить или перезаписать без дополнительных шагов. Раскрытие папок происходит лениво: дочерние элементы подгружаются по клику.
При клике на файл его детали открываются справа: имя, размер, путь, контрольная сумма, метаданные формата (например, Maven groupId/artifactId/version или Docker tags).
Поиск, сортировка и фильтры¶
Над деревом расположено поле Search artifacts: введите подстроку и нажмите Enter — появится плоский список найденных артефактов с подсветкой контекста. Клик по строке откроет деталки соответствующего артефакта.
Рядом с поиском расположены две кнопки.
Кнопка Sort управляет сортировкой дерева:
- Sort by —
Name,Date addedилиDate modified; - Sort direction —
A to ZилиZ to A.
Кнопка-фильтр (иконка воронки) для proxy-репозиториев открывает дополнительный переключатель Show uncached artifacts. По умолчанию дерево показывает только то, что уже лежит в локальном кэше. С включённым флагом Save также подгружает в дерево артефакты, известные upstream, но ещё не скачанные — это удобно, чтобы предварительно посмотреть, что доступно в проксируемом источнике, не запуская реальный pull. Это доступно не для всех форматов репозиториев из-за различия протоколов.
Действия над одним артефактом¶
После выбора артефакта в правой панели доступны:
- Download — скачивание файла локально;
- Lock artifact — пометить артефакт как
release. После lock артефакт нельзя удалить или перезаписать обычнымupload— это нужно, чтобы выпущенные версии не могли быть подменены; - Delete artifact — удалить файл из репозитория (для hosted) или из кэша (для proxy).
Lock — необратимая операция в UI
Снять флаг release можно только через API: PUT /api/v1/artifacts/release?id=<artifact-id> с {"is_release": false}.
Групповые действия¶
Слева от каждой строки дерева есть чекбокс. После выделения нескольких файлов в верхней части появляется панель с действиями:
- Lock — массово зафиксировать выделенные артефакты;
- Delete — массово удалить.
Обе операции атомарны для всей выборки.
Подключение клиентов и аутентификация¶
Save поддерживает несколько способов аутентификации, чтобы покрыть как интерактивные клиенты, так и CI-конвейеры. Конкретный способ выбирается клиентом самостоятельно через заголовок Authorization (или специальные заголовки формата).
| Способ | Заголовок | Тип в cs-auth | Когда применять |
|---|---|---|---|
| Basic Auth (пользователь) | Authorization: Basic base64(<username>:<password>) |
basic |
Интерактивная работа из IDE, ручные curl и mvn/pip/npm от имени конкретного пользователя |
| Basic Auth (robot-аккаунт) | Authorization: Basic base64(sa$<robot-name>:<api-key>) |
api_key |
CI/CD-пайплайны, runners сборки, любые сервисные интеграции |
| Bearer JWT | Authorization: Bearer <jwt> |
bearer_jwt |
Сессионные запросы из веб-интерфейса и других сервисов после логина через cs-auth |
| Bearer (opaque token) | Authorization: Bearer <opaque-token> |
npm_token |
Любой не-JWT bearer-токен; на практике — npm-клиент после npm adduser / npm login |
X-NuGet-ApiKey |
X-NuGet-ApiKey: <api-key> |
nuget_key |
Только NuGet-формат, для совместимости с dotnet nuget push |
| Docker v2 token | Authorization: Bearer <docker-jwt> |
docker_token |
OCI-клиенты после прохождения цикла 401 → retry → 200 |
Bearer-токен с тремя сегментами через точку классифицируется как JWT, остальные — как opaque npm-токен. Префикс sa$ в Basic Auth — это маркер service-аккаунта (robot).
Robot-аккаунты для CI/CD¶
Для интеграции с CI/CD не рекомендуется использовать личные пароли — они привязаны к сотруднику и быстро устаревают. Вместо этого создаётся robot-аккаунт — служебная учётная запись с отдельной ролью и долгоживущим API-ключом.
Создание через веб-интерфейс¶
- В боковом меню откройте
Settings -> Robot accounts. - Нажмите Create robot account в правом верхнем углу.
- Заполните поля:
- Login — служебное имя для аутентификации (например,
ci-builder). Save сам добавит к введённому значению префикс для service-аккаунта; - Name — человеко-читаемое название (например,
CI Builder Bot); - Description — необязательное описание;
- Expires in — дата истечения ключа. Под полем доступны быстрые пресеты
Week,Month,Year. Если ключ должен жить вечно, поставьте флаг Never справа от выбора даты — поле выбора даты автоматически блокируется; - Global permissions — глобальные разрешения для робота;
- Scoped permissions — разрешения, ограниченные одним, несколькими (или всеми сразу) проектами или репозиториями. Переключатель Scope выбирает уровень (Projects / Repositories), затем для каждого scope добавляются записи
Add project permissions/Add repository permissions.
- Login — служебное имя для аутентификации (например,
- Нажмите Create robot account.
После успешного создания на экране автоматически открывается модальное окно с API-ключом — это пароль для Basic Auth.
Окно с API-ключом¶
После нажатия Create robot account Save открывает окно с API-ключом. В тем доступны:
- API key — поле в режиме «только для чтения» с самим значением ключа и кнопкой Copy, копирующей его в буфер обмена;
- Key prefix — короткий префикс ключа. По нему можно опознать ключ в журнале аудита, не раскрывая полный секрет;
- Expires at — дата истечения (если она задана);
- Warning — текст с сервера, например
Store this API key securely — it cannot be retrieved again.
Под секретом находится кнопка I have copied the key, которая закрывает окно и переводит на страницу деталей созданного robot-аккаунта.
API-ключ показывается только один раз
После закрытия окна посмотреть или восстановить тот же ключ нельзя — Save хранит только хэш. Скопируйте ключ и сохраните его в secret-storage CI (GitLab CI variables, GitHub Actions secrets, HashiCorp Vault) до того, как закроете окно. Если ключ утерян, перевыпустите его (вручную в форме редактирования robot-аккаунта или через API POST /admin/robots/<id>/rotate-key) — после ротации старое значение становится недействительным.
Создание через API¶
curl -X POST https://save.example.com/api/v1/admin/robots \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin-jwt>" \
-d '{
"username": "ci-builder",
"display_name": "CI Builder Bot",
"description": "Robot account for CI/CD pipelines",
"permissions": {
"project": {
"backend-team": ["project_artifacts.download", "project_artifacts.upload"]
}
},
"key_expires_in_seconds": 7776000
}'
В ответе вернётся api_key, который выдаётся только один раз при создании — сохраните его в secret-storage CI.
Использование в клиенте¶
username = sa$<robot-name>, password = <api-key> — обычный Basic Auth:
Экранирование $ в shell
В bash символ $ в одинарных кавычках сохраняется как есть, а в двойных — экранируется как \$. В YAML / TOML / XML конфигах экранирование не требуется.
API-ключ NuGet — особенность реализации
Заголовок X-NuGet-ApiKey поддерживается напрямую: cs-auth классифицирует его как тип nuget_key и валидирует по 12-символьному префиксу ключа. Для NuGet работают оба варианта, но мы рекомендуем Basic Auth с robot-аккаунтом — это единообразно с остальными форматами, и в журнале аудита явно отражается личность robot'а.
Анонимный доступ на чтение¶
Если включён глобальный флаг AllowAnonymousRead, неаутентифицированным запросам выдаётся PermissionSet с правами projects.view, project_repos.view, project_artifacts.view, project_artifacts.download для всех проектов. Для Docker / OCI этот режим всё равно требует цикла 401 → /v2/token → 200, иначе Docker-клиент не сможет работать (см. Работа с OCI / docker).
Текущее значение флага видно в Settings -> Configuration. Изменение значения выполняется через API:
curl -X PUT https://save.example.com/api/v1/admin/config \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin-jwt>" \
-d '{"key": "AllowAnonymousRead", "value": "true"}'
Политики очистки¶
Чтобы хранилище не разрасталось бесконечно, на репозитории привязываются политики очистки — правила автоматического удаления (или удержания) артефактов. Save поддерживает пять типов политик; для большинства задач достаточно простых, для сложных AND/OR-условий используется тип expression.
Создание политики¶
- В боковом меню откройте Cleanup.
- Нажмите Create policy.
- Заполните общие поля: Display name, Description, при необходимости — Schedule (cron-выражение из пяти полей: минуты, часы, день, месяц, день недели).
- Выберите Policy type — определяет основное правило очистки:
| Тип политики | Назначение | Параметр value |
|---|---|---|
delete-snapshots-older-than |
Удалять SNAPSHOT/dev-версии старше N дней | количество дней, например 30 |
keep-latest-versions |
Оставлять только N последних версий каждого артефакта, остальное удалять | N, например 5 |
delete-by-age |
Удалять любые артефакты старше N дней | количество дней |
delete-by-size |
Удалять самые старые артефакты при превышении лимита размера | размер в гигабайтах целым числом, например 50 |
expression |
Гибкое DSL-правило с AND/OR-комбинацией критериев | вместо value передаётся объект expression |
- Укажите Formats, к которым применяется политика. Если оставить пустым, политика будет применяться ко всем форматам.
- Поставьте флаг Active, чтобы политика начала работать сразу.
- Для типа
expressionдополнительно соберите дерево критериев — каждый критерий это сочетаниеtype, оператора сравнения (eq,ne,gt,lt,matches,contains) и значения; критерии можно объединять группами с логическим операторомANDилиOR. - Нажмите Create policy.
Доступные критерии для expression¶
Полный список — GET /api/v1/enums/cleanup-criterion-types.
| Группа | type |
Назначение |
|---|---|---|
| Возраст | created_before |
Возраст артефакта (дней) |
last_downloaded_days |
Дней с момента последней загрузки | |
not_downloaded_since |
Никогда не скачивался или не скачивался с указанной даты | |
| Версия | version_pattern |
Glob-паттерн по версии |
is_snapshot, is_prerelease, is_release |
Маркеры snapshot / pre-release / release | |
| Имя/путь | name_pattern, path_pattern |
Glob-паттерны |
| Размер | size_greater_than, size_less_than |
Размер артефакта |
| Docker | docker_tag, docker_untagged |
Тег / отсутствие тега |
| Maven | maven_classifier, maven_packaging |
Classifier / packaging |
| npm | npm_scope |
Скоуп пакета |
| PyPI | pypi_package_type |
sdist, bdist_wheel, … |
| NuGet | nuget_is_prerelease |
NuGet-флаг pre-release |
| OCI | oci_artifact_type |
Тип OCI-артефакта (Helm, Cosign, SBOM, …) |
| Retention | keep_latest |
Оставлять N последних версий |
Привязка политики к репозиторию¶
Привязка происходит на форме создания или редактирования репозитория (или проекта — тогда политика каскадно применяется ко всем его репозиториям).
- Откройте репозиторий и нажмите Edit в шапке.
- Прокрутите до раздела Cleanup policy.
- В левой колонке (Available) — все существующие политики, в правой (Applied) — уже привязанные. Перенесите нужные политики стрелкой между колонками.
- Сохраните изменения.
Ручной запуск и предварительный просмотр через API¶
# Сухой прогон — посмотреть, что было бы удалено, без сохранения политики
curl -X POST https://save.example.com/api/v1/cleanup/preview \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"repository_id": 42,
"policy_type": "delete-snapshots-older-than",
"value": "30"
}'
# Запуск уже сохранённых политик (с опциональным dry_run)
curl -X POST "https://save.example.com/api/v1/cleanup/execute?project=backend-team" \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"policies": ["delete-old-snapshots", "keep-latest-5"],
"dry_run": true
}'
Управление доступом¶
Управление пользователями, ролями и правами на проекты и репозитории выполняется отдельным сервисом cs-auth. API проксируется через Save под префиксами /api/v1/auth/* и /api/v1/admin/*. Способы аутентификации описаны выше в разделе Подключение клиентов и аутентификация.
В веб-интерфейсе нужные разделы находятся в Settings:
- Roles — описания ролей с набором разрешений;
- Users — учётные записи людей;
- Robot accounts — служебные учётные записи (см. выше).
API cs-auth
Конкретные эндпоинты для управления пользователями, ролями и project membership — это поверхность API сервиса cs-auth. Save прозрачно их форвардит, но в своём swagger не описывает.
Уровни доступа¶
Права в CodeScoring.Save гранулярны, в формате <resource>.<action>. Роли в cs-auth определяются пользователем и представляют собой набор таких разрешений.
На уровне репозитория (артефакты внутри репозитория):
| Permission | Что разрешает |
|---|---|
artifacts.view |
Просмотр списка и метаданных артефактов |
artifacts.download |
Скачивание артефактов |
artifacts.upload |
Публикация артефактов (актуально для hosted) |
artifacts.delete |
Удаление артефактов |
artifacts.lock |
Lock/unlock одного или всех артефактов |
На уровне репозитория (сам репозиторий):
| Permission | Что разрешает |
|---|---|
repos.view |
Просмотр настроек репозитория и статистики |
repos.edit |
Изменение настроек репозитория |
repos.delete |
Удаление репозитория |
На уровне проекта (cascade-permissions, распространяются на все репозитории и артефакты проекта):
| Permission | Что разрешает |
|---|---|
projects.view, projects.create, projects.edit, projects.delete |
Управление проектами |
project_repos.view, project_repos.create, project_repos.delete, project_repos.edit |
Управление всеми репозиториями проекта |
project_artifacts.view, project_artifacts.upload, project_artifacts.download, project_artifacts.delete, project_artifacts.lock, project_artifacts.unlock |
Все операции с артефактами в любом репозитории проекта |
Глобальные (только через global scope роли):
| Permission | Что разрешает |
|---|---|
cleanup.view, cleanup.edit, cleanup.delete |
Управление политиками очистки |
roles.create, roles.delete |
Управление ролями |
users.create, users.delete |
Управление пользователями |
config.view, config.manage |
Просмотр и редактирование конфигурации |
audit.view |
Просмотр журнала аудита |
Cascade-логика
Project-scope permissions автоматически cascade на repository-scope: пользователь с project_artifacts.download на проекте получит право artifacts.download на любой репозиторий внутри этого проекта. Для wildcard-доступа ко всем проектам / репозиториям используется ключ *.
Привязка пользователя или robot-аккаунта к проекту¶
Привязка участника к проекту — это назначение конкретной роли конкретному пользователю или robot-аккаунту в рамках одного проекта. Назначенный участник получает все разрешения роли, а в шапке проекта он отображается как member.
Через веб-интерфейс¶
Раздел в разработке
Раздел Members на странице проекта пока находится в разработке. Backend поддерживает все необходимые операции (/api/v1/admin/projects/<project>/members), но в UI вкладки Members на странице проекта ещё нет.
До появления вкладки выполните операции через API ниже.
Через API¶
Добавление участника:
curl -X POST https://save.example.com/api/v1/admin/projects/backend-team/members \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin-jwt>" \
-d '{
"user_id": 5,
"role_id": 2
}'
Для пользователей role_id обязателен, для robot-аккаунтов (флаг is_service=true) — может быть опущен.
Просмотр списка участников:
curl -u "<admin-username>:<admin-password>" \
"https://save.example.com/api/v1/admin/projects/backend-team/members?limit=50"
Смена роли существующему участнику:
curl -X PUT https://save.example.com/api/v1/admin/projects/backend-team/members/5 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <admin-jwt>" \
-d '{"role_id": 3}'
Удаление участника из проекта:
curl -X DELETE https://save.example.com/api/v1/admin/projects/backend-team/members/5 \
-H "Authorization: Bearer <admin-jwt>"
Те же действия через API¶
Каждое действие, описанное выше для интерфейса, доступно и через REST API. Это полезно для скриптов первоначальной настройки, инфраструктуры как кода (Terraform / Ansible) и интеграционных тестов.
Создание проекта¶
curl -X POST https://save.example.com/api/v1/projects \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"name": "backend-team",
"display_name": "Backend Team",
"description": "Backend services and microservices",
"color": "#4A90D9"
}'
Создание Proxy-репозитория¶
curl -X POST https://save.example.com/api/v1/repos \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"project": "backend-team",
"name": "maven-central",
"display_name": "Maven Central (proxy)",
"format": "maven",
"repository_type": "proxy",
"remote_url": "https://repo1.maven.org/maven2/",
"cache_ttl": 86400
}'
Создание Hosted-репозитория¶
curl -X POST https://save.example.com/api/v1/repos \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"project": "backend-team",
"name": "internal-maven",
"display_name": "Internal Maven",
"format": "maven",
"repository_type": "hosted"
}'
Назначение политики очистки¶
curl -X POST "https://save.example.com/api/v1/cleanup/assignments?project=backend-team" \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"policies": [
{"policy_name": "delete-old-snapshots", "priority": 10, "enabled": true}
]
}'
Создание политики очистки¶
curl -X POST https://save.example.com/api/v1/cleanup/policies \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"name": "delete-old-snapshots",
"display_name": "Delete Old Maven Snapshots",
"description": "Удалять SNAPSHOT-версии Maven старше 30 дней",
"policy_type": "delete-snapshots-older-than",
"value": "30",
"formats": ["maven"],
"enabled": true,
"schedule": "0 2 * * *"
}'
Создание политики на основе выражения¶
curl -X POST https://save.example.com/api/v1/cleanup/policies \
-H "Content-Type: application/json" \
-u "<username>:<password>" \
-d '{
"name": "clean-old-prereleases",
"display_name": "Clean Old Pre-releases",
"policy_type": "expression",
"formats": ["maven", "npm"],
"expression": {
"action": "delete",
"logical_operator": "and",
"criteria": [
{"type": "is_prerelease", "value": "true"},
{"type": "created_before", "value": "14"}
]
},
"enabled": true
}'
Мониторинг¶
Журнал аудита¶
Журнал аудита фиксирует все изменения в проектах, репозиториях, артефактах, ролях и robot-аккаунтах. В UI он доступен:
- Глобально —
Settings -> Audit log; - По проекту — на странице проекта в шапке справа есть иконка журнала, ведущая на отфильтрованный по проекту журнал.
Каждая запись содержит время события, инициатора, тип ресурса и его идентификатор, тип действия и набор полей с подробностями (имя загруженного артефакта, изменённые параметры репозитория и т.п.). Записи группируются по дням и отображаются в виде таймлайна, а ссылки внутри записи кликабельны (открывается соответствующий проект, репозиторий, политика, пользователь или роль).
Журнал можно выгрузить за период через кнопку Export в шапке (форматы JSON или HTML).
# Аудит-журнал по конкретному репозиторию через API
curl -u "<username>:<password>" \
"https://save.example.com/api/v1/admin/audit?resource_type=repository&q=maven-central&limit=50"
Статистика репозитория¶
Текущие агрегированные показатели по репозиторию доступны через API:
Ответ:
{
"id": 42,
"name": "maven-central",
"project_name": "backend-team",
"artifact_count": 1523,
"total_size": 16413032448,
"cache_hit_ratio": 0.85,
"last_activity": "2026-03-17T10:30:00Z"
}
Поля статистики
Эндпоинт возвращает только агрегированные показатели. Поле cache_hit_ratio присутствует только для proxy-репозиториев.
Состояние сервиса¶
Глобальный health-check сервиса. Отдельных health-эндпоинтов на репозиторий нет: доступность upstream проверяется фоновыми воркерами и отражается через метрики Prometheus.
Логи¶
Логи централизованные, в формате JSON. Фильтрация по конкретному репозиторию — через стандартные средства log-aggregator'а.