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 в продакшене с помощью Docker. Требования к оборудованию, настройка GPU и конфигурации обратного прокси для Nginx, Traefik и Cloudflare."
|
||||
i18n_output_hash: b5d2efef5f93
|
||||
i18n_source_hash: 98172965118b
|
||||
i18n_source_hash: 2a722f86da75
|
||||
i18n_provenance: human
|
||||
i18n_output_hash: b5b424e99554
|
||||
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 в логах:
|
||||
### Проверьте ускорение графического процессора {#verify-gpu-acceleration}
|
||||
|
||||
Проверьте обнаружение CUDA в журналах:
|
||||
|
||||
```bash
|
||||
docker logs SnapOtter 2>&1 | head -20
|
||||
# Look for: [gpu] CUDA available via torch
|
||||
```
|
||||
|
||||
Если инструменты ИИ работают на ЦП, даже если `--gpus all` и NVIDIA Container Toolkit настроены правильно, переустановите соответствующий пакет (например, «Удаление фона») из **Настройки → Функции AI**. Программа установки восстанавливает сборку ONNX Runtime для графического процессора, которую в противном случае сборка только для ЦП, полученная другим пакетом (например, транскрипцией), может затенить в общей среде искусственного интеллекта. Если переустановка из пользовательского интерфейса не восстанавливает графический процессор в старом образе, см. руководство по восстановлению в [ошибке № 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-монтирований) |
|
||||
| `PGID` | `999` | Запускать с этим GID (для прав bind-монтирований) |
|
||||
| `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 (пакетная обработка, ИИ-инструменты, установка функций). Увеличенные тайм-ауты позволяют завершать загрузки больших файлов без того, чтобы Caddy закрывал соединение раньше времени.
|
||||
`flush_interval -1` отключает буферизацию ответов, которая необходима для событий хода выполнения SSE (пакетная обработка, инструменты искусственного интеллекта, установка функций), а также для потоковой передачи больших загрузок файлов вместо остановки. Расширенные тайм-ауты позволяют завершать загрузку больших файлов без досрочного закрытия соединения Caddy.
|
||||
|
||||
### Cloudflare Tunnels {#cloudflare-tunnels}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user