mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: release QA hardening across processing, media, security, and CI gates (#649)
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.
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Структура монорепозиторію, архітектура застосунків і пакетів, життєвий цикл запиту та споживання ресурсів SnapOtter."
|
||||
i18n_output_hash: 6a1de194bb8b
|
||||
i18n_source_hash: a53946e760b0
|
||||
i18n_source_hash: 50e076925c4b
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 4490df3a46a7
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Архітектура {#architecture}
|
||||
@@ -52,7 +53,7 @@ snapotter/
|
||||
|
||||
### API (`apps/api`) {#api-apps-api}
|
||||
|
||||
Сервер Fastify v5, що надає 241 маршрут інструментів у п'яти модальностях (image, video, audio, PDF, file) і обробляє:
|
||||
Сервер Fastify v5, що надає 243 маршрут інструментів у п'яти модальностях (image, video, audio, PDF, file) і обробляє:
|
||||
- Завантаження файлів, керування тимчасовим робочим простором та постійне зберігання файлів
|
||||
- Бібліотеку файлів користувача (таблиця `user_files`): за замовчуванням збережене редагування зберігається як незалежний новий файл, або як пов'язана з батьківською версія, коли ви перезаписуєте оригінал. Вона фіксує, які інструменти було застосовано (`toolChain`), і отримує автоматично згенеровану мініатюру для сторінки Files
|
||||
- Виконання інструментів (маршрутизує кожен запит інструмента до рушія зображень або мосту AI)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Усі змінні середовища SnapOtter зі значеннями за замовчуванням. Налаштуйте автентифікацію, сховище, моделі AI, аналітику тощо."
|
||||
i18n_source_hash: 8e9e9ca2840c
|
||||
i18n_source_hash: 25970c776f7c
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 498d74ca4a81
|
||||
i18n_output_hash: 52fb4064af72
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Конфігурація {#configuration}
|
||||
@@ -19,28 +20,51 @@ i18n_output_hash: 498d74ca4a81
|
||||
| `RATE_LIMIT_PER_MIN` | `1000` | Максимальна кількість запитів за хвилину на одну IP. Задайте 0, щоб вимкнути обмеження частоти запитів. |
|
||||
| `CORS_ORIGIN` | (порожньо) | Розділені комами дозволені джерела для CORS або порожньо лише для того самого джерела. |
|
||||
| `LOG_LEVEL` | `info` | Детальність журналювання. Одне з: `fatal`, `error`, `warn`, `info`, `debug`, `trace`. |
|
||||
| `TRUST_PROXY` | `true` | Довіряти заголовкам `X-Forwarded-For` від зворотного проксі. Задайте `false`, якщо не за проксі. |
|
||||
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Яким вузлам дозволено задавати IP клієнта через `X-Forwarded-For`. Значення за замовчуванням вірить лише вузлу з приватної мережі, тож зворотному проксі в мережі Docker або в локальній мережі довіра є, а підробленому заголовку від публічного клієнта немає. Задавайте `true`, лише якщо попереду стоїть підконтрольний вам проксі з публічною адресою. |
|
||||
|
||||
### Автентифікація {#authentication}
|
||||
|
||||
Дві булеві змінні нижче приймають лише `true` і `false`. Будь-що інше, чи то `1`, `yes` чи `on`, не проходить перевірку, і сервер завершує роботу, так і не почавши слухати.
|
||||
|
||||
| Змінна | За замовчуванням | Опис |
|
||||
|---|---|---|
|
||||
| `AUTH_ENABLED` | `false` | Задайте `true`, щоб вимагати входу. Образ Docker за замовчуванням має `true`. |
|
||||
| `AUTH_ENABLED` | `true` | Вимагати вхід. Задайте `false`, щоб працювати взагалі без облікових записів: тоді будь-який запит отримує права адміністратора, тож лишайте так лише в довіреній мережі. |
|
||||
| `DEFAULT_USERNAME` | `admin` | Ім'я користувача для початкового облікового запису адміністратора. Використовується лише під час першого запуску. |
|
||||
| `DEFAULT_PASSWORD` | `admin` | Пароль для початкового облікового запису адміністратора. Змініть його після першого входу. |
|
||||
| `MAX_USERS` | `0` (необмежено) | Максимальна кількість зареєстрованих облікових записів користувачів. Задайте 0 для необмеженої кількості. |
|
||||
| `SESSION_DURATION_HOURS` | `168` | Тривалість сеансу входу в годинах (за замовчуванням 7 днів). |
|
||||
| `SKIP_MUST_CHANGE_PASSWORD` | - | Задайте будь-яке непорожнє значення, щоб обійти примусовий запит на зміну пароля під час першого входу |
|
||||
| `SKIP_MUST_CHANGE_PASSWORD` | `false` | Задайте `true`, щоб пропустити примусовий запит на зміну пароля під час першого входу. |
|
||||
|
||||
### Сховище {#storage}
|
||||
|
||||
| Змінна | За замовчуванням | Опис |
|
||||
|---|---|---|
|
||||
| `STORAGE_MODE` | `local` | `local` або `s3`. S3/MinIO вимагає ліцензії з функцією s3_storage. |
|
||||
| `DATABASE_URL` | `postgres://snapotter:snapotter@postgres:5432/snapotter` | Рядок підключення до PostgreSQL. |
|
||||
| `REDIS_URL` | `redis://redis:6379` | Рядок підключення до Redis (використовується для черг завдань BullMQ). |
|
||||
| `WORKSPACE_PATH` | `./tmp/workspace` | Каталог для тимчасових файлів під час обробки. Очищується автоматично. |
|
||||
| `FILES_STORAGE_PATH` | `./data/files` | Каталог для постійних файлів користувача (завантажені зображення, збережені результати). |
|
||||
| `STORAGE_MODE` | `local` | `local` або `s3`. S3 і MinIO потребують ліцензії з функцією s3_storage, а також змінних `S3_*` нижче. |
|
||||
| `DATABASE_URL` | `postgres://snapotter:snapotter@localhost:5432/snapotter` | Рядок підключення до PostgreSQL. Стек Compose спрямовує його на власний сервіс `postgres`; лишіть його незаданим (разом із `REDIS_URL`), щоб отримати вбудований режим. |
|
||||
| `REDIS_URL` | `redis://localhost:6379` | Рядок підключення до Redis (використовується для черг завдань BullMQ). Compose спрямовує його на власний сервіс `redis`. |
|
||||
| `WORKSPACE_PATH` | `./tmp/workspace` | Каталог для тимчасових файлів під час обробки. Очищується автоматично. Образ задає `/tmp/workspace`. |
|
||||
| `FILES_STORAGE_PATH` | `./data/files` | Каталог для постійних файлів користувача (завантажені зображення, збережені результати). Образ задає `/data/files`. |
|
||||
|
||||
### Об'єктне сховище S3 {#s3-object-storage}
|
||||
|
||||
Читається лише тоді, коли задано `STORAGE_MODE=s3`. Пропустіть будь-яку з трьох обов'язкових змінних, і запуск завершиться помилкою з назвою тієї змінної, яку ви не задали.
|
||||
|
||||
| Змінна | За замовчуванням | Опис |
|
||||
|---|---|---|
|
||||
| `S3_BUCKET` | (порожньо) | Бакет, у якому зберігаються завантаження та результати. Обов'язкова. |
|
||||
| `S3_ACCESS_KEY_ID` | (порожньо) | Ключ доступу. Обов'язкова. У контейнері його можна натомість змонтувати файлом через `S3_ACCESS_KEY_ID_FILE`. |
|
||||
| `S3_SECRET_ACCESS_KEY` | (порожньо) | Секретний ключ. Обов'язкова. Та сама домовленість щодо файлів: `S3_SECRET_ACCESS_KEY_FILE`. |
|
||||
| `S3_REGION` | `us-east-1` | Регіон бакета. |
|
||||
| `S3_ENDPOINT` | (порожньо) | Власна кінцева точка для MinIO, R2, Backblaze та інших S3-сумісних сховищ. Порожньо означає AWS. |
|
||||
| `S3_FORCE_PATH_STYLE` | `false` | Задайте `true` для MinIO та всього іншого, що очікує `endpoint/bucket/key` замість адресації за віртуальним хостом. |
|
||||
| `S3_PREFIX` | (порожньо) | Префікс ключів, щоб один бакет міг обслуговувати кілька екземплярів. |
|
||||
|
||||
### Шифрування збережених даних {#encryption-at-rest}
|
||||
|
||||
| Змінна | За замовчуванням | Опис |
|
||||
|---|---|---|
|
||||
| `DATA_ENCRYPTION_KEY` | (порожньо) | 64 шістнадцяткові символи (32 байти). Шифрує чутливі налаштування, збережені в базі даних. Будь-що, що не є 64 шістнадцятковими символами, відхиляється під час запуску. |
|
||||
| `DATA_ENCRYPTION_KEY_PREVIOUS` | (порожньо) | Ключ, від якого ви відходите під час ротації, у тому самому форматі. Задайте обидва на час ротації, щоб наявні рядки й далі розшифровувалися, а потім приберіть цей. |
|
||||
|
||||
### Вбудований режим {#embedded-mode}
|
||||
|
||||
@@ -59,16 +83,15 @@ i18n_output_hash: 498d74ca4a81
|
||||
|
||||
| Змінна | За замовчуванням | Опис |
|
||||
|---|---|---|
|
||||
| `MAX_UPLOAD_SIZE_MB` | `100` | Максимальний розмір файлу на одне завантаження в мегабайтах. Задайте 0 для необмеженого. |
|
||||
| `MAX_BATCH_SIZE` | `100` | Максимальна кількість файлів в одному пакетному запиті. Задайте 0 для необмеженого. |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `0` (необмежено) | Максимальний розмір файлу на одне завантаження в мегабайтах. Задайте 0 для необмеженого. Опублікований образ постачається зі значенням `0`; збірка з вихідного коду починає зі 100. |
|
||||
| `MAX_BATCH_SIZE` | `0` (необмежено) | Максимальна кількість файлів в одному пакетному запиті. Задайте 0 для необмеженого. Опублікований образ постачається зі значенням `0`; збірка з вихідного коду починає зі 100. |
|
||||
| `CONCURRENT_JOBS` | `0` (авто) | Кількість пакетних завдань, що виконуються паралельно. Задайте 0 для автовизначення на основі доступних ядер CPU. |
|
||||
| `MAX_MEGAPIXELS` | `0` (необмежено) | Максимальна дозволена роздільна здатність зображення в мегапікселях. Задайте 0 для необмеженого. |
|
||||
| `MAX_WORKER_THREADS` | `0` (авто) | Максимальна кількість робочих потоків для обробки зображень. Задайте 0 для автовизначення на основі доступних ядер CPU. |
|
||||
| `PROCESSING_TIMEOUT_S` | `0` (без обмеження) | Максимальний час обробки на один запит у секундах. Задайте 0 для відсутності таймауту. |
|
||||
| `MAX_PIPELINE_STEPS` | `20` | Максимальна кількість кроків у конвеєрі. Задайте 0 для відсутності обмеження. |
|
||||
| `MAX_CANVAS_PIXELS` | `0` (без обмеження) | Максимальний розмір полотна в пікселях для вихідних зображень. Задайте 0 для відсутності обмеження. |
|
||||
| `MAX_SVG_SIZE_MB` | `0` (необмежено) | Максимальний розмір файлу SVG у мегабайтах. Задайте 0 для необмеженого. |
|
||||
| `MAX_SPLIT_GRID` | `100` | Максимальний розмір сітки для інструмента розділення зображення. |
|
||||
| `MAX_SVG_SIZE_MB` | `50` | Найбільший SVG, який приймається перед очищенням, у мегабайтах. Тут `0` поводиться інакше, ніж у сусідніх рядках: він повністю знімає обмеження розміру до розбору, а не піднімає його, тож цю змінну краще лишити заданою. |
|
||||
| `MAX_PDF_PAGES` | `0` (необмежено) | Максимальна кількість сторінок PDF для конвертації PDF-у-зображення. Задайте 0 для необмеженого. |
|
||||
|
||||
### Очищення {#cleanup}
|
||||
@@ -82,7 +105,7 @@ i18n_output_hash: 498d74ca4a81
|
||||
|
||||
| Змінна | За замовчуванням | Опис |
|
||||
|---|---|---|
|
||||
| `DEFAULT_THEME` | `light` | Типова тема для нових сеансів. `light` або `dark`. |
|
||||
| `DEFAULT_THEME` | `light` | Типова тема для нових сеансів. `light`, `dark` або `system`. |
|
||||
| `DEFAULT_LOCALE` | `en` | Типова мова інтерфейсу. |
|
||||
| `DEFAULT_TOOL_VIEW` | `sidebar` | Типове компонування інструментів. `sidebar` або `fullscreen`. |
|
||||
|
||||
@@ -124,13 +147,13 @@ services:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_PASSWORD: snapotter # Змініть це для нелокальних розгортань
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Як зробити внесок у SnapOtter. Звіти про помилки, запити на функції, pull request-и та вимоги CLA."
|
||||
i18n_source_hash: 528802503035
|
||||
i18n_source_hash: 6c920a5f83e0
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 12a7eac534af
|
||||
i18n_output_hash: 624e5a689563
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Внесок {#contributing}
|
||||
@@ -53,7 +54,7 @@ i18n_output_hash: 12a7eac534af
|
||||
|
||||
### Передумови {#prerequisites}
|
||||
|
||||
- Node.js 22+
|
||||
- Node.js 22.22+
|
||||
- pnpm 9+
|
||||
- Python 3.11+ (лише для інструментів ШІ)
|
||||
- Docker (необов'язково, для повного інтеграційного тестування)
|
||||
@@ -71,7 +72,7 @@ docker compose -f docker-compose.dev.yml up -d
|
||||
# Install dependencies
|
||||
pnpm install
|
||||
|
||||
# Start dev servers (web on :1349, API on :13490)
|
||||
# Start dev servers (web on :1351, API on :13490)
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Схема бази даних PostgreSQL, таблиці, міграції та процедури резервного копіювання для SnapOtter."
|
||||
i18n_source_hash: 50d5d4f220cf
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 8b7453bf7c82
|
||||
i18n_source_hash: a68264552836
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: 5de59a4b91b6
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# База даних {#database}
|
||||
@@ -145,6 +146,17 @@ API-ключі для програмного доступу. Необробле
|
||||
| `details` | jsonb | Дані, специфічні для дії |
|
||||
| `createdAt` | timestamp | Час дії |
|
||||
|
||||
### user_preferences {#user-preferences}
|
||||
|
||||
Стан інтерфейсу для кожного користувача з ключем за назвою налаштування. Зберігає закріплені інструменти головної сторінки, які записуються через `PUT /api/v1/preferences`.
|
||||
|
||||
| Стовпець | Тип | Примітки |
|
||||
|---|---|---|
|
||||
| `userId` | text | Зовнішній ключ на users, каскадне видалення. Первинний ключ разом із `key` |
|
||||
| `key` | text | Назва налаштування. Первинний ключ разом із `userId` |
|
||||
| `value` | jsonb | Вміст налаштування |
|
||||
| `updatedAt` | timestamp | Час останнього запису |
|
||||
|
||||
## Міграції {#migrations}
|
||||
|
||||
Drizzle відповідає за міграції схеми. Файли міграцій знаходяться у `apps/api/drizzle/`. Під час розробки:
|
||||
@@ -159,27 +171,35 @@ npx drizzle-kit migrate # apply pending migrations
|
||||
|
||||
## Резервне копіювання та відновлення {#backup-and-restore}
|
||||
|
||||
Реляційна база даних знаходиться в томі `SnapOtter-pgdata` контейнера Postgres, а не в томі `/data` застосунку.
|
||||
Реляційна база даних знаходиться в томі `SnapOtter-pgdata` контейнера Postgres, а не в томі `/data` програми.
|
||||
|
||||
**Варіант 1: pg_dump (рекомендовано)**
|
||||
**Логічна резервна копія з перевіркою (рекомендовано)**
|
||||
|
||||
```bash
|
||||
# Dump the database while the stack is running
|
||||
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
|
||||
# Dump into PostgreSQL's portable custom archive format
|
||||
docker exec SnapOtter-postgres \
|
||||
pg_dump --format=custom --no-owner -U snapotter snapotter > snapotter.dump
|
||||
test -s snapotter.dump
|
||||
docker exec -i SnapOtter-postgres pg_restore --list < snapotter.dump >/dev/null
|
||||
|
||||
# Restore into a fresh database
|
||||
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
|
||||
# Restore into a fresh/disposable target first and fail on the first SQL error
|
||||
docker exec -i SnapOtter-postgres \
|
||||
pg_restore --exit-on-error --clean --if-exists --no-owner \
|
||||
-U snapotter -d snapotter < snapotter.dump
|
||||
```
|
||||
|
||||
**Варіант 2: Знімок тому**
|
||||
Цей дамп бази даних не містить збережених об’єктів бібліотеки в `/data/files` або тривалому стані BullMQ у Redis. Створюйте резервні копії та відновлюйте їх за допомогою скоординованої процедури в [Безпека та посилення](/uk/guide/security#backup-and-recovery).
|
||||
|
||||
**Знімок холодного обсягу**
|
||||
|
||||
```bash
|
||||
# Stop the stack, then snapshot the pgdata volume
|
||||
docker compose down
|
||||
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
|
||||
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
|
||||
# Stop every service first, then use your storage platform to snapshot the
|
||||
# PostgreSQL, app-data, and Redis volumes as one crash-consistent set.
|
||||
docker compose -f docker/docker-compose.yml stop
|
||||
```
|
||||
|
||||
Не копіюйте живий каталог даних PostgreSQL за допомогою `tar`. Створюйте префікси імен томів за проектом, тому вирішуйте ідентифікатори змонтованих томів із `docker inspect` або вашої платформи зберігання, а не припускайте буквальну мітку `SnapOtter-pgdata`.
|
||||
|
||||
### Міграція з 1.x (SQLite) {#migrating-from-1-x-sqlite}
|
||||
|
||||
Оновлення з SnapOtter 1.x має власний посібник: див. [Оновлення з 1.x до 2.0](./upgrading). Коротко: повторно використайте свій наявний том `/data`, і 2.0 автоматично виявить та імпортує `/data/snapotter.db` під час першого запуску (або встановіть `SQLITE_MIGRATE_PATH`, щоб явно вказати на нього). Спершу зробіть резервну копію всього тому `/data`, а не лише `snapotter.db`: 1.x використовує режим SQLite WAL, тож зупинений контейнер часто залишає більшість своїх даних у `snapotter.db-wal` поруч із майже порожнім `snapotter.db`.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Розгорніть SnapOtter у продакшені за допомогою Docker. Вимоги до апаратного забезпечення, налаштування GPU та конфігурації зворотного проксі для Nginx, Traefik і Cloudflare."
|
||||
i18n_output_hash: 4d221e5eaf97
|
||||
i18n_source_hash: 98172965118b
|
||||
i18n_source_hash: 2a722f86da75
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: a466f9f8a47f
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Розгортання {#deployment}
|
||||
@@ -47,7 +48,7 @@ services:
|
||||
# - MAX_USERS=0 # Max user accounts
|
||||
|
||||
# --- Networking ---
|
||||
# - TRUST_PROXY=true # Trust X-Forwarded-For headers (set false if not behind a proxy)
|
||||
# - TRUST_PROXY=loopback,linklocal,uniquelocal # Which peers may set the client IP via X-Forwarded-For (default shown)
|
||||
|
||||
# --- Bind mount permissions ---
|
||||
# - PUID=1000 # Match your host user's UID (run: id -u)
|
||||
@@ -82,7 +83,7 @@ services:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
@@ -170,13 +171,13 @@ services:
|
||||
container_name: SnapOtter-postgres
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_PASSWORD: snapotter # Змініть це для нелокальних розгортань
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
@@ -207,13 +208,17 @@ volumes:
|
||||
docker compose -f docker-compose-gpu.yml up -d
|
||||
```
|
||||
|
||||
Перевірте виявлення CUDA у логах:
|
||||
### Перевірте прискорення GPU {#verify-gpu-acceleration}
|
||||
|
||||
Перевірте виявлення CUDA в журналах:
|
||||
|
||||
```bash
|
||||
docker logs SnapOtter 2>&1 | head -20
|
||||
# Look for: [gpu] CUDA available via torch
|
||||
```
|
||||
|
||||
Якщо інструменти штучного інтелекту працюють на ЦП, навіть якщо `--gpus all` і NVIDIA Container Toolkit налаштовано правильно, переінсталюйте відповідний комплект (наприклад, Background Removal) із **Налаштування → Функції штучного інтелекту**. Інсталятор відновлює збірку графічного процесора ONNX Runtime, яку збірка лише для центрального процесора, залучена іншим пакетом (наприклад, транскрипцією), інакше може затіняти в спільному середовищі ШІ. Якщо перевстановлення з інтерфейсу користувача не відновлює GPU на старішому образі, перегляньте посібник із відновлення в [випуск №490](https://github.com/snapotter-hq/SnapOtter/issues/490).
|
||||
|
||||
## Вимоги до апаратного забезпечення {#hardware-requirements}
|
||||
|
||||
Ці цифри отримані з бенчмарків на низці систем, від сучасної робочої станції amd64 з NVIDIA RTX 4070 до Raspberry Pi, на яких запускали весь каталог інструментів і перебирали ліміти ресурсів Docker, щоб знайти реальний мінімум.
|
||||
@@ -436,11 +441,11 @@ securityContext:
|
||||
| `AUTH_ENABLED` | `true` | Увімкнути/вимкнути вимогу входу |
|
||||
| `DEFAULT_USERNAME` | `admin` | Початкове ім'я адміністратора |
|
||||
| `DEFAULT_PASSWORD` | `admin` | Початковий пароль адміністратора (примусова зміна при першому вході) |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `100` | Ліміт завантаження на файл |
|
||||
| `MAX_BATCH_SIZE` | `100` | Максимум файлів на пакетний запит |
|
||||
| `MAX_UPLOAD_SIZE_MB` | `0` (необмежено) | Ліміт завантаження на файл у МБ. Образ постачається зі значенням `0`; збірка з вихідного коду стартує зі 100 |
|
||||
| `MAX_BATCH_SIZE` | `0` (необмежено) | Максимум файлів на пакетний запит. Образ постачається зі значенням `0`; збірка з вихідного коду стартує зі 100 |
|
||||
| `RATE_LIMIT_PER_MIN` | `1000` | Запити API за хвилину на IP (встановіть 0, щоб вимкнути) |
|
||||
| `MAX_USERS` | `0` (необмежено) | Максимальна кількість облікових записів користувачів |
|
||||
| `TRUST_PROXY` | `true` | Довіряти заголовкам X-Forwarded-For від зворотного проксі |
|
||||
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Яким вузлам дозволено задавати IP клієнта через `X-Forwarded-For`. Типово лише приватні мережі |
|
||||
| `PUID` | `999` | Запускати з цим UID (для прав bind mount) |
|
||||
| `PGID` | `999` | Запускати з цим GID (для прав bind mount) |
|
||||
| `LOG_LEVEL` | `info` | Рівень деталізації логів: fatal, error, warn, info, debug, trace |
|
||||
@@ -483,7 +488,13 @@ curl http://localhost:1349/api/v1/health
|
||||
|
||||
## Зворотний проксі {#reverse-proxy}
|
||||
|
||||
SnapOtter встановлює `TRUST_PROXY=true` за замовчуванням, тож обмеження швидкості й логування використовують реальний IP клієнта із заголовків `X-Forwarded-For`.
|
||||
Типово `TRUST_PROXY` має значення `loopback,linklocal,uniquelocal`, тож SnapOtter вірить заголовку `X-Forwarded-For` лише від вузла з приватної мережі. Зворотному проксі на тому самому хості, у мережі Docker або у вашій локальній мережі довіра є одразу, а отже обмеження швидкості, захист входу від перебору паролів, журнал аудиту та список дозволених IP в enterprise-версії бачать справжній IP клієнта без жодного налаштування.
|
||||
|
||||
Задавайте `TRUST_PROXY=true` лише тоді, коли проксі попереду звертається до SnapOtter з **публічної** адреси, наприклад хмарний балансувальник навантаження в іншій мережі. На безпосередньо відкритому екземплярі це значення віддає `request.ip` під контроль зловмисника: той, хто змінює заголовок, отримує свіжий лічильник обмеження швидкості на кожен запит.
|
||||
|
||||
Дві речі варто знати, перш ніж вимірювати IP клієнтів. Docker Desktop на macOS і Windows обслуговує опублікований порт через проксі в просторі користувача, який переписує будь-яку адресу джерела на шлюз віртуальної машини `192.168.65.1`, тож там жодне значення `TRUST_PROXY` не поверне справжнього клієнта; усе, що дивиться в інтернет, розгортайте на Linux. І на будь-якій платформі звернення до опублікованого порту через `localhost` бачиться як шлюз мосту, а не як ваш клієнт, тому перевірка через localhost нічого не каже про те, як визначається справжній клієнт. Повну таблицю значень `TRUST_PROXY` та застереження щодо Docker Desktop наведено в [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md#client-ip-resolution-trust_proxy).
|
||||
|
||||
Дві речі важливі для кожного проксі нижче: дозволити великі тіла запитів (завантаження) і не буферизувати відповіді. Проксі-сервер із буферизацією відповідей порушує прогрес SSE і, що більш помітно, робить завантаження великого файлу «початком, але ніколи не завершенням», оскільки проксі-сервер зберігає весь файл перед його передачею. SnapOtter надсилає `X-Accel-Buffering: no` під час завантажень, тому nginx транслює їх, навіть якщо буферизація залишилася в іншому місці, але проксі, крім nginx, потребують явного вимкнення буферизації відповіді (показано в кожній конфігурації нижче). Якщо завантаження частково зупиняється, перше, що потрібно перевірити — буферизаційний проксі-сервер.
|
||||
|
||||
### Nginx {#nginx}
|
||||
|
||||
@@ -505,7 +516,7 @@ server {
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
|
||||
# SSE support (batch progress, feature install progress)
|
||||
# Потокові відповіді замість буферизації: необхідні для прогресу SSE (пакети, штучний інтелект, встановлення функцій) і для завантаження великих файлів.
|
||||
proxy_buffering off;
|
||||
proxy_read_timeout 300s;
|
||||
}
|
||||
@@ -549,7 +560,7 @@ images.example.com {
|
||||
}
|
||||
```
|
||||
|
||||
`flush_interval -1` вимикає буферизацію відповідей, що потрібно для подій прогресу SSE (пакетна обробка, AI-інструменти, встановлення функцій). Продовжені таймаути дозволяють завершити завантаження великих файлів без того, щоб Caddy передчасно закривав з'єднання.
|
||||
`flush_interval -1` вимикає буферизацію відповіді, необхідну для подій прогресу SSE (пакетна обробка, інструменти штучного інтелекту, встановлення функцій) і для потокового передавання великих файлів замість зупинки. Розширені тайм-аути дозволяють завершити завантаження великих файлів без передчасного закриття з’єднання Caddy.
|
||||
|
||||
### Cloudflare Tunnels {#cloudflare-tunnels}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Локальне налаштування розробки, команди, конвенції коду та як додати новий інструмент до SnapOtter."
|
||||
i18n_source_hash: cb03724d2829
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 4a74c237b20d
|
||||
i18n_source_hash: 56acc1bf9a9b
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: 7be8e7403bd6
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Посібник для розробників {#developer-guide}
|
||||
@@ -11,12 +12,12 @@ i18n_output_hash: 4a74c237b20d
|
||||
|
||||
## Передумови {#prerequisites}
|
||||
|
||||
- [Node.js](https://nodejs.org/) 22+
|
||||
- [Node.js](https://nodejs.org/) 22.22+
|
||||
- [pnpm](https://pnpm.io/) 9+ (`corepack enable && corepack prepare pnpm@latest --activate`)
|
||||
- [Docker](https://www.docker.com/) (потрібен для локальних Postgres + Redis, збірок контейнерів та функцій ШІ)
|
||||
- Git
|
||||
|
||||
Python 3.10+ потрібен лише якщо ви працюєте над сайдкаром ШІ/ML (видалення фону, апскейлінг, OCR).
|
||||
Python 3.11+ потрібен лише якщо ви працюєте над сайдкаром ШІ/ML (видалення фону, апскейлінг, OCR).
|
||||
|
||||
## Налаштування {#setup}
|
||||
|
||||
@@ -32,10 +33,10 @@ pnpm dev
|
||||
|
||||
| Сервіс | URL | Примітки |
|
||||
|----------|--------------------------|------------------------------------|
|
||||
| Фронтенд | http://localhost:1349 | Сервер розробки Vite, проксіює /api |
|
||||
| Фронтенд | http://localhost:1351 | Сервер розробки Vite, проксіює /api |
|
||||
| Бекенд | http://localhost:13490 | Fastify API (доступ через проксі) |
|
||||
|
||||
Відкрийте http://localhost:1349 у вашому браузері. Увійдіть з `admin` / `admin`. Вам буде запропоновано змінити пароль під час першого входу.
|
||||
Відкрийте http://localhost:1351 у вашому браузері. Увійдіть з `admin` / `admin`. Вам буде запропоновано змінити пароль під час першого входу.
|
||||
|
||||
## Структура проєкту {#project-structure}
|
||||
|
||||
@@ -220,6 +221,17 @@ docker build -f docker/Dockerfile -t snapotter:latest .
|
||||
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest .
|
||||
```
|
||||
|
||||
## Домени версій випуску {#release-version-domains}
|
||||
|
||||
SnapOtter навмисно має три домени версій. Не копіюйте один домен в інший під час випуску:
|
||||
|
||||
- Версія випуску програми охоплює кореневий маніфест, усі пакети приватної робочої області та `APP_VERSION`. Semantic-release надає це значення, а `pnpm version:sync <version>` оновлює кожну робочу область перед випуском програми.
|
||||
- OpenAPI `info.version` — це стабільний публічний великий контракт API. Усі локалізовані специфікації залишаються на `<major>.0.0` для випусків сумісних програм і змінюються лише тоді, коли контракт API переходить на нову основну версію.
|
||||
- `docker/feature-manifest.json` зберігає `imageVersion: 2.0.0` як незмінну епоху зберігання наборів функцій. Ці шляхи архіву v2 не є версіями пакетів програм. Точне оптичне розпізнавання символів використовує формат виконання версії 3 і окремо записує походження випуску програми.
|
||||
|
||||
`tests/unit/infra/release-version-policy.test.ts` забезпечує дотримання цих меж. Домен нової версії або міграція повинні разом оновити цей контракт і відповідний дизайн міграції артефакту.
|
||||
Незалежні значення API і застарілого пакета знаходяться в `config/release-version-policy.json`; синхронізація версії програми ніколи не повинна неявно переписувати цей файл політики.
|
||||
|
||||
## Змінні середовища {#environment-variables}
|
||||
|
||||
Повний список дивіться у [Посібнику з конфігурації](/uk/guide/configuration). Ключові для розробки:
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Теги Docker-образу SnapOtter, тести продуктивності GPU, закріплення версій і мультиплатформна підтримка для AMD64 та ARM64."
|
||||
i18n_output_hash: 8d481651c9cb
|
||||
i18n_source_hash: fda322e78b4b
|
||||
i18n_source_hash: 566e20ca07fc
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: b3d630e0aebf
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Docker-образ {#docker-image}
|
||||
@@ -93,13 +94,13 @@ services:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_PASSWORD: snapotter # Змініть це для нелокальних розгортань
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter -d snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
@@ -140,9 +141,9 @@ volumes:
|
||||
| Тег | Опис |
|
||||
|-----|------------|
|
||||
| `latest` | Останній випуск |
|
||||
| `1.11.0` | Точна версія |
|
||||
| `1.11` | Останній патч у 1.11.x |
|
||||
| `1` | Останній мінорний у 1.x |
|
||||
| `2.1.0` | Точна версія |
|
||||
| `2.1` | Останній патч у 2.1.x |
|
||||
| `2` | Останній мінорний у 2.x |
|
||||
|
||||
## Платформи {#platforms}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Встановіть SnapOtter за допомогою Docker однією командою. Включає налаштування Docker Compose, збирання з вихідного коду й повний огляд функцій."
|
||||
i18n_output_hash: a97c15d102b5
|
||||
i18n_source_hash: 68bf7f60b68d
|
||||
i18n_provenance: human
|
||||
i18n_source_hash: 8040133a6982
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: 5859f9d6859f
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Початок роботи {#getting-started}
|
||||
@@ -17,7 +18,7 @@ i18n_provenance: human
|
||||
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
Цей єдиний контейнер запускає все, що йому потрібно: без встановленого `DATABASE_URL` він запускає власні PostgreSQL і Redis на інтерфейсі loopback (вбудований режим) і зберігає всі дані в томі `SnapOtter-data`. Це найшвидший спосіб спробувати SnapOtter або самостійно розмістити його в homelab. Для продакшену запустіть стек [Docker Compose](#docker-compose) нижче, який тримає PostgreSQL і Redis у власних контейнерах. Вбудований режим працює від root (за замовчуванням) і автоматично вимикається, щойно ви встановлюєте `DATABASE_URL`.
|
||||
Цей єдиний контейнер запускає все, що йому потрібно: без встановлення `DATABASE_URL` він запускає власний PostgreSQL і Redis на інтерфейсі петлі (вбудований режим) і зберігає всі дані в тому `SnapOtter-data`. Це найшвидший спосіб спробувати SnapOtter або самостійне розміщення в домашній лабораторії. Для виробництва використовуйте [канонічний стек Docker Compose](#docker-compose), який зберігає PostgreSQL і Redis у власних контейнерах. Вбудований режим працює як root (за замовчуванням) і вимикається автоматично, щойно ви встановите `DATABASE_URL`.
|
||||
|
||||
Встановлюєте на Raspberry Pi, старому ноутбуці чи невеликому VPS? Див. [Робота на слабкому обладнанні](/uk/guide/low-resource): там є покроковий посібник із підібраними налаштуваннями й пояснення, чого очікувати від обмеженого обладнання.
|
||||
|
||||
@@ -40,7 +41,7 @@ SnapOtter містить анонімну продуктову аналітик
|
||||
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest
|
||||
```
|
||||
|
||||
Потребує [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Автоматично переходить на CPU, коли CUDA недоступний. Прискорення на iGPU Intel/AMD через VA-API, Quick Sync або OpenCL наразі не підтримується для AI-інференсу. Див. [Docker Tags](/uk/guide/docker-tags) щодо бенчмарків.
|
||||
Потрібен [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Автоматично повертається до ЦП, коли CUDA недоступна. Прискорення Intel/AMD iGPU через VA-API, Quick Sync або OpenCL на сьогодні не підтримується для висновків ШІ. Див. [Теги Docker](/uk/guide/docker-tags) для тестів. Якщо інструменти штучного інтелекту працюють на ЦП, незважаючи на `--gpus all`, див. [Перевірте прискорення GPU](/uk/guide/deployment#verify-gpu-acceleration).
|
||||
:::
|
||||
|
||||
::: details Також на GHCR
|
||||
@@ -53,65 +54,31 @@ docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snap
|
||||
|
||||
## Docker Compose {#docker-compose}
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest # or ghcr.io/snapotter-hq/snapotter:latest
|
||||
ports:
|
||||
- "1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_USERNAME=admin
|
||||
- DEFAULT_PASSWORD=admin
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
Використовуйте робочий файл, який підтримується та перевіряється з кожним випуском, замість копіювання скороченого прикладу Compose із цієї сторінки:
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
```bash
|
||||
install -d -m 700 snapotter && cd snapotter
|
||||
curl --proto '=https' --tlsv1.2 -fsSLo docker-compose.yml \
|
||||
https://raw.githubusercontent.com/snapotter-hq/SnapOtter/v2.1.0/docker/docker-compose.yml
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
# Keep generated service credentials out of shell history and world-readable files.
|
||||
umask 077
|
||||
POSTGRES_PASSWORD="$(openssl rand -hex 32)"
|
||||
REDIS_PASSWORD="$(openssl rand -hex 32)"
|
||||
printf 'POSTGRES_PASSWORD=%s\nREDIS_PASSWORD=%s\n' \
|
||||
"$POSTGRES_PASSWORD" "$REDIS_PASSWORD" > .env
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
docker compose -f docker-compose.yml pull
|
||||
docker compose -f docker-compose.yml up -d --no-build
|
||||
```
|
||||
|
||||
Див. [Конфігурація](/uk/guide/configuration) щодо всіх змінних середовища.
|
||||
Канонічний [`docker/docker-compose.yml`](https://github.com/snapotter-hq/SnapOtter/blob/v2.1.0/docker/docker-compose.yml) включає всі чотири томи часу виконання, перевірки працездатності, обмеження ресурсів, надійну конфігурацію Redis, закріплені зображення бази даних/кешу та поточний захист контейнера. Змініть стандартний пароль адміністратора одразу після першого входу. Для відтворюваного розгортання прикріпіть зображення програми SnapOtter до тегу випуску або перевіреного дайджесту замість `latest`.
|
||||
|
||||
Перегляньте [Конфігурація](/uk/guide/configuration) для всіх змінних середовища та [Безпека та зміцнення](/uk/guide/security) для секретів, мережевої політики та вказівок щодо резервного копіювання.
|
||||
|
||||
## Збирання з вихідного коду {#build-from-source}
|
||||
|
||||
**Передумови:** Node.js 22+, pnpm 9+, Docker (для Postgres + Redis), Python 3.10+ (для функцій AI), Git.
|
||||
**Передумови:** Node.js 22.22+, pnpm 9+, Docker (для Postgres + Redis), Python 3.11+ (для функцій AI), Git.
|
||||
|
||||
```bash
|
||||
git clone https://github.com/snapotter-hq/SnapOtter.git
|
||||
@@ -121,7 +88,7 @@ pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
- Фронтенд: [http://localhost:1349](http://localhost:1349)
|
||||
- Фронтенд: [http://localhost:1351](http://localhost:1351)
|
||||
- Бекенд: [http://localhost:13490](http://localhost:13490)
|
||||
|
||||
## Що ви можете робити {#what-you-can-do}
|
||||
@@ -130,11 +97,11 @@ pnpm dev
|
||||
|
||||
| Модальність | Кількість | Приклади інструментів |
|
||||
|----------|-------|---------------|
|
||||
| **Зображення** | 105 | Зміна розміру, Обрізання, Стиснення, Конвертація, Видалення фону, Upscale, OCR, Водяний знак, Колаж, Colorize, Інструменти GIF, пресети форматів |
|
||||
| **Зображення** | 107 | Зміна розміру, Обрізання, Стиснення, Конвертація, Видалення фону, Upscale, OCR, Водяний знак, Колаж, Colorize, Інструменти GIF, пресети форматів |
|
||||
| **Відео** | 57 | Обрізання, Обрізання за краями, Стиснення, Конвертація, Об'єднання, Витягнення аудіо, Автосубтитри, Відео у GIF, Зміна розміру, Стабілізація, пресети форматів |
|
||||
| **Аудіо** | 27 | Обрізання, Об'єднання, Конвертація, Нормалізація, Зменшення шуму, Транскрипція, Зсув висоти тону, Затухання, Створення рингтонів, пресети форматів |
|
||||
| **PDF / Документ** | 42 | Об'єднання, Розділення, Стиснення, OCR, Водяний знак, Редагування (redact), Word у PDF, Excel у PDF, Обертання, Захист, Відновлення |
|
||||
| **Файли** | 10 | CSV у JSON, JSON у XML, Об'єднання CSV, Розділення CSV, Створення ZIP, Витягнення ZIP, Створення діаграм, YAML/JSON |
|
||||
| **PDF / Документ** | 29 | Об'єднання, Розділення, Стиснення, OCR, Водяний знак, Редагування (redact), Word у PDF, Excel у PDF, Обертання, Захист, Відновлення |
|
||||
| **Файли** | 23 | CSV у JSON, JSON у XML, Об'єднання CSV, Розділення CSV, Створення ZIP, Витягнення ZIP, Створення діаграм, YAML/JSON |
|
||||
|
||||
### Конвеєри {#pipelines}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
---
|
||||
i18n_source_hash: f5de74aee1b9
|
||||
i18n_source_hash: 521c03a6416c
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: 27b701493717
|
||||
i18n_output_hash: e8532c6c8a52
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
# Робота на слабкому обладнанні {#low-resource-setups}
|
||||
|
||||
@@ -59,7 +60,7 @@ services:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=snapotter
|
||||
- POSTGRES_PASSWORD=snapotter
|
||||
- POSTGRES_PASSWORD=snapotter # Змініть це для нелокальних розгортань
|
||||
- POSTGRES_DB=snapotter
|
||||
volumes:
|
||||
- ./postgres-data:/var/lib/postgresql/data
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Налаштуйте провізіонінг SCIM 2.0 для синхронізації користувачів і груп з вашого постачальника ідентифікації до SnapOtter. Охоплює Okta, Azure AD / Entra ID та власні інтеграції."
|
||||
i18n_source_hash: bbd50119ec12
|
||||
i18n_source_hash: 06ee702b386e
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 8b95a7ec2ac6
|
||||
i18n_output_hash: 40fd5043d957
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Провізіонінг SCIM {#scim-provisioning}
|
||||
@@ -17,7 +18,7 @@ SnapOtter реалізує SCIM 2.0 (System for Cross-domain Identity Management
|
||||
|
||||
- Запущений екземпляр SnapOtter, доступний за публічним URL
|
||||
- Ключ ліцензії enterprise з функцією `scim`
|
||||
- Доступ адміністратора до SnapOtter (для створення чи відкликання токена SCIM потрібен дозвіл `users:manage`)
|
||||
- Вбудований обліковий запис SnapOtter `admin` із повним ефективним набором дозволів. Делегована спеціальна роль або ключ API адміністратора, у якому відсутні будь-які дозволи адміністратора, не можуть створити або відкликати глобальний маркер SCIM.
|
||||
- Доступ адміністратора до налаштувань провізіонінгу вашого постачальника ідентифікації
|
||||
|
||||
## Швидкий старт {#quick-start}
|
||||
@@ -34,7 +35,7 @@ curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "a1b2c3d4e5f6...",
|
||||
"token": "so_scim_v2_a1b2c3d4e5f6...",
|
||||
"message": "Save this token - it cannot be retrieved again"
|
||||
}
|
||||
```
|
||||
@@ -49,15 +50,19 @@ curl -X POST https://photos.example.com/api/v1/enterprise/scim/token \
|
||||
|
||||
### Створення токена {#generating-a-token}
|
||||
|
||||
`POST /api/v1/enterprise/scim/token` створює новий токен SCIM. Ця кінцева точка потребує дійсної сесії з дозволом `users:manage`.
|
||||
`POST /api/v1/enterprise/scim/token` генерує новий маркер SCIM. Оскільки маркер може надавати та змінювати користувачів у примірнику, для цієї кінцевої точки потрібна вбудована роль `admin` із повним ефективним набором дозволів адміністратора. Утримання `users:manage` у спеціальній ролі недостатньо.
|
||||
|
||||
Токен повертається у відкритому вигляді рівно один раз. SnapOtter зберігає лише хеш scrypt. Якщо ви втратите токен, відкличте його та створіть новий.
|
||||
|
||||
Одночасно активний лише один токен SCIM. Створення нового токена замінює попередній.
|
||||
|
||||
::: warning Перевипуск токена після оновлення
|
||||
Застарілі неверсійовані маркери SCIM відхилено. Після оновлення до випуску, який видає токени `so_scim_v2_...`, згенеруйте новий токен і оновіть постачальника ідентифікаційної інформації, перш ніж відновити надання.
|
||||
:::
|
||||
|
||||
### Відкликання токена {#revoking-a-token}
|
||||
|
||||
`DELETE /api/v1/enterprise/scim/token` відкликає поточний токен SCIM. Ця кінцева точка також потребує `users:manage`.
|
||||
`DELETE /api/v1/enterprise/scim/token` скасовує поточний маркер SCIM. Він має ті ж повні вбудовані вимоги адміністратора, що й генерація маркерів.
|
||||
|
||||
### Обмеження частоти запитів {#rate-limiting}
|
||||
|
||||
@@ -279,7 +284,7 @@ Azure провізіонує користувачів і групи за фік
|
||||
|
||||
### 401 "Invalid token" {#_401-invalid-token}
|
||||
|
||||
Токен не відповідає збереженому хешу. Це трапляється, якщо токен було відкликано та створено заново. Оновіть токен у налаштуваннях провізіонінгу свого IdP.
|
||||
Маркер має неправильний формат, використовує вилучений неверсійний формат або не відповідає збереженому хешу. Згенеруйте поточний маркер `so_scim_v2_...` і оновіть його в налаштуваннях ініціалізації IdP.
|
||||
|
||||
### 401 "SCIM not configured" {#_401-scim-not-configured}
|
||||
|
||||
|
||||
+88
-157
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Посібник із посилення безпеки для SnapOtter. Безпека контейнерів, мережева ізоляція, секрети Docker, розгортання в Kubernetes та артефакти відповідності."
|
||||
i18n_source_hash: 986f7658430c
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 6b9158af7666
|
||||
i18n_source_hash: 9ff337fa0417
|
||||
i18n_provenance: machine
|
||||
i18n_output_hash: 09a77c679598
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Безпека та посилення {#security-hardening}
|
||||
@@ -11,133 +12,45 @@ SnapOtter обробляє файли повністю на вашій інфр
|
||||
|
||||
Контейнер працює від імені виділеного не-root користувача (`snapotter`) з усіма скиненими можливостями Linux, окрім мінімального необхідного набору. Щодо повної політики розкриття вразливостей і архітектури безпеки див. [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) на GitHub.
|
||||
|
||||
## Посилення контейнера {#container-hardening}
|
||||
## Зміцнення контейнера {#container-hardening}
|
||||
|
||||
[Стандартний docker-compose.yml](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) містить посилення безпеки для продакшену. Ось розбір кожного параметра й чому він важливий:
|
||||
Канонічні файли Compose [CPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) і [GPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose-gpu.yml) є джерелом правди. Не копіюйте скорочений приклад у виробництво; розгорнути файл із тегу випуску, який ви перевірили.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
SnapOtter:
|
||||
image: snapotter/snapotter:latest
|
||||
ports:
|
||||
# Bind to localhost only for internet-facing deployments:
|
||||
- "127.0.0.1:1349:1349"
|
||||
volumes:
|
||||
- SnapOtter-data:/data
|
||||
- SnapOtter-workspace:/tmp/workspace
|
||||
environment:
|
||||
- AUTH_ENABLED=true
|
||||
- DEFAULT_PASSWORD=change-me-immediately
|
||||
- RATE_LIMIT_PER_MIN=1000
|
||||
- DATABASE_URL=postgres://snapotter:snapotter@postgres:5432/snapotter
|
||||
- REDIS_URL=redis://redis:6379
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
Обидва стеки застосовують такі елементи керування:
|
||||
|
||||
# --- Resource limits ---
|
||||
mem_limit: 6g # Prevents runaway memory from crashing the host
|
||||
memswap_limit: 6g # No swap - fail fast instead of degrading the host
|
||||
cpus: 4 # Cap CPU usage to 4 cores
|
||||
pids_limit: 512 # Prevents fork bombs
|
||||
- Обмеження пам'яті, підкачки, процесора та PID містять нестандартну власну обробку.
|
||||
- Кожна служба втрачає всі можливості Linux. Додаток додає лише `CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER, KILL` для володіння томом, одностороннє видалення ідентифікаційної інформації `gosu` і витончене пересилання сигналу. PostgreSQL і Redis отримують лише ту підмножину, яку потребують їхні офіційні точки входу.
|
||||
|
||||
# --- Capability restrictions ---
|
||||
cap_drop:
|
||||
- ALL # Drop ALL Linux capabilities first
|
||||
cap_add:
|
||||
- CHOWN # Needed for volume permission setup
|
||||
- SETUID # Needed for gosu privilege drop (root -> snapotter)
|
||||
- SETGID # Needed for gosu privilege drop
|
||||
- DAC_OVERRIDE # Needed for volume permission setup
|
||||
- FOWNER # Needed for volume permission setup
|
||||
— `security_opt: [no-new-privileges:true]` не дозволяє процесам у контейнерах програми, PostgreSQL і Redis отримати додаткові привілеї. Це залишається сумісним із `gosu`: точка входу починається від імені root, готує томи та передається лише виділеному користувачеві `snapotter`.
|
||||
|
||||
# --- Logging ---
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "50m" # Rotate logs at 50 MB
|
||||
max-file: "5" # Keep 5 rotated log files
|
||||
— Вхідні дані зображень PostgreSQL і Redis закріплені дайджестом. Програму також слід прикріпити до тегу перевіреного випуску або дайджесту, а не до `latest`.
|
||||
|
||||
# --- Health check ---
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "--max-time", "5", "http://localhost:1349/api/v1/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 60s
|
||||
retries: 3
|
||||
— Перевірки працездатності, обмежена ротація журналів JSON, надійний Redis AOF і політика перезапуску визначаються централізовано в канонічних файлах.
|
||||
|
||||
shm_size: "2gb" # Required for Python ML shared memory
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
image: postgres:17-alpine
|
||||
environment:
|
||||
POSTGRES_USER: snapotter
|
||||
POSTGRES_PASSWORD: snapotter
|
||||
POSTGRES_DB: snapotter
|
||||
volumes:
|
||||
- SnapOtter-pgdata:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U snapotter"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 15s
|
||||
|
||||
redis:
|
||||
image: redis:8-alpine
|
||||
command: ["redis-server", "--maxmemory-policy", "noeviction", "--appendonly", "yes"]
|
||||
volumes:
|
||||
- SnapOtter-redisdata:/data
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 12
|
||||
start_period: 10s
|
||||
|
||||
volumes:
|
||||
SnapOtter-data:
|
||||
SnapOtter-workspace:
|
||||
SnapOtter-pgdata:
|
||||
SnapOtter-redisdata:
|
||||
```
|
||||
|
||||
### Чому `no-new-privileges` не встановлено {#why-no-new-privileges-is-not-set}
|
||||
|
||||
`security_opt: [no-new-privileges:true]` навмисно пропущено. Точка входу стартує від root, щоб виправити власника томів, потім скидається до користувача `snapotter` через [gosu](https://github.com/tianon/gosu), що потребує setuid. Щойно скидання привілеїв завершується, процес працює від імені `snapotter` з усіма можливостями, окрім п'яти перелічених вище, видаленими.
|
||||
|
||||
Якщо ви використовуєте Kubernetes або прапорець `--user` Docker для запуску безпосередньо від імені не-root (в обхід gosu), `no-new-privileges` безпечно вмикати.
|
||||
Для розгортання з підключенням до Інтернету прив’яжіть порт 1349 до loopback і завершіть TLS на підтримуваному зворотному проксі-сервері. Створюйте унікальні облікові дані PostgreSQL і Redis, зберігайте секрети в захищених файлах або в менеджері секретів і негайно змінюйте початковий пароль адміністратора.
|
||||
|
||||
### Чому `read_only` не встановлено {#why-read-only-is-not-set}
|
||||
|
||||
`read_only: true` не встановлено, оскільки перепризначення PUID/PGID записує в `/etc/passwd` і `/etc/group` під час запуску. Якщо ви використовуєте прапорець `--user` Docker або `runAsUser` Kubernetes замість PUID/PGID, ви можете безпечно увімкнути кореневу файлову систему тільки для читання.
|
||||
`read_only: true` не встановлено, оскільки перевідповідання PUID/PGID записує в `/etc/passwd` і `/etc/group` під час запуску. Якщо ви використовуєте прапор Docker `--user` або Kubernetes `runAsUser` замість PUID/PGID, ви можете безпечно ввімкнути кореневу файлову систему лише для читання.
|
||||
|
||||
## Мережева ізоляція {#network-isolation}
|
||||
## Ізоляція мережі {#network-isolation}
|
||||
|
||||
Під час звичайної роботи контейнер робить **нуль вихідних мережевих з'єднань**. Уся обробка файлів відбувається локально з використанням вбудованих бібліотек.
|
||||
Обробка файлів є локальною, але інсталяція за замовчуванням **не є системою без виходу**. Анонімна аналітика продуктів використовує PostHog, а звіти про збої використовують Sentry, якщо ввімкнено телеметрію. Встановіть `SNAPOTTER_TELEMETRY=0` (або вимкніть аналітику в меню «Налаштування» > «Система» > «Конфіденційність»), щоб вимкнути обидва параметри. SnapOtter ніколи не включає в ці події завантажені файли, імена файлів, вихід OCR, текст документа чи інший вміст файлу.
|
||||
|
||||
```
|
||||
Browser --> Reverse Proxy (TLS) --> SnapOtter container --> (nothing)
|
||||
```
|
||||
Інший вихідний трафік керується функціями: інсталяція комплекту/моделі штучного інтелекту завантажує підписані вхідні дані випуску; Імпорт URL-адреси отримує загальнодоступну URL-адресу, яку запитує користувач; і явно налаштовані OIDC, SAML, OpenTelemetry, веб-хуки, S3-сумісне сховище або подібні інтеграції зв’язуються з пунктами призначення, вибраними адміністратором. Завантаження моделей під час виконання за замовчуванням вимкнено. Установіть `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=1` лише для явного ввімкнення автоматичних резервних завантажень. [Офлайн-пакет імпорту](/uk/guide/deployment) може надавати функції AI без виходу моделі середовища виконання.
|
||||
|
||||
Єдиний виняток — це **завантаження моделей AI**: коли користувач встановлює бандл функцій AI через UI, контейнер завантажує заздалегідь зібраний архів бандла з Hugging Face, плюс кілька окремих файлів моделей із GitHub Releases, Google Storage і PyPI. Ці завантаження відбуваються один раз на бандл і зберігаються в томі `/data`.
|
||||
**Рекомендації щодо брандмауера:**
|
||||
|
||||
**Рекомендації щодо фаєрволу:**
|
||||
|
||||
| Сценарій | Правило для вихідного трафіку |
|
||||
|Сценарій|Вихідне правило|
|
||||
|---|---|
|
||||
| Ізольований (без AI) | Заблокувати весь вихідний трафік від контейнера |
|
||||
| Потрібні бандли AI | Дозволити HTTPS до `huggingface.co`, `*.xethub.hf.co`, `cdn-lfs.huggingface.co`, `github.com`, `objects.githubusercontent.com`, `storage.googleapis.com`, `pypi.org`, `files.pythonhosted.org` під час встановлення, потім заблокувати |
|
||||
| Після встановлення AI | Заблокувати весь вихідний трафік — моделі кешуються локально |
|
||||
|З повітряним проміжком|Встановіть `SNAPOTTER_TELEMETRY=0` і `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=0`, використовуйте офлайн-імпорт пакетів AI, вимкніть імпорт URL-адрес і зовнішню інтеграцію, а потім заблокуйте вихід|
|
||||
|Телеметрія за замовчуванням|Дозволити кінцеві точки PostHog і Sentry, указані в журналах вашого браузера/мережі; вимкнути телеметрію, якщо політика не дозволяє їх|
|
||||
|Потрібні пакети AI|Під час встановлення дозвольте HTTPS до `huggingface.co, *.xethub.hf.co, cdn-lfs.huggingface.co, github.com, objects.githubusercontent.com, storage.googleapis.com, pypi.org, files.pythonhosted.org`; потім заблокуйте ці хости|
|
||||
|Зовнішні інтеграції|Дозволити лише точні призначення OIDC/SAML/OTLP/webhook/object-storage, налаштовані адміністратором|
|
||||
|
||||
Архіви бандлів обслуговуються зі сховища Xet від Hugging Face, яке передає через кінцеві точки `*.xethub.hf.co` паралельно і завдяки чому завантаження багатогігабайтних бандлів швидке. Якщо ваш фаєрвол дозволяє `huggingface.co`, але блокує `*.xethub.hf.co`, встановлення все одно вдаються, але переходять на повільніше однопотокове завантаження, тож додайте хости Xet до дозволеного списку, щоб залишатися на швидкому шляху. Повністю офлайн-встановлення можуть пропустити все це й натомість використати [Імпорт офлайн-бандлів](/uk/guide/deployment).
|
||||
Архіви пакетів обслуговуються зі сховища Xet Hugging Face, яке паралельно передається через кінцеві точки `*.xethub.hf.co` і завдяки чому швидко завантажуються пакети на кілька ГБ. Якщо ваш брандмауер дозволяє `huggingface.co`, але блокує `*.xethub.hf.co`, встановлення все одно вдасться, але повернеться до повільнішого однопотокового завантаження, тому внесіть хости Xet у білий список, щоб залишатися на швидкому шляху. Повністю автономна інсталяція може пропустити все це та використовувати [Offline Bundle Import](/uk/guide/deployment).
|
||||
|
||||
Щодо конфігурації зворотного проксі (Nginx, Traefik, Caddy, Cloudflare Tunnels) див. [посібник із розгортання](/uk/guide/deployment#reverse-proxy).
|
||||
Для конфігурації зворотного проксі (Nginx, Traefik, Caddy, Cloudflare Tunnels) див. [Посібник із розгортання](/uk/guide/deployment#reverse-proxy).
|
||||
|
||||
## Секрети Docker {#docker-secrets}
|
||||
|
||||
@@ -257,83 +170,101 @@ spec:
|
||||
|
||||
## Резервне копіювання та відновлення {#backup-and-recovery}
|
||||
|
||||
Постійний стан розділений між двома томами:
|
||||
Виробничий стек Compose визначає чотири томи. Зупиніть вхід і дайте активним завданням завершитися, перш ніж виконувати координоване резервне копіювання, щоб PostgreSQL, Redis і стан файлу описували той самий момент часу.
|
||||
|
||||
| Том | Вміст | Критичний? |
|
||||
|Обсяг|Зміст|Відновлювальне лікування|
|
||||
|---|---|---|
|
||||
| `SnapOtter-pgdata` | База даних PostgreSQL (користувачі, налаштування, конвеєри, завдання, журнал аудиту) | Так |
|
||||
| `/data` (том застосунку) | Завантажені користувачами файли, моделі AI, Python venv | Частково (див. нижче) |
|
||||
|`SnapOtter-pgdata`|Користувачі PostgreSQL, налаштування, конвеєри, завдання, метадані файлів і журнал аудиту|Критичний; використовуйте швидкий логічний дамп для портативного відновлення|
|
||||
|`SnapOtter-data`|Збережені бібліотечні об’єкти, журнали та стан AI (`/data/files, /data/logs, /data/ai, /data/ai/venv`)|Створіть резервну копію всього тому; щоб заощадити місце, навмисно пропустіть усі стани ШІ та перевстановіть його комплекти|
|
||||
|`SnapOtter-redisdata`|Redis AOF для тривалого стану черги BullMQ|Резервне копіювання після призупинення програми та примусового запуску `SAVE`; необхідні для точного відновлення роботи в черзі|
|
||||
|`SnapOtter-workspace`|Тимчасові ключі зберігання об’єктів (`/tmp/workspace/uploads, /tmp/workspace/outputs`)|Не створюйте резервну копію після того, як усі завдання вичерпано або скасовано; ніколи не викидайте його, поки завдання активні|
|
||||
|
||||
У межах тому `/data`:
|
||||
|
||||
| Шлях | Вміст | Критичний? |
|
||||
|---|---|---|
|
||||
| `/data/uploads/`, `/data/outputs/` | Файли користувачів і результати обробки | Так |
|
||||
| `/data/ai/` | Завантажені файли моделей AI | Ні (можна завантажити повторно) |
|
||||
| `/data/venv/` | Віртуальне середовище Python | Ні (перезбирається під час запуску) |
|
||||
Компонувати зазвичай префікси імен томів із назвою проекту. Розділіть реальний вихідний том із підключеного контейнера замість того, щоб припускати, що відображуване ім’я, наприклад `SnapOtter-data`, є ім’ям тому Docker.
|
||||
|
||||
### Резервне копіювання бази даних {#database-backup}
|
||||
|
||||
Використовуйте `pg_dump`, щоб зробити резервну копію бази даних, поки стек працює:
|
||||
Використовуйте спеціальний формат архіву PostgreSQL і перевірте архів, перш ніж розглядати резервну копію як завершену:
|
||||
|
||||
```bash
|
||||
# Dump the database
|
||||
docker exec SnapOtter-postgres pg_dump -U snapotter snapotter > backup.sql
|
||||
docker exec SnapOtter-postgres \
|
||||
pg_dump --format=custom --no-owner -U snapotter snapotter > snapotter.dump
|
||||
test -s snapotter.dump
|
||||
docker exec -i SnapOtter-postgres pg_restore --list < snapotter.dump >/dev/null
|
||||
|
||||
# Restore into a fresh database
|
||||
cat backup.sql | docker exec -i SnapOtter-postgres psql -U snapotter snapotter
|
||||
# Restore only into a fresh/disposable target first; any SQL error fails the command.
|
||||
docker exec -i SnapOtter-postgres \
|
||||
pg_restore --exit-on-error --clean --if-exists --no-owner \
|
||||
-U snapotter -d snapotter < snapotter.dump
|
||||
```
|
||||
|
||||
Як альтернатива, зупиніть стек і зробіть знімок тому `SnapOtter-pgdata`:
|
||||
Перевірте кожну резервну копію, відновивши її в ізольований стек, перевіривши записи бази даних і контрольні суми файлів і запустивши програму. `tests/qa/backup-restore-drill.sh` репозиторію автоматизує цей шлюз випуску проти явного `QA_IMAGE`.
|
||||
|
||||
Якщо натомість ваша платформа робить миттєві знімки томів, що відповідають збоям, спочатку зупиніть увесь стек і зробіть миттєві знімки всіх критичних томів як один набір. Необроблена копія каталогу даних PostgreSQL із запущеного контейнера не є підтримуваною логічною резервною копією.
|
||||
|
||||
### Резервне копіювання файлів і черги {#file-and-queue-backup}
|
||||
|
||||
Призупиніть програму перед захопленням томів файлів і черги. Використовуйте `docker inspect`, щоб розпізнати фактичну назву тому, змусити Redis зберегти поточний стан і архівувати зі збереженням права власності та дозволів:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
docker run --rm -v SnapOtter-pgdata:/data -v $(pwd)/backup:/backup \
|
||||
alpine tar czf /backup/snapotter-pgdata.tar.gz -C /data .
|
||||
docker stop SnapOtter
|
||||
docker exec SnapOtter-redis redis-cli -a "$REDIS_PASSWORD" --no-auth-warning SAVE
|
||||
docker stop SnapOtter-redis
|
||||
|
||||
DATA_VOLUME="$(docker inspect SnapOtter --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Name}}{{end}}{{end}}')"
|
||||
REDIS_VOLUME="$(docker inspect SnapOtter-redis --format '{{range .Mounts}}{{if eq .Destination "/data"}}{{.Name}}{{end}}{{end}}')"
|
||||
|
||||
install -d -m 700 backup
|
||||
docker run --rm -v "$DATA_VOLUME:/source:ro" -v "$PWD/backup:/backup" \
|
||||
alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce tar czf /backup/snapotter-data.tar.gz -C /source .
|
||||
docker run --rm -v "$REDIS_VOLUME:/source:ro" -v "$PWD/backup:/backup" \
|
||||
alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce tar czf /backup/snapotter-redis.tar.gz -C /source .
|
||||
sha256sum backup/snapotter-*.tar.gz > backup/SHA256SUMS
|
||||
```
|
||||
|
||||
### Резервне копіювання файлів користувачів {#user-files-backup}
|
||||
|
||||
```bash
|
||||
# Snapshot the app data volume (excluding re-downloadable AI models)
|
||||
docker run --rm -v SnapOtter-data:/data -v $(pwd)/backup:/backup \
|
||||
alpine tar czf /backup/snapotter-files.tar.gz \
|
||||
--exclude='ai' --exclude='venv' -C /data .
|
||||
```
|
||||
|
||||
Моделі AI разом сягають близько 24 GB для всіх бандлів. Оскільки їх можна завантажити повторно, виключіть `/data/ai/` і `/data/venv/` з резервних копій, щоб заощадити місце. Критичними є лише база даних і файли користувачів.
|
||||
Перезапустіть Redis перед програмою. Якщо ви навмисно виключаєте `/data/ai`, видаліть усе піддерево AI, а не зберігайте запис `installed.json` без його моделей або віртуального середовища. Зберігайте файли резервних копій у зашифрованому вигляді, з контрольованим доступом і окремо від хоста, на якому запущено SnapOtter.
|
||||
|
||||
## Артефакти відповідності {#compliance-artifacts}
|
||||
|
||||
Кожен реліз SnapOtter містить такі артефакти безпеки:
|
||||
Кожен випуск SnapOtter містить такі артефакти безпеки:
|
||||
|
||||
| Артефакт | Формат | Де його знайти |
|
||||
|---|---|---|
|
||||
| SBOM (CycloneDX) | JSON | Ресурс [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-sbom.cdx.json` |
|
||||
| SBOM (SPDX) | JSON | Ресурс [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-sbom.spdx.json` |
|
||||
| Сканування вразливостей | Trivy JSON | Ресурс [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-trivy.json` |
|
||||
| Сканування вразливостей | SARIF | Вкладка [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) |
|
||||
| Статичний аналіз | CodeQL (JS/TS + Python) | Вкладка [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security), запускається щотижня + на кожен PR |
|
||||
| Огляд залежностей | Нативний GitHub | Перевірка на кожен PR, дає збій при додаваннях високої серйозності |
|
||||
| Аудит залежностей Python | pip-audit | Журнал запуску CI при кожному push |
|
||||
| Політика безпеки | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) у репозиторії |
|
||||
| Звільнити предметну прив'язку | Канонічна атестація JSON + GitHub | [Випуск GitHub](https://github.com/snapotter-hq/SnapOtter/releases) актив: `snapotter-v{version}-release-subjects.json` |
|
||||
| Архів SBOM | CycloneDX і SPDX JSON | Випустити активи: `snapotter-v{version}-archive-linux-{arch}-sbom.{cdx,spdx}.json` |
|
||||
| Зображення SBOM | CycloneDX і SPDX JSON | Випустити активи: `snapotter-v{version}-image-linux-{arch}-sbom.{cdx,spdx}.json` |
|
||||
| Сканування вразливостей | Trivy JSON | Випустіть активи з відповідними префіксами `archive-linux-{arch}` або `image-linux-{arch}` |
|
||||
| Сканування вразливостей | SARIF | Вкладка [Безпека GitHub](https://github.com/snapotter-hq/SnapOtter/security). |
|
||||
| Статичний аналіз | CodeQL (JS/TS + Python) | Вкладка [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security), запускається щотижня + за PR |
|
||||
| Огляд залежності | GitHub рідний | Перевірка за PR, не вдається виконати додавання високої серйозності |
|
||||
| Аудит залежностей Python | pip-audit | Журнал запуску CI під час кожного натискання |
|
||||
| Політика безпеки | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) у сховищі |
|
||||
| Оновлення залежностей | Dependabot | Автоматизовані щотижневі PR для npm, pip, Docker, Actions |
|
||||
|
||||
**Запуск власного сканування:**
|
||||
|
||||
Завантажте SBOM з релізу й проскануйте його за допомогою бажаного інструмента:
|
||||
Завантажте маніфест теми випуску та переконайтеся, що він підтверджений робочим процесом випуску:
|
||||
|
||||
```bash
|
||||
gh attestation verify snapotter-v2.1.0-release-subjects.json \
|
||||
--repo snapotter-hq/SnapOtter \
|
||||
--signer-workflow snapotter-hq/SnapOtter/.github/workflows/release.yml
|
||||
```
|
||||
|
||||
У маніфесті окремо записуються `releaseTag`, `releaseCommit` і `workflowTriggerCommit`. Переконайтеся, що `releaseCommit` є комітом, видаленим із незмінного тегу, а потім перевірте дайджест SHA-256 архіву, зображення, SBOM або сканування, який ви використовуєте, на його запис у `subjects`. Ця відмінність є навмисною: перевірка щойно створеного коміту випуску не змінює ідентифікатор коміту в облікових даних OIDC робочого циклу.
|
||||
|
||||
Ви також можете сканувати завантажений SBOM або безпосередньо зображення:
|
||||
|
||||
```bash
|
||||
# Scan with Grype using the CycloneDX SBOM
|
||||
grype sbom:snapotter-v1.17.2-sbom.cdx.json
|
||||
grype sbom:snapotter-v2.1.0-image-linux-amd64-sbom.cdx.json
|
||||
|
||||
# Scan with Trivy using the SPDX SBOM
|
||||
trivy sbom snapotter-v1.17.2-sbom.spdx.json
|
||||
trivy sbom snapotter-v2.1.0-image-linux-amd64-sbom.spdx.json
|
||||
|
||||
# Scan the Docker image directly
|
||||
trivy image snapotter/snapotter:1.17.2
|
||||
trivy image snapotter/snapotter:2.1.0
|
||||
```
|
||||
|
||||
::: info
|
||||
SBOM і сканування вразливостей відображають точний образ, опублікований для того релізу. Бандли моделей AI, встановлені після розгортання, не включені до SBOM, оскільки вони завантажуються під час виконання.
|
||||
::: info
|
||||
Зображення SBOMs і скановані зображення відображають точне зображення конкретної архітектури, опубліковане для цього випуску. Архів SBOMs і скани описують попередньо зібраний архів окремо. Комплекти моделей AI, встановлені після розгортання, не включені в ці SBOMs, оскільки вони завантажуються під час виконання.
|
||||
:::
|
||||
|
||||
@@ -11,7 +11,7 @@ SnapOtter обробляє файли у п'яти модальностях: з
|
||||
|
||||
## Формати зображень {#image-formats}
|
||||
|
||||
SnapOtter підтримує понад 55 форматів зображень для введення та 13 форматів для виведення.
|
||||
SnapOtter підтримує понад 55 форматів зображень для введення та 17 форматів для виведення.
|
||||
|
||||
## Формати введення {#input-formats}
|
||||
|
||||
@@ -104,7 +104,7 @@ SnapOtter підтримує понад 55 форматів зображень
|
||||
| PAM | .pam | Sharp (native) | Довільна карта |
|
||||
| PFM | .pfm | Sharp (native) | Карта з плаваючою комою |
|
||||
|
||||
## Формати виведення (13) {#output-formats-13}
|
||||
## Формати виведення (17) {#output-formats-13}
|
||||
|
||||
| Формат | Кодувальник | Контроль якості | Доступний у |
|
||||
|--------|---------|----------------|-------------|
|
||||
@@ -121,6 +121,10 @@ SnapOtter підтримує понад 55 форматів зображень
|
||||
| ICO | ImageMagick CLI | Без втрат | Інструмент Convert |
|
||||
| JP2 | opj_compress CLI | Коефіцієнт стиснення | Інструмент Convert |
|
||||
| QOI | Вбудований кодек | Без втрат | Інструмент Convert |
|
||||
| PSD | ImageMagick CLI | Без втрат | Інструмент Convert |
|
||||
| PPM | ImageMagick CLI | Без втрат | Інструмент Convert |
|
||||
| EPS | ImageMagick CLI | Без втрат | Інструмент Convert |
|
||||
| TGA | ImageMagick CLI | Без втрат | Інструмент Convert |
|
||||
|
||||
## Формати відео {#video-formats}
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
description: "Керуйте користувачами, вбудованими та власними ролями, дозволами, ключами API, командами, сеансами й журналом аудиту в SnapOtter."
|
||||
i18n_source_hash: 5e28af686c96
|
||||
i18n_source_hash: bea8955f3aff
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: 3ef564692abf
|
||||
i18n_output_hash: 802ed8983042
|
||||
i18n_hash_version: 2
|
||||
---
|
||||
|
||||
# Користувачі, ролі та дозволи {#users-roles-permissions}
|
||||
@@ -82,12 +83,12 @@ SnapOtter містить три вбудовані ролі. Їх не можн
|
||||
| `pipelines:all` | Переглядати конвеєри всіх користувачів та керувати ними |
|
||||
| `settings:read` | Переглядати налаштування екземпляра |
|
||||
| `settings:write` | Змінювати налаштування екземпляра |
|
||||
| `users:manage` | Створювати, оновлювати та видаляти облікові записи користувачів |
|
||||
| `users:manage` | Створюйте облікові записи користувачів і керуйте ними в межах повноважень актора |
|
||||
| `teams:manage` | Створювати, оновлювати та видаляти команди |
|
||||
| `features:manage` | Встановлювати комплекти AI-функцій та керувати ними |
|
||||
| `system:health` | Доступ до кінцевих точок стану та готовності |
|
||||
| `audit:read` | Переглядати журнал аудиту та перелічувати ролі |
|
||||
| `compliance:manage` | Керувати життєвим циклом GDPR та функціями відповідності |
|
||||
| `compliance:manage` | Керуйте життєвим циклом GDPR і функціями відповідності; деструктивні операції користувача залишаються обмеженими повноваженнями |
|
||||
| `webhooks:manage` | Налаштовувати вихідні вебхуки |
|
||||
| `security:manage` | Керувати налаштуваннями безпеки (список дозволених IP, примусове застосування SSO) |
|
||||
|
||||
@@ -110,15 +111,17 @@ curl -X POST http://localhost:1349/api/v1/roles \
|
||||
|
||||
Назви ролей мають бути 2-30 символів, малими літерами, буквено-цифровими, з дефісами й підкресленнями.
|
||||
|
||||
### Дозволи, зарезервовані для адміністратора {#admin-reserved-permissions}
|
||||
### Межі делегованого адміністрування {#delegated-administration-boundaries}
|
||||
|
||||
Три дозволи зарезервовані для вбудованих ролей і не можуть бути призначені власним ролям:
|
||||
Усі 17 дозволів можна делегувати за допомогою спеціальних ролей, але адміністративний дозвіл не робить цю роль еквівалентною вбудованій ролі `admin`. Мутації користувача, дозволені `users:manage`, деструктивні операції, дозволені `compliance:manage`, і керування нестандартними ролями, дозволені `security:manage`, обмежені поточними повноваженнями актора:
|
||||
|
||||
- `compliance:manage`
|
||||
- `webhooks:manage`
|
||||
- `security:manage`
|
||||
- Вбудовані ролі слідують за `admin` > `editor` > `user`; настроювані ролі знаходяться нижче вбудованих ролей.
|
||||
- Дозволи цілі повинні міститися в **ефективних** дозволах актора. Таким чином, ключ API із обмеженою областю не може використовувати дозволи, випущені з його області.
|
||||
- Доступ до інструментів цільової ролі має бути обмежений власним доступом до інструментів актора.
|
||||
- Вимкнений обліковий запис перевіряється на його початкову роль, якщо ця роль записана як `disabled:<original-role>`.
|
||||
- Для видалення настроюваної ролі також потрібні повноваження для призначення вбудованого резервного варіанта `user`; недієздатні учасники залишаються недієздатними як `disabled:user`.
|
||||
|
||||
API ролей відхиляє будь-який запит, що містить ці дозволи. Лише вбудована роль `admin` має до них доступ.
|
||||
Глобальні облікові дані та конфігурація суворіші: для видачі або відкликання маркера SCIM та імпорту конфігурації екземпляра потрібна вбудована роль `admin` із повними ефективними повноваженнями адміністратора.
|
||||
|
||||
### Дозволи на рівні інструментів {#tool-level-permissions}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user