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:
SnapOtter
2026-07-27 15:37:30 +08:00
committed by GitHub
parent bc32f86a07
commit d10d0f544f
855 changed files with 54564 additions and 13092 deletions
+4 -3
View File
@@ -1,8 +1,9 @@
---
description: "Monorepo-Struktur, App- und Paketarchitektur, Request-Lebenszyklus und Ressourcen-Footprint von SnapOtter."
i18n_output_hash: af8ecb20c86e
i18n_source_hash: a53946e760b0
i18n_source_hash: 50e076925c4b
i18n_provenance: human
i18n_output_hash: 3700f01eae84
i18n_hash_version: 2
---
# Architektur {#architecture}
@@ -52,7 +53,7 @@ Gemeinsam genutzte TypeScript-Typen, Konstanten (wie `APP_VERSION` und Werkzeugd
### API (`apps/api`) {#api-apps-api}
Ein Fastify-v5-Server, der 241 Werkzeug-Routen über fünf Modalitäten (image, video, audio, PDF, file) bereitstellt und Folgendes übernimmt:
Ein Fastify-v5-Server, der 243 Werkzeug-Routen über fünf Modalitäten (image, video, audio, PDF, file) bereitstellt und Folgendes übernimmt:
- Datei-Uploads, Verwaltung des temporären Arbeitsbereichs und persistenter Dateispeicher
- Benutzer-Dateibibliothek (`user_files`-Tabelle): Ein gespeicherter Edit wird standardmäßig als eigenständige neue Datei abgelegt, oder als übergeordnet verknüpfte Version, wenn du das Original überschreibst. Sie erfasst, welche Werkzeuge angewendet wurden (`toolChain`), und erhält ein automatisch generiertes Thumbnail für die Files-Seite
- Werkzeugausführung (leitet jede Werkzeuganfrage an die Image-Engine oder die KI-Brücke weiter)
+40 -17
View File
@@ -1,8 +1,9 @@
---
description: "Alle SnapOtter-Umgebungsvariablen mit Standardwerten. Konfiguriere Auth, Storage, KI-Modelle, Analyse und mehr."
i18n_source_hash: 8e9e9ca2840c
i18n_source_hash: 25970c776f7c
i18n_provenance: human
i18n_output_hash: 874b73f5ab4e
i18n_output_hash: 89c266bf51be
i18n_hash_version: 2
---
# Konfiguration {#configuration}
@@ -19,28 +20,51 @@ Die gesamte Konfiguration erfolgt über Umgebungsvariablen. Jede Variable hat ei
| `RATE_LIMIT_PER_MIN` | `1000` | Maximale Anzahl von Anfragen pro Minute pro IP. Auf 0 setzen, um die Ratenbegrenzung zu deaktivieren. |
| `CORS_ORIGIN` | (leer) | Kommagetrennte erlaubte Origins für CORS, oder leer für ausschließlich Same-Origin. |
| `LOG_LEVEL` | `info` | Log-Ausführlichkeit. Eines von: `fatal`, `error`, `warn`, `info`, `debug`, `trace`. |
| `TRUST_PROXY` | `true` | `X-Forwarded-For`-Headern von einem Reverse-Proxy vertrauen. Auf `false` setzen, wenn nicht hinter einem Proxy. |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Welche Gegenstellen die Client-IP über `X-Forwarded-For` setzen dürfen. Der Standard glaubt nur einer Gegenstelle aus einem privaten Netz, also gilt ein Reverse-Proxy im Docker-Netzwerk oder im LAN als vertrauenswürdig, der gefälschte Header eines öffentlichen Clients dagegen nicht. Setze `true` nur dann, wenn ein von dir kontrollierter Proxy unter einer öffentlichen Adresse davorsitzt. |
### Authentifizierung {#authentication}
Die beiden folgenden Booleans akzeptieren nur `true` und `false`. Alles andere, ob `1`, `yes` oder `on`, scheitert an der Validierung, und der Server beendet sich, bevor er zu lauschen beginnt.
| Variable | Standard | Beschreibung |
|---|---|---|
| `AUTH_ENABLED` | `false` | Auf `true` setzen, um eine Anmeldung zu erzwingen. Das Docker-Image verwendet standardmäßig `true`. |
| `AUTH_ENABLED` | `true` | Eine Anmeldung erzwingen. Auf `false` setzen, um ganz ohne Konten zu laufen; das gibt jeder Anfrage Admin-Rechte, beschränke das also auf ein vertrauenswürdiges Netzwerk. |
| `DEFAULT_USERNAME` | `admin` | Benutzername für das anfängliche Admin-Konto. Wird nur beim ersten Start verwendet. |
| `DEFAULT_PASSWORD` | `admin` | Passwort für das anfängliche Admin-Konto. Ändere dies nach der ersten Anmeldung. |
| `MAX_USERS` | `0` (unbegrenzt) | Maximale Anzahl registrierter Benutzerkonten. Auf 0 setzen für unbegrenzt. |
| `SESSION_DURATION_HOURS` | `168` | Lebensdauer der Anmeldesitzung in Stunden (Standard sind 7 Tage). |
| `SKIP_MUST_CHANGE_PASSWORD` | - | Auf einen beliebigen nicht-leeren Wert setzen, um die erzwungene Passwortänderungsaufforderung bei der ersten Anmeldung zu umgehen |
| `SKIP_MUST_CHANGE_PASSWORD` | `false` | Auf `true` setzen, um die erzwungene Passwortänderungsaufforderung bei der ersten Anmeldung zu überspringen. |
### Storage {#storage}
| Variable | Standard | Beschreibung |
|---|---|---|
| `STORAGE_MODE` | `local` | `local` oder `s3`. S3/MinIO erfordert eine Lizenz mit dem Feature s3_storage. |
| `DATABASE_URL` | `postgres://snapotter:snapotter@postgres:5432/snapotter` | PostgreSQL-Verbindungszeichenfolge. |
| `REDIS_URL` | `redis://redis:6379` | Redis-Verbindungszeichenfolge (wird für BullMQ-Job-Warteschlangen verwendet). |
| `WORKSPACE_PATH` | `./tmp/workspace` | Verzeichnis für temporäre Dateien während der Verarbeitung. Wird automatisch aufgeräumt. |
| `FILES_STORAGE_PATH` | `./data/files` | Verzeichnis für persistente Benutzerdateien (hochgeladene Bilder, gespeicherte Ergebnisse). |
| `STORAGE_MODE` | `local` | `local` oder `s3`. S3 und MinIO benötigen eine Lizenz mit dem Feature s3_storage sowie die untenstehenden `S3_*`-Variablen. |
| `DATABASE_URL` | `postgres://snapotter:snapotter@localhost:5432/snapotter` | PostgreSQL-Verbindungszeichenfolge. Der Compose-Stack richtet sie auf seinen `postgres`-Dienst; lass sie (zusammen mit `REDIS_URL`) ungesetzt, um den eingebetteten Modus zu bekommen. |
| `REDIS_URL` | `redis://localhost:6379` | Redis-Verbindungszeichenfolge (wird für BullMQ-Job-Warteschlangen verwendet). Compose richtet sie auf seinen `redis`-Dienst. |
| `WORKSPACE_PATH` | `./tmp/workspace` | Verzeichnis für temporäre Dateien während der Verarbeitung. Wird automatisch aufgeräumt. Das Image setzt `/tmp/workspace`. |
| `FILES_STORAGE_PATH` | `./data/files` | Verzeichnis für persistente Benutzerdateien (hochgeladene Bilder, gespeicherte Ergebnisse). Das Image setzt `/data/files`. |
### S3-Objektspeicher {#s3-object-storage}
Wird nur gelesen, wenn `STORAGE_MODE=s3` gilt. Fehlt eine der drei erforderlichen Variablen, schlägt der Start fehl und nennt den Namen der Variable, die du weggelassen hast.
| Variable | Standard | Beschreibung |
|---|---|---|
| `S3_BUCKET` | (leer) | Bucket, der Uploads und Ausgaben enthält. Erforderlich. |
| `S3_ACCESS_KEY_ID` | (leer) | Access Key. Erforderlich. Im Container kannst du ihn stattdessen einhängen, über `S3_ACCESS_KEY_ID_FILE`. |
| `S3_SECRET_ACCESS_KEY` | (leer) | Secret Key. Erforderlich. Gleiche Datei-Konvention: `S3_SECRET_ACCESS_KEY_FILE`. |
| `S3_REGION` | `us-east-1` | Region des Buckets. |
| `S3_ENDPOINT` | (leer) | Eigener Endpunkt für MinIO, R2, Backblaze und andere S3-kompatible Speicher. Leer bedeutet AWS. |
| `S3_FORCE_PATH_STYLE` | `false` | Auf `true` setzen für MinIO und alles andere, das `endpoint/bucket/key` statt der Virtual-Host-Adressierung erwartet. |
| `S3_PREFIX` | (leer) | Schlüsselpräfix, damit ein Bucket mehrere Instanzen aufnehmen kann. |
### Verschlüsselung im Ruhezustand {#encryption-at-rest}
| Variable | Standard | Beschreibung |
|---|---|---|
| `DATA_ENCRYPTION_KEY` | (leer) | 64 Hex-Zeichen (32 Byte). Verschlüsselt sensible Einstellungen, die in der Datenbank gespeichert sind. Alles, was nicht 64 Hex-Zeichen lang ist, wird beim Start abgelehnt. |
| `DATA_ENCRYPTION_KEY_PREVIOUS` | (leer) | Der Schlüssel, von dem du wegrotierst, im gleichen Format. Setze während einer Rotation beide, damit vorhandene Zeilen weiterhin entschlüsselt werden, und entferne diesen danach. |
### Eingebetteter Modus {#embedded-mode}
@@ -59,16 +83,15 @@ Telemetrie-Hinweis: Der eingebettete Modus übernimmt den Analyse-Standard des I
| Variable | Standard | Beschreibung |
|---|---|---|
| `MAX_UPLOAD_SIZE_MB` | `100` | Maximale Dateigröße pro Upload in Megabyte. Auf 0 setzen für unbegrenzt. |
| `MAX_BATCH_SIZE` | `100` | Maximale Anzahl von Dateien in einer einzelnen Stapelanfrage. Auf 0 setzen für unbegrenzt. |
| `MAX_UPLOAD_SIZE_MB` | `0` (unbegrenzt) | Maximale Dateigröße pro Upload in Megabyte. Auf 0 setzen für unbegrenzt. Das veröffentlichte Image wird mit `0` ausgeliefert; ein Build aus dem Quellcode startet bei 100. |
| `MAX_BATCH_SIZE` | `0` (unbegrenzt) | Maximale Anzahl von Dateien in einer einzelnen Stapelanfrage. Auf 0 setzen für unbegrenzt. Das veröffentlichte Image wird mit `0` ausgeliefert; ein Build aus dem Quellcode startet bei 100. |
| `CONCURRENT_JOBS` | `0` (auto) | Anzahl der Stapeljobs, die parallel laufen. Auf 0 setzen, um automatisch anhand der verfügbaren CPU-Kerne zu erkennen. |
| `MAX_MEGAPIXELS` | `0` (unbegrenzt) | Maximal erlaubte Bildauflösung in Megapixeln. Auf 0 setzen für unbegrenzt. |
| `MAX_WORKER_THREADS` | `0` (auto) | Maximale Worker-Threads für die Bildverarbeitung. Auf 0 setzen, um automatisch anhand der verfügbaren CPU-Kerne zu erkennen. |
| `PROCESSING_TIMEOUT_S` | `0` (kein Limit) | Maximale Verarbeitungszeit pro Anfrage in Sekunden. Auf 0 setzen für kein Timeout. |
| `MAX_PIPELINE_STEPS` | `20` | Maximale Anzahl von Schritten in einer Pipeline. Auf 0 setzen für kein Limit. |
| `MAX_CANVAS_PIXELS` | `0` (kein Limit) | Maximale Leinwandgröße in Pixeln für Ausgabebilder. Auf 0 setzen für kein Limit. |
| `MAX_SVG_SIZE_MB` | `0` (unbegrenzt) | Maximale SVG-Dateigröße in Megabyte. Auf 0 setzen für unbegrenzt. |
| `MAX_SPLIT_GRID` | `100` | Maximale Rasterdimension für das Bildaufteilungswerkzeug. |
| `MAX_SVG_SIZE_MB` | `50` | Größte SVG-Datei, die vor der Bereinigung akzeptiert wird, in Megabyte. `0` verhält sich hier anders als in den umliegenden Zeilen. Es entfernt die Größenbeschränkung vor dem Parsen vollständig, statt sie anzuheben, lass diesen Wert also gesetzt. |
| `MAX_PDF_PAGES` | `0` (unbegrenzt) | Maximale Anzahl von PDF-Seiten für die PDF-zu-Image-Konvertierung. Auf 0 setzen für unbegrenzt. |
### Bereinigung {#cleanup}
@@ -82,7 +105,7 @@ Telemetrie-Hinweis: Der eingebettete Modus übernimmt den Analyse-Standard des I
| Variable | Standard | Beschreibung |
|---|---|---|
| `DEFAULT_THEME` | `light` | Standard-Theme für neue Sitzungen. `light` oder `dark`. |
| `DEFAULT_THEME` | `light` | Standard-Theme für neue Sitzungen. `light`, `dark` oder `system`. |
| `DEFAULT_LOCALE` | `en` | Standard-Oberflächensprache. |
| `DEFAULT_TOOL_VIEW` | `sidebar` | Standard-Werkzeuglayout. `sidebar` oder `fullscreen`. |
@@ -124,13 +147,13 @@ services:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # Ändern Sie dies für nicht lokale Bereitstellungen
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
+5 -4
View File
@@ -1,8 +1,9 @@
---
description: "Wie man zu SnapOtter beiträgt. Fehlerberichte, Feature-Anfragen, Pull Requests und CLA-Anforderungen."
i18n_source_hash: 528802503035
i18n_source_hash: 6c920a5f83e0
i18n_provenance: human
i18n_output_hash: dad4aeee07c4
i18n_output_hash: ed043841f564
i18n_hash_version: 2
---
# Mitwirken {#contributing}
@@ -53,7 +54,7 @@ Wenn du im Auftrag deines Arbeitgebers beiträgst und dein Arbeitgeber die IP-Re
### Voraussetzungen {#prerequisites}
- Node.js 22+
- Node.js 22.22+
- pnpm 9+
- Python 3.11+ (nur für AI-Tools)
- Docker (optional, für vollständige Integrationstests)
@@ -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
```
+35 -15
View File
@@ -1,8 +1,9 @@
---
description: "PostgreSQL-Datenbankschema, Tabellen, Migrationen und Backup-Verfahren für SnapOtter."
i18n_source_hash: 50d5d4f220cf
i18n_provenance: human
i18n_output_hash: dd3579a83805
i18n_source_hash: a68264552836
i18n_provenance: machine
i18n_output_hash: 37efb265dd4b
i18n_hash_version: 2
---
# Datenbank {#database}
@@ -145,6 +146,17 @@ Protokoll sicherheitsrelevanter Aktionen.
| `details` | jsonb | Aktionsspezifische Daten |
| `createdAt` | timestamp | Zeitpunkt der Aktion |
### user_preferences {#user-preferences}
Oberflächenzustand pro Benutzer, abgelegt unter einem Präferenznamen. Speichert die angehefteten Tools der Startseite, die über `PUT /api/v1/preferences` geschrieben werden.
| Spalte | Typ | Hinweise |
|---|---|---|
| `userId` | text | FK auf users, kaskadierendes Löschen. Zusammen mit `key` der Primärschlüssel |
| `key` | text | Name der Präferenz. Zusammen mit `userId` der Primärschlüssel |
| `value` | jsonb | Inhalt der Präferenz |
| `updatedAt` | timestamp | Zeitpunkt des letzten Schreibvorgangs |
## Migrationen {#migrations}
Drizzle übernimmt die Schema-Migrationen. Die Migrationsdateien liegen in `apps/api/drizzle/`. Während der Entwicklung:
@@ -157,29 +169,37 @@ npx drizzle-kit migrate # apply pending migrations
In der Produktion werden ausstehende Migrationen beim Start automatisch angewendet.
## Backup und Wiederherstellung {#backup-and-restore}
## Sichern und Wiederherstellen von {#backup-and-restore}
Die relationale Datenbank liegt im Volume `SnapOtter-pgdata` des Postgres-Containers, nicht im Volume `/data` der App.
Die relationale Datenbank befindet sich im `SnapOtter-pgdata`-Volume des Postgres-Containers, nicht im `/data`-Volume der App.
**Option 1: pg_dump (empfohlen)**
**Logische Sicherung mit Validierung (empfohlen)**
```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
```
**Option 2: Volume-Snapshot**
Dieser Datenbank-Dump enthält keine gespeicherten Bibliotheksobjekte im `/data/files`- oder dauerhaften BullMQ-Status in Redis. Sichern und wiederherstellen Sie diese mit dem koordinierten Verfahren in [Sicherheit und Härtung](/de/guide/security#backup-and-recovery).
**Schnappschuss des kalten Volumens**
```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
```
Kopieren Sie kein Live-PostgreSQL-Datenverzeichnis mit `tar`. Verfassen Sie Volume-Namen mit Präfixen nach Projekt. Lösen Sie daher die gemounteten Volume-IDs von `docker inspect` oder Ihrer Speicherplattform auf, anstatt die wörtliche Bezeichnung `SnapOtter-pgdata` anzunehmen.
### Migration von 1.x (SQLite) {#migrating-from-1-x-sqlite}
Das Upgrade von SnapOtter 1.x hat einen eigenen Leitfaden: siehe [Upgrade von 1.x auf 2.0](./upgrading). Kurz gesagt: Verwende dein bestehendes Volume `/data` weiter, und 2.0 erkennt und importiert `/data/snapotter.db` beim ersten Start automatisch (oder setze `SQLITE_MIGRATE_PATH`, um explizit darauf zu verweisen). Sichere zuerst das gesamte Volume `/data`, nicht nur `snapotter.db`: 1.x nutzt den SQLite-WAL-Modus, sodass ein gestoppter Container einen Großteil seiner Daten oft in `snapotter.db-wal` neben einer fast leeren `snapotter.db` ablegt.
+24 -13
View File
@@ -1,8 +1,9 @@
---
description: "SnapOtter mit Docker in die Produktion bringen. Hardware-Anforderungen, GPU-Einrichtung und Reverse-Proxy-Konfigurationen für Nginx, Traefik und Cloudflare."
i18n_output_hash: 0ea42bb214de
i18n_source_hash: 98172965118b
i18n_source_hash: 2a722f86da75
i18n_provenance: human
i18n_output_hash: 8af3dc6a0ca9
i18n_hash_version: 2
---
# Deployment {#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 # Ändern Sie dies für nicht lokale Bereitstellungen
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
```
Prüfe die CUDA-Erkennung in den Logs:
### Überprüfen Sie die GPU-Beschleunigung {#verify-gpu-acceleration}
Überprüfen Sie die CUDA-Erkennung in den Protokollen:
```bash
docker logs SnapOtter 2>&1 | head -20
# Look for: [gpu] CUDA available via torch
```
Wenn KI-Tools auf der CPU ausgeführt werden, obwohl `--gpus all` und das NVIDIA Container Toolkit korrekt eingerichtet sind, installieren Sie das betroffene Bundle (z. B. Hintergrundentfernung) über **Einstellungen → KI-Funktionen** neu. Das Installationsprogramm stellt den GPU-Build von ONNX Runtime wieder her, den ein reiner CPU-Build, der von einem anderen Bundle (z. B. Transkription) abgerufen wird, andernfalls in der gemeinsam genutzten KI-Umgebung abbilden kann. Wenn die Neuinstallation über die Benutzeroberfläche die GPU auf einem älteren Image nicht wiederherstellt, lesen Sie die manuelle Reparatur in [Problem Nr. 490](https://github.com/snapotter-hq/SnapOtter/issues/490).
## Hardware-Anforderungen {#hardware-requirements}
Diese Werte stammen aus Benchmarks über eine Reihe von Systemen hinweg, von einer modernen amd64-Workstation mit einer NVIDIA RTX 4070 bis hinunter zu einem Raspberry Pi. Auf jedem wurde der gesamte Tool-Katalog ausgeführt und die Docker-Ressourcenlimits durchlaufen, um die tatsächliche Untergrenze zu ermitteln.
@@ -436,11 +441,11 @@ Der Startfehler nennt die genau zu verwendende UID, daher ist der schnellste Weg
| `AUTH_ENABLED` | `true` | Login-Pflicht aktivieren/deaktivieren |
| `DEFAULT_USERNAME` | `admin` | Anfänglicher Admin-Benutzername |
| `DEFAULT_PASSWORD` | `admin` | Anfängliches Admin-Passwort (erzwungene Änderung beim ersten Login) |
| `MAX_UPLOAD_SIZE_MB` | `100` | Upload-Limit pro Datei |
| `MAX_BATCH_SIZE` | `100` | Max. Dateien pro Stapelanfrage |
| `MAX_UPLOAD_SIZE_MB` | `0` (unbegrenzt) | Upload-Limit pro Datei in MB. Das Image kommt mit `0`; ein Build aus dem Quellcode startet bei 100 |
| `MAX_BATCH_SIZE` | `0` (unbegrenzt) | Max. Dateien pro Stapelanfrage. Das Image kommt mit `0`; ein Build aus dem Quellcode startet bei 100 |
| `RATE_LIMIT_PER_MIN` | `1000` | API-Anfragen pro Minute und IP (0 zum Deaktivieren) |
| `MAX_USERS` | `0` (unbegrenzt) | Maximale Benutzerkonten |
| `TRUST_PROXY` | `true` | X-Forwarded-For-Header vom Reverse-Proxy vertrauen |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Welche Gegenstellen die Client-IP über `X-Forwarded-For` setzen dürfen. Standardmäßig nur private Netze |
| `PUID` | `999` | Als diese UID ausführen (für Bind-Mount-Berechtigungen) |
| `PGID` | `999` | Als diese GID ausführen (für Bind-Mount-Berechtigungen) |
| `LOG_LEVEL` | `info` | Log-Ausführlichkeit: fatal, error, warn, info, debug, trace |
@@ -483,7 +488,13 @@ curl http://localhost:1349/api/v1/health
## Reverse-Proxy {#reverse-proxy}
SnapOtter setzt `TRUST_PROXY=true` standardmäßig, sodass Ratenbegrenzung und Protokollierung die echte Client-IP aus den `X-Forwarded-For`-Headern verwenden.
`TRUST_PROXY` steht standardmäßig auf `loopback,linklocal,uniquelocal`, sodass SnapOtter `X-Forwarded-For` nur einer Gegenstelle aus einem privaten Netz glaubt. Einem Reverse-Proxy auf demselben Host, in einem Docker-Netzwerk oder im LAN wird also von Haus aus vertraut, womit Ratenbegrenzung, die Brute-Force-Sperre beim Login, das Audit-Log und die Enterprise-IP-Allowlist ohne jede Konfiguration die echte Client-IP sehen.
Setze `TRUST_PROXY=true` nur dann, wenn der vorgeschaltete Proxy SnapOtter von einer **öffentlichen** Adresse aus erreicht, etwa ein Cloud-Load-Balancer in einem anderen Netz. Auf einer direkt exponierten Instanz macht dieser Wert `request.ip` angreifergesteuert, denn wer den Header durchrotiert, bekommt pro Anfrage einen frischen Zähler für die Ratenbegrenzung.
Zwei Dinge solltest du wissen, bevor du Client-IPs misst. Docker Desktop unter macOS und Windows bedient einen veröffentlichten Port über einen Userland-Proxy, der jede Quelladresse auf das VM-Gateway `192.168.65.1` umschreibt; dort holt kein Wert von `TRUST_PROXY` den echten Client zurück, also setze alles Internet-Zugängliche unter Linux auf. Und auf jeder Plattform wird ein Zugriff auf einen veröffentlichten Port über `localhost` als Bridge-Gateway statt als dein Client gesehen, ein Test über localhost sagt also nichts darüber aus, wie ein echter Client zugeordnet wird. Die vollständige Tabelle der `TRUST_PROXY`-Werte und den Docker-Desktop-Vorbehalt findest du in [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md#client-ip-resolution-trust_proxy).
Für jeden unten aufgeführten Proxy sind zwei Dinge wichtig: Erlauben Sie große Anforderungstexte (Uploads) und puffern Sie keine Antworten. Ein antwortpuffernder Proxy unterbricht den SSE-Fortschritt und führt, was sichtbarer ist, dazu, dass der Download einer großen Datei „startet, aber nie beendet“ wird, da der Proxy die gesamte Datei speichert, bevor er sie weitergibt. SnapOtter sendet `X-Accel-Buffering: no` bei Downloads, sodass nginx sie streamt, auch wenn die Pufferung an anderer Stelle beibehalten wird. Bei anderen Proxys als nginx muss die Antwortpufferung jedoch explizit deaktiviert werden (siehe unten in jeder Konfiguration). Wenn ein Download teilweise ins Stocken gerät, ist als erstes zu überprüfen, ob ein Puffer-Proxy vorgeschaltet ist.
### 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)
# Antworten streamen statt puffern: Wird für den SSE-Fortschritt (Batch, KI, Feature-Installationen) und für das Herunterladen großer Dateien benötigt.
proxy_buffering off;
proxy_read_timeout 300s;
}
@@ -549,7 +560,7 @@ images.example.com {
}
```
`flush_interval -1` deaktiviert die Antwort-Pufferung, was für SSE-Fortschrittsereignisse (Stapelverarbeitung, KI-Tools, Feature-Installationen) erforderlich ist. Die verlängerten Zeitüberschreitungen erlauben es, große Datei-Uploads abzuschließen, ohne dass Caddy die Verbindung vorzeitig schließt.
`flush_interval -1` deaktiviert die Antwortpufferung, die für SSE-Fortschrittsereignisse (Stapelverarbeitung, KI-Tools, Funktionsinstallationen) und für das Durchströmen großer Dateidownloads erforderlich ist, anstatt zum Stillstand zu kommen. Durch die verlängerten Zeitüberschreitungen können große Datei-Uploads abgeschlossen werden, ohne dass Caddy die Verbindung vorzeitig schließt.
### Cloudflare Tunnels {#cloudflare-tunnels}
+19 -7
View File
@@ -1,8 +1,9 @@
---
description: "Lokales Entwicklungs-Setup, Befehle, Code-Konventionen und wie man ein neues Tool zu SnapOtter hinzufügt."
i18n_source_hash: cb03724d2829
i18n_provenance: human
i18n_output_hash: 175a711c72f7
i18n_source_hash: 56acc1bf9a9b
i18n_provenance: machine
i18n_output_hash: 1aff0a0fd957
i18n_hash_version: 2
---
# Entwicklerleitfaden {#developer-guide}
@@ -11,12 +12,12 @@ Wie man eine lokale Entwicklungsumgebung einrichtet und Code zu SnapOtter beitr
## Voraussetzungen {#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/) (erforderlich für lokales Postgres + Redis, Container-Builds und AI-Features)
- Git
Python 3.10+ wird nur benötigt, wenn du am AI/ML-Sidecar arbeitest (Hintergrundentfernung, Hochskalierung, OCR).
Python 3.11+ wird nur benötigt, wenn du am AI/ML-Sidecar arbeitest (Hintergrundentfernung, Hochskalierung, OCR).
## Setup {#setup}
@@ -32,10 +33,10 @@ Dies startet zwei Dev-Server:
| Dienst | URL | Hinweise |
|----------|--------------------------|------------------------------------|
| Frontend | http://localhost:1349 | Vite-Dev-Server, proxyt /api |
| Frontend | http://localhost:1351 | Vite-Dev-Server, proxyt /api |
| Backend | http://localhost:13490 | Fastify-API (über Proxy erreichbar) |
Öffne http://localhost:1349 in deinem Browser. Melde dich mit `admin` / `admin` an. Bei der ersten Anmeldung wirst du aufgefordert, das Passwort zu ändern.
Öffne http://localhost:1351 in deinem Browser. Melde dich mit `admin` / `admin` an. Bei der ersten Anmeldung wirst du aufgefordert, das Passwort zu ändern.
## Projektstruktur {#project-structure}
@@ -220,6 +221,17 @@ Verwende BuildKit-Cache-Mounts für schnellere Rebuilds:
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest .
```
## Release-Versionsdomänen {#release-version-domains}
SnapOtter verfügt absichtlich über drei Versionsdomänen. Kopieren Sie während einer Veröffentlichung nicht eine Domäne in eine andere:
- Die Anwendungsfreigabeversion deckt das Root-Manifest, alle privaten Arbeitsbereichspakete und `APP_VERSION` ab. Semantic-release stellt diesen Wert bereit und `pnpm version:sync <version>` aktualisiert jeden Arbeitsbereich vor einer Anwendungsfreigabe.
- OpenAPI `info.version` ist der stabile öffentliche API-Großvertrag. Alle lokalisierten Spezifikationen bleiben für kompatible Anwendungsversionen auf `<major>.0.0` und ändern sich nur, wenn der API-Vertrag auf eine neue Hauptversion umgestellt wird.
- `docker/feature-manifest.json` behält `imageVersion: 2.0.0` als unveränderliche Legacy-Feature-Bundle-Speicherepoche bei. Bei diesen v2-Archivpfaden handelt es sich nicht um Anwendungspaketversionen. Accurate OCR verwendet das Laufzeitformat v3 und zeichnet die Herkunft der Anwendungsversion separat auf.
`tests/unit/infra/release-version-policy.test.ts` erzwingt diese Grenzen. Eine neue Versionsdomäne oder Migration muss diesen Vertrag und das relevante Artefaktmigrationsdesign zusammen aktualisieren.
Die unabhängigen API- und Legacy-Bundle-Werte befinden sich in `config/release-version-policy.json`; Die Synchronisierung der Anwendungsversion darf diese Richtliniendatei niemals implizit neu schreiben.
## Umgebungsvariablen {#environment-variables}
Die vollständige Liste findest du im [Konfigurationsleitfaden](/de/guide/configuration). Wichtige für die Entwicklung:
+8 -7
View File
@@ -1,8 +1,9 @@
---
description: "SnapOtter Docker-Image-Tags, GPU-Benchmarks, Versionsfixierung und Multi-Plattform-Unterstützung für AMD64 und ARM64."
i18n_output_hash: bf7df15424fd
i18n_source_hash: fda322e78b4b
i18n_source_hash: 566e20ca07fc
i18n_provenance: human
i18n_output_hash: 0fe4a1489769
i18n_hash_version: 2
---
# Docker-Image {#docker-image}
@@ -93,13 +94,13 @@ services:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # Ändern Sie dies für nicht lokale Bereitstellungen
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 @@ Für NVIDIA-CUDA-Beschleunigung über Docker Compose fügen Sie den deploy-Absch
| Tag | Beschreibung |
|-----|------------|
| `latest` | Neueste Version |
| `1.11.0` | Exakte Version |
| `1.11` | Neuester Patch in 1.11.x |
| `1` | Neueste Minor-Version in 1.x |
| `2.1.0` | Exakte Version |
| `2.1` | Neuester Patch in 2.1.x |
| `2` | Neueste Minor-Version in 2.x |
## Plattformen {#platforms}
+27 -60
View File
@@ -1,8 +1,9 @@
---
description: "SnapOtter mit Docker in einem einzigen Befehl installieren. Enthält Docker-Compose-Einrichtung, Bauen aus dem Quellcode und eine vollständige Funktionsübersicht."
i18n_output_hash: 14356fc91e39
i18n_source_hash: 68bf7f60b68d
i18n_provenance: human
i18n_source_hash: 8040133a6982
i18n_provenance: machine
i18n_output_hash: c7c22489510f
i18n_hash_version: 2
---
# Erste Schritte {#getting-started}
@@ -17,7 +18,7 @@ Erkunde die vollständige Oberfläche unter [demo.snapotter.com](https://demo.sn
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
```
Dieser einzelne Container führt alles aus, was er benötigt: Ohne gesetztes `DATABASE_URL` startet er sein eigenes PostgreSQL und Redis auf der Loopback-Schnittstelle (Embedded-Modus) und hält alle Daten im `SnapOtter-data`-Volume. Es ist der schnellste Weg, SnapOtter auszuprobieren oder in einem Homelab selbst zu hosten. Für die Produktion führe den [Docker-Compose](#docker-compose)-Stack unten aus, der PostgreSQL und Redis in ihren eigenen Containern hält. Der Embedded-Modus läuft als root (der Standard) und schaltet sich automatisch aus, sobald du `DATABASE_URL` setzt.
Dieser einzelne Container führt alles aus, was er benötigt: Wenn kein `DATABASE_URL` festgelegt ist, startet er sein eigenes PostgreSQL und Redis auf der Loopback-Schnittstelle (eingebetteter Modus) und behält alle Daten im `SnapOtter-data`-Volume. Dies ist der schnellste Weg, SnapOtter auszuprobieren oder sich selbst auf einem Homelab zu hosten. Verwenden Sie für die Produktion den [kanonischen Docker Compose-Stack](#docker-compose), der PostgreSQL und Redis in ihren eigenen Containern hält. Der eingebettete Modus wird als Root ausgeführt (Standardeinstellung) und automatisch deaktiviert, sobald Sie `DATABASE_URL` festlegen.
Du installierst auf einem Raspberry Pi, einem alten Laptop oder einem kleinen VPS? Siehe [Ressourcenarme Setups](/de/guide/low-resource) für eine abgestimmte Schritt-für-Schritt-Anleitung und einen Überblick darüber, was dich auf eingeschränkter Hardware erwartet.
@@ -40,7 +41,7 @@ Fügen Sie `--gpus all` für NVIDIA CUDA-beschleunigte Hintergrundentfernung, Ho
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest
```
Erfordert das [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Fällt automatisch auf die CPU zurück, wenn CUDA nicht verfügbar ist. Intel/AMD-iGPU-Beschleunigung über VA-API, Quick Sync oder OpenCL wird für KI-Inferenz derzeit nicht unterstützt. Siehe [Docker-Tags](/de/guide/docker-tags) für Benchmarks.
Erfordert das [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Fällt automatisch auf die CPU zurück, wenn CUDA nicht verfügbar ist. Die Intel/AMD iGPU-Beschleunigung über VA-API, Quick Sync oder OpenCL wird derzeit für KI-Inferenz nicht unterstützt. Benchmarks finden Sie unter [Docker-Tags](/de/guide/docker-tags). Wenn KI-Tools trotz `--gpus all` auf der CPU laufen, siehe [GPU-Beschleunigung überprüfen](/de/guide/deployment#verify-gpu-acceleration).
:::
::: details Auch auf GHCR
@@ -53,65 +54,31 @@ Beide Registries veröffentlichen bei jedem Release dasselbe Image.
## 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
Verwenden Sie die Produktionsdatei, die mit jeder Version gepflegt und getestet wird, anstatt ein verkürztes Compose-Beispiel von dieser Seite zu kopieren:
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
```
Siehe [Konfiguration](/de/guide/configuration) für alle Umgebungsvariablen.
Das kanonische [`docker/docker-compose.yml`](https://github.com/snapotter-hq/SnapOtter/blob/v2.1.0/docker/docker-compose.yml) umfasst alle vier Laufzeit-Volumes, Gesundheitsprüfungen, Ressourcenlimits, dauerhafte Redis-Konfiguration, angeheftete Datenbank-/Cache-Images und die aktuelle Containerhärtung. Ändern Sie das Standard-Administratorkennwort sofort nach der ersten Anmeldung. Für eine reproduzierbare Bereitstellung heften Sie das SnapOtter-Anwendungsimage an das von Ihnen überprüfte Release-Tag oder Digest, anstatt `latest` zu folgen.
Siehe [Konfiguration](/de/guide/configuration) für alle Umgebungsvariablen und [Sicherheit und Härtung](/de/guide/security) für Geheimnisse, Netzwerkrichtlinien und Backup-Anleitungen.
## Aus dem Quellcode bauen {#build-from-source}
**Voraussetzungen:** Node.js 22+, pnpm 9+, Docker (für Postgres + Redis), Python 3.10+ (für KI-Funktionen), Git.
**Voraussetzungen:** Node.js 22.22+, pnpm 9+, Docker (für Postgres + Redis), Python 3.11+ (für KI-Funktionen), Git.
```bash
git clone https://github.com/snapotter-hq/SnapOtter.git
@@ -121,7 +88,7 @@ pnpm install
pnpm dev
```
- Frontend: [http://localhost:1349](http://localhost:1349)
- Frontend: [http://localhost:1351](http://localhost:1351)
- Backend: [http://localhost:13490](http://localhost:13490)
## Was du tun kannst {#what-you-can-do}
@@ -130,11 +97,11 @@ pnpm dev
| Modalität | Anzahl | Beispiel-Tools |
|----------|-------|---------------|
| **Bild** | 105 | Größe ändern, zuschneiden, komprimieren, konvertieren, Hintergrund entfernen, hochskalieren, OCR, Wasserzeichen, Collage, kolorieren, GIF-Tools, Format-Vorlagen |
| **Bild** | 107 | Größe ändern, zuschneiden, komprimieren, konvertieren, Hintergrund entfernen, hochskalieren, OCR, Wasserzeichen, Collage, kolorieren, GIF-Tools, Format-Vorlagen |
| **Video** | 57 | Trimmen, zuschneiden, komprimieren, konvertieren, zusammenführen, Audio extrahieren, Auto-Untertitel, Video zu GIF, Größe ändern, stabilisieren, Format-Vorlagen |
| **Audio** | 27 | Trimmen, zusammenführen, konvertieren, normalisieren, Rauschunterdrückung, transkribieren, Tonhöhenverschiebung, Ein-/Ausblenden, Klingelton-Ersteller, Format-Vorlagen |
| **PDF / Dokument** | 42 | Zusammenführen, teilen, komprimieren, OCR, Wasserzeichen, schwärzen, Word zu PDF, Excel zu PDF, drehen, schützen, reparieren |
| **Dateien** | 10 | CSV zu JSON, JSON zu XML, CSVs zusammenführen, CSV teilen, ZIP erstellen, ZIP entpacken, Diagramm-Ersteller, YAML/JSON |
| **PDF / Dokument** | 29 | Zusammenführen, teilen, komprimieren, OCR, Wasserzeichen, schwärzen, Word zu PDF, Excel zu PDF, drehen, schützen, reparieren |
| **Dateien** | 23 | CSV zu JSON, JSON zu XML, CSVs zusammenführen, CSV teilen, ZIP erstellen, ZIP entpacken, Diagramm-Ersteller, YAML/JSON |
### Pipelines {#pipelines}
+4 -3
View File
@@ -1,7 +1,8 @@
---
i18n_source_hash: f5de74aee1b9
i18n_source_hash: 521c03a6416c
i18n_provenance: machine
i18n_output_hash: 3b61925b1289
i18n_output_hash: 78970ccc33b0
i18n_hash_version: 2
---
# Ressourcenarme Setups {#low-resource-setups}
@@ -59,7 +60,7 @@ services:
image: postgres:17-alpine
environment:
- POSTGRES_USER=snapotter
- POSTGRES_PASSWORD=snapotter
- POSTGRES_PASSWORD=snapotter # Ändern Sie dies für nicht lokale Bereitstellungen
- POSTGRES_DB=snapotter
volumes:
- ./postgres-data:/var/lib/postgresql/data
+12 -7
View File
@@ -1,8 +1,9 @@
---
description: "Richten Sie SCIM-2.0-Provisionierung ein, um Benutzer und Gruppen von Ihrem Identitätsanbieter mit SnapOtter zu synchronisieren. Behandelt Okta, Azure AD / Entra ID und benutzerdefinierte Integrationen."
i18n_source_hash: bbd50119ec12
i18n_source_hash: 06ee702b386e
i18n_provenance: human
i18n_output_hash: 58dab63bf748
i18n_output_hash: 1d2bc3b76da5
i18n_hash_version: 2
---
# SCIM-Provisionierung {#scim-provisioning}
@@ -17,7 +18,7 @@ Die SCIM-Provisionierung erfordert eine **Enterprise**-Lizenz mit der Funktion `
- Eine laufende SnapOtter-Instanz, die unter einer öffentlichen URL erreichbar ist
- Einen Enterprise-Lizenzschlüssel mit der Funktion `scim`
- Admin-Zugriff auf SnapOtter (die Berechtigung `users:manage` ist erforderlich, um ein SCIM-Token zu erzeugen oder zu widerrufen)
- Ein integriertes SnapOtter `admin`-Konto mit seinem vollständigen effektiven Berechtigungssatz. Eine delegierte benutzerdefinierte Rolle oder ein Administrator-API-Schlüssel, dem jegliche Administratorberechtigung fehlt, kann das globale SCIM-Token nicht generieren oder widerrufen.
- Admin-Zugriff auf die Provisionierungseinstellungen Ihres Identitätsanbieters
## Schnellstart {#quick-start}
@@ -34,7 +35,7 @@ Die Antwort enthält das Token. Speichern Sie es sofort; es kann nicht erneut ab
```json
{
"token": "a1b2c3d4e5f6...",
"token": "so_scim_v2_a1b2c3d4e5f6...",
"message": "Save this token - it cannot be retrieved again"
}
```
@@ -49,15 +50,19 @@ SCIM-Endpunkte verwenden ein dediziertes Bearer-Token, getrennt von Benutzersitz
### Ein Token erzeugen {#generating-a-token}
`POST /api/v1/enterprise/scim/token` erzeugt ein neues SCIM-Token. Dieser Endpunkt erfordert eine gültige Sitzung mit der Berechtigung `users:manage`.
`POST /api/v1/enterprise/scim/token` generiert ein neues SCIM-Token. Da das Token Benutzer in der gesamten Instanz bereitstellen und ändern kann, erfordert dieser Endpunkt die integrierte `admin`-Rolle mit dem vollständigen effektiven Administratorberechtigungssatz. Es reicht nicht aus, `users:manage` in einer benutzerdefinierten Rolle zu halten.
Das Token wird genau einmal im Klartext zurückgegeben. SnapOtter speichert nur einen scrypt-Hash. Wenn Sie das Token verlieren, widerrufen Sie es und erzeugen ein neues.
Es ist immer nur ein SCIM-Token gleichzeitig aktiv. Das Erzeugen eines neuen Tokens ersetzt das vorherige.
::: warning Neuausstellung des Tokens nach dem Upgrade
Ältere, nicht versionierte SCIM-Token werden abgelehnt. Generieren Sie nach dem Upgrade auf eine Version, die `so_scim_v2_...`-Tokens ausgibt, ein neues Token und aktualisieren Sie Ihren Identitätsanbieter, bevor Sie mit der Bereitstellung fortfahren.
:::
### Ein Token widerrufen {#revoking-a-token}
`DELETE /api/v1/enterprise/scim/token` widerruft das aktuelle SCIM-Token. Dieser Endpunkt erfordert ebenfalls `users:manage`.
`DELETE /api/v1/enterprise/scim/token` widerruft das aktuelle SCIM-Token. Es gelten die gleichen vollständigen integrierten Administratoranforderungen wie bei der Token-Generierung.
### Ratenbegrenzung {#rate-limiting}
@@ -279,7 +284,7 @@ Die SCIM-Anfrage enthielt keinen `Authorization: Bearer <token>`-Header. Prüfen
### 401 "Invalid token" {#_401-invalid-token}
Das Token stimmt nicht mit dem gespeicherten Hash überein. Das passiert, wenn das Token widerrufen und neu erzeugt wurde. Aktualisieren Sie das Token in den Provisionierungseinstellungen Ihres IdP.
Das Token ist fehlerhaft, verwendet das nicht mehr versionierte Format oder stimmt nicht mit dem gespeicherten Hash überein. Generieren Sie ein aktuelles `so_scim_v2_...`-Token und aktualisieren Sie das Token in den Bereitstellungseinstellungen Ihres IdP.
### 401 "SCIM not configured" {#_401-scim-not-configured}
+93 -162
View File
@@ -1,8 +1,9 @@
---
description: "Leitfaden zur Sicherheitshärtung für SnapOtter. Container-Sicherheit, Netzwerkisolierung, Docker-Secrets, Kubernetes-Deployment und Compliance-Artefakte."
i18n_source_hash: 986f7658430c
i18n_provenance: human
i18n_output_hash: 807a330f6ec7
i18n_source_hash: 9ff337fa0417
i18n_provenance: machine
i18n_output_hash: ec85a2663f1c
i18n_hash_version: 2
---
# Sicherheit & Härtung {#security-hardening}
@@ -11,133 +12,45 @@ SnapOtter verarbeitet Dateien vollständig auf deiner Infrastruktur. Es sendet s
Der Container läuft als dedizierter Non-Root-Benutzer (`snapotter`) mit allen entfernten Linux-Capabilities außer dem minimal erforderlichen Satz. Für die vollständige Richtlinie zur Offenlegung von Schwachstellen und die Sicherheitsarchitektur siehe [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) auf GitHub.
## Container-Härtung {#container-hardening}
## Containerhärtung {#container-hardening}
Die [Standard-docker-compose.yml](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) enthält Produktions-Sicherheitshärtung. Hier ist eine Aufschlüsselung jeder Option und warum sie wichtig ist:
Die kanonischen Compose-Dateien [CPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) und [GPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose-gpu.yml) sind die Quelle der Wahrheit. Kopieren Sie kein gekürztes Beispiel in die Produktion. Stellen Sie die Datei mit dem von Ihnen überprüften Release-Tag bereit.
```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
Beide Stapel wenden die folgenden Steuerelemente an:
# --- 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
- Speicher-, Swap-, CPU- und PID-Grenzwerte führen zu einer außer Kontrolle geratenen nativen Verarbeitung.
- Jeder Dienst lässt alle Linux-Funktionen fallen. Die Anwendung fügt nur `CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER, KILL` für den Volume-Besitz, den unidirektionalen `gosu`-Identitätsverlust und die ordnungsgemäße Signalweiterleitung zurück. PostgreSQL und Redis erhalten nur die Teilmenge, die ihre offiziellen Einstiegspunkte benötigen.
# --- 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]` verhindert, dass Prozesse in den Anwendungs-, PostgreSQL- und Redis-Containern zusätzliche Berechtigungen erhalten. Dies bleibt mit `gosu` kompatibel: Der Einstiegspunkt beginnt als Root, bereitet die Volumes vor und fällt nur auf den dedizierten `snapotter`-Benutzer.
# --- Logging ---
logging:
driver: json-file
options:
max-size: "50m" # Rotate logs at 50 MB
max-file: "5" # Keep 5 rotated log files
PostgreSQL- und Redis-Bildeingaben werden durch Digest gepinnt. Die Anwendung sollte ebenfalls an ein verifiziertes Release-Tag oder Digest angeheftet werden und nicht an `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
Gesundheitsprüfungen, begrenzte JSON-Protokollrotation, dauerhaftes Redis AOF und Neustartrichtlinie werden zentral in den kanonischen Dateien definiert.
shm_size: "2gb" # Required for Python ML shared memory
restart: unless-stopped
Binden Sie für eine mit dem Internet verbundene Bereitstellung Port 1349 an den Loopback und beenden Sie TLS an einem verwalteten Reverse-Proxy. Generieren Sie eindeutige PostgreSQL- und Redis-Anmeldeinformationen, speichern Sie Geheimnisse in geschützten Dateien oder einem Secret Manager und ändern Sie sofort das anfängliche Administratorkennwort.
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
### Warum `read_only` nicht auf {#why-read-only-is-not-set} gesetzt ist
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
`read_only: true` ist nicht festgelegt, da die PUID/PGID-Neuzuordnung beim Start in `/etc/passwd` und `/etc/group` schreibt. Wenn Sie das `--user`-Flag von Docker oder Kubernetes `runAsUser` anstelle von PUID/PGID verwenden, können Sie sicher ein schreibgeschütztes Root-Dateisystem aktivieren.
volumes:
SnapOtter-data:
SnapOtter-workspace:
SnapOtter-pgdata:
SnapOtter-redisdata:
```
## Netzwerkisolation {#network-isolation}
### Warum `no-new-privileges` nicht gesetzt ist {#why-no-new-privileges-is-not-set}
Die Dateiverarbeitung erfolgt lokal, aber eine Standardinstallation ist **kein ausgangsfreies System**. Anonyme Produktanalysen nutzen PostHog und Absturzberichte nutzen Sentry, wenn Telemetrie aktiviert ist. Stellen Sie `SNAPOTTER_TELEMETRY=0` ein (oder deaktivieren Sie die Analyse unter Einstellungen > System > Datenschutz), um beides zu deaktivieren. SnapOtter bezieht niemals hochgeladene Dateien, Dateinamen, OCR-Ausgaben, Dokumenttexte oder andere Dateiinhalte in diese Ereignisse ein.
`security_opt: [no-new-privileges:true]` wird bewusst weggelassen. Der Entrypoint startet als root, um die Volume-Eigentümerschaft zu korrigieren, und fällt dann über [gosu](https://github.com/tianon/gosu) auf den `snapotter`-Benutzer zurück, was setuid erfordert. Sobald der Privilegienabwurf abgeschlossen ist, läuft der Prozess als `snapotter` mit allen entfernten Capabilities außer den fünf oben aufgeführten.
Wenn du Kubernetes oder Dockers `--user`-Flag verwendest, um direkt als Non-Root zu laufen (und gosu zu umgehen), kann `no-new-privileges` sicher aktiviert werden.
### Warum `read_only` nicht gesetzt ist {#why-read-only-is-not-set}
`read_only: true` ist nicht gesetzt, weil die PUID/PGID-Neuzuordnung beim Start nach `/etc/passwd` und `/etc/group` schreibt. Wenn du Dockers `--user`-Flag oder Kubernetes `runAsUser` anstelle von PUID/PGID verwendest, kannst du ein schreibgeschütztes Root-Dateisystem sicher aktivieren.
## Netzwerkisolierung {#network-isolation}
Während des normalen Betriebs stellt der Container **null ausgehende Netzwerkverbindungen** her. Die gesamte Dateiverarbeitung geschieht lokal mit mitgelieferten Bibliotheken.
```
Browser --> Reverse Proxy (TLS) --> SnapOtter container --> (nothing)
```
Die einzige Ausnahme sind **KI-Modell-Downloads**: Wenn ein Benutzer ein KI-Feature-Bundle über die Oberfläche installiert, lädt der Container das vorgefertigte Bundle-Archiv von Hugging Face herunter, plus einige einzelne Modelldateien von GitHub Releases, Google Storage und PyPI. Diese Downloads geschehen einmal pro Bundle und werden im `/data`-Volume gespeichert.
Anderer ausgehender Datenverkehr ist funktionsgesteuert: Die AI-Bundle-/Modellinstallation lädt signierte Release-Eingaben herunter; Der URL-Import ruft eine vom Benutzer angeforderte öffentliche URL ab. und explizit konfigurierte OIDC, SAML, OpenTelemetry, Webhooks, S3-kompatibler Speicher oder ähnliche Integrationen wenden sich an die vom Administrator ausgewählten Ziele. Modell-Downloads zur Laufzeit sind standardmäßig deaktiviert. Setzen Sie `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=1` nur, um automatische Fallback-Downloads ausdrücklich zu aktivieren. Ein [Offline-Bundle-Import](/de/guide/deployment) kann KI-Funktionen ohne Laufzeitmodellausgang bereitstellen.
**Firewall-Empfehlungen:**
| Szenario | Ausgehende Regel |
|Szenario|Ausgehende Regel|
|---|---|
| Air-Gapped (keine KI) | Blockiere allen ausgehenden Verkehr vom Container |
| KI-Bundles benötigt | Erlaube HTTPS zu `huggingface.co`, `*.xethub.hf.co`, `cdn-lfs.huggingface.co`, `github.com`, `objects.githubusercontent.com`, `storage.googleapis.com`, `pypi.org`, `files.pythonhosted.org` während der Installation, dann blockieren |
| Nach der KI-Installation | Blockiere allen ausgehenden Verkehr - Modelle sind lokal zwischengespeichert |
|Luftspaltig|Legen Sie `SNAPOTTER_TELEMETRY=0` und `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=0` fest, verwenden Sie den Offline-AI-Bundle-Import, deaktivieren Sie den URL-Import und externe Integrationen und blockieren Sie dann den ausgehenden Datenverkehr|
|Standardtelemetrie|Erlauben Sie die in Ihren Browser-/Netzwerkprotokollen aufgeführten PostHog- und Sentry-Endpunkte; Deaktivieren Sie die Telemetrie, wenn die Richtlinie dies nicht zulässt|
|KI-Pakete erforderlich|Erlauben Sie während der Installation HTTPS zu `huggingface.co, *.xethub.hf.co, cdn-lfs.huggingface.co, github.com, objects.githubusercontent.com, storage.googleapis.com, pypi.org, files.pythonhosted.org`; Blockieren Sie dann diese Hosts|
|Externe Integrationen|Lassen Sie nur die genauen vom Administrator konfigurierten OIDC-/SAML-/OTLP-/Webhook-/Objektspeicherziele zu|
Bundle-Archive werden aus dem Xet-Storage von Hugging Face bereitgestellt, das über die `*.xethub.hf.co`-Endpunkte parallel überträgt und die Multi-GB-Bundle-Downloads schnell macht. Wenn deine Firewall `huggingface.co` erlaubt, aber `*.xethub.hf.co` blockiert, gelingen die Installationen dennoch, fallen aber auf einen langsameren Single-Stream-Download zurück; setze also die Xet-Hosts auf die Allowlist, um auf dem schnellen Pfad zu bleiben. Vollständig offline durchgeführte Installationen können all dies überspringen und stattdessen den [Offline-Bundle-Import](/de/guide/deployment) verwenden.
Bundle-Archive werden vom Xet-Speicher von Hugging Face bereitgestellt, der parallel über die `*.xethub.hf.co`-Endpunkte übertragen wird und Paket-Downloads mit mehreren GB schnell ermöglicht. Wenn Ihre Firewall `huggingface.co` zulässt, `*.xethub.hf.co` jedoch blockiert, sind Installationen weiterhin erfolgreich, greifen jedoch auf einen langsameren Single-Stream-Download zurück. Setzen Sie die Xet-Hosts daher auf die Zulassungsliste, um auf dem schnellen Pfad zu bleiben. Vollständige Offline-Installationen können dies alles überspringen und stattdessen [Offline-Bundle-Import](/de/guide/deployment) verwenden.
Für die Reverse-Proxy-Konfiguration (Nginx, Traefik, Caddy, Cloudflare Tunnels) siehe den [Deployment-Leitfaden](/de/guide/deployment#reverse-proxy).
Informationen zur Reverse-Proxy-Konfiguration (Nginx, Traefik, Caddy, Cloudflare Tunnels) finden Sie im [Bereitstellungshandbuch](/de/guide/deployment#reverse-proxy).
## Docker-Secrets {#docker-secrets}
@@ -255,85 +168,103 @@ Da `runAsUser: 999` auf Pod-Ebene gesetzt ist, überspringt der Entrypoint gosu
Für die Ressourcendimensionierung siehe [Hardware-Anforderungen](/de/guide/deployment#hardware-requirements).
## Backup und Wiederherstellung {#backup-and-recovery}
## Sicherung und Wiederherstellung {#backup-and-recovery}
Der persistente Zustand ist über zwei Volumes verteilt:
Der Compose-Produktionsstapel definiert vier Bände. Stoppen Sie den eingehenden Datenverkehr und lassen Sie aktive Jobs beenden, bevor Sie ein koordiniertes Backup erstellen, damit PostgreSQL, Redis und Dateistatus denselben Zeitpunkt beschreiben.
| Volume | Inhalt | Kritisch? |
|Volumen|Inhalt|Erholungsbehandlung|
|---|---|---|
| `SnapOtter-pgdata` | PostgreSQL-Datenbank (Benutzer, Einstellungen, Pipelines, Jobs, Audit-Log) | Ja |
| `/data` (App-Volume) | Von Benutzern hochgeladene Dateien, KI-Modelle, Python-venv | Teilweise (siehe unten) |
|`SnapOtter-pgdata`|PostgreSQL-Benutzer, Einstellungen, Pipelines, Jobs, Dateimetadaten und Prüfprotokoll|Kritisch; Verwenden Sie einen ausfallsicheren logischen Speicherauszug für die tragbare Wiederherstellung|
|`SnapOtter-data`|Gespeicherte Bibliotheksobjekte, Protokolle und AI-Status (`/data/files, /data/logs, /data/ai, /data/ai/venv`)|Sichern Sie das gesamte Volume; Um Platz zu sparen, lassen Sie bewusst alle AI-Status weg und installieren Sie die Bundles neu|
|`SnapOtter-redisdata`|Redis AOF für dauerhaften BullMQ-Warteschlangenstatus|Sichern Sie, nachdem Sie die App angehalten und `SAVE` erzwungen haben. erforderlich, um die in der Warteschlange befindliche Arbeit genau fortzusetzen|
|`SnapOtter-workspace`|Temporäre Objektspeicherschlüssel (`/tmp/workspace/uploads, /tmp/workspace/outputs`)|Führen Sie kein Backup durch, nachdem alle Jobs gelöscht oder abgebrochen wurden. Verwerfen Sie es niemals, während Jobs aktiv sind|
Innerhalb des `/data`-Volumes:
Compose stellt Volume-Namen normalerweise den Projektnamen voran. Lösen Sie das tatsächliche Quell-Volume aus dem gemounteten Container auf, anstatt davon auszugehen, dass ein Anzeigename wie `SnapOtter-data` der Name des Docker-Volumes ist.
| Pfad | Inhalt | Kritisch? |
|---|---|---|
| `/data/uploads/`, `/data/outputs/` | Benutzerdateien und Verarbeitungsergebnisse | Ja |
| `/data/ai/` | Heruntergeladene KI-Modelldateien | Nein (erneut herunterladbar) |
| `/data/venv/` | Virtuelle Python-Umgebung | Nein (beim Start neu gebaut) |
### Datenbanksicherung {#database-backup}
### Datenbank-Backup {#database-backup}
Verwende `pg_dump`, um die Datenbank zu sichern, während der Stack läuft:
Verwenden Sie das benutzerdefinierte Archivformat von PostgreSQL und überprüfen Sie das Archiv, bevor Sie die Sicherung als abgeschlossen betrachten:
```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
```
Alternativ stoppe den Stack und erstelle einen Snapshot des `SnapOtter-pgdata`-Volumes:
Testen Sie jedes Backup, indem Sie es in einem isolierten Stapel wiederherstellen, Datenbankeinträge und Dateiprüfsummen überprüfen und die Anwendung starten. Das `tests/qa/backup-restore-drill.sh` des Repositorys automatisiert dieses Release-Gate gegen ein explizites `QA_IMAGE`.
Wenn Ihre Plattform stattdessen absturzkonsistente Volume-Snapshots erstellt, stoppen Sie zuerst den gesamten Stack und erstellen Sie Snapshots aller kritischen Volumes als einen Satz. Eine Rohkopie des PostgreSQL-Datenverzeichnisses aus einem laufenden Container ist kein unterstütztes logisches Backup.
### Datei- und Warteschlangensicherung {#file-and-queue-backup}
Halten Sie die Anwendung an, bevor Sie Datei- und Warteschlangenvolumes erfassen. Verwenden Sie `docker inspect`, um den tatsächlichen Volume-Namen aufzulösen, Redis zu zwingen, seinen aktuellen Status beizubehalten, und unter Beibehaltung von Besitz und Berechtigungen zu archivieren:
```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
```
### Backup der Benutzerdateien {#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 .
```
KI-Modelle machen über alle Bundles hinweg bis zu etwa 24 GB aus. Da sie erneut herunterladbar sind, schließe `/data/ai/` und `/data/venv/` von Backups aus, um Platz zu sparen. Nur die Datenbank und die Benutzerdateien sind kritisch.
Starten Sie Redis vor der Anwendung neu. Wenn Sie `/data/ai` absichtlich ausschließen, entfernen Sie den gesamten AI-Teilbaum, anstatt einen `installed.json`-Datensatz ohne seine Modelle oder die virtuelle Umgebung beizubehalten. Bewahren Sie Sicherungsdateien verschlüsselt, zugriffskontrolliert und getrennt vom Host auf, auf dem SnapOtter ausgeführt wird.
## Compliance-Artefakte {#compliance-artifacts}
Jedes SnapOtter-Release enthält die folgenden Sicherheitsartefakte:
Jede SnapOtter-Version enthält die folgenden Sicherheitsartefakte:
| Artefakt | Format | Wo zu finden |
| Artefakt | Format | Wo es zu finden ist |
|---|---|---|
| SBOM (CycloneDX) | JSON | [GitHub-Release](https://github.com/snapotter-hq/SnapOtter/releases)-Asset: `snapotter-v{version}-sbom.cdx.json` |
| SBOM (SPDX) | JSON | [GitHub-Release](https://github.com/snapotter-hq/SnapOtter/releases)-Asset: `snapotter-v{version}-sbom.spdx.json` |
| Schwachstellen-Scan | Trivy JSON | [GitHub-Release](https://github.com/snapotter-hq/SnapOtter/releases)-Asset: `snapotter-v{version}-trivy.json` |
| Schwachstellen-Scan | SARIF | Tab [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) |
| Statische Analyse | CodeQL (JS/TS + Python) | Tab [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security), läuft wöchentlich + pro PR |
| Dependency-Review | GitHub nativ | Prüfung pro PR, scheitert bei Ergänzungen hoher Schwere |
| Python-Dependency-Audit | pip-audit | CI-Laufprotokoll bei jedem Push |
| Sicherheitsrichtlinie | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) im Repository |
| Dependency-Updates | Dependabot | Automatisierte wöchentliche PRs für npm, pip, Docker, Actions |
| Betreffbindung freigeben | Kanonische JSON + GitHub-Bescheinigung | [GitHub Release](https://github.com/snapotter-hq/SnapOtter/releases) Asset: `snapotter-v{version}-release-subjects.json` |
| Archiv SBOM | CycloneDX und SPDX JSON | Release-Assets: `snapotter-v{version}-archive-linux-{arch}-sbom.{cdx,spdx}.json` |
| Bild SBOM | CycloneDX und SPDX JSON | Release-Assets: `snapotter-v{version}-image-linux-{arch}-sbom.{cdx,spdx}.json` |
| Schwachstellenscans | Trivy JSON | Geben Sie Assets mit passenden `archive-linux-{arch}`- oder `image-linux-{arch}`-Präfixen frei |
| Schwachstellenscan | SARIF | Registerkarte [GitHub Sicherheit](https://github.com/snapotter-hq/SnapOtter/security). |
| Statische Analyse | CodeQL (JS/TS + Python) | Registerkarte [GitHub Sicherheit](https://github.com/snapotter-hq/SnapOtter/security), wird wöchentlich und pro PR ausgeführt |
| Abhängigkeitsüberprüfung | GitHub nativ | Die Prüfung pro PR schlägt bei Ergänzungen mit hohem Schweregrad fehl |
| Python Abhängigkeitsprüfung | pip-audit | CI-Ausführungsprotokoll bei jedem Push |
| Sicherheitspolitik | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) im Repository |
| Abhängigkeitsaktualisierungen | Dependabot | Automatisierte wöchentliche PRs für npm, pip, Docker, Aktionen |
**Deinen eigenen Scan ausführen:**
**Führen Sie Ihren eigenen Scan durch:**
Lade die SBOM aus dem Release herunter und scanne sie mit deinem bevorzugten Tool:
Laden Sie das Release-Subjekt-Manifest herunter und überprüfen Sie, ob es vom Release-Workflow bestätigt wurde:
```bash
gh attestation verify snapotter-v2.1.0-release-subjects.json \
--repo snapotter-hq/SnapOtter \
--signer-workflow snapotter-hq/SnapOtter/.github/workflows/release.yml
```
Das Manifest zeichnet `releaseTag`, `releaseCommit` und `workflowTriggerCommit` separat auf. Stellen Sie sicher, dass es sich bei `releaseCommit` um den Commit handelt, der aus dem unveränderlichen Tag entfernt wurde, und überprüfen Sie dann den SHA-256-Digest des Archivs, Images, SBOM oder Scans, den Sie verwenden, anhand seines Eintrags in `subjects`. Diese Unterscheidung ist beabsichtigt: Das Auschecken eines neu erstellten Release-Commits ändert nicht die Commit-Identität in den OIDC-Anmeldeinformationen des Workflows.
Sie können auch ein heruntergeladenes SBOM oder das Bild direkt scannen:
```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
Die SBOM und der Schwachstellen-Scan spiegeln genau das für dieses Release veröffentlichte Image wider. Nach dem Deployment installierte KI-Modell-Bundles sind nicht in der SBOM enthalten, da sie zur Laufzeit heruntergeladen werden.
::: info
Das Image SBOMs und die Scans spiegeln genau das architekturspezifische Image wider, das für diese Version veröffentlicht wurde. Archiv SBOMs und Scans beschreiben das vorgefertigte Archiv separat. Nach der Bereitstellung installierte AI-Modellpakete sind in diesen SBOMs nicht enthalten, da sie zur Laufzeit heruntergeladen werden.
:::
+6 -2
View File
@@ -11,7 +11,7 @@ SnapOtter verarbeitet Dateien über fünf Modalitäten hinweg: Bild, Video, Audi
## Bildformate {#image-formats}
SnapOtter unterstützt 55+ Bildformate für die Eingabe und 13 Formate für die Ausgabe.
SnapOtter unterstützt 55+ Bildformate für die Eingabe und 17 Formate für die Ausgabe.
## Eingabeformate {#input-formats}
@@ -104,7 +104,7 @@ SnapOtter unterstützt 55+ Bildformate für die Eingabe und 13 Formate für die
| PAM | .pam | Sharp (nativ) | Beliebige Map |
| PFM | .pfm | Sharp (nativ) | Float-Map |
## Ausgabeformate (13) {#output-formats-13}
## Ausgabeformate (17) {#output-formats-13}
| Format | Encoder | Qualitätssteuerung | Verfügbar in |
|--------|---------|----------------|-------------|
@@ -121,6 +121,10 @@ SnapOtter unterstützt 55+ Bildformate für die Eingabe und 13 Formate für die
| ICO | ImageMagick CLI | Verlustfrei | Konvertierungswerkzeug |
| JP2 | opj_compress CLI | Kompressionsverhältnis | Konvertierungswerkzeug |
| QOI | Inline-Codec | Verlustfrei | Konvertierungswerkzeug |
| PSD | ImageMagick CLI | Verlustfrei | Konvertierungswerkzeug |
| PPM | ImageMagick CLI | Verlustfrei | Konvertierungswerkzeug |
| EPS | ImageMagick CLI | Verlustfrei | Konvertierungswerkzeug |
| TGA | ImageMagick CLI | Verlustfrei | Konvertierungswerkzeug |
## Videoformate {#video-formats}
+13 -10
View File
@@ -1,8 +1,9 @@
---
description: "Verwalte Benutzer, integrierte und benutzerdefinierte Rollen, Berechtigungen, API-Schlüssel, Teams, Sitzungen und das Audit-Log in SnapOtter."
i18n_source_hash: 5e28af686c96
i18n_source_hash: bea8955f3aff
i18n_provenance: human
i18n_output_hash: 5794e14e4e84
i18n_output_hash: d773a75e3981
i18n_hash_version: 2
---
# Benutzer, Rollen & Berechtigungen {#users-roles-permissions}
@@ -82,12 +83,12 @@ Alle 17 Berechtigungen. Volle Kontrolle über die Instanz.
| `pipelines:all` | Pipelines aller Benutzer ansehen und verwalten |
| `settings:read` | Instanzeinstellungen ansehen |
| `settings:write` | Instanzeinstellungen ändern |
| `users:manage` | Benutzerkonten erstellen, aktualisieren und löschen |
| `users:manage` | Erstellen und verwalten Sie Benutzerkonten innerhalb der Autoritätsgrenzen des Akteurs |
| `teams:manage` | Teams erstellen, aktualisieren und löschen |
| `features:manage` | KI-Feature-Bundles installieren und verwalten |
| `system:health` | Auf Health- und Readiness-Endpunkte zugreifen |
| `audit:read` | Das Audit-Log ansehen und Rollen auflisten |
| `compliance:manage` | DSGVO-Lebenszyklus und Compliance-Funktionen verwalten |
| `compliance:manage` | Verwalten Sie den DSGVO-Lebenszyklus und die Compliance-Funktionen. Zerstörerische Benutzeroperationen bleiben autoritätsgebunden |
| `webhooks:manage` | Ausgehende Webhooks konfigurieren |
| `security:manage` | Sicherheitseinstellungen verwalten (IP-Zulassungsliste, SSO-Erzwingung) |
@@ -110,15 +111,17 @@ curl -X POST http://localhost:1349/api/v1/roles \
Rollennamen müssen 2 bis 30 Zeichen lang sein, kleingeschrieben alphanumerisch mit Bindestrichen und Unterstrichen.
### Für Administratoren reservierte Berechtigungen {#admin-reserved-permissions}
### Delegierte Verwaltungsgrenzen {#delegated-administration-boundaries}
Drei Berechtigungen sind für integrierte Rollen reserviert und können benutzerdefinierten Rollen nicht zugewiesen werden:
Alle 17 Berechtigungen können über benutzerdefinierte Rollen delegiert werden, aber eine Administratorberechtigung macht diese Rolle nicht gleichwertig mit der integrierten `admin`-Rolle. Von `users:manage` autorisierte Benutzermutationen, von `compliance:manage` autorisierte destruktive Operationen und von `security:manage` autorisierte benutzerdefinierte Rollenverwaltung unterliegen den aktuellen Berechtigungen des Akteurs:
- `compliance:manage`
- `webhooks:manage`
- `security:manage`
- Integrierte Rollen folgen `admin` > `editor` > `user`; Benutzerdefinierte Rollen sind unterhalb der integrierten Rollen aufgeführt.
- Die Berechtigungen des Ziels müssen in den **wirksamen** Berechtigungen des Akteurs enthalten sein. Ein bereichsbezogener API-Schlüssel kann daher keine Berechtigungen ausüben, die in seinem Bereich fehlen.
- Der Tool-Zugriff einer Zielrolle muss durch den eigenen Tool-Zugriff des Akteurs begrenzt sein.
- Ein deaktiviertes Konto wird mit seiner ursprünglichen Rolle verglichen, wenn diese Rolle als `disabled:<original-role>` aufgezeichnet ist.
- Zum Löschen einer benutzerdefinierten Rolle ist außerdem die Berechtigung zum Zuweisen des integrierten `user`-Fallbacks erforderlich. deaktivierte Mitglieder bleiben als `disabled:user` deaktiviert.
Die Rollen-API weist jede Anfrage ab, die diese Berechtigungen enthält. Nur die integrierte Rolle `admin` hat Zugriff darauf.
Globale Anmeldeinformationen und Konfiguration sind strenger: Das Ausstellen oder Widerrufen des SCIM-Tokens und das Importieren der Instanzkonfiguration erfordern die integrierte `admin`-Rolle mit vollständiger effektiver Administratorberechtigung.
### Berechtigungen auf Werkzeugebene {#tool-level-permissions}