Skip to content

3. Rollback e2e + hardening

Omisen edited this page Jul 26, 2026 · 4 revisions

L'ultima fase: da "funziona nei test" a "pronto per una macchina reale". Non aggiunge funzionalità pericolose — aggiunge garanzie e chiude i debiti. Vive in tests/rollback_e2e.rs, src/logging.rs, src/lockfile.rs, e nei due TODO chiusi.

È la chiusura del cerchio aperto all'inizio: la promessa "o l'installazione riesce, o il sistema torna esattamente com'era" diventa una proprietà verificata, non un'intenzione.


Rollback end-to-end (il cuore, G7)

Finora ogni undo era testato in isolamento. Qui si testa la proprietà emergente del rollback sull'intera sequenza: inietti un fallimento allo step N e verifichi che la catena 0..N-1 si annulli riportando il sistema allo stato pre-installazione.

SystemModel: un modello stateful del sistema

A differenza del mock che registra le operazioni, il SystemModel modella uno stato coerente (utenti, pacchetti, servizi enabled/active, ruoli/DB, file/symlink e contenuti, regole ufw). Ogni mutazione aggiorna lo stato; ogni undo lo ripristina; tutti gli step di una sequenza condividono lo stesso modello. Così "tornato al vergine" è verificabile alla lettera:

stato_finale == stato_iniziale

Gli scenari

Scenario Cosa dimostra
Catena completa + fallimento finale rollback dell'intera sequenza → stato identico; il .bashrc byte-per-byte
Fallimento a metà (dopo utente/deps/postgres/ruolo/DB) tutto ciò che era stato creato sparisce
Risorse preesistenti del cliente l'hard-stop init ferma la catena; il rollback non tocca nulla di preesistente

Lo scenario delle risorse preesistenti è la prova delle tre protezioni come proprietà dell'intera catena, non del singolo step: partendo da un sistema con PostgreSQL installato+attivo e un database odoo che esiste già (dati del cliente), dopo il rollback:

  • il DB del cliente NON viene droppato (anti-drop, Fase 5);
  • PostgreSQL resta installato (D3) e il servizio già attivo resta attivo (D4);
  • /opt/odoo preesistente resta.

È il momento in cui l'installer diventa sicuro da puntare a una macchina reale.


Logging su file (G1)

tracing con due layer: TTY (con colori, coordinato con la barra) + file senza ANSI (/opt/odoo/.installer.log, writer non-bloccante). Cattura l'intera esecuzione (INFO+), errori e rollback inclusi — l'artefatto da farsi mandare per il post-mortem. Degrada a TTY-only se il path non è scrivibile (dry-run senza root), senza fallire. La password non vi finisce mai (garantito dal Secret).


Lockfile anti-concorrenza (G5)

Un flock esclusivo non-bloccante (via nix) su /opt/odoo/.installer.lock, con guard RAII: il rilascio avviene su successo, errore o panic (Drop). Una seconda esecuzione simultanea → errore chiaro "un'altra installazione è in corso", senza mutare nulla. Acquisito dopo i preflight e prima di ogni mutazione; saltato in dry-run.


Chiusura dei due TODO

Checksum wkhtmltopdf — decisione TOFU (trust-on-first-use)

La release ufficiale wkhtmltopdf/packaging non pubblica checksum né firme per i .deb (solo il tag git è firmato GPG). Non esiste quindi un checksum upstream.

Decisione onesta: pinning manuale TOFU. Il meccanismo fail-closed di 1.5 resta invariato; la tabella default_checksums() va popolata con pin generati una volta da fonte fidata (HTTPS ufficiale). Da lì l'installer verifica ogni download contro il tuo pin — protegge da mirror compromessi, download corrotti e alterazioni successive, anche senza una firma upstream. Sono pin TOFU, non checksum ufficiali: la documentazione lo dichiara, con la procedura per generarli/aggiornarli. Finché la tabella è vuota, il fail-closed rifiuta l'installazione — comportamento onesto, mai bypassato.

Cautela cluster PostgreSQL

Il TODO di 1.6 SetupPostgres: anche con --aggressive-rollback, prima di purgare PostgreSQL si verifica (best-effort) che il cluster non ospiti altri database oltre al nostro. Se ne trova → purge declinato con warning (stop+disable comunque applicati); se l'elenco non è ottenibile → fail-safe (non purga). La decisione è presa prima dello stop, perché elencare i DB richiede un postgres attivo.


Note di design

  • Lockfile e logging vivono in main/moduli dedicati; il trait Step e il motore restano intatti.
  • I test e2e girano interamente su SystemModel — senza sistema reale, senza root.
  • Con questa fase il progetto è funzionalmente completo. Resta solo l'epilogo: documentazione.

Clone this wiki locally