Deploy, visione e repo: difetti minori dalla revisione del 21/09 #38

Closed
opened 2026-09-21 20:14:55 +00:00 by Adriano · 3 comments
Owner

GRAVITÀ: bassa

  1. Dockerfile, Dockerfile.frontend, Dockerfile.vision — nessuna direttiva USER: server, client e worker (che apre immagini utente con PIL/opencv) girano come root. VERIFICATO: grep -n "^USER" Dockerfile* → 0.
  2. Dockerfile:1,4 ; Dockerfile.frontend:1,4,8 ; Dockerfile.vision:1,9 — uv:latest, basi senza digest, curl setup_20.x | bash: immagini non riproducibili (Tailwind invece è pinnato per audit ISO/IATF).
  3. docker-compose.yml:25-52,71-82 ; docker-compose.dev.yml:62-91 — server e client senza healthcheck, depends_on senza condizione: migrazione fallita = restart loop che risulta «Up».
  4. src/frontend/flask_app/config.py:21 ; nginx/nginx.conf:10,61-65 — SESSION_COOKIE_SECURE=True ma il profilo nginx (on-premise) ascolta solo sulla 80: da IP di LAN il login non regge. PRESUNTO, da provare prima dell'installazione da Tràfilo.
  5. src/backend/services/vision_service.py:208-224 ; routers/vision.py:104-122 — file scritto prima del commit (orfani); nessun GET/list/DELETE per le immagini di riferimento (fino a 50 MB l'una).
  6. src/backend/models/orm/vision.py:15-17,50-52 ; recipe_service.py:72-113 — FK task_id senza ondelete: cancellare un task con immagini/esecuzioni → 500 su MySQL (PRESUNTO); il copy-on-write non copia le immagini di riferimento.
  7. src/backend/api/routers/vision.py:67-72 — lot_number/serial_number senza max_length (→ 500 su MySQL strict), execute non controlla task_type, versione corrente, ricetta attiva.
  8. .gitignore:32-41 — uploads/vision/ e uploads/<recipe_id>/<version_id>/ non ignorati. VERIFICATO: git check-ignore → rc=1.
  9. src/backend_temp/requirements.txt — residuo tracciato, non citato da nessuno.
  10. nginx/nginx.conf:54-59,19-22 — la location regex delle estensioni statiche ha precedenza su /api/; il suo add_header annulla gli header di sicurezza; /uploads/ punta a una rotta che il backend non ha. PRESUNTO.
  11. docker-compose.yml:91-98 — label Traefik v1/v2 (SSLRedirect, browserXSSFilter), middleware solo su tmflow-web, dominio cablato. PRESUNTO (versione Traefik non verificata).
  12. README.md:463-470 ; pyproject.toml:3 ; CLAUDE.md — README dice «390 pass, 1 fail», oggi 391 passed 4 skipped 0 failed; version = "2.0.0" sul ramo V3.0.0; i test di visione su Python 3.11 vengono saltati in silenzio («2 skipped»), girano solo con --python 3.13 --extra vision-worker (8 passed).
  13. docker-compose.yml:54-69 — il container vision non ha volumi: un grafo con dxf_path non è eseguibile; GIF/WebP animati misurati sul primo frame; convert("L") riduce a 8 bit i PNG a 16.

ORIGINE: revisione fable del 21/09/2026 su ramo V3.0.0, commit 8cc5e82. Documento completo: _output/2026-09-21-TieMeasureFlow-revisione.md su Wasabi.

GRAVITÀ: bassa 1. Dockerfile, Dockerfile.frontend, Dockerfile.vision — nessuna direttiva USER: server, client e worker (che apre immagini utente con PIL/opencv) girano come root. VERIFICATO: `grep -n "^USER" Dockerfile*` → 0. 2. Dockerfile:1,4 ; Dockerfile.frontend:1,4,8 ; Dockerfile.vision:1,9 — `uv:latest`, basi senza digest, `curl setup_20.x | bash`: immagini non riproducibili (Tailwind invece è pinnato per audit ISO/IATF). 3. docker-compose.yml:25-52,71-82 ; docker-compose.dev.yml:62-91 — server e client senza healthcheck, `depends_on` senza condizione: migrazione fallita = restart loop che risulta «Up». 4. src/frontend/flask_app/config.py:21 ; nginx/nginx.conf:10,61-65 — SESSION_COOKIE_SECURE=True ma il profilo nginx (on-premise) ascolta solo sulla 80: da IP di LAN il login non regge. PRESUNTO, da provare prima dell'installazione da Tràfilo. 5. src/backend/services/vision_service.py:208-224 ; routers/vision.py:104-122 — file scritto prima del commit (orfani); nessun GET/list/DELETE per le immagini di riferimento (fino a 50 MB l'una). 6. src/backend/models/orm/vision.py:15-17,50-52 ; recipe_service.py:72-113 — FK `task_id` senza ondelete: cancellare un task con immagini/esecuzioni → 500 su MySQL (PRESUNTO); il copy-on-write non copia le immagini di riferimento. 7. src/backend/api/routers/vision.py:67-72 — `lot_number`/`serial_number` senza max_length (→ 500 su MySQL strict), `execute` non controlla `task_type`, versione corrente, ricetta attiva. 8. .gitignore:32-41 — `uploads/vision/` e `uploads/<recipe_id>/<version_id>/` non ignorati. VERIFICATO: `git check-ignore` → rc=1. 9. src/backend_temp/requirements.txt — residuo tracciato, non citato da nessuno. 10. nginx/nginx.conf:54-59,19-22 — la location regex delle estensioni statiche ha precedenza su `/api/`; il suo `add_header` annulla gli header di sicurezza; `/uploads/` punta a una rotta che il backend non ha. PRESUNTO. 11. docker-compose.yml:91-98 — label Traefik v1/v2 (`SSLRedirect`, `browserXSSFilter`), middleware solo su tmflow-web, dominio cablato. PRESUNTO (versione Traefik non verificata). 12. README.md:463-470 ; pyproject.toml:3 ; CLAUDE.md — README dice «390 pass, 1 fail», oggi 391 passed 4 skipped 0 failed; `version = "2.0.0"` sul ramo V3.0.0; i test di visione su Python 3.11 vengono saltati in silenzio («2 skipped»), girano solo con `--python 3.13 --extra vision-worker` (8 passed). 13. docker-compose.yml:54-69 — il container `vision` non ha volumi: un grafo con `dxf_path` non è eseguibile; GIF/WebP animati misurati sul primo frame; `convert("L")` riduce a 8 bit i PNG a 16. ORIGINE: revisione fable del 21/09/2026 su ramo `V3.0.0`, commit 8cc5e82. Documento completo: `_output/2026-09-21-TieMeasureFlow-revisione.md` su Wasabi.
Adriano added the bug label 2026-09-21 20:14:55 +00:00
Adriano added the assegnata:jeeg label 2026-09-21 20:23:33 +00:00
Author
Owner

⚡ jeeg — preso in carico 2026-09-21T20:23:34Z
ramo: lavoro/jeeg · capacità: docker, gpu, systemd

⚡ jeeg — **preso in carico** 2026-09-21T20:23:34Z ramo: `lavoro/jeeg` · capacità: docker, gpu, systemd
Author
Owner

ANALISI (passo 1) — ramo lavoro/jeeg, worktree ~/lavoro/TieMeasureFlow su jeeg, lotto C1+C2

MODIFICHE C1 (codice visione), punti 5, 6, 7 dell'issue:
5. src/backend/services/vision_service.py:208-224 — scrivi il file DOPO il flush riuscito, e cancellalo se il commit successivo fallisce (try/except attorno, o scrivi su nome temporaneo e rinomina dopo flush). src/backend/api/routers/vision.py — aggiungi GET /api/vision/reference-images?task_id= (lista) e DELETE /api/vision/reference-images/{id} (Maker; cancella riga e file).
6. nuova migrazione 014_vision_fk_ondelete.py (down_revision = l'attuale head 013): vision_results.task_id e vision_reference_images.task_id con ondelete="CASCADE" (batch_alter_table per compatibilità SQLite), e stessi ondelete nei modelli src/backend/models/orm/vision.py. Alla cancellazione di un task i file di riferimento su disco vanno rimossi: fallo nel service di cancellazione solo se esiste un punto unico in vision_service; altrimenti MANCA. _copy_tasks_to_version (recipe_service.py) NON si tocca qui: scrivi MANCA «le immagini di riferimento non seguono la nuova versione».
7. src/backend/api/routers/vision.py:67-72 — lot_number/serial_number max_length=100; production_run_id gt=0 e validato con validate_run_for_version di measurement_service (la crea il lotto A1: se al momento non esiste, importala in modo tollerante NO — aspetta: usa un controllo locale equivalente e scrivi nel rapporto che va unificato); execute rifiuta 422 se task.task_type != "camera_measure", 409 se la versione non è corrente o la ricetta non attiva.
MODIFICHE C2 (deploy/repo), punti 1-4, 8-13:

  1. Dockerfile, Dockerfile.frontend, Dockerfile.vision: utente non root (useradd -u 10001 app, chown di /app e /app/uploads, USER app).
  2. pin: ghcr.io/astral-sh/uv:<versione esplicita> (usa quella di uv --version locale), basi python con tag patch esplicito; Node da immagine ufficiale multi-stage invece di curl | bash se fattibile senza riscrivere, altrimenti MANCA.
  3. compose (prod e dev): healthcheck su server (/api/health o la rotta di salute esistente: verificala in src/backend/main.py) e client; depends_on con condition: service_healthy; WEB_CONCURRENCY=4 e TRUSTED_PROXY_COUNT=1 nell'environment del server (li legge il lotto A2).
  4. SESSION_COOKIE_SECURE: nuova env SESSION_COOKIE_SECURE (default true) in docker-compose.dev.yml/.env.example documentata per l'on-premise HTTP; la lettura in src/frontend/flask_app/config.py è del lotto B2 → scrivi la variabile nei compose e avvisa nel rapporto.
  5. .gitignore: uploads/* con eccezione .gitkeep al posto dell'elenco.
  6. git rm src/backend_temp/requirements.txt.
  7. nginx/nginx.conf: la location delle estensioni statiche limitata a ^/static/; header di sicurezza ripetuti dove c'è add_header; rimuovi location /uploads/ se il backend non la serve (verificato: nessun mount) e il PathPrefix /uploads/ di Traefik.
  8. docker-compose.yml: label Traefik v3 (stsSeconds, contentTypeNosniff, frameDeny; niente SSLRedirect/browserXSSFilter), middleware anche su tmflow-api, dominio da ${APP_DOMAIN:?}.
  9. README.md conteggi test aggiornati con il comando e l'ambiente; pyproject.toml version = "3.0.0" (poi uv lock se il lock riporta la versione); documenta il comando dei test di visione su Python 3.13.
  10. docker-compose*.yml: volume uploads in sola lettura montato nel container vision. GIF/WebP animati: MANCA (decisione di prodotto).
ANALISI (passo 1) — ramo `lavoro/jeeg`, worktree `~/lavoro/TieMeasureFlow` su jeeg, lotto C1+C2 MODIFICHE C1 (codice visione), punti 5, 6, 7 dell'issue: 5. src/backend/services/vision_service.py:208-224 — scrivi il file DOPO il flush riuscito, e cancellalo se il commit successivo fallisce (try/except attorno, o scrivi su nome temporaneo e rinomina dopo flush). src/backend/api/routers/vision.py — aggiungi `GET /api/vision/reference-images?task_id=` (lista) e `DELETE /api/vision/reference-images/{id}` (Maker; cancella riga e file). 6. nuova migrazione `014_vision_fk_ondelete.py` (down_revision = l'attuale head 013): `vision_results.task_id` e `vision_reference_images.task_id` con `ondelete="CASCADE"` (batch_alter_table per compatibilità SQLite), e stessi `ondelete` nei modelli src/backend/models/orm/vision.py. Alla cancellazione di un task i file di riferimento su disco vanno rimossi: fallo nel service di cancellazione solo se esiste un punto unico in vision_service; altrimenti MANCA. `_copy_tasks_to_version` (recipe_service.py) NON si tocca qui: scrivi MANCA «le immagini di riferimento non seguono la nuova versione». 7. src/backend/api/routers/vision.py:67-72 — `lot_number`/`serial_number` `max_length=100`; `production_run_id` `gt=0` e validato con `validate_run_for_version` di measurement_service (la crea il lotto A1: se al momento non esiste, importala in modo tollerante NO — aspetta: usa un controllo locale equivalente e scrivi nel rapporto che va unificato); `execute` rifiuta 422 se `task.task_type != "camera_measure"`, 409 se la versione non è corrente o la ricetta non attiva. MODIFICHE C2 (deploy/repo), punti 1-4, 8-13: 1. Dockerfile, Dockerfile.frontend, Dockerfile.vision: utente non root (`useradd -u 10001 app`, chown di /app e /app/uploads, `USER app`). 2. pin: `ghcr.io/astral-sh/uv:<versione esplicita>` (usa quella di `uv --version` locale), basi python con tag patch esplicito; Node da immagine ufficiale multi-stage invece di `curl | bash` se fattibile senza riscrivere, altrimenti MANCA. 3. compose (prod e dev): healthcheck su server (`/api/health` o la rotta di salute esistente: verificala in src/backend/main.py) e client; `depends_on` con `condition: service_healthy`; `WEB_CONCURRENCY=4` e `TRUSTED_PROXY_COUNT=1` nell'environment del server (li legge il lotto A2). 4. SESSION_COOKIE_SECURE: nuova env `SESSION_COOKIE_SECURE` (default true) in docker-compose.dev.yml/.env.example documentata per l'on-premise HTTP; la lettura in src/frontend/flask_app/config.py è del lotto B2 → scrivi la variabile nei compose e avvisa nel rapporto. 8. .gitignore: `uploads/*` con eccezione `.gitkeep` al posto dell'elenco. 9. `git rm src/backend_temp/requirements.txt`. 10. nginx/nginx.conf: la location delle estensioni statiche limitata a `^/static/`; header di sicurezza ripetuti dove c'è `add_header`; rimuovi `location /uploads/` se il backend non la serve (verificato: nessun mount) e il PathPrefix `/uploads/` di Traefik. 11. docker-compose.yml: label Traefik v3 (`stsSeconds`, `contentTypeNosniff`, `frameDeny`; niente `SSLRedirect`/`browserXSSFilter`), middleware anche su tmflow-api, dominio da `${APP_DOMAIN:?}`. 12. README.md conteggi test aggiornati con il comando e l'ambiente; pyproject.toml `version = "3.0.0"` (poi `uv lock` se il lock riporta la versione); documenta il comando dei test di visione su Python 3.13. 13. docker-compose*.yml: volume uploads in sola lettura montato nel container `vision`. GIF/WebP animati: MANCA (decisione di prodotto).
Author
Owner

Soluzione

ESITO: fatto
COSA: 1 utente non root 10001 nelle tre immagini (build e run verificati); 2 basi e uv pinnati, Node da stage ufficiale; 3 healthcheck e service_healthy; 4 SESSION_COOKIE_SECURE da env (false per on-premise HTTP — da provare con un tablet da Tràfilo); 5 file di riferimento scritto dopo il flush, GET/DELETE delle immagini; 6 FK ON DELETE CASCADE (migrazione 014) e immagini di riferimento copiate nel copy-on-write, file cancellato solo se non più referenziato; 7 limiti e gate su execute; 8 .gitignore uploads/*; 9 backend_temp rimosso; 10 nginx: statiche solo ^/static/, header ripetuti, /uploads/ tolta; 11 label Traefik v3, SAMEORIGIN, dominio da APP_DOMAIN; 12 versione 3.0.0 e conteggi README; 13 volume uploads in sola lettura nel worker. Restano in issue nuova: file orfani su delete_task, GIF/WebP animati.
COMMIT (ramo lavoro/jeeg, unito su V3.0.0 a d483fa1): d483fa1; 48c47e8; 96dd8d6; e10585a; 8b43e7a; 12d5b7e; 54bc384; 65f6a4b; 1c5292d; 1576fa1; b024724; 10261b6; 7a21ec4; 1921bc3; ac9bc14; d1833ba; 48089bc; a6d555d
PROVA: uv run --extra server --extra client --extra dev pytest -q → 622 passed, 4 skipped (erano 391); visione su Python 3.13 → 16 passed (erano 8).

**Soluzione** ESITO: fatto COSA: 1 utente non root 10001 nelle tre immagini (build e run verificati); 2 basi e uv pinnati, Node da stage ufficiale; 3 healthcheck e `service_healthy`; 4 `SESSION_COOKIE_SECURE` da env (false per on-premise HTTP — da provare con un tablet da Tràfilo); 5 file di riferimento scritto dopo il flush, GET/DELETE delle immagini; 6 FK `ON DELETE CASCADE` (migrazione 014) e immagini di riferimento copiate nel copy-on-write, file cancellato solo se non più referenziato; 7 limiti e gate su execute; 8 .gitignore `uploads/*`; 9 backend_temp rimosso; 10 nginx: statiche solo `^/static/`, header ripetuti, `/uploads/` tolta; 11 label Traefik v3, SAMEORIGIN, dominio da APP_DOMAIN; 12 versione 3.0.0 e conteggi README; 13 volume uploads in sola lettura nel worker. Restano in issue nuova: file orfani su delete_task, GIF/WebP animati. COMMIT (ramo lavoro/jeeg, unito su V3.0.0 a d483fa1): d483fa1; 48c47e8; 96dd8d6; e10585a; 8b43e7a; 12d5b7e; 54bc384; 65f6a4b; 1c5292d; 1576fa1; b024724; 10261b6; 7a21ec4; 1921bc3; ac9bc14; d1833ba; 48089bc; a6d555d PROVA: `uv run --extra server --extra client --extra dev pytest -q` → 622 passed, 4 skipped (erano 391); visione su Python 3.13 → 16 passed (erano 8).
Adriano removed the assegnata:jeeg label 2026-09-21 21:56:46 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Adriano/TieMeasureFlow#38