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: "Struttura del monorepo, architettura di app e pacchetti, ciclo di vita di una richiesta e impronta sulle risorse di SnapOtter."
i18n_output_hash: 5a4f11a25575
i18n_source_hash: a53946e760b0
i18n_source_hash: 50e076925c4b
i18n_provenance: human
i18n_output_hash: c3c0755b6082
i18n_hash_version: 2
---
# Architettura {#architecture}
@@ -52,7 +53,7 @@ Tipi TypeScript condivisi, costanti (come `APP_VERSION` e le definizioni degli s
### API (`apps/api`) {#api-apps-api}
Un server Fastify v5 che espone 241 route di strumenti su cinque modalità (immagine, video, audio, PDF, file) e gestisce:
Un server Fastify v5 che espone 243 route di strumenti su cinque modalità (immagine, video, audio, PDF, file) e gestisce:
- Upload di file, gestione dello spazio di lavoro temporaneo e archiviazione persistente dei file
- Libreria di file utente (tabella `user_files`): per impostazione predefinita, una modifica salvata viene archiviata come nuovo file indipendente, oppure come versione collegata al genitore quando sovrascrivi l'originale. Registra quali strumenti sono stati applicati (`toolChain`) e ottiene una miniatura auto-generata per la pagina File
- Esecuzione degli strumenti (instrada ogni richiesta di strumento all'image engine o all'AI bridge)
+40 -17
View File
@@ -1,8 +1,9 @@
---
description: "Tutte le variabili d'ambiente di SnapOtter con i valori predefiniti. Configura autenticazione, archiviazione, modelli AI, analisi e altro."
i18n_source_hash: 8e9e9ca2840c
i18n_source_hash: 25970c776f7c
i18n_provenance: human
i18n_output_hash: 26b7e763f3f2
i18n_output_hash: 06445505769a
i18n_hash_version: 2
---
# Configurazione {#configuration}
@@ -19,28 +20,51 @@ Tutta la configurazione avviene tramite variabili d'ambiente. Ogni variabile ha
| `RATE_LIMIT_PER_MIN` | `1000` | Numero massimo di richieste al minuto per IP. Imposta a 0 per disabilitare il rate limiting. |
| `CORS_ORIGIN` | (vuoto) | Origini consentite per CORS separate da virgola, oppure vuoto per solo same-origin. |
| `LOG_LEVEL` | `info` | Verbosità dei log. Uno tra: `fatal`, `error`, `warn`, `info`, `debug`, `trace`. |
| `TRUST_PROXY` | `true` | Considera attendibili le intestazioni `X-Forwarded-For` da un reverse proxy. Imposta a `false` se non sei dietro un proxy. |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Quali peer possono impostare l'IP del client tramite `X-Forwarded-For`. Il valore predefinito crede solo a un peer su rete privata, quindi un reverse proxy su una rete Docker o su una LAN è attendibile, mentre l'intestazione falsificata di un client pubblico non lo è. Imposta `true` solo quando davanti c'è un proxy che controlli tu, su un indirizzo pubblico. |
### Autenticazione {#authentication}
I due booleani qui sotto accettano solo `true` e `false`. Qualsiasi altro valore, che sia `1`, `yes` oppure `on`, non supera la validazione e il server termina prima di mettersi in ascolto.
| Variabile | Predefinito | Descrizione |
|---|---|---|
| `AUTH_ENABLED` | `false` | Imposta a `true` per richiedere il login. L'immagine Docker ha come predefinito `true`. |
| `AUTH_ENABLED` | `true` | Richiede il login. Imposta a `false` per funzionare senza alcun account, il che concede a ogni richiesta i diritti di admin, quindi tienilo su una rete fidata. |
| `DEFAULT_USERNAME` | `admin` | Nome utente per l'account admin iniziale. Usato solo alla prima esecuzione. |
| `DEFAULT_PASSWORD` | `admin` | Password per l'account admin iniziale. Cambiala dopo il primo login. |
| `MAX_USERS` | `0` (illimitato) | Numero massimo di account utente registrati. Imposta a 0 per illimitato. |
| `SESSION_DURATION_HOURS` | `168` | Durata della sessione di login in ore (il predefinito è 7 giorni). |
| `SKIP_MUST_CHANGE_PASSWORD` | - | Imposta a un qualsiasi valore non vuoto per bypassare la richiesta forzata di cambio password al primo login |
| `SKIP_MUST_CHANGE_PASSWORD` | `false` | Imposta a `true` per saltare la richiesta forzata di cambio password al primo login. |
### Archiviazione {#storage}
| Variabile | Predefinito | Descrizione |
|---|---|---|
| `STORAGE_MODE` | `local` | `local` o `s3`. S3/MinIO richiede una licenza con la funzionalità s3_storage. |
| `DATABASE_URL` | `postgres://snapotter:snapotter@postgres:5432/snapotter` | Stringa di connessione PostgreSQL. |
| `REDIS_URL` | `redis://redis:6379` | Stringa di connessione Redis (usata per le code di lavori BullMQ). |
| `WORKSPACE_PATH` | `./tmp/workspace` | Directory per i file temporanei durante l'elaborazione. Pulita automaticamente. |
| `FILES_STORAGE_PATH` | `./data/files` | Directory per i file utente persistenti (immagini caricate, risultati salvati). |
| `STORAGE_MODE` | `local` | `local` o `s3`. S3 e MinIO richiedono una licenza con la funzionalità s3_storage, oltre alle variabili `S3_*` qui sotto. |
| `DATABASE_URL` | `postgres://snapotter:snapotter@localhost:5432/snapotter` | Stringa di connessione PostgreSQL. Lo stack Compose la punta al suo servizio `postgres`; lasciala non impostata (insieme a `REDIS_URL`) per ottenere la modalità embedded. |
| `REDIS_URL` | `redis://localhost:6379` | Stringa di connessione Redis (usata per le code di lavori BullMQ). Compose la punta al suo servizio `redis`. |
| `WORKSPACE_PATH` | `./tmp/workspace` | Directory per i file temporanei durante l'elaborazione. Pulita automaticamente. L'immagine imposta `/tmp/workspace`. |
| `FILES_STORAGE_PATH` | `./data/files` | Directory per i file utente persistenti (immagini caricate, risultati salvati). L'immagine imposta `/data/files`. |
### Archiviazione oggetti S3 {#s3-object-storage}
Lette solo quando `STORAGE_MODE=s3`. Se manca una delle tre obbligatorie, l'avvio fallisce indicando il nome della variabile che hai tralasciato.
| Variabile | Predefinito | Descrizione |
|---|---|---|
| `S3_BUCKET` | (vuoto) | Bucket che contiene upload e output. Obbligatorio. |
| `S3_ACCESS_KEY_ID` | (vuoto) | Access key. Obbligatoria. Nel container puoi invece montarla, tramite `S3_ACCESS_KEY_ID_FILE`. |
| `S3_SECRET_ACCESS_KEY` | (vuoto) | Secret key. Obbligatoria. Stessa convenzione per i file: `S3_SECRET_ACCESS_KEY_FILE`. |
| `S3_REGION` | `us-east-1` | Regione del bucket. |
| `S3_ENDPOINT` | (vuoto) | Endpoint personalizzato per MinIO, R2, Backblaze e altri store compatibili con S3. Vuoto significa AWS. |
| `S3_FORCE_PATH_STYLE` | `false` | Imposta a `true` per MinIO e per qualsiasi altro servizio che si aspetta `endpoint/bucket/key` invece dell'indirizzamento virtual-host. |
| `S3_PREFIX` | (vuoto) | Prefisso delle chiavi, così un solo bucket può ospitare più istanze. |
### Crittografia a riposo {#encryption-at-rest}
| Variabile | Predefinito | Descrizione |
|---|---|---|
| `DATA_ENCRYPTION_KEY` | (vuoto) | 64 caratteri esadecimali (32 byte). Cifra le impostazioni sensibili salvate nel database. Qualsiasi cosa che non sia di 64 caratteri esadecimali viene rifiutata all'avvio. |
| `DATA_ENCRYPTION_KEY_PREVIOUS` | (vuoto) | La chiave che stai abbandonando durante una rotazione, nello stesso formato. Impostale entrambe durante la rotazione così le righe esistenti restano decifrabili, poi rimuovi questa. |
### Modalità embedded {#embedded-mode}
@@ -59,16 +83,15 @@ Nota sulla telemetria: la modalità embedded eredita il valore predefinito delle
| Variabile | Predefinito | Descrizione |
|---|---|---|
| `MAX_UPLOAD_SIZE_MB` | `100` | Dimensione massima del file per upload in megabyte. Imposta a 0 per illimitato. |
| `MAX_BATCH_SIZE` | `100` | Numero massimo di file in una singola richiesta batch. Imposta a 0 per illimitato. |
| `MAX_UPLOAD_SIZE_MB` | `0` (illimitato) | Dimensione massima del file per upload in megabyte. Imposta a 0 per illimitato. L'immagine pubblicata viene fornita con `0`; una build dai sorgenti parte da 100. |
| `MAX_BATCH_SIZE` | `0` (illimitato) | Numero massimo di file in una singola richiesta batch. Imposta a 0 per illimitato. L'immagine pubblicata viene fornita con `0`; una build dai sorgenti parte da 100. |
| `CONCURRENT_JOBS` | `0` (auto) | Numero di lavori batch che girano in parallelo. Imposta a 0 per rilevarlo automaticamente in base ai core CPU disponibili. |
| `MAX_MEGAPIXELS` | `0` (illimitato) | Risoluzione massima dell'immagine consentita in megapixel. Imposta a 0 per illimitato. |
| `MAX_WORKER_THREADS` | `0` (auto) | Numero massimo di thread worker per l'elaborazione delle immagini. Imposta a 0 per rilevarlo automaticamente in base ai core CPU disponibili. |
| `PROCESSING_TIMEOUT_S` | `0` (nessun limite) | Tempo massimo di elaborazione per richiesta in secondi. Imposta a 0 per nessun timeout. |
| `MAX_PIPELINE_STEPS` | `20` | Numero massimo di passaggi in una pipeline. Imposta a 0 per nessun limite. |
| `MAX_CANVAS_PIXELS` | `0` (nessun limite) | Dimensione massima del canvas in pixel per le immagini di output. Imposta a 0 per nessun limite. |
| `MAX_SVG_SIZE_MB` | `0` (illimitato) | Dimensione massima del file SVG in megabyte. Imposta a 0 per illimitato. |
| `MAX_SPLIT_GRID` | `100` | Dimensione massima della griglia per lo strumento di divisione delle immagini. |
| `MAX_SVG_SIZE_MB` | `50` | Il più grande SVG accettato prima della sanificazione, in megabyte. Qui `0` si comporta diversamente rispetto alle righe vicine. Rimuove del tutto il limite di dimensione applicato prima del parsing invece di alzarlo, quindi lascia questo valore impostato. |
| `MAX_PDF_PAGES` | `0` (illimitato) | Numero massimo di pagine PDF per la conversione PDF-a-immagine. Imposta a 0 per illimitato. |
### Pulizia {#cleanup}
@@ -82,7 +105,7 @@ Nota sulla telemetria: la modalità embedded eredita il valore predefinito delle
| Variabile | Predefinito | Descrizione |
|---|---|---|
| `DEFAULT_THEME` | `light` | Tema predefinito per le nuove sessioni. `light` o `dark`. |
| `DEFAULT_THEME` | `light` | Tema predefinito per le nuove sessioni. `light`, `dark` o `system`. |
| `DEFAULT_LOCALE` | `en` | Lingua predefinita dell'interfaccia. |
| `DEFAULT_TOOL_VIEW` | `sidebar` | Layout predefinito degli strumenti. `sidebar` o `fullscreen`. |
@@ -124,13 +147,13 @@ services:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # Modificarlo per distribuzioni non locali
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: "Come contribuire a SnapOtter. Segnalazioni di bug, richieste di funzionalità, pull request e requisiti CLA."
i18n_source_hash: 528802503035
i18n_source_hash: 6c920a5f83e0
i18n_provenance: human
i18n_output_hash: 9060b8d556c7
i18n_output_hash: 3a1857dfcf53
i18n_hash_version: 2
---
# Contribuire {#contributing}
@@ -53,7 +54,7 @@ Se stai contribuendo per conto del tuo datore di lavoro e questi mantiene i diri
### Prerequisiti {#prerequisites}
- Node.js 22+
- Node.js 22.22+
- pnpm 9+
- Python 3.11+ (solo per gli strumenti AI)
- Docker (facoltativo, per il test di integrazione completo)
@@ -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
```
+34 -14
View File
@@ -1,8 +1,9 @@
---
description: "Schema del database PostgreSQL, tabelle, migrazioni e procedure di backup per SnapOtter."
i18n_source_hash: 50d5d4f220cf
i18n_provenance: human
i18n_output_hash: 6498644e25e3
i18n_source_hash: a68264552836
i18n_provenance: machine
i18n_output_hash: fdef77ac4a47
i18n_hash_version: 2
---
# Database {#database}
@@ -145,6 +146,17 @@ Registro delle azioni rilevanti per la sicurezza.
| `details` | jsonb | Dati specifici dell'azione |
| `createdAt` | timestamp | Data dell'azione |
### user_preferences {#user-preferences}
Stato dell'interfaccia per singolo utente, indicizzato per nome della preferenza. Conserva gli strumenti fissati della pagina iniziale, scritti tramite `PUT /api/v1/preferences`.
| Colonna | Tipo | Note |
|---|---|---|
| `userId` | text | FK verso users, con eliminazione a cascata. Chiave primaria insieme a `key` |
| `key` | text | Nome della preferenza. Chiave primaria insieme a `userId` |
| `value` | jsonb | Contenuto della preferenza |
| `updatedAt` | timestamp | Ultima scrittura |
## Migrazioni {#migrations}
Drizzle gestisce le migrazioni dello schema. I file di migrazione risiedono in `apps/api/drizzle/`. Durante lo sviluppo:
@@ -159,27 +171,35 @@ In produzione, le migrazioni in sospeso vengono applicate automaticamente all'av
## Backup e ripristino {#backup-and-restore}
Il database relazionale risiede nel volume `SnapOtter-pgdata` del container Postgres, non nel volume `/data` dell'app.
Il database relazionale si trova nel volume `SnapOtter-pgdata` del contenitore Postgres, non nel volume `/data` dell'app.
**Opzione 1: pg_dump (consigliata)**
**Backup logico con convalida (consigliato)**
```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
```
**Opzione 2: Snapshot del volume**
Questo dump del database non contiene oggetti di libreria salvati in `/data/files` o lo stato BullMQ durevole in Redis. Effettuare il backup e il ripristino di quelli con la procedura coordinata in [Sicurezza e rafforzamento](/it/guide/security#backup-and-recovery).
**Istantanea del volume freddo**
```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
```
Non copiare una directory di dati PostgreSQL live con `tar`. Componi i prefissi dei nomi dei volumi in base al progetto, quindi risolvi gli ID dei volumi montati da `docker inspect` o dalla tua piattaforma di archiviazione anziché assumere l'etichetta letterale `SnapOtter-pgdata`.
### Migrazione dalla 1.x (SQLite) {#migrating-from-1-x-sqlite}
L'aggiornamento da SnapOtter 1.x ha una guida dedicata: vedi [Aggiornamento dalla 1.x alla 2.0](./upgrading). In breve, riutilizza il tuo volume `/data` esistente e la 2.0 rileva e importa automaticamente `/data/snapotter.db` al primo avvio (oppure imposta `SQLITE_MIGRATE_PATH` per puntarvi esplicitamente). Esegui prima il backup dell'intero volume `/data`, non solo di `snapotter.db`: la 1.x usa la modalità WAL di SQLite, quindi un container arrestato lascia spesso la maggior parte dei suoi dati in `snapotter.db-wal` accanto a un `snapotter.db` quasi vuoto.
+24 -13
View File
@@ -1,8 +1,9 @@
---
description: "Distribuisci SnapOtter in produzione con Docker. Requisiti hardware, configurazione GPU e configurazioni di reverse proxy per Nginx, Traefik e Cloudflare."
i18n_output_hash: 28e72d02cd08
i18n_source_hash: 98172965118b
i18n_source_hash: 2a722f86da75
i18n_provenance: human
i18n_output_hash: ba64458b434b
i18n_hash_version: 2
---
# Distribuzione {#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 # Modificarlo per distribuzioni non locali
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
```
Controlla il rilevamento di CUDA nei log:
### Verifica l'accelerazione GPU {#verify-gpu-acceleration}
Controlla il rilevamento CUDA nei log:
```bash
docker logs SnapOtter 2>&1 | head -20
# Look for: [gpu] CUDA available via torch
```
Se gli strumenti AI vengono eseguiti sulla CPU anche se `--gpus all` e NVIDIA Container Toolkit sono configurati correttamente, reinstallare il pacchetto interessato (ad esempio Rimozione sfondo) da **Impostazioni → Funzionalità AI**. Il programma di installazione ripristina la build GPU di ONNX Runtime, che una build solo CPU inserita da un altro bundle (come la trascrizione) potrebbe altrimenti oscurare nell'ambiente AI condiviso. Se la reinstallazione dall'interfaccia utente non ripristina la GPU su un'immagine precedente, consulta la riparazione manuale nel [problema n. 490](https://github.com/snapotter-hq/SnapOtter/issues/490).
## Requisiti hardware {#hardware-requirements}
Questi valori provengono da benchmark eseguiti su una gamma di sistemi, da una moderna workstation amd64 con una NVIDIA RTX 4070 fino a un Raspberry Pi, eseguendo l'intero catalogo di strumenti su ciascuno e variando i limiti di risorse Docker per trovare il vero limite minimo.
@@ -436,11 +441,11 @@ L'errore di avvio indica l'UID esatto da usare, quindi il percorso più rapido
| `AUTH_ENABLED` | `true` | Abilita/disabilita il requisito di login |
| `DEFAULT_USERNAME` | `admin` | Nome utente admin iniziale |
| `DEFAULT_PASSWORD` | `admin` | Password admin iniziale (cambio forzato al primo login) |
| `MAX_UPLOAD_SIZE_MB` | `100` | Limite di upload per file |
| `MAX_BATCH_SIZE` | `100` | Numero massimo di file per richiesta batch |
| `MAX_UPLOAD_SIZE_MB` | `0` (illimitato) | Limite di upload per file in MB. L'immagine viene fornita con `0`; una build dai sorgenti parte da 100 |
| `MAX_BATCH_SIZE` | `0` (illimitato) | Numero massimo di file per richiesta batch. L'immagine viene fornita con `0`; una build dai sorgenti parte da 100 |
| `RATE_LIMIT_PER_MIN` | `1000` | Richieste API al minuto per IP (imposta 0 per disabilitare) |
| `MAX_USERS` | `0` (illimitato) | Numero massimo di account utente |
| `TRUST_PROXY` | `true` | Fidati degli header X-Forwarded-For dal reverse proxy |
| `TRUST_PROXY` | `loopback,linklocal,uniquelocal` | Quali peer possono impostare l'IP del client tramite `X-Forwarded-For`. Solo reti private per impostazione predefinita |
| `PUID` | `999` | Esegui con questo UID (per i permessi dei bind mount) |
| `PGID` | `999` | Esegui con questo GID (per i permessi dei bind mount) |
| `LOG_LEVEL` | `info` | Verbosità dei log: fatal, error, warn, info, debug, trace |
@@ -483,7 +488,13 @@ curl http://localhost:1349/api/v1/health
## Reverse Proxy {#reverse-proxy}
SnapOtter imposta `TRUST_PROXY=true` per impostazione predefinita, così il rate limiting e il logging usano l'IP reale del client dagli header `X-Forwarded-For`.
`TRUST_PROXY` vale `loopback,linklocal,uniquelocal` per impostazione predefinita, quindi SnapOtter crede all'intestazione `X-Forwarded-For` solo se arriva da un peer su una rete privata. Un reverse proxy sullo stesso host, su una rete Docker o sulla tua LAN è attendibile fin da subito, il che significa che il rate limiting, il limitatore anti forza bruta del login, il log di audit e la allowlist di IP dell'edizione enterprise vedono tutti l'IP reale del client senza alcuna configurazione.
Imposta `TRUST_PROXY=true` solo quando il proxy davanti raggiunge SnapOtter da un indirizzo **pubblico**, per esempio un bilanciatore di carico cloud su un'altra rete. Su un'istanza esposta direttamente quel valore rende `request.ip` controllabile da un attaccante, perché chi ruota l'intestazione ottiene un contatore di rate limit nuovo a ogni richiesta.
Due cose da sapere prima di metterti a misurare gli IP dei client. Docker Desktop su macOS e Windows serve una porta pubblicata attraverso un proxy in spazio utente che riscrive ogni indirizzo di origine sul gateway della VM `192.168.65.1`, quindi lì nessun valore di `TRUST_PROXY` recupera il client reale; per tutto ciò che è esposto a internet usa Linux. E su qualsiasi piattaforma, raggiungere una porta pubblicata tramite `localhost` viene osservato come il gateway del bridge e non come il tuo client, perciò una prova in locale non dice nulla su come venga attribuito un client reale. La tabella completa dei valori di `TRUST_PROXY` e l'avvertenza su Docker Desktop sono in [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md#client-ip-resolution-trust_proxy).
Due cose contano per ogni proxy riportato di seguito: consentire corpi di richieste di grandi dimensioni (caricamenti) e non bufferizzare le risposte. Un proxy con buffer di risposta interrompe l'avanzamento di SSE e, in modo più visibile, fa sì che il download di un file di grandi dimensioni "avvii ma non finisca mai", perché il proxy trattiene l'intero file prima di trasmetterlo. SnapOtter invia `X-Accel-Buffering: no` sui download in modo che nginx li trasmetta in streaming anche se il buffering è lasciato attivo altrove, ma i proxy diversi da nginx necessitano che il buffering della risposta sia disabilitato esplicitamente (mostrato in ciascuna configurazione di seguito). Se un download si blocca parzialmente, la prima cosa da controllare è un proxy di buffering di fronte.
### 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)
# Risposte in streaming anziché buffering: necessarie per l'avanzamento di SSE (batch, AI, installazioni di funzionalità) e per download di file di grandi dimensioni.
proxy_buffering off;
proxy_read_timeout 300s;
}
@@ -549,7 +560,7 @@ images.example.com {
}
```
`flush_interval -1` disabilita il buffering delle risposte, che è richiesto per gli eventi di avanzamento SSE (elaborazione batch, strumenti AI, installazioni di funzionalità). I timeout estesi permettono agli upload di file grandi di completarsi senza che Caddy chiuda la connessione in anticipo.
`flush_interval -1` disabilita il buffering della risposta, necessario per gli eventi di avanzamento di SSE (elaborazione batch, strumenti AI, installazioni di funzionalità) e per lo streaming di download di file di grandi dimensioni anziché in stallo. I timeout estesi consentono il completamento dei caricamenti di file di grandi dimensioni senza che Caddy chiuda anticipatamente la connessione.
### Cloudflare Tunnels {#cloudflare-tunnels}
+19 -7
View File
@@ -1,8 +1,9 @@
---
description: "Configurazione dell'ambiente di sviluppo locale, comandi, convenzioni di codice e come aggiungere un nuovo strumento a SnapOtter."
i18n_source_hash: cb03724d2829
i18n_provenance: human
i18n_output_hash: ea717bcba5fa
i18n_source_hash: 56acc1bf9a9b
i18n_provenance: machine
i18n_output_hash: a505794ce109
i18n_hash_version: 2
---
# Guida per sviluppatori {#developer-guide}
@@ -11,12 +12,12 @@ Come configurare un ambiente di sviluppo locale e contribuire con codice a SnapO
## Prerequisiti {#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/) (richiesto per Postgres + Redis locali, build dei container e funzionalità AI)
- Git
Python 3.10+ è necessario solo se stai lavorando sul sidecar AI/ML (rimozione dello sfondo, upscaling, OCR).
Python 3.11+ è necessario solo se stai lavorando sul sidecar AI/ML (rimozione dello sfondo, upscaling, OCR).
## Configurazione {#setup}
@@ -32,10 +33,10 @@ Questo avvia due dev server:
| Servizio | URL | Note |
|----------|--------------------------|------------------------------------|
| Frontend | http://localhost:1349 | Dev server Vite, fa da proxy a /api |
| Frontend | http://localhost:1351 | Dev server Vite, fa da proxy a /api |
| Backend | http://localhost:13490 | API Fastify (accessibile via proxy) |
Apri http://localhost:1349 nel tuo browser. Accedi con `admin` / `admin`. Ti verrà chiesto di cambiare la password al primo login.
Apri http://localhost:1351 nel tuo browser. Accedi con `admin` / `admin`. Ti verrà chiesto di cambiare la password al primo login.
## Struttura del progetto {#project-structure}
@@ -220,6 +221,17 @@ Usa le cache mount di BuildKit per rebuild più veloci:
DOCKER_BUILDKIT=1 docker build -f docker/Dockerfile -t snapotter:latest .
```
## Rilascia i domini della versione {#release-version-domains}
SnapOtter ha intenzionalmente tre domini di versione. Non copiare un dominio in un altro durante un rilascio:
- La versione di rilascio dell'applicazione copre il manifest root, tutti i pacchetti dell'area di lavoro privata e `APP_VERSION`. Semantic-release fornisce questo valore e `pnpm version:sync <version>` aggiorna ogni area di lavoro prima del rilascio dell'applicazione.
- OpenAPI `info.version` è il contratto pubblico stabile API-major. Tutte le specifiche localizzate rimangono su `<major>.0.0` per i rilasci di applicazioni compatibili e cambiano solo quando il contratto API passa a una nuova versione principale.
- `docker/feature-manifest.json` mantiene `imageVersion: 2.0.0` come epoca di archiviazione del pacchetto di funzionalità legacy immutabile. Tali percorsi di archivio v2 non sono versioni del pacchetto dell'applicazione. L'OCR accurato utilizza il formato runtime v3 e registra separatamente la provenienza del rilascio dell'applicazione.
`tests/unit/infra/release-version-policy.test.ts` rafforza questi limiti. Un nuovo dominio di versione o una migrazione deve aggiornare insieme il contratto e la progettazione di migrazione dell'artefatto pertinente.
I valori API indipendenti e quelli del bundle legacy risiedono in `config/release-version-policy.json`; la sincronizzazione della versione dell'applicazione non deve mai riscrivere implicitamente il file della politica.
## Variabili d'ambiente {#environment-variables}
Vedi la [Guida alla configurazione](/it/guide/configuration) per l'elenco completo. Quelle principali per lo sviluppo:
+8 -7
View File
@@ -1,8 +1,9 @@
---
description: "Tag delle immagini Docker di SnapOtter, benchmark GPU, blocco delle versioni e supporto multipiattaforma per AMD64 e ARM64."
i18n_output_hash: a04890140b33
i18n_source_hash: fda322e78b4b
i18n_source_hash: 566e20ca07fc
i18n_provenance: human
i18n_output_hash: 21ed931741d0
i18n_hash_version: 2
---
# Immagine Docker {#docker-image}
@@ -93,13 +94,13 @@ services:
image: postgres:17-alpine
environment:
POSTGRES_USER: snapotter
POSTGRES_PASSWORD: snapotter
POSTGRES_PASSWORD: snapotter # Modificarlo per distribuzioni non locali
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 @@ Per l'accelerazione NVIDIA CUDA tramite Docker Compose, aggiungi la sezione depl
| Tag | Descrizione |
|-----|------------|
| `latest` | Ultima release |
| `1.11.0` | Versione esatta |
| `1.11` | Ultima patch di 1.11.x |
| `1` | Ultima minor di 1.x |
| `2.1.0` | Versione esatta |
| `2.1` | Ultima patch di 2.1.x |
| `2` | Ultima minor di 2.x |
## Piattaforme {#platforms}
+28 -61
View File
@@ -1,8 +1,9 @@
---
description: "Installa SnapOtter con Docker in un solo comando. Include la configurazione di Docker Compose, la compilazione dal codice sorgente e una panoramica completa delle funzionalità."
i18n_output_hash: 193499a11aa6
i18n_source_hash: 68bf7f60b68d
i18n_provenance: human
i18n_source_hash: 8040133a6982
i18n_provenance: machine
i18n_output_hash: 5061d54954a1
i18n_hash_version: 2
---
# Per iniziare {#getting-started}
@@ -17,7 +18,7 @@ Esplora l'interfaccia completa su [demo.snapotter.com](https://demo.snapotter.co
docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data snapotter/snapotter:latest
```
Questo singolo container esegue tutto ciò di cui ha bisogno: senza alcun `DATABASE_URL` impostato, avvia il proprio PostgreSQL e Redis sull'interfaccia loopback (modalità integrata) e conserva tutti i dati nel volume `SnapOtter-data`. È il modo più rapido per provare SnapOtter o auto-ospitarlo su un homelab. Per la produzione, esegui lo stack [Docker Compose](#docker-compose) qui sotto, che mantiene PostgreSQL e Redis nei loro container. La modalità integrata gira come root (l'impostazione predefinita) e si disattiva automaticamente non appena imposti `DATABASE_URL`.
Questo singolo contenitore esegue tutto ciò di cui ha bisogno: senza alcun set `DATABASE_URL`, avvia il proprio PostgreSQL e Redis sull'interfaccia di loopback (modalità incorporata) e mantiene tutti i dati nel volume `SnapOtter-data`. È il modo più veloce per provare SnapOtter o ospitare autonomamente un laboratorio domestico. Per la produzione, utilizzare lo [stack canonico Docker Compose](#docker-compose), che mantiene PostgreSQL e Redis nei propri contenitori. La modalità incorporata viene eseguita come root (impostazione predefinita) e si disattiva automaticamente non appena si imposta `DATABASE_URL`.
Stai installando su un Raspberry Pi, un vecchio laptop o un piccolo VPS? Vedi [Configurazioni a basse risorse](/it/guide/low-resource) per una guida già calibrata e per sapere cosa aspettarti da hardware limitato.
@@ -40,7 +41,7 @@ Aggiungi `--gpus all` per NVIDIA rimozione dello sfondo, upscaling, migliorament
docker run -d --name SnapOtter -p 1349:1349 --gpus all -v SnapOtter-data:/data snapotter/snapotter:latest
```
Richiede il [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Effettua automaticamente il fallback su CPU quando CUDA non è disponibile. L'accelerazione tramite iGPU Intel/AMD attraverso VA-API, Quick Sync o OpenCL non è supportata per l'inferenza AI al momento. Vedi [Tag Docker](/it/guide/docker-tags) per i benchmark.
Richiede [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html). Ritorna automaticamente alla CPU quando CUDA non è disponibile. L'accelerazione iGPU Intel/AMD tramite VA-API, Quick Sync o OpenCL non è attualmente supportata per l'inferenza AI. Vedi [Docker Tags](/it/guide/docker-tags) per i benchmark. Se gli strumenti AI vengono eseguiti sulla CPU nonostante `--gpus all`, vedere [Verificare l'accelerazione GPU](/it/guide/deployment#verify-gpu-acceleration).
:::
::: details Anche su GHCR
@@ -51,67 +52,33 @@ docker run -d --name SnapOtter -p 1349:1349 -v SnapOtter-data:/data ghcr.io/snap
Entrambi i registry pubblicano la stessa immagine a ogni rilascio.
:::
## Docker Compose {#docker-compose}
## Docker Componi {#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
Utilizza il file di produzione mantenuto e testato con ogni versione invece di copiare un esempio di Compose abbreviato da questa pagina:
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
```
Vedi [Configurazione](/it/guide/configuration) per tutte le variabili d'ambiente.
Il [`docker/docker-compose.yml`](https://github.com/snapotter-hq/SnapOtter/blob/v2.1.0/docker/docker-compose.yml) canonico include tutti e quattro i volumi di runtime, controlli di integrità, limiti delle risorse, configurazione Redis durevole, immagini di database/cache bloccate e l'attuale rafforzamento del contenitore. Modificare la password amministratore predefinita immediatamente dopo il primo accesso. Per una distribuzione riproducibile, aggiungi l'immagine dell'applicazione SnapOtter al tag di rilascio o al digest che hai verificato invece di seguire `latest`.
Consulta [Configurazione](/it/guide/configuration) per tutte le variabili di ambiente e [Sicurezza e protezione avanzata](/it/guide/security) per segreti, criteri di rete e indicazioni sul backup.
## Compilazione dal codice sorgente {#build-from-source}
**Prerequisiti:** Node.js 22+, pnpm 9+, Docker (per Postgres + Redis), Python 3.10+ (per le funzionalità AI), Git.
**Prerequisiti:** Node.js 22.22+, pnpm 9+, Docker (per Postgres + Redis), Python 3.11+ (per le funzionalità AI), 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)
## Cosa puoi fare {#what-you-can-do}
@@ -130,11 +97,11 @@ pnpm dev
| Modalità | Numero | Strumenti di esempio |
|----------|-------|---------------|
| **Immagine** | 105 | Ridimensiona, Ritaglia, Comprimi, Converti, Rimuovi sfondo, Upscaling, OCR, Filigrana, Collage, Colorizza, Strumenti GIF, preset di formato |
| **Immagine** | 107 | Ridimensiona, Ritaglia, Comprimi, Converti, Rimuovi sfondo, Upscaling, OCR, Filigrana, Collage, Colorizza, Strumenti GIF, preset di formato |
| **Video** | 57 | Taglia, Ritaglia, Comprimi, Converti, Unisci, Estrai audio, Sottotitoli automatici, Da video a GIF, Ridimensiona, Stabilizza, preset di formato |
| **Audio** | 27 | Taglia, Unisci, Converti, Normalizza, Riduzione del rumore, Trascrivi, Cambio di tonalità, Dissolvenza, Creatore di suonerie, preset di formato |
| **PDF / Documenti** | 42 | Unisci, Dividi, Comprimi, OCR, Filigrana, Oscura, Da Word a PDF, Da Excel a PDF, Ruota, Proteggi, Ripara |
| **File** | 10 | Da CSV a JSON, Da JSON a XML, Unisci CSV, Dividi CSV, Crea ZIP, Estrai ZIP, Creatore di grafici, YAML/JSON |
| **PDF / Documenti** | 29 | Unisci, Dividi, Comprimi, OCR, Filigrana, Oscura, Da Word a PDF, Da Excel a PDF, Ruota, Proteggi, Ripara |
| **File** | 23 | Da CSV a JSON, Da JSON a XML, Unisci CSV, Dividi CSV, Crea ZIP, Estrai ZIP, Creatore di grafici, YAML/JSON |
### Pipeline {#pipelines}
+4 -3
View File
@@ -1,7 +1,8 @@
---
i18n_source_hash: f5de74aee1b9
i18n_source_hash: 521c03a6416c
i18n_provenance: machine
i18n_output_hash: 81cc593eda8d
i18n_output_hash: 09c689ff490a
i18n_hash_version: 2
---
# Configurazioni a basse risorse {#low-resource-setups}
@@ -59,7 +60,7 @@ services:
image: postgres:17-alpine
environment:
- POSTGRES_USER=snapotter
- POSTGRES_PASSWORD=snapotter
- POSTGRES_PASSWORD=snapotter # Modificarlo per distribuzioni non locali
- POSTGRES_DB=snapotter
volumes:
- ./postgres-data:/var/lib/postgresql/data
+12 -7
View File
@@ -1,8 +1,9 @@
---
description: "Configura il provisioning SCIM 2.0 per sincronizzare utenti e gruppi dal tuo provider di identità a SnapOtter. Copre Okta, Azure AD / Entra ID e integrazioni personalizzate."
i18n_source_hash: bbd50119ec12
i18n_source_hash: 06ee702b386e
i18n_provenance: human
i18n_output_hash: 6322df68028d
i18n_output_hash: d6bde5a4dbac
i18n_hash_version: 2
---
# Provisioning SCIM {#scim-provisioning}
@@ -17,7 +18,7 @@ Il provisioning SCIM richiede una licenza **enterprise** con la funzionalità `s
- Un'istanza SnapOtter in esecuzione raggiungibile a un URL pubblico
- Una chiave di licenza enterprise con la funzionalità `scim`
- Accesso admin a SnapOtter (è richiesto il permesso `users:manage` per generare o revocare un token SCIM)
- Un account SnapOtter `admin` integrato con il suo set di autorizzazioni completo ed efficace. Un ruolo personalizzato delegato o una chiave API di amministrazione priva di autorizzazioni di amministratore non può generare o revocare il token SCIM globale.
- Accesso admin alle impostazioni di provisioning del tuo provider di identità
## Avvio rapido {#quick-start}
@@ -34,7 +35,7 @@ La risposta contiene il token. Salvalo subito; non può essere recuperato di nuo
```json
{
"token": "a1b2c3d4e5f6...",
"token": "so_scim_v2_a1b2c3d4e5f6...",
"message": "Save this token - it cannot be retrieved again"
}
```
@@ -49,15 +50,19 @@ Gli endpoint SCIM usano un token bearer dedicato, separato dalle sessioni utente
### Generare un token {#generating-a-token}
`POST /api/v1/enterprise/scim/token` genera un nuovo token SCIM. Questo endpoint richiede una sessione valida con il permesso `users:manage`.
`POST /api/v1/enterprise/scim/token` genera un nuovo token SCIM. Poiché il token può eseguire il provisioning e modificare gli utenti nell'istanza, questo endpoint richiede il ruolo `admin` integrato con il set completo di autorizzazioni di amministratore effettive. Mantenere `users:manage` in un ruolo personalizzato non è sufficiente.
Il token viene restituito in chiaro esattamente una volta. SnapOtter memorizza solo un hash scrypt. Se perdi il token, revocalo e generane uno nuovo.
È attivo un solo token SCIM alla volta. La generazione di un nuovo token sostituisce quello precedente.
::: warning Riemissione del token dopo l'aggiornamento
I token SCIM legacy senza versione vengono rifiutati. Dopo l'aggiornamento a una versione che emette token `so_scim_v2_...`, genera un nuovo token e aggiorna il tuo provider di identità prima di riprendere il provisioning.
:::
### Revocare un token {#revoking-a-token}
`DELETE /api/v1/enterprise/scim/token` revoca il token SCIM corrente. Anche questo endpoint richiede `users:manage`.
`DELETE /api/v1/enterprise/scim/token` revoca l'attuale token SCIM. Ha gli stessi requisiti amministrativi integrati completi della generazione di token.
### Limitazione della frequenza {#rate-limiting}
@@ -279,7 +284,7 @@ La richiesta SCIM non includeva un header `Authorization: Bearer <token>`. Contr
### 401 "Invalid token" {#_401-invalid-token}
Il token non corrisponde all'hash memorizzato. Questo accade se il token è stato revocato e rigenerato. Aggiorna il token nelle impostazioni di provisioning del tuo IdP.
Il token non ha un formato corretto, utilizza il formato ritirato senza versione o non corrisponde all'hash archiviato. Genera un token `so_scim_v2_...` corrente e aggiorna il token nelle impostazioni di provisioning del tuo IdP.
### 401 "SCIM not configured" {#_401-scim-not-configured}
+90 -162
View File
@@ -1,8 +1,9 @@
---
description: "Guida al rafforzamento della sicurezza per SnapOtter. Sicurezza del container, isolamento di rete, Docker secrets, distribuzione Kubernetes e artefatti di conformità."
i18n_source_hash: 986f7658430c
i18n_provenance: human
i18n_output_hash: 24c63a8f7f16
i18n_source_hash: 9ff337fa0417
i18n_provenance: machine
i18n_output_hash: f1901f67dfe4
i18n_hash_version: 2
---
# Sicurezza e rafforzamento {#security-hardening}
@@ -11,133 +12,42 @@ SnapOtter elabora i file interamente sulla tua infrastruttura. Invia analytics d
Il container gira come utente non-root dedicato (`snapotter`) con tutte le capacità Linux rimosse tranne il set minimo richiesto. Per la policy completa di divulgazione delle vulnerabilità e l'architettura di sicurezza, vedi [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) su GitHub.
## Rafforzamento del container {#container-hardening}
## Indurimento del contenitore {#container-hardening}
Il [docker-compose.yml predefinito](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) include il rafforzamento della sicurezza per la produzione. Ecco una descrizione di ciascuna opzione e del perché è importante:
I file canonici Compose [CPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose.yml) e [GPU](https://github.com/snapotter-hq/SnapOtter/blob/main/docker/docker-compose-gpu.yml) sono la fonte della verità. Non copiare un esempio abbreviato nella produzione; distribuisci il file dal tag di rilascio che hai verificato.
```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
Entrambi gli stack applicano i seguenti controlli:
# --- 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
- I limiti di memoria, scambio, CPU e PID contengono un'elaborazione nativa fuori controllo.
- Ogni servizio elimina tutte le funzionalità di Linux. L'applicazione aggiunge nuovamente solo `CHOWN, SETUID, SETGID, DAC_OVERRIDE, FOWNER, KILL` per la proprietà del volume, il rilascio unidirezionale dell'identità `gosu` e l'inoltro regolare del segnale. PostgreSQL e Redis ricevono solo il sottoinsieme di cui hanno bisogno i loro punti di ingresso ufficiali.
- `security_opt: [no-new-privileges:true]` impedisce ai processi nell'applicazione, nei contenitori PostgreSQL e Redis di ottenere privilegi aggiuntivi. Questo rimane compatibile con `gosu`: il punto di ingresso inizia come root, prepara i volumi e scende solo all'utente `snapotter` dedicato.
- Gli input di immagini PostgreSQL e Redis sono bloccati da digest. Allo stesso modo, l'applicazione dovrebbe essere fissata a un tag di rilascio verificato o a un digest anziché a `latest`.
- I controlli di integrità, la rotazione limitata dei log JSON, l'AOF Redis durevole e la policy di riavvio sono definiti centralmente nei file canonici.
# --- 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
# --- Logging ---
logging:
driver: json-file
options:
max-size: "50m" # Rotate logs at 50 MB
max-file: "5" # Keep 5 rotated log files
# --- 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
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:
```
### Perché `no-new-privileges` non è impostato {#why-no-new-privileges-is-not-set}
`security_opt: [no-new-privileges:true]` è volutamente omesso. L'entrypoint parte come root per correggere la proprietà dei volumi, poi scende all'utente `snapotter` tramite [gosu](https://github.com/tianon/gosu), che richiede setuid. Una volta completata la riduzione dei privilegi, il processo gira come `snapotter` con tutte le capacità rimosse tranne le cinque elencate sopra.
Se usi Kubernetes o il flag `--user` di Docker per eseguire direttamente come non-root (bypassando gosu), `no-new-privileges` può essere abilitato in sicurezza.
Per una distribuzione con connessione Internet, associare la porta 1349 al loopback e terminare TLS su un proxy inverso mantenuto. Genera credenziali PostgreSQL e Redis univoche, archivia i segreti in file protetti o in un gestore di segreti e modifica immediatamente la password iniziale dell'amministratore.
### Perché `read_only` non è impostato {#why-read-only-is-not-set}
`read_only: true` non è impostato perché il rimappaggio PUID/PGID scrive su `/etc/passwd` e `/etc/group` all'avvio. Se usi il flag `--user` di Docker o `runAsUser` di Kubernetes invece di PUID/PGID, puoi abilitare in sicurezza un filesystem root di sola lettura.
`read_only: true` non è impostato perché la rimappatura PUID/PGID scrive su `/etc/passwd` e `/etc/group` all'avvio. Se utilizzi il flag `--user` di Docker o Kubernetes `runAsUser` invece di PUID/PGID, puoi abilitare in sicurezza un filesystem root di sola lettura.
## Isolamento di rete {#network-isolation}
## Isolamento della rete {#network-isolation}
Durante il normale funzionamento, il container effettua **zero connessioni di rete in uscita**. Tutta l'elaborazione dei file avviene localmente usando librerie integrate.
L'elaborazione dei file è locale, ma un'installazione predefinita **non è un sistema egress-free**. L'analisi anonima dei prodotti utilizza PostHog e la segnalazione degli arresti anomali utilizza Sentry quando la telemetria è abilitata. Imposta `SNAPOTTER_TELEMETRY=0` (o disabilita l'analisi in Impostazioni > Sistema > Privacy) per disattivarli entrambi. SnapOtter non include mai file caricati, nomi di file, output OCR, testo di documenti o altri contenuti di file in tali eventi.
```
Browser --> Reverse Proxy (TLS) --> SnapOtter container --> (nothing)
```
Il resto del traffico in uscita è basato sulle funzionalità: download di installazione di bundle/modelli AI, input di rilascio firmati; L'importazione dell'URL recupera un URL pubblico richiesto dall'utente; e OIDC, SAML, OpenTelemetry, webhook, storage compatibile con S3 o integrazioni simili esplicitamente configurati contattano le destinazioni scelte dall'amministratore. I download dei modelli in fase di esecuzione sono disabilitati per impostazione predefinita. Imposta `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=1` solo per abilitare esplicitamente i download di fallback automatici. Un'[importazione di bundle offline](/it/guide/deployment) può fornire funzionalità AI senza uscita dal modello runtime.
L'unica eccezione sono i **download dei modelli AI**: quando un utente installa un bundle di funzionalità AI tramite l'interfaccia, il container scarica l'archivio del bundle pre-costruito da Hugging Face, più alcuni singoli file di modelli da GitHub Releases, Google Storage e PyPI. Questi download avvengono una volta per bundle e sono memorizzati nel volume `/data`.
**Consigli sul firewall:**
**Raccomandazioni sul firewall:**
| Scenario | Regola in uscita |
|Scenario|Regola in uscita|
|---|---|
| Air-gapped (senza AI) | Blocca tutto il traffico in uscita dal container |
| Bundle AI necessari | Consenti HTTPS verso `huggingface.co`, `*.xethub.hf.co`, `cdn-lfs.huggingface.co`, `github.com`, `objects.githubusercontent.com`, `storage.googleapis.com`, `pypi.org`, `files.pythonhosted.org` durante l'installazione, poi blocca |
| Dopo l'installazione AI | Blocca tutto il traffico in uscita, i modelli sono memorizzati nella cache locale |
|Con intercapedine d'aria|Imposta `SNAPOTTER_TELEMETRY=0` e `SNAPOTTER_ALLOW_MODEL_DOWNLOAD=0`, utilizza l'importazione di bundle AI offline, disabilita l'importazione di URL e le integrazioni esterne, quindi blocca l'uscita|
|Telemetria predefinita|Consenti gli endpoint PostHog e Sentry elencati dai log del tuo browser/rete; disabilitare la telemetria se i criteri non lo consentono|
|Sono necessari pacchetti AI|Durante l'installazione, consenti HTTPS a `huggingface.co, *.xethub.hf.co, cdn-lfs.huggingface.co, github.com, objects.githubusercontent.com, storage.googleapis.com, pypi.org, files.pythonhosted.org`; quindi blocca quegli host|
|Integrazioni esterne|Consenti solo le destinazioni OIDC/SAML/OTLP/webhook/object storage esatte configurate dall'amministratore|
Gli archivi dei bundle vengono serviti dall'archiviazione Xet di Hugging Face, che trasferisce in parallelo attraverso gli endpoint `*.xethub.hf.co` ed è ciò che rende veloci i download di bundle da diversi GB. Se il tuo firewall consente `huggingface.co` ma blocca `*.xethub.hf.co`, le installazioni riescono comunque ma ripiegano su un download a flusso singolo più lento, quindi metti in allowlist gli host Xet per restare sul percorso veloce. Le installazioni completamente offline possono saltare tutto questo e usare invece l'[Importazione di bundle offline](/it/guide/deployment).
Gli archivi dei bundle vengono serviti dallo storage Xet di Hugging Face, che trasferisce sugli endpoint `*.xethub.hf.co` in parallelo ed è ciò che rende veloci i download dei bundle multi-GB. Se il tuo firewall consente `huggingface.co` ma blocca `*.xethub.hf.co`, le installazioni riescono comunque, ma ricadono in un download a flusso singolo più lento, quindi consenti agli host Xet di rimanere sul percorso veloce. Le installazioni completamente offline possono saltare tutto questo e utilizzare invece [Importazione bundle offline](/it/guide/deployment).
Per la configurazione del reverse proxy (Nginx, Traefik, Caddy, Cloudflare Tunnels), vedi la [guida alla distribuzione](/it/guide/deployment#reverse-proxy).
Per la configurazione del proxy inverso (Nginx, Traefik, Caddy, Cloudflare Tunnels), consultare la [Guida all'implementazione](/it/guide/deployment#reverse-proxy).
## Docker Secrets {#docker-secrets}
@@ -257,83 +167,101 @@ Per il dimensionamento delle risorse, vedi [Requisiti hardware](/it/guide/deploy
## Backup e ripristino {#backup-and-recovery}
Lo stato persistente è suddiviso su due volumi:
Lo stack Compose di produzione definisce quattro volumi. Interrompi l'ingresso e lascia che i processi attivi finiscano prima di eseguire un backup coordinato in modo che PostgreSQL, Redis e lo stato dei file descrivano lo stesso momento.
| Volume | Contenuti | Critico? |
|Volume|Contenuto|Trattamento di recupero|
|---|---|---|
| `SnapOtter-pgdata` | Database PostgreSQL (utenti, impostazioni, pipeline, job, log di audit) | Sì |
| `/data` (volume app) | File caricati dagli utenti, modelli AI, venv Python | Parzialmente (vedi sotto) |
|`SnapOtter-pgdata`|Utenti PostgreSQL, impostazioni, pipeline, processi, metadati di file e registro di controllo|Critico; utilizzare un dump logico fail-fast per il ripristino portatile|
|`SnapOtter-data`|Oggetti della libreria salvati, registri e stato AI (`/data/files, /data/logs, /data/ai, /data/ai/venv`)|Eseguire il backup dell'intero volume; per risparmiare spazio, ometti deliberatamente tutti gli stati dell'IA e reinstalla i relativi bundle|
|`SnapOtter-redisdata`|Redis AOF per uno stato della coda BullMQ durevole|Eseguire il backup dopo aver messo in pausa l'app e forzato `SAVE`; necessario per riprendere esattamente il lavoro in coda|
|`SnapOtter-workspace`|Chiavi di archiviazione temporanea degli oggetti (`/tmp/workspace/uploads, /tmp/workspace/outputs`)|Non eseguire il backup dopo che tutti i lavori sono stati svuotati o annullati; non scartarlo mai mentre i lavori sono attivi|
All'interno del volume `/data`:
| Percorso | Contenuti | Critico? |
|---|---|---|
| `/data/uploads/`, `/data/outputs/` | File utente e risultati di elaborazione | Sì |
| `/data/ai/` | File di modelli AI scaricati | No (riscaricabili) |
| `/data/venv/` | Ambiente virtuale Python | No (ricostruito all'avvio) |
Compose normalmente prefissa i nomi dei volumi con il nome del progetto. Risolvi il volume di origine reale dal contenitore montato invece di presupporre che un nome visualizzato come `SnapOtter-data` sia il nome del volume Docker.
### Backup del database {#database-backup}
Usa `pg_dump` per eseguire il backup del database mentre lo stack è in esecuzione:
Utilizza il formato di archivio personalizzato di PostgreSQL e verifica l'archivio prima di considerare il backup completo:
```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
```
In alternativa, ferma lo stack e crea uno snapshot del volume `SnapOtter-pgdata`:
Testare ogni backup ripristinandolo in uno stack isolato, controllando i record del database e i checksum dei file e avviando l'applicazione. `tests/qa/backup-restore-drill.sh` del repository automatizza il gate di rilascio rispetto a un `QA_IMAGE` esplicito.
Se invece la tua piattaforma esegue snapshot di volumi coerenti con gli arresti anomali, arresta prima l'intero stack e crea uno snapshot di tutti i volumi critici come un unico set. Una copia grezza della directory dati PostgreSQL da un contenitore in esecuzione non è un backup logico supportato.
### Backup di file e code {#file-and-queue-backup}
Mettere in pausa l'applicazione prima di acquisire file e volumi di coda. Utilizza `docker inspect` per risolvere il nome del volume effettivo, forzare Redis a mantenere il suo stato corrente e archiviare conservando proprietà e autorizzazioni:
```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 dei file utente {#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 .
```
I modelli AI ammontano fino a circa 24 GB su tutti i bundle. Poiché sono riscaricabili, escludi `/data/ai/` e `/data/venv/` dai backup per risparmiare spazio. Solo il database e i file utente sono critici.
Riavviare Redis prima dell'applicazione. Se escludi intenzionalmente `/data/ai`, rimuovi l'intero sottoalbero AI anziché preservare un record `installed.json` senza i relativi modelli o ambiente virtuale. Mantieni i file di backup crittografati, con accesso controllato e separati dall'host che esegue SnapOtter.
## Artefatti di conformità {#compliance-artifacts}
Ogni release di SnapOtter include i seguenti artefatti di sicurezza:
Ogni versione SnapOtter include i seguenti elementi di sicurezza:
| Artefatto | Formato | Dove trovarlo |
|---|---|---|
| SBOM (CycloneDX) | JSON | Asset della [release GitHub](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-sbom.cdx.json` |
| SBOM (SPDX) | JSON | Asset della [release GitHub](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-sbom.spdx.json` |
| Scansione delle vulnerabilità | Trivy JSON | Asset della [release GitHub](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-trivy.json` |
| Scansione delle vulnerabilità | SARIF | Scheda [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security) |
| Analisi statica | CodeQL (JS/TS + Python) | Scheda [GitHub Security](https://github.com/snapotter-hq/SnapOtter/security), eseguita settimanalmente + per PR |
| Revisione delle dipendenze | Nativa di GitHub | Controllo per PR, fallisce sulle aggiunte ad alta gravità |
| Audit delle dipendenze Python | pip-audit | Log di esecuzione CI a ogni push |
| Policy di sicurezza | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) nel repository |
| Aggiornamenti delle dipendenze | Dependabot | PR settimanali automatiche per npm, pip, Docker, Actions |
| Rilascia il soggetto vincolante | Attestazione canonica JSON + GitHub | Risorsa [Rilascio GitHub](https://github.com/snapotter-hq/SnapOtter/releases): `snapotter-v{version}-release-subjects.json` |
| Archivio SBOM | CycloneDX e SPDX JSON | Risorse di rilascio: `snapotter-v{version}-archive-linux-{arch}-sbom.{cdx,spdx}.json` |
| Immagine SBOM | CycloneDX e SPDX JSON | Risorse di rilascio: `snapotter-v{version}-image-linux-{arch}-sbom.{cdx,spdx}.json` |
| Scansioni delle vulnerabilità | Trivy JSON | Rilascia risorse con prefissi `archive-linux-{arch}` o `image-linux-{arch}` corrispondenti |
| Scansione delle vulnerabilità | SARIF | Scheda [GitHub Sicurezza](https://github.com/snapotter-hq/SnapOtter/security). |
| Analisi statica | CodeQL (JS/TS + Python) | Scheda [GitHub Sicurezza](https://github.com/snapotter-hq/SnapOtter/security), eseguita settimanalmente + per PR |
| Revisione delle dipendenze | GitHub nativo | Il controllo per PR fallisce in caso di aggiunte con gravità elevata |
| Controllo delle dipendenze Python | pip-audit | Il registro di esecuzione CI viene eseguito a ogni push |
| Politica di sicurezza | Markdown | [SECURITY.md](https://github.com/snapotter-hq/SnapOtter/blob/main/SECURITY.md) nel repository |
| Aggiornamenti delle dipendenze | Dependabot | PR settimanali automatizzati per npm, pip, Docker, azioni |
**Eseguire la tua scansione:**
**Esecuzione della tua scansione:**
Scarica l'SBOM dalla release e scansionalo con lo strumento che preferisci:
Scarica il manifest dell'oggetto del rilascio e verifica che sia stato attestato dal flusso di lavoro del rilascio:
```bash
gh attestation verify snapotter-v2.1.0-release-subjects.json \
--repo snapotter-hq/SnapOtter \
--signer-workflow snapotter-hq/SnapOtter/.github/workflows/release.yml
```
Il manifest registra `releaseTag`, `releaseCommit` e `workflowTriggerCommit` separatamente. Verifica che `releaseCommit` sia il commit estratto dal tag immutabile, quindi verifica il digest SHA-256 dell'archivio, dell'immagine, SBOM o esegui la scansione rispetto alla sua voce in `subjects`. Questa distinzione è intenzionale: l'estrazione di un commit di rilascio appena creato non modifica l'identità del commit nella credenziale OIDC del flusso di lavoro.
Puoi anche scansionare direttamente un SBOM scaricato o l'immagine:
```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
L'SBOM e la scansione delle vulnerabilità riflettono l'immagine esatta pubblicata per quella release. I bundle di modelli AI installati dopo la distribuzione non sono inclusi nell'SBOM poiché vengono scaricati a runtime.
::: info
L'immagine SBOMs e le scansioni riflettono l'esatta immagine specifica dell'architettura pubblicata per quella versione. L'archivio SBOMs e le scansioni descrivono separatamente l'archivio precostruito. I bundle del modello AI installati dopo la distribuzione non sono inclusi in questi SBOMs perché vengono scaricati in fase di runtime.
:::
+6 -2
View File
@@ -11,7 +11,7 @@ SnapOtter elabora file in cinque modalità: immagine, video, audio, PDF e file.
## Formati immagine {#image-formats}
SnapOtter supporta oltre 55 formati immagine in input e 13 formati in output.
SnapOtter supporta oltre 55 formati immagine in input e 17 formati in output.
## Formati di input {#input-formats}
@@ -104,7 +104,7 @@ SnapOtter supporta oltre 55 formati immagine in input e 13 formati in output.
| PAM | .pam | Sharp (nativo) | Mappa arbitraria |
| PFM | .pfm | Sharp (nativo) | Mappa float |
## Formati di output (13) {#output-formats-13}
## Formati di output (17) {#output-formats-13}
| Formato | Encoder | Controllo qualità | Disponibile in |
|--------|---------|----------------|-------------|
@@ -121,6 +121,10 @@ SnapOtter supporta oltre 55 formati immagine in input e 13 formati in output.
| ICO | ImageMagick CLI | Senza perdita | Strumento di conversione |
| JP2 | opj_compress CLI | Rapporto di compressione | Strumento di conversione |
| QOI | Codec inline | Senza perdita | Strumento di conversione |
| PSD | ImageMagick CLI | Senza perdita | Strumento di conversione |
| PPM | ImageMagick CLI | Senza perdita | Strumento di conversione |
| EPS | ImageMagick CLI | Senza perdita | Strumento di conversione |
| TGA | ImageMagick CLI | Senza perdita | Strumento di conversione |
## Formati video {#video-formats}
+13 -10
View File
@@ -1,8 +1,9 @@
---
description: "Gestisci utenti, ruoli integrati e personalizzati, permessi, chiavi API, team, sessioni e il log di audit in SnapOtter."
i18n_source_hash: 5e28af686c96
i18n_source_hash: bea8955f3aff
i18n_provenance: human
i18n_output_hash: c77cc53481fb
i18n_output_hash: 317e535b9400
i18n_hash_version: 2
---
# Utenti, ruoli e permessi {#users-roles-permissions}
@@ -82,12 +83,12 @@ Tutti e 17 i permessi. Controllo completo sull'istanza.
| `pipelines:all` | Visualizzare e gestire le pipeline di tutti gli utenti |
| `settings:read` | Visualizzare le impostazioni dell'istanza |
| `settings:write` | Modificare le impostazioni dell'istanza |
| `users:manage` | Creare, aggiornare ed eliminare account utente |
| `users:manage` | Crea e gestisci gli account utente entro i limiti di autorità dell'attore |
| `teams:manage` | Creare, aggiornare ed eliminare team |
| `features:manage` | Installare e gestire i bundle di funzionalità AI |
| `system:health` | Accedere agli endpoint di salute e prontezza |
| `audit:read` | Visualizzare il log di audit ed elencare i ruoli |
| `compliance:manage` | Gestire il ciclo di vita GDPR e le funzionalità di conformità |
| `compliance:manage` | Gestire il ciclo di vita e le funzionalità di conformità del GDPR; le operazioni utente distruttive rimangono limitate all'autorità |
| `webhooks:manage` | Configurare i webhook in uscita |
| `security:manage` | Gestire le impostazioni di sicurezza (allowlist IP, imposizione SSO) |
@@ -110,15 +111,17 @@ curl -X POST http://localhost:1349/api/v1/roles \
I nomi dei ruoli devono avere da 2 a 30 caratteri, alfanumerici minuscoli con trattini e trattini bassi.
### Permessi riservati agli amministratori {#admin-reserved-permissions}
### I confini dell'amministrazione delegata {#delegated-administration-boundaries}
Tre permessi sono riservati ai ruoli integrati e non possono essere assegnati ai ruoli personalizzati:
Tutte le 17 autorizzazioni possono essere delegate tramite ruoli personalizzati, ma un'autorizzazione amministrativa non rende tale ruolo equivalente al ruolo `admin` integrato. Le mutazioni dell'utente autorizzate da `users:manage`, le operazioni distruttive autorizzate da `compliance:manage` e la gestione dei ruoli personalizzati autorizzata da `security:manage` sono vincolate dall'attuale autorità dell'attore:
- `compliance:manage`
- `webhooks:manage`
- `security:manage`
- I ruoli integrati seguono `admin` > `editor` > `user`; i ruoli personalizzati sono sotto i ruoli integrati.
- Le autorizzazioni del target devono essere contenute nelle autorizzazioni **effettive** dell'attore. Una chiave API con ambito pertanto non può esercitare le autorizzazioni omesse dal suo ambito.
- L'accesso allo strumento di un ruolo target deve essere contenuto dall'accesso allo strumento stesso dell'attore.
- Un account disabilitato viene confrontato con il suo ruolo originale quando tale ruolo viene registrato come `disabled:<original-role>`.
- L'eliminazione di un ruolo personalizzato richiede anche l'autorizzazione per assegnare il fallback `user` integrato; i membri disabili rimangono disabilitati come `disabled:user`.
L'API dei ruoli rifiuta qualsiasi richiesta che includa questi permessi. Solo il ruolo integrato `admin` vi ha accesso.
Le credenziali globali e la configurazione sono più rigorose: l'emissione o la revoca del token SCIM e l'importazione della configurazione dell'istanza richiedono il ruolo `admin` integrato con completa autorità di amministrazione effettiva.
### Permessi a livello di strumento {#tool-level-permissions}