A release-readiness QA pass over the whole product. The commits split into defects a user would hit and gates that were reporting green while measuring nothing. ## Fixes that change behaviour Rate limiting was bypassable on every install: TRUST_PROXY defaulted to true, so request.ip came from a client-set header and a forged X-Forwarded-For got past the login limiter. The default is now a private-network trust list. A transient Postgres outage stranded in-flight jobs, leaving finished output on disk with no row pointing at it. A reconciler now resolves those rows and adopts the bytes rather than dropping the work. A Redis connection that moved to a new address wedged every read-blocked consumer, so completions stopped signalling while health still answered 200. Socket timeouts plus subscriber pings recover it. Installing more than one AI bundle left the shared venv multi-versioned and silently broke three tools. The installer now reconciles distributions to one version each. Converting an image to JXL at quality 1 through 4 returned a 500, because libjxl 0.7 rejects the distance those values compute. The quality is floored at what the encoder honours. A missing ffmpeg was also reported to the user as a corrupt upload; it now says the engine is unavailable. RAW uploads reached an unpatched LibRaw on arm64, so it is built from source at 0.22.2, and the release scan was split so it can fail on an unfixed critical instead of hiding it behind ignore-unfixed. ## Gates that could not fail Two mutation lanes ran zero mutants because Stryker crawled the gitignored docs build; coverage discarded its whole report on any failing test; the lint gate skipped root tests, scripts, and two workspaces; and several generated matrices counted a host missing ffmpeg as a passing tool. Each now measures what it claims. Full evidence and the outstanding release items are tracked locally and are not part of this branch.
20 KiB
description, i18n_source_hash, i18n_provenance, i18n_output_hash, i18n_hash_version
| description | i18n_source_hash | i18n_provenance | i18n_output_hash | i18n_hash_version |
|---|---|---|---|---|
| Налаштуйте провізіонінг SCIM 2.0 для синхронізації користувачів і груп з вашого постачальника ідентифікації до SnapOtter. Охоплює Okta, Azure AD / Entra ID та власні інтеграції. | 06ee702b386e | human | 40fd5043d957 | 2 |
Провізіонінг SCIM
SnapOtter реалізує SCIM 2.0 (System for Cross-domain Identity Management) для автоматизованого провізіонінгу користувачів і груп. Ваш постачальник ідентифікації може створювати, оновлювати, деактивувати та повторно активувати облікові записи користувачів і синхронізувати членство у групах автоматично.
::: tip Функція enterprise
Провізіонінг SCIM потребує ліцензії enterprise з функцією scim. Він недоступний у плані team. Без цієї функції всі кінцеві точки SCIM (крім discovery) повертають 403.
:::
Передумови
- Запущений екземпляр SnapOtter, доступний за публічним URL
- Ключ ліцензії enterprise з функцією
scim - Вбудований обліковий запис SnapOtter
adminіз повним ефективним набором дозволів. Делегована спеціальна роль або ключ API адміністратора, у якому відсутні будь-які дозволи адміністратора, не можуть створити або відкликати глобальний маркер SCIM. - Доступ адміністратора до налаштувань провізіонінгу вашого постачальника ідентифікації
Швидкий старт
- Створіть токен SCIM Bearer:
curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
-H "Cookie: snapotter-session=YOUR_SESSION" \
-H "Content-Type: application/json"
Відповідь містить токен. Збережіть його негайно; отримати його повторно неможливо.
{
"token": "so_scim_v2_a1b2c3d4e5f6...",
"message": "Save this token - it cannot be retrieved again"
}
- У вашому постачальнику ідентифікації налаштуйте провізіонінг SCIM з такими параметрами:
- Base URL:
https://photos.example.com/api/v1/scim/v2 - Authentication: Bearer token (вставте токен із кроку 1)
- Base URL:
Автентифікація
Кінцеві точки SCIM використовують окремий токен Bearer, відмінний від сесій користувачів та ключів API.
Створення токена
POST /api/v1/enterprise/scim/token генерує новий маркер SCIM. Оскільки маркер може надавати та змінювати користувачів у примірнику, для цієї кінцевої точки потрібна вбудована роль admin із повним ефективним набором дозволів адміністратора. Утримання users:manage у спеціальній ролі недостатньо.
Токен повертається у відкритому вигляді рівно один раз. SnapOtter зберігає лише хеш scrypt. Якщо ви втратите токен, відкличте його та створіть новий.
Одночасно активний лише один токен SCIM. Створення нового токена замінює попередній.
::: warning Перевипуск токена після оновлення
Застарілі неверсійовані маркери SCIM відхилено. Після оновлення до випуску, який видає токени so_scim_v2_..., згенеруйте новий токен і оновіть постачальника ідентифікаційної інформації, перш ніж відновити надання.
:::
Відкликання токена
DELETE /api/v1/enterprise/scim/token скасовує поточний маркер SCIM. Він має ті ж повні вбудовані вимоги адміністратора, що й генерація маркерів.
Обмеження частоти запитів
Кінцеві точки SCIM обмежені 1000 запитами за хвилину на токен. Перевищення цього ліміту повертає HTTP 429.
Підтримувані ресурси
| Ресурс SCIM | Концепція SnapOtter | Create | Read | Update | Delete |
|---|---|---|---|---|---|
| User | Обліковий запис користувача | Так | Так | Так | М'яке видалення |
| Group | Team | Так | Так | Так | Так |
::: warning
Групи SCIM зіставляються з teams SnapOtter, а не з ролями. SCIM не може встановлювати роль користувача. Усім користувачам, створеним через SCIM, призначається роль user. Щоб змінити роль користувача, скористайтеся адмін-інтерфейсом SnapOtter.
:::
Операції з користувачами
Створення користувача
POST /api/v1/scim/v2/Users
Створює новий обліковий запис користувача з authProvider, встановленим у scim, та роллю user. Користувача призначено до команди Default. Якщо active дорівнює false, роль натомість встановлюється у disabled.
Обов'язкові атрибути: userName. Необов'язкові: externalId, emails, active (за замовчуванням true).
Список і фільтрація користувачів
GET /api/v1/scim/v2/Users
Повертає посторінковий список користувачів. Підтримує параметри запиту startIndex та count (максимум 200 результатів на сторінку).
Фільтрація підтримує лише eq (дорівнює) за такими атрибутами:
userName eq "jane"externalId eq "ext-12345"
Інші оператори фільтрації та атрибути повертають HTTP 400.
Отримання користувача
GET /api/v1/scim/v2/Users/:id
Повертає одного користувача за його ідентифікатором користувача SnapOtter.
Заміна користувача
PUT /api/v1/scim/v2/Users/:id
Замінює атрибути користувача. Підтримує userName, externalId, emails та active. Зміни імені користувача перевіряються на конфлікти (409, якщо нове ім'я користувача вже зайняте іншим користувачем).
Часткове оновлення користувача
PATCH /api/v1/scim/v2/Users/:id
Часткове оновлення за допомогою SCIM PatchOp. Підтримувані операції:
| Операція | Шляхи |
|---|---|
replace |
active, userName, externalId, emails, emails[type eq "work"].value, name.formatted, displayName |
add |
Те саме, що й replace |
remove |
externalId, emails |
Шляхи name.formatted та displayName приймаються для сумісності, але не мають постійного ефекту (SnapOtter не зберігає окреме відображуване ім'я).
Операції replace без значення (де значення є об'єктом без path) також підтримуються, з ключами userName, externalId, emails та active.
Деактивація користувача (м'яке видалення)
DELETE /api/v1/scim/v2/Users/:id
SnapOtter не видаляє користувачів остаточно через SCIM. Натомість DELETE виконує м'яку деактивацію:
- Роль користувача змінюється з поточного значення (наприклад,
editor) наdisabled:editor, зберігаючи початкову роль. - Пароль користувача очищується.
- Усі активні сесії відкликаються.
- Усі ключі API відкликаються.
Користувач більше не може входити в систему чи використовувати будь-які ключі API. Його дані (файли, історія) зберігаються.
Повторна активація користувача
Щоб повторно активувати раніше деактивованого користувача, надішліть запит PUT або PATCH з active: true. SnapOtter відновлює початкову роль, що була до деактивації (наприклад, disabled:editor знову стає editor). Якщо початкову роль визначити не вдається, відбувається повернення до user.
::: details Приклад: деактивація та повторна активація через PATCH
// Deactivate
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "path": "active", "value": false }
]
}
// Reactivate
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:PatchOp"],
"Operations": [
{ "op": "replace", "path": "active", "value": true }
]
}
:::
Операції з групами
Групи SCIM зіставляються з командами SnapOtter. Створення групи створює команду. Членство у групі визначає, до якої команди належить користувач.
Створення групи
POST /api/v1/scim/v2/Groups
Обов'язково: displayName. Необов'язково: members (масив { value: userId }).
Список і фільтрація груп
GET /api/v1/scim/v2/Groups
Фільтрація підтримує лише displayName eq "...". Посторінково з startIndex та count (максимум 200 результатів на сторінку).
Отримання групи
GET /api/v1/scim/v2/Groups/:id
Заміна групи
PUT /api/v1/scim/v2/Groups/:id
Замінює назву групи та повний список членства. Наявні члени, яких немає в новому списку, переміщуються до команди Default.
Часткове оновлення групи
PATCH /api/v1/scim/v2/Groups/:id
Підтримує такі операції:
| Операція | Шлях | Ефект |
|---|---|---|
add |
members |
Додає користувачів до команди |
remove |
members[value eq "userId"] |
Переміщує користувача до команди Default |
replace |
displayName |
Перейменовує команду |
replace |
members |
Замінює всіх членів (видалені члени переміщуються до команди Default) |
Видалення групи
DELETE /api/v1/scim/v2/Groups/:id
Видаляє команду. Усі члени видаленої команди переміщуються до команди Default. Користувачі не деактивуються та не видаляються.
Налаштування IdP
Okta
- У консолі адміністратора Okta відкрийте свій застосунок SnapOtter (або створіть його).
- Перейдіть на вкладку Provisioning і натисніть Configure API Integration.
- Позначте Enable API Integration та введіть:
- Base URL:
https://photos.example.com/api/v1/scim/v2 - API Token: токен SCIM Bearer, створений вище
- Base URL:
- Натисніть Test API Credentials, а потім Save.
- У розділі Provisioning > To App увімкніть:
- Create Users
- Update User Attributes
- Deactivate Users
- У розділі Push Groups налаштуйте, які групи Okta синхронізувати як команди SnapOtter.
Azure AD / Entra ID
- На порталі Azure перейдіть до свого корпоративного застосунку SnapOtter.
- Перейдіть до Provisioning і встановіть Provisioning Mode у Automatic.
- У розділі Admin Credentials введіть:
- Tenant URL:
https://photos.example.com/api/v1/scim/v2 - Secret Token: токен SCIM Bearer, створений вище
- Tenant URL:
- Натисніть Test Connection, а потім Save.
- У розділі Mappings налаштуйте зіставлення атрибутів користувачів і груп. Значення за замовчуванням зазвичай працюють, але переконайтеся, що
userNameзіставляється зuserPrincipalNameчиmailза потреби. - Встановіть Provisioning Status у On і збережіть.
Azure провізіонує користувачів і групи за фіксованим циклом синхронізації (зазвичай кожні 40 хвилин).
Кінцеві точки discovery
Ці три кінцеві точки доступні без автентифікації та описують можливості сервера SCIM:
| Кінцева точка | Опис |
|---|---|
GET /api/v1/scim/v2/ServiceProviderConfig |
Можливості сервера та підтримувані функції |
GET /api/v1/scim/v2/Schemas |
Визначення схем User і Group |
GET /api/v1/scim/v2/ResourceTypes |
Доступні типи ресурсів (User, Group) |
ServiceProviderConfig оголошує такі можливості:
| Функція | Підтримується |
|---|---|
| Patch | Так |
| Bulk | Ні |
| Filter | Так (максимум 200 результатів, лише оператор eq) |
| Change password | Ні |
| Sort | Ні |
| ETag | Ні |
Обмеження
- Фільтрація: підтримується лише оператор
eq. Складні фільтри, операториand/or,co(contains) іsw(starts with) не реалізовано. - Пакетні операції: не підтримуються.
- Sort і ETag: не підтримуються.
- Ролі: SCIM не може призначати ролі SnapOtter. Усі провізіоновані користувачі отримують роль
user. - MAX_USERS: обмеження змінної середовища
MAX_USERSне застосовується під час створення користувачів через SCIM. Якщо вам потрібно обмежити кількість користувачів, керуйте призначеннями у своєму IdP. - Один токен: одночасно активним може бути лише один токен SCIM. Якщо кільком IdP потрібен доступ через SCIM, вони мають спільно використовувати токен.
- Групи є командами: групи SCIM відповідають командам, а не ролям чи групам дозволів.
Усунення несправностей
403 "SCIM provisioning requires an enterprise license with the scim feature"
Ваша ліцензія не включає функцію scim, або ліцензію не налаштовано. SCIM потребує ліцензії плану enterprise. Переконайтеся, що SNAPOTTER_LICENSE_KEY встановлено, а ліцензія включає функцію scim.
401 "Bearer token required"
Запит SCIM не містив заголовка Authorization: Bearer <token>. Перевірте конфігурацію провізіонінгу свого IdP.
401 "Invalid token"
Маркер має неправильний формат, використовує вилучений неверсійний формат або не відповідає збереженому хешу. Згенеруйте поточний маркер so_scim_v2_... і оновіть його в налаштуваннях ініціалізації IdP.
401 "SCIM not configured"
Токен SCIM ще не створено. Скористайтеся кінцевою точкою POST /api/v1/enterprise/scim/token, щоб створити його.
409 "User already exists" / "userName already taken"
Користувач із таким самим іменем уже існує. Це може статися, коли IdP повторює невдале створення. Перевірте наявність дублікатів імен користувачів на панелі адміністратора SnapOtter.
429 "SCIM rate limit exceeded"
IdP надсилає понад 1000 запитів за хвилину. Зазвичай це трапляється під час великої початкової синхронізації. Більшість IdP автоматично повторюють спроби після скидання вікна обмеження частоти. Якщо проблема не зникає, перевірте інтервал синхронізації провізіонінгу свого IdP.
Користувачів деповізіоновано, але не видалено з інтерфейсу
DELETE у SCIM є м'якою деактивацією. Деактивовані користувачі й далі відображаються у списку користувачів адміністратора зі статусом «вимкнено». Це зроблено навмисно, щоб зберегти їхні дані. Їхня роль відображається як disabled:<original-role>.