From 90514636545ada5b2da449e444816270a9f7150e Mon Sep 17 00:00:00 2001 From: Codex Date: Sun, 13 Sep 2026 17:28:10 +0200 Subject: [PATCH] docs: document full and embedded rendering with server authentication --- AGENTS.md | 5 + PROJECT_STATE.md | 19 +- README.md | 14 +- deploy/psd/thothii-installation.yaml.example | 4 + docs/architecture/application-shell.md | 130 ++++++++++++ docs/architecture/authentication.md | 49 ++++- docs/architecture/components.md | 8 + docs/architecture/overview.md | 11 +- docs/contracts/portal-shell-adapter-v1.md | 35 +++- docs/guida-utente.md | 23 ++- docs/index.md | 4 + docs/install/authentication-local.md | 12 +- docs/install/authentication-oidc.md | 23 +++ docs/install/authentication-upstream.md | 186 ++++++++++++++++++ docs/install/authentik.md | 11 +- .../examples/thothii-installation.local.yaml | 3 + .../examples/thothii-installation.server.yaml | 5 + docs/install/first-start.md | 14 +- docs/installazione-docker-4-contesti.md | 8 + .../server-upgrade-gitea-workspace-v2.md | 20 +- docs/operations/shell-and-localization.md | 136 ++++++++++++- .../authentication-manual-acceptance.md | 86 ++++++++ mkdocs.yml | 3 + tools/tht/README.md | 5 + 24 files changed, 789 insertions(+), 25 deletions(-) create mode 100644 docs/architecture/application-shell.md create mode 100644 docs/install/authentication-upstream.md create mode 100644 docs/testing/authentication-manual-acceptance.md diff --git a/AGENTS.md b/AGENTS.md index be29bc0b..f397b6f7 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -102,6 +102,11 @@ frontend (React/SSE) → backend (Fastify) → pi --mode rpc → tht/harness → model interaction uses the session manifest's immutable `interaction_language`. Workspace content, SQL, and identifiers remain unchanged. For shell modes, portal integration, or translations, read `docs/operations/shell-and-localization.md`. +- **Server identity:** for portal login/logout, proxy headers, or Omics deploy, read + `docs/install/authentication-upstream.md` before changing authentication. Omics + uses embedded/upstream, not a second ThothII OIDC login. Full/embedded rendering + is documented in `docs/architecture/application-shell.md`; release acceptance + is in `docs/testing/authentication-manual-acceptance.md`. - **Workspace schema v4** defines workspace identity and optional Evidence only. PostgreSQL Metadata Catalog owns database identity, binding, schema, descriptions, sensitivity, and relationships; embedding/model facts come from the installation catalog. The legacy `harness/workspaces/*.yaml` runtime snapshots still use diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index 1d764efc..c4ac82e2 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -17,13 +17,28 @@ requirements as mandatory; do not replace the running server stack in place. Full/embedded shell, EN/IT UI, immutable session interaction language, dark theme, fullscreen and full-mode logout are implemented. The local Mac descriptor explicitly sets `shell.mode: full` and `shell.defaultLocale: en`; the native `tht` and local -core/frontend images were updated on 2026-09-13. Omics remains embedded and server -verified, through the replaceable presentation-only PortalAdapter. Its changes are +core/frontend images were updated on 2026-09-13. Omics uses embedded with server-side +identity verification and a replaceable presentation-only PortalAdapter; this does +not mean this branch was verified on the production server. Its changes are in Omics commit `95154e1`; production deployment remains pending. See `docs/operations/shell-and-localization.md` for integration and installation instructions and `docs/reports/2026-09-13-full-shell-implementation.md` for tests, independent reviews, local browser checks and rollback details. +### Documentation handoff before branch closure — 2026-09-13 + +Current rendering architecture is in `docs/architecture/application-shell.md`; +the exact portal identity/proxy contract is in `docs/install/authentication-upstream.md`. +`docs/operations/shell-and-localization.md` is the configuration and coordinated +Omics delivery/deploy runbook, including server-side fetch GitHub → explicit push +Gitea PSD from `/home/chirone/omics_portal`. The acceptance matrix is +`docs/testing/authentication-manual-acceptance.md`. README, documentation navigation, +user/installation/authentication guides and descriptor examples point to these +paths. Local examples explicitly use full/en; the projected server example is +for standalone OIDC, not Omics upstream. No runtime configuration or deployment +was changed by this documentation pass. Closing/merging the branch and actual +PSD acceptance remain separate, unperformed steps. + ### Agreed Omics delivery route — 2026-09-13 The owner approved GitHub as an intermediate transport for Omics: publish only diff --git a/README.md b/README.md index 3008e41e..ed976785 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,18 @@ ThothII is a human-reviewed NL-to-SQL workflow with a React frontend and a Fasti core. The portable deployment runs two application services plus the installation-local metadata catalog; DWH and LLM services remain external. Semantic services are bundled in Compose. -Authentication is configured through the single host CLI tht: see the [local authentication guide](docs/install/authentication-local.md), -[generic OIDC guide](docs/install/authentication-oidc.md), and [manual acceptance matrix](docs/testing/authentication-manual-acceptance.md). +The same frontend supports **full** (its own header) and **embedded** (inside a +portal). This choice is independent of authentication: the Mac uses full/local, +Omics uses embedded/upstream with its existing login, and a standalone server +can use full/OIDC. See [rendering architecture](docs/architecture/application-shell.md) +and [configuration, Omics delivery and deploy](docs/operations/shell-and-localization.md). + +Local/OIDC authentication is configured through the host CLI `tht`; portal +authentication is established by the trusted server proxy. See the +[local guide](docs/install/authentication-local.md), +[OIDC guide](docs/install/authentication-oidc.md), +[upstream integration](docs/install/authentication-upstream.md), and +[manual acceptance matrix](docs/testing/authentication-manual-acceptance.md). ## Docker Compose: local startup diff --git a/deploy/psd/thothii-installation.yaml.example b/deploy/psd/thothii-installation.yaml.example index 4f4b653c..39634fb7 100644 --- a/deploy/psd/thothii-installation.yaml.example +++ b/deploy/psd/thothii-installation.yaml.example @@ -2,6 +2,10 @@ # Replace every absolute path before using this as an advanced reference. schemaVersion: 2 profile: local +# Mac standalone example; the Omics server requires embedded/upstream separately. +shell: + mode: full + defaultLocale: en projectDirectory: "/projects/ThothII" envFile: "/projects/ThothII/deploy/psd/operator.env" workspaceRepository: diff --git a/docs/architecture/application-shell.md b/docs/architecture/application-shell.md new file mode 100644 index 00000000..66cbe8eb --- /dev/null +++ b/docs/architecture/application-shell.md @@ -0,0 +1,130 @@ +# Rendering full ed embedded + +ThothII ha una sola applicazione React, una sola build Vite e gli stessi servizi +backend. «Doppio rendering» significa due modi di ospitare quella applicazione, +non due versioni delle pagine e non rendering React sul server. Django renderizza +il contenitore Omics; React renderizza ThothII nel browser, dentro `#root`. + +## Tre decisioni indipendenti + +| Decisione | Configurazione | Effetto | +| --- | --- | --- | +| Distribuzione | `profile: local` oppure `server` | Compose, percorsi e vincoli operativi | +| Presentazione | `shell.mode: full` oppure `embedded` | Proprietario di header e preferenze | +| Autenticazione | `auth.yaml` local/OIDC oppure `AUTH_MODE=upstream` | Chi verifica l'identità, come arriva al backend | + +Il Mac usa **full + local**, con lingua iniziale inglese. L'integrazione Omics +usa **embedded + upstream**, con accesso già verificato dal portale. Un server +autonomo può usare **full + oidc**. Cambiare `shell.mode` non abilita un metodo +di autenticazione e non modifica permessi o proprietari delle sessioni. + +Full con upstream può visualizzare un'identità già verificata dal proxy, ma non +ha un logout ThothII disponibile: non è il profilo autonomo con login/logout. +Embedded non avvia login locale o OIDC anche se il backend è configurato così; +questa combinazione non realizza il login unico Omics e non va usata come fallback. + +## Composizione comune + +```mermaid +flowchart TD + CONFIG["config.js pubblico"] --> SHELL["ShellProvider"] + FULL["Preferenze full nel browser"] --> SHELL + HOST["Documento Omics"] --> ADAPTER["OmicsPortalAdapter: solo presentazione"] + ADAPTER --> SHELL + SHELL --> GATE["AuthGate: verifica GET /me"] + GATE --> APP["AppShell: stesse pagine, sessioni e amministrazione"] + AUTH["Backend: cookie locale/OIDC o identità upstream"] --> GATE +``` + +`ShellProvider` risolve la configurazione, applica lingua/tema e monta i contenuti +solo dopo uno snapshot host valido in embedded. `AuthGate` verifica l'accesso; +`AppShell` e le pagine non devono leggere selettori o eventi specifici di Omics. +Il cambio utente smonta lo stato applicativo della precedente identità. + +## Full + +- Header ThothII rosso Omics `#CB333B` in entrambi i temi; logo interamente chiaro. +- Selettore EN/IT, tema light/dark, fullscreen e nome verificato dell'utente. +- Menu del nome con logout soltanto per local/OIDC; nessuna rotellina admin. + L'amministrazione resta nella navigazione applicativa, secondo i permessi. +- Margine sinistro vuoto e simmetrico al destro: `max(20px, 1.5rem)`, normalmente + 24px con radice a 16px. Non è una seconda sidebar di navigazione. +- Lingua e tema ricordati sullo stesso origin in `localStorage`, nelle chiavi + `thothii:shell:locale` e `thothii:shell:theme`. Non sono preferenze server per + utente. In assenza di preferenze: `defaultLocale` e tema light. +- Fullscreen usa `document.documentElement.requestFullscreen()` e + `document.exitFullscreen()`: nasconde il contorno del browser dove supportato. + L'icona cambia sullo stato reale, anche dopo Esc; un rifiuto mostra un errore. + Non è un semplice ingrandimento CSS e non scatta automaticamente all'accesso. + +## Embedded + +- Nessun header ThothII, selettore lingua, toggle tema, login o logout autonomo. + I controlli rimangono nell'header generale Omics. +- React è nello stesso documento della pagina `/kokoro/datamart-builder/`, non + in un iframe. Non serve `postMessage` né un secondo protocollo di sessione. +- L'adapter legge la lingua Django già confermata, osserva il tema del documento + e ascolta il fullscreen reale. Le azioni rimangono di proprietà del portale. +- Un contesto Omics mancante o invalido mostra un errore d'integrazione; non + passa silenziosamente a full e non offre un secondo login. +- Il portale assegna l'altezza disponibile sotto il proprio header: catena flex + con `min-height: 0`, root contenuto e altezza applicativa vincolata al contenitore. + Il contratto ThothII espone `--thoth-app-height` (fallback `100dvh`); verificare + il contenitore reale, non presumere che l'intera viewport appartenga a React. + Il template Omics mantiene inoltre i suoi override di compatibilità. + +Il reset CSS è limitato al mount React e ai popup dell'applicazione, senza +richiedere CSS `@scope`. I token e i popup seguono il tema applicativo. Questo +non rende indipendenti fogli di stile arbitrari caricati dal portale: la verifica +del documento condiviso rimane necessaria a ogni integrazione. + +## Caricamento e configurazione pubblica + +Il descrittore installato è la sorgente di verità. Il CLI genera +`generated/frontend/config.js` e il suo mount di sola lettura nella proiezione +`generated/compose.models.yaml`. Il file pubblico contiene solo `backendBaseUrl` +e `shell`, mai identità, token, password o percorsi host. Va caricato **prima** del +modulo React e servito senza cache. Nessuna build separata è richiesta per +cambiare modalità; occorre rigenerare e applicare i mount tramite il lifecycle. + +L'ordine Omics è: config pubblico → override del solo prefisso API → asset dal +manifest Vite. L'override deve conservare `shell`; l'adapter non configura il proxy. +Il default completo di shell omessa è embedded/en/omics-portal. Il CLI normalizza +anche singoli campi omessi; un oggetto `shell` scritto manualmente nel browser +deve invece contenere `mode` e `defaultLocale`, altrimenti viene rifiutato. + +## Lingua, continuità e dati + +La lingua UI traduce il testo dell'applicazione, non i contenuti di dominio. +Alla creazione, la lingua UI viene acquisita come `interactionLanguage`; il +manifest salva `interaction_language`, che governa domande e scelte del modello. +Alla ripresa vale la lingua salvata, non l'ultima scelta dell'header. Per i manifest +precedenti senza campo viene fissata la lingua workspace disponibile alla prima ripresa. + +Il cambio lingua Omics invia il form Django e ricarica la pagina. ThothII conserva +solo l'ID della selezione in `sessionStorage`, separato per pathname, issuer e +subject. Riapre i documenti, non avvia una generazione. Bozze non inviate e modifiche +non salvate richiedono conferma prima della navigazione; non sono una trascrizione +salvata. La ripresa operativa resta esplicita. + +## Punti di implementazione e manutenzione + +| Sorgente | Responsabilità | +| --- | --- | +| `tools/tht/internal/config/shell.go` | Normalizzazione e validazione del descrittore | +| `tools/tht/internal/modelprojection/projection.go` | Config pubblico e mount generati | +| `frontend/src/api/runtime-config.ts` | Validazione browser e prefisso API same-origin | +| `frontend/src/shell/host/ShellProvider.tsx` | Composizione, preferenze e tema | +| `frontend/src/shell/host/FullHeader.tsx` | Controlli solo full | +| `frontend/src/shell/host/OmicsPortalAdapter.ts` | Conoscenza del documento Omics | +| `frontend/src/auth/AuthGate.tsx` | Accesso e ricontrolli al ritorno alla pagina | +| `backend/src/auth/auth.ts` e `principal.ts` | Verifica server dell'identità | + +Per un altro portale servono un'implementazione del +[PortalAdapter](../contracts/portal-shell-adapter-v1.md), la sua registrazione nei +validatori CLI/browser e nel punto di composizione, oltre al +[contratto di autenticazione server](../install/authentication-upstream.md). +Il nome di una classe non è un plugin caricabile dinamicamente da YAML. + +Procedure: [configurazione e deploy](../operations/shell-and-localization.md), +[autenticazione](authentication.md), [accettazione](../testing/authentication-manual-acceptance.md). diff --git a/docs/architecture/authentication.md b/docs/architecture/authentication.md index f7e77731..4d5f74ea 100644 --- a/docs/architecture/authentication.md +++ b/docs/architecture/authentication.md @@ -1,18 +1,27 @@ # Authentication architecture -ThothII has two production authentication modes: `local` and generic `oidc`. The host operator -surface is one CLI, `tht`; there is no separate authentication executable. The backend owns -opaque browser sessions and authorization, while `tht` owns protected configuration and local-user -files. +ThothII supports `local` and generic `oidc` through protected `auth.yaml`, plus +the trusted-proxy `upstream` path used by Omics. The host operator surface is +one CLI, `tht`; there is no separate authentication executable. The backend owns +authorization in all paths and opaque browser sessions only in local/OIDC. +`tht` owns protected local/OIDC configuration and local-user files; upstream +identity is supplied per request by the authenticated server proxy. + +Presentation is separate: [full/embedded rendering](application-shell.md) does +not select authentication. The Mac uses full/local; Omics uses embedded/upstream; +a standalone server can use full/OIDC. Do not configure a second ThothII OIDC +login simply because Omics itself authenticates users through Authentik. ```mermaid flowchart TB BROWSER["Browser"] --> BOUNDARY["Authentication boundary"] BOUNDARY --> LOCAL["Local users\nArgon2id hashes"] BOUNDARY --> OIDC["OIDC provider\nAuthorization Code PKCE"] + BOUNDARY --> UPSTREAM["Trusted proxy\nVerified portal session"] OIDC --> GROUPS["Groups claim\nexact mapping"] LOCAL --> PRINCIPAL["Thoth principal"] GROUPS --> PRINCIPAL + UPSTREAM --> PRINCIPAL PRINCIPAL --> ROLES["Roles"] ROLES --> PERMISSIONS["Permissions"] PERMISSIONS --> ROUTES["Protected routes"] @@ -21,6 +30,13 @@ flowchart TB ## Configuration and trust boundaries +The following protected-file configuration applies to local/OIDC. Upstream uses +`AUTH_MODE=upstream` without a mounted `auth.yaml` or authentication runtime +projection. The backend refuses both authorities together. `AUTH_MODE=none` +and `mock` are development/test modes, not production fallbacks. The exact +upstream setup, header contract, proxy hops and origin checks are in the +[server integration guide](../install/authentication-upstream.md). + The installation descriptor points to an operator-controlled authentication directory. It contains non-secret `auth.yaml` and, for local mode, `users.yaml`. POSIX installations use a private directory and owner-only regular files; Windows uses equivalent owner-only ACLs. Secret values are @@ -49,6 +65,10 @@ Authentik is the first certified group-catalog adapter, not a special browser lo ## Group authorization +This section describes **ThothII's direct OIDC login**, not the embedded Omics +path. Omics checks its own capability and administrator status and supplies +normalized identity headers; ThothII does not repeat the OIDC groups exchange. + OIDC must return a direct, non-empty `groups` claim whose value is a JSON array of strings. Missing, malformed, indirect, or overage-style claims fail closed. The browser callback returns HTTP 401 with the generic code `oidc_callback_failed`; it does not expose the internal reason. @@ -100,6 +120,10 @@ prerequisite fails. ## Browser sessions +This section applies only to **local and direct OIDC**. Upstream reuses the +portal's authenticated session at the proxy boundary, not a ThothII cookie; +its `/me` response has `session: null` and `csrfToken: null`. + The browser receives only an opaque `HttpOnly`, `SameSite=Lax` cookie named `thothii_session`. State-changing cookie requests require the in-memory CSRF token, same-origin `Origin`, and Fetch Metadata checks when present. The frontend never stores bearer tokens or session secrets in Web @@ -116,5 +140,20 @@ affected sessions. Authentication configuration revision changes invalidate all reload. Logout deletes the server record. Backup restore excludes active sessions and OIDC state, recreates empty private auth-state directories, and therefore forces reauthentication. +Full local/OIDC logout calls `POST /auth/logout`, revokes the server session and +clears its cookie. It does not call the identity provider's global logout. If the +provider still has an SSO session, the next OIDC login can complete without +another password prompt. Embedded has no ThothII logout control: use the portal. + +## Access revalidation + +The frontend treats `/me` as the access authority. In embedded it does not fetch +`/auth/config` or offer local/OIDC login. On focus, pageshow, visibility return +and event-stream reconnection it rechecks access. A 401/403 from this probe clears +protected state; a 403 on one operation is not automatically an app-wide logout. +Neither the DOM adapter nor the proxy's initial SSE check guarantees instantaneous +revocation of streams already open in other tabs. + See the [local guide](../install/authentication-local.md), [generic OIDC guide](../install/authentication-oidc.md), -and [Authentik guide](../install/authentik.md) for operator procedures. +[Authentik guide](../install/authentik.md), [upstream integration](../install/authentication-upstream.md), +and [manual acceptance matrix](../testing/authentication-manual-acceptance.md). diff --git a/docs/architecture/components.md b/docs/architecture/components.md index 47906fb6..d8ff4a0b 100644 --- a/docs/architecture/components.md +++ b/docs/architecture/components.md @@ -44,6 +44,14 @@ Dipendenze principali: ## Session sequence +The shared frontend is wrapped by `ShellProvider` (full preferences or a +replaceable portal presentation adapter), then `AuthGate` (backend identity), +then `AppShell`. Omics-specific DOM details belong only to `OmicsPortalAdapter`; +credentials and principal validation belong to the server, never that adapter. +Full/embedded do not duplicate the session workflow below. See +[rendering architecture](application-shell.md) and +[upstream identity](../install/authentication-upstream.md) for both boundaries. + The main path starts with a user question and ends with an SSE event. Reviewer decisions use the same channel and are persisted by the harness. ```mermaid diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index e7924292..e3b0941b 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -4,8 +4,11 @@ ThothII is a **human-in-the-loop datamart builder**. It turns a natural-language question into validated SQL, and optionally a dbt datamart, through a **deterministic eight-phase NL-to-SQL workflow** in which the model *proposes* and a human reviewer *decides* at gates. -Production authentication uses local authentication or generic OIDC. `tht` is the only operator CLI. -For sessions, roles, groups, diagnostics, and recovery, see the [authentication documentation](authentication.md). +Production authentication uses local authentication, generic OIDC, or the +trusted-proxy upstream path used by Omics. `tht` is the operator CLI for the +installation and local/OIDC configuration. For roles and recovery, see +[authentication](authentication.md). One React build supports full and embedded; +[rendering architecture](application-shell.md) separates presentation from identity. ```mermaid flowchart LR @@ -101,7 +104,9 @@ the core can admit a new session. - `tht -c`/`--config` is a **per-command** option. It must follow the subcommand, never precede it (`ThtRunner.buildArgv` enforces this). - `--json` output must be plain JSON on stdout. It is a machine-readable contract. -- UI strings are in English. Document *content* stays in the workspace language because it is the actual data; only chrome and labels are in English. +- UI strings support English and Italian, with English fallback. Session interaction language + is pinned at creation; document content remains in the workspace language. See + [shell and localization](../operations/shell-and-localization.md). - Each workspace defines identity and optional Evidence only. The PostgreSQL Metadata Catalog defines its DWH target and binding; secrets remain in the protected workspace secret store. - Settings are global (`backend/data/settings.json`: workspace/thinking); provider/model choices are diff --git a/docs/contracts/portal-shell-adapter-v1.md b/docs/contracts/portal-shell-adapter-v1.md index 65b99c6f..d57b9c17 100644 --- a/docs/contracts/portal-shell-adapter-v1.md +++ b/docs/contracts/portal-shell-adapter-v1.md @@ -24,6 +24,9 @@ shell: Se `shell` o `mode` sono omessi, la modalità è embedded. L'adapter embedded predefinito è `omics-portal`; un nome sconosciuto è un errore di configurazione. +Questi default sono normalizzati dal CLI prima della proiezione. Nel browser, +shell interamente omessa ha gli stessi default, ma un oggetto `shell` parziale +senza `mode` o `defaultLocale` viene rifiutato: non scrivere proiezioni a mano. Full non istanzia adapter. `defaultLocale` inizializza full; in embedded il locale proviene dal portale. L'autenticazione si configura separatamente dalla shell. @@ -59,9 +62,11 @@ L'integrazione monta React nel documento Django, non in un iframe. | Tema | `data-bs-theme` su `html` | osservazione limitata a quell'attributo | | Fullscreen | stato effettivo del documento | evento del browser, inclusa uscita con Esc | -L'attributo `lang` storicamente fisso a `en` nel template base non deve essere -usato come surrogato della lingua selezionata. Leggere il valore renderizzato dal -server evita anche di anticipare un cambio lingua prima che il form abbia successo. +Il template Omics aggiornato allinea anche `html lang` alla lingua Django, ma +la fonte dell'adapter rimane `select.omics-language-select[data-lang]`. Leggere +il valore renderizzato evita di anticipare un cambio lingua prima che il form +abbia successo. Cambiare soltanto `select.value` o `data-lang` senza il normale +reload non è un trasporto runtime implementato per la lingua. L'assenza del contesto host atteso produce un errore di integrazione; non abilita controlli locali. Non si introducono eventi `ready/state`, handshake, timeout, @@ -76,7 +81,7 @@ essere letti dai componenti applicativi. | Lingua | selettore locale | selettore Omics, normale reload Django | | Tema | toggle locale light/dark | stato Omics | | Fullscreen | controllo locale, stato reale | controllo Omics, stato reale | -| Login/logout | autenticazione ThothII configurata | autenticazione Omics esistente | +| Login/logout | ThothII local/OIDC; upstream non offre logout locale | autenticazione Omics esistente | | Nome utente | header ThothII | header Omics | | Rotellina amministrativa | mai | eventuale comando del portale | @@ -87,6 +92,12 @@ principal header normalizzati al backend ThothII. La UI usa `/me`; non effettua un secondo login. Un altro portale deve soddisfare anche questo contratto server, oltre a fornire una nuova implementazione dell'adapter UI. +Il [contratto upstream](../install/authentication-upstream.md) specifica header, +origine, rete e configurazioni incompatibili. Lo snapshot non può contenere +`authenticated`, utente, ruoli, cookie o token; un evento browser non autorizza +una richiesta API. Il prefisso API viene configurato separatamente prima del +caricamento React, non viene dedotto dall'adapter. + Il logout del portale segue la sua navigazione. Una perdita di accesso rilevata dal server chiude lo stato protetto; un 403 di una singola operazione non equivale automaticamente a logout. La riconnessione degli eventi e il ritorno alla pagina @@ -102,9 +113,23 @@ rimane quella registrata nel manifest, secondo ADR 0022. Un nuovo adapter può usare un diverso documento o trasporto, ma deve rispettare la stessa sottoscrizione e mantenere la conoscenza del portale nella propria -implementazione. Non occorre implementare ora iframe o un secondo portale. +implementazione. Oggi `ShellProvider` istanzia direttamente `OmicsPortalAdapter`: +per sostituirlo aggiornare quel punto e i nomi accettati in +`tools/tht/internal/config/shell.go` e `frontend/src/api/runtime-config.ts`. +Non è disponibile il caricamento dinamico di classi da una stringa YAML. +Non occorre implementare ora iframe o un secondo portale. + +La nuova implementazione deve pubblicare uno snapshot iniziale completo, poi gli +aggiornamenti; segnalare contesto invalido; liberare tutti i listener alla +disiscrizione. Locale ben formato ma non tradotto significa fallback inglese; +locale assente/malformato e tema diverso da light/dark sono errori di integrazione. +Non cambiare componenti applicativi o workflow per aggiungere selettori specifici +del nuovo portale. Verificare snapshot prima/dopo il montaggio, tema, fullscreen con Esc, cleanup, contesto host mancante, assenza di header ThothII embedded, accesso singolo, locale dopo reload e compatibilità del prefisso API. Full deve funzionare senza alcun elemento Omics presente. + +Vedere anche [architettura del rendering](../architecture/application-shell.md) +e [matrice di accettazione](../testing/authentication-manual-acceptance.md). diff --git a/docs/guida-utente.md b/docs/guida-utente.md index c7af470f..03f5d5ae 100644 --- a/docs/guida-utente.md +++ b/docs/guida-utente.md @@ -4,6 +4,26 @@ This guide is for a reviewer using a configured ThothII installation. Installati publication, preprocessing, and database administration are separate paths; links to them are at the end of this page. +## Standalone or inside Omics + +In **full** mode, ThothII has its own red header. Sign in using the installation's +local account or the configured identity provider. The header lets you select +English/Italian, light/dark, and fullscreen; Esc exits fullscreen. Open the user +name menu to log out of ThothII. OIDC logout does not necessarily log out other +applications using the same provider. + +In **embedded** mode, first sign in to Omics and choose **Datamart Builder** in +its left menu. ThothII opens with that authenticated identity: there is no second +login or duplicate header. Use Omics's language, theme, fullscreen and logout +controls. If portal access expires, return to Omics, sign in and reopen the page. + +The Mac starts in English unless the browser remembers another choice. Changing +the UI language affects labels, not saved domain content. A new session takes +the selected language for the model's questions and reviewer choices; an existing +session retains its saved language when resumed. Omics's language change reloads +the page: confirm or cancel any unsaved-work warning. Reopening the saved session +selection shows documents; it does not automatically restart generation. + ## Before creating a session An administrator must have selected a workspace and configured the installation-wide provider, @@ -56,4 +76,5 @@ happen from the workflow’s point of view. - To author material the workflow can retrieve, use [Evidence](evidence.md). A proposal from a session does not become Evidence automatically: a curator must review and publish it in Git. - For login and access recovery, use [local authentication](install/authentication-local.md) or - [OIDC authentication](install/authentication-oidc.md). + [OIDC authentication](install/authentication-oidc.md) for full, or contact the + portal administrator for [embedded/upstream access](install/authentication-upstream.md). diff --git a/docs/index.md b/docs/index.md index ffc5e74d..0950cbe2 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,6 +8,10 @@ Start with the path that matches the work you need to do: | I need to… | Start here | | --- | --- | | Install or operate one instance | [Install and first start](install/first-start.md) | +| Choose full/embedded and configure the shell | [Shell and localization](operations/shell-and-localization.md) | +| Reuse an authenticated server portal without a second login | [Upstream authentication](install/authentication-upstream.md) | +| Understand how the two renderings share the same application | [Rendering architecture](architecture/application-shell.md) | +| Validate login, logout and portal integration before release | [Acceptance matrix](testing/authentication-manual-acceptance.md) | | Add, update, or prepare a workspace | [Workspace operations](operations/workspaces.md) | | Ask a question and review the SQL workflow | [User guide](guida-utente.md) | | Configure and refresh an authoritative database catalog | [Database management](operations/database-management.md) | diff --git a/docs/install/authentication-local.md b/docs/install/authentication-local.md index 22e441b2..8dcfd589 100644 --- a/docs/install/authentication-local.md +++ b/docs/install/authentication-local.md @@ -1,6 +1,11 @@ # Local authentication -Use local mode for a standalone PC or Mac. Configure it through `tht`; passwords are entered at an +Use local mode for a standalone PC or Mac, with `shell.mode: full` and +`shell.defaultLocale: en` in the installation descriptor. Presentation and +authentication are independent: selecting full does not create accounts. Omics +embedded instead uses the [upstream guide](authentication-upstream.md), not local users. + +Configure local authentication through `tht`; passwords are entered at an echo-free prompt or read from a protected `--password-file`, never from a command argument. ## Bootstrap @@ -56,6 +61,11 @@ machine use; JSON output is pristine on stdout. ## Session behavior and recovery +Full shows its own login form and, after login, the verified display name in its +header. The name menu contains Log out. This sends a CSRF-protected request to +`/api/auth/logout`, revokes the session and returns to login. Language/theme +preferences may remain in the browser; they are not credentials. + An ordinary login expires after 2 hours idle or 12 hours absolute. Selecting **Remember me** makes the cookie persistent and changes the limits to 7 days idle or 30 days absolute. Remembered sessions survive a browser and backend restart, but not a user revision change, configuration diff --git a/docs/install/authentication-oidc.md b/docs/install/authentication-oidc.md index a970b675..84d42a46 100644 --- a/docs/install/authentication-oidc.md +++ b/docs/install/authentication-oidc.md @@ -1,10 +1,20 @@ # Generic OIDC authentication +Use this guide for **ThothII's own login**, normally `shell.mode: full` on an +autonomous server. It is not the integration procedure for an already logged-in +Omics user. That deployment uses [embedded/upstream](authentication-upstream.md), +even when Omics's identity provider is Authentik. + OIDC mode supports a standards-based provider. The browser flow is generic: Authorization Code, PKCE S256, state, nonce, issuer/signature/audience/expiry validation, and the fixed callback `/api/auth/oidc/callback`. The browser and API must use the same origin; configure the reverse proxy to preserve that public origin and callback path. +`publicUrl` is the public origin, without an application subpath. The current +full OIDC browser entry and callback use `/api/auth/oidc/login` and +`/api/auth/oidc/callback`; arbitrary prefixed OIDC hosting is not implemented by +selecting a different `backendBaseUrl`. + Configure the installation with `tht`: ```sh @@ -18,6 +28,9 @@ The OIDC client secret is supplied through the protected secret bundle under the `THT_OIDC_CLIENT_SECRET`; it is never written into `auth.yaml`. The default scopes are exactly `openid`, `profile`, and `email`. +Keep `AUTH_MODE` unset when using this file. A simultaneously mounted local/OIDC +configuration and `AUTH_MODE=upstream` is an error, not a fallback chain. + The non-secret OIDC configuration has this exact shape (replace angle-bracket placeholders with operator values): @@ -92,3 +105,13 @@ relevant diagnostic surface. The complete closed diagnostic-code union and exact role-to-permission expansion are in the [authentication architecture](../architecture/authentication.md). + +## Browser login and logout + +ThothII redirects the browser to the provider and creates its own opaque session +after validating the callback. An existing provider SSO session may avoid another +password prompt, but this remains a distinct ThothII login/session, unlike Omics +upstream. Full's name menu logs out of ThothII only. It does not revoke the +provider session or log out other applications, so a subsequent login can return +immediately through SSO. No provider token is placed in the UI adapter or browser +storage. See the [manual acceptance matrix](../testing/authentication-manual-acceptance.md). diff --git a/docs/install/authentication-upstream.md b/docs/install/authentication-upstream.md new file mode 100644 index 00000000..e0d60b09 --- /dev/null +++ b/docs/install/authentication-upstream.md @@ -0,0 +1,186 @@ +# Autenticazione tramite portale e proxy fidato + +Questa è la modalità **upstream** usata dall'integrazione Omics. Non è il login +OIDC diretto di ThothII: l'utente accede a Omics come già fa, poi sceglie +Datamart Builder e trova ThothII già autenticato. Non deve essere creato un utente +locale ThothII né effettuato un secondo scambio OIDC dall'applicazione embedded. + +## Il confine di fiducia + +```mermaid +sequenceDiagram + actor U as Utente già autenticato + participant N as Nginx Omics + participant D as Django Omics + participant T as Core ThothII upstream + U->>D: Apri Datamart Builder + D-->>U: Pagina autorizzata con mount React + U->>N: GET /datamart-builder/api/me (cookie Omics) + N->>D: Subrequest interna /datamart-builder/api-auth + D-->>N: 200 + identità verificata, oppure 403 + N->>T: GET /me + intestazioni normalizzate (solo se autorizzato) + T-->>U: Identità e permessi applicativi, oppure rifiuto +``` + +L'header e l'adapter JavaScript non autenticano nessuno. Il backend accetta una +richiesta upstream solo con un'identità valida ricevuta da un percorso di rete +fidato. Gli header non sono firmati da ThothII: la protezione è il proxy che +verifica la sessione e sovrascrive l'identità, insieme all'isolamento del core. +Un core upstream direttamente raggiungibile da client non fidati è una falla, +non una modalità alternativa di accesso. + +## Configurazione del core + +Per Omics il descrittore pubblico deve contenere: + +```yaml +shell: + mode: embedded + defaultLocale: en + adapter: omics-portal +``` + +Separatamente, il **processo core** deve ricevere `AUTH_MODE=upstream`. Definirlo +nell'override Compose approvato e incluso nell'installazione; una variabile nel +file di interpolazione `.env` non viene passata automaticamente al container: + +```yaml +services: + core: + environment: + AUTH_MODE: upstream +``` + +È solo il frammento di selezione auth, non un file Compose completo né una +configurazione di rete sufficiente. Non aggiunge porte pubbliche. + +Condizioni obbligatorie: + +1. Nessun `auth.yaml` local/OIDC deve essere effettivamente montato al percorso + letto dal core (default `/run/thothii-auth/auth.yaml`). Se è presente insieme + ad `AUTH_MODE`, l'avvio fallisce. Non impostare `AUTH_MODE=local` o `oidc`: + questi due modi si selezionano dal file, non da quella variabile. +2. Non configurare `authentication.runtimeProjection` per questo percorso: è la + proiezione delle configurazioni cookie local/OIDC, non l'identità Omics. + Nemmeno `THT_AUTH_RUNTIME_PROJECTION_ROOT` deve attivarla nel core. +3. Il descrittore e Compose base continuano a richiedere `authentication.configDirectory` + e `THT_AUTH_CONFIG_ROOT` coerenti. Per una nuova installazione upstream usare + una directory dedicata senza `auth.yaml`, non cancellare la configurazione di + un'installazione esistente. I cambi di modalità richiedono un piano separato. +4. Non esiste `tht auth configure --mode upstream`: il CLI configura gli utenti + locali o l'OIDC diretto. Conservare il percorso proxy già operativo per Omics. +5. `profile: server`, storage delle sessioni e `THOTH_PUBLIC_EXPOSURE` hanno propri + vincoli, che rimangono attivi. La shell embedded non li soddisfa automaticamente. + +Il sorgente considera upstream un percorso di compatibilità con il proxy; è +quello usato dall'integrazione Omics corrente. `none` e `mock` sono per sviluppo/test, +non soluzioni a errori di configurazione in produzione. + +## Intestazioni richieste all'ingresso del core + +| Header | Regola ThothII | Valore Omics | +| --- | --- | --- | +| `X-Thoth-Principal-Issuer` | Stringa stabile, obbligatoria | `portal` | +| `X-Thoth-Principal-Subject` | ID stabile dell'utente, obbligatorio | `str(user.pk)` Django | +| `X-Thoth-Principal-Display-Name` | Facoltativo, se presente non vuoto | Nome completo o username | +| `X-Thoth-Is-Admin` | Obbligatorio: `0`, `1`, `false` o `true` | Risultato di `is_authentik_admin(user)` | + +Le stringhe sono ripulite degli spazi esterni, devono avere al massimo 512 +caratteri e non contenere caratteri di controllo. Header mancanti o invalidi +producono 401. `false`/`0` assegna il ruolo `user`; `true`/`1` assegna `user` e +`admin`. Il core espande i permessi dal proprio catalogo, non da un array inviato +dal browser. `/me` richiede `session.use`. + +La coppia `(issuer, subject)` identifica il proprietario delle sessioni. +Non sostituire il subject con un nome visualizzato o un'email modificabile; non +cambiare issuer/subject di utenti esistenti per correggere un problema grafico. +Passare da identità `portal` a identità OIDC diretta non migra la proprietà dei dati. + +## Omics: percorsi e componenti esatti + +| Percorso | Destinazione e funzione | +| --- | --- | +| `/kokoro/datamart-builder/` | Pagina Django con `datamart_builder.access` | +| `/datamart-builder/config.js` | Config pubblico del frontend, senza cache | +| `/datamart-builder/assets/…` | Asset frontend risolti dal manifest Vite | +| `/datamart-builder/api/…` | Nginx con `auth_request`, poi core senza il prefisso | +| `/_thothii_auth` | Location Nginx interna, non un login pubblico | +| `/datamart-builder/api-auth` | Django verifica sessione Omics e capability | + +Nel repository Omics: + +- `kokoro/datamart_catalog_views.py`: `DatamartBuilderView` e + `datamart_builder_api_auth`; la verifica API risponde 200 o 403, anche 403 + quando la sessione è assente/scaduta. Non trasforma l'API in una pagina di login. +- `nginx/nginx.conf`: API direttamente a `thothii-core:8787`, config e asset a + `thothii-frontend:8080`; verificare alias e reti Docker effettivi sul server. +- `templates/kokoro/datamart_builder.html`: mount, config e override del prefisso. +- `kokoro/templatetags/vite.py`: manifest da + `http://thothii-frontend:8080/.vite/manifest.json`, cache Django di 30 secondi. + +Nginx usa il cookie Omics nella subrequest a Django. Sulle richieste al core +sovrascrive i quattro header con i risultati della verifica e rimuove +`Cookie`, `Authorization` e `X-Authenticated-User`. Nessuna password o token del +portale deve essere copiato nel config pubblico, nello snapshot adapter o in Web Storage. +`GET /datamart-builder/api/me` restituisce l'identità e i permessi; in upstream +`session` e `csrfToken` sono `null`: non viene creata una sessione-cookie ThothII. + +## Non confondere i due percorsi proxy + +L'esempio generico `deploy/nginx-authenticated-proxy.conf.example` usa **due hop**: +proxy host → frontend Nginx ThothII → core. Sul tratto privato verso il frontend +trasporta `X-Thoth-Trusted-Principal-*` e `X-Thoth-Trusted-Is-Admin`; il frontend +li converte nei quattro header del core e li elimina prima dell'inoltro. + +Omics usa invece **Nginx Omics → core direttamente** per le API e invia gli header +normalizzati senza `Trusted`. Non incollare l'esempio a due hop in questa location: +la famiglia di header sbagliata produce 401. In entrambi i casi i valori devono +venire dalla verifica server, mai dagli header del client. Il tratto privato del +percorso generico deve essere inaccessibile ai client non fidati. + +## Origine delle richieste e stream + +Browser e API devono restare sullo stesso origin. Il frontend accetta `/api` o un +prefisso same-origin come `/datamart-builder/api`, non un URL `http://core:8787`. +In upstream le scritture con `Origin` sono confrontate con protocollo e Host +percepiti dal core; non usano il token CSRF della sessione ThothII local/OIDC. +Le richieste senza Origin hanno il trattamento non-browser: l'autenticazione del +proxy rimane indispensabile anche per esse. + +Nel Nginx Omics esaminato il TLS termina a monte e una mappa **esatta** converte +`https://aritmolab.policlinicosandonato.it` in +`http://aritmolab.policlinicosandonato.it` per il confronto interno. Le altre origini +rimangono invariate e devono essere negate quando non coincidono. È una scelta +specifica della topologia corrente, non un modello da estendere con wildcard, +cancellazione di Origin o riscrittura incondizionata. Verificare Host/protocollo +al core e i dinieghi cross-origin nella topologia realmente rilasciata. + +La location API disabilita buffering/cache per SSE e mantiene timeout lunghi. +`auth_request` verifica ogni nuova richiesta, ma non interrompe istantaneamente +uno stream già aperto quando il portale revoca l'utente. ThothII ricontrolla `/me` +al ritorno alla pagina e alla riconnessione degli eventi; non promettere revoca +istantanea fra tutte le schede. + +## Logout, rientro e diagnosi + +In embedded logout e successivo login sono di Omics. ThothII non chiama +`/auth/logout`, non cancella il cookie Django e non apre un suo login. +Il rifiuto 401/403 di `/me` rimuove lo stato protetto e richiede il rientro dal +portale. Un 403 su una singola operazione non equivale al logout dell'applicazione. + +| Sintomo | Controllo mirato | +| --- | --- | +| Secondo header | Config servito: deve essere embedded, non full | +| Nessuna UI e errore preferenze | Selettore Omics `data-lang` e `html data-bs-theme` | +| `/me` 401 dal core | Header obbligatori, famiglia Trusted/normalizzata, percorso proxy | +| `/me` 403 dal proxy | Sessione Omics e capability `datamart_builder.access` | +| `/me` funziona ma POST 403 | Distinguere permesso operativo da mismatch Origin/Host/protocollo | +| 502 o asset assenti | Alias/rete Docker e manifest Vite; attesa cache manifest 30 s | +| Avvio core rifiutato | Coesistenza di `auth.yaml` o runtime projection con `AUTH_MODE` | +| Logout full seguito da rientro IdP immediato | Il logout ThothII non è logout globale OIDC | + +Non raccogliere cookie, token, segreti o dump completi delle configurazioni nei +report. Registrare codici HTTP, nomi dei percorsi, revisioni e risultati dei test. + +Consegna e rilascio: [procedura Omics](../operations/shell-and-localization.md#verifica-prima-del-deploy-server). +Collaudo obbligatorio: [matrice di accettazione](../testing/authentication-manual-acceptance.md). diff --git a/docs/install/authentik.md b/docs/install/authentik.md index c1b50cfd..48a3c30b 100644 --- a/docs/install/authentik.md +++ b/docs/install/authentik.md @@ -1,7 +1,14 @@ # Authentik provider configuration -ThothII uses generic OIDC in the browser. Authentik provides the identity provider and group -catalog without adding a proprietary login flow. +For **full with direct OIDC**, ThothII uses generic OIDC in the browser. Authentik +provides the identity provider and group catalog without adding a proprietary flow. +The provider/client/group setup below applies to that case only. + +For **embedded in Omics**, retain Omics's existing Authentik authentication and +configure ThothII as upstream. Omics verifies `datamart_builder.access` and +administrator status and the proxy supplies the identity; no additional ThothII +OIDC client, login or local user is required for that path. Follow the +[portal integration guide](authentication-upstream.md). ```mermaid sequenceDiagram diff --git a/docs/install/examples/thothii-installation.local.yaml b/docs/install/examples/thothii-installation.local.yaml index 86e4177d..178c653b 100644 --- a/docs/install/examples/thothii-installation.local.yaml +++ b/docs/install/examples/thothii-installation.local.yaml @@ -3,6 +3,9 @@ # Replace every absolute placeholder. Select exactly one Git transport override. schemaVersion: 2 profile: local +shell: + mode: full + defaultLocale: en projectDirectory: "/absolute/path/to/ThothII" envFile: "/absolute/path/to/ThothII/deploy/env/local.env" workspaceRepository: diff --git a/docs/install/examples/thothii-installation.server.yaml b/docs/install/examples/thothii-installation.server.yaml index 5cba44c2..a2bd04d0 100644 --- a/docs/install/examples/thothii-installation.server.yaml +++ b/docs/install/examples/thothii-installation.server.yaml @@ -3,6 +3,11 @@ # Replace every absolute placeholder. Select exactly one Git transport override. schemaVersion: 2 profile: server +# Standalone server with protected direct OIDC auth, not the Omics upstream path. +# For Omics use authentication-upstream.md: embedded, no auth runtime projection. +shell: + mode: full + defaultLocale: en projectDirectory: "/absolute/path/to/ThothII" envFile: "/absolute/path/to/thothii-server-operator/server.env" workspaceRepository: diff --git a/docs/install/first-start.md b/docs/install/first-start.md index 52466f64..88ddf592 100644 --- a/docs/install/first-start.md +++ b/docs/install/first-start.md @@ -24,7 +24,7 @@ version control, a URL, or a command line. From the repository root, start the interactive setup and select the local profile: ```sh -tht setup --profile local +tht setup --profile local --shell-mode full --shell-default-locale en ``` It writes the selected non-secret descriptor below `deploy//`, the associated @@ -32,6 +32,18 @@ operator env file, and can create protected secret templates. Keep the descripto to commands as `--installation /absolute/path/thothii-installation.yaml` when more than one installation can be discovered. +The explicit shell options are important: compatibility defaults without them +are embedded/en/omics-portal, which expects an Omics document. The Mac's standalone +installation must use full, with English as its initial locale. Existing browser +language preferences take precedence over that initial value. Full does not +configure authentication; setup separately bootstraps local login. + +For a server portal, use the [embedded/upstream procedure](authentication-upstream.md) +instead of creating a second ThothII login. For a standalone server, use full +with [direct OIDC](authentication-oidc.md). Shell mode does not follow `profile` +automatically. See [configuration and regeneration](../operations/shell-and-localization.md) +before modifying an existing installation. + If the descriptor is prepared manually instead, begin with [`thothii-installation.local.yaml`](examples/thothii-installation.local.yaml), set mode `0600` or `0400`, and ensure `THT_INSTALLATION_CONFIG_SOURCE` in the selected env file points to that exact diff --git a/docs/installazione-docker-4-contesti.md b/docs/installazione-docker-4-contesti.md index 81e65766..71656380 100644 --- a/docs/installazione-docker-4-contesti.md +++ b/docs/installazione-docker-4-contesti.md @@ -1,5 +1,13 @@ # Docker installation in the current operating contexts +Rendering and authentication are independent of these Docker contexts. Explicitly +select full/en for the Mac, full/OIDC for an autonomous server, or +embedded/upstream for Omics. The same frontend image supports both renderings; +generated `config.js` and the host page decide the container, while the backend +and trusted proxy decide identity. See [shell configuration and deploy](operations/shell-and-localization.md) +and [server portal authentication](install/authentication-upstream.md). Do not +apply the standalone server authentication projection to the Omics upstream path. + ThothII uses one Compose topology: - `frontend` diff --git a/docs/operations/server-upgrade-gitea-workspace-v2.md b/docs/operations/server-upgrade-gitea-workspace-v2.md index a9f5e153..10b4e6bc 100644 --- a/docs/operations/server-upgrade-gitea-workspace-v2.md +++ b/docs/operations/server-upgrade-gitea-workspace-v2.md @@ -4,6 +4,22 @@ Questo runbook è il passaggio di consegne per il Codex che opererà sul server installazione precedente alla configurazione corrente di ThothII senza modificare Authentik o il DWH esterno e senza cancellare lo stack precedente durante il primo cutover. +## Scelta preliminare: server autonomo oppure Omics + +I passaggi di questo runbook che configurano OIDC diretto, gruppi e +`authentication.runtimeProjection` riguardano **ThothII autonomo**, da rendere +con `shell.mode: full`. Non applicarli all'integrazione Datamart Builder: Omics +usa **embedded/upstream** e mantiene il proprio accesso Authentik. Il core riceve +l'identità verificata dal proxy senza un secondo login né un secondo auth.yaml. + +Prima dell'inventario identificare quale percorso è approvato. Per Omics seguire +[autenticazione upstream](../install/authentication-upstream.md) e +[rilascio coordinato dei due repository](shell-and-localization.md#preparare-il-rilascio-coordinato); +i gate di backup, isolamento, catalogo, storage e rollback di questo runbook +rimangono validi, ma non copiare i passi auth del percorso autonomo. Il passaggio +da issuer `portal` a un issuer OIDC differente non trasferisce automaticamente +la proprietà delle sessioni. + La procedura si applica a `main` quando contiene almeno il commit `eba6148511675fc6a187aabb69a975adc5e3c542`. Deve essere presente anche questo file. Il commit minimo è un controllo di sicurezza, non un invito a fermarsi a quella revisione: installare sempre @@ -57,7 +73,9 @@ La topologia base attesa è: | `embedding-model-init` | scarica/verifica il modello | job one-shot, deve terminare con exit 0 | `catalog-db` non è il DWH. Non pubblica porte sull'host e usa credenziali runtime e migrator -separate. Ollama non controlla le password utente: l'autenticazione resta OIDC tramite Authentik. +separate. Ollama non controlla le password utente: nel percorso autonomo vale +OIDC tramite Authentik; nel percorso embedded Omics verifica l'accesso e il core +usa upstream. Il PostgreSQL per le **sessioni** è un'altra funzione ancora. L'overlay `deploy/compose.session-server.yaml.example` è esplicitamente opt-in: non abilitarlo durante questo diff --git a/docs/operations/shell-and-localization.md b/docs/operations/shell-and-localization.md index d3d2da54..bbdb1a9e 100644 --- a/docs/operations/shell-and-localization.md +++ b/docs/operations/shell-and-localization.md @@ -1,7 +1,11 @@ # Shell, autenticazione e lingue -Questa guida accompagna la [specifica approvata](../plans/2026-09-13-full-shell-spec.md) -e il [contratto Portal Shell Adapter](../contracts/portal-shell-adapter-v1.md). +Questa è la procedura operativa del rendering corrente. Leggerla insieme a +[architettura full/embedded](../architecture/application-shell.md), +[autenticazione upstream](../install/authentication-upstream.md) e +[contratto PortalAdapter](../contracts/portal-shell-adapter-v1.md). +La [specifica approvata](../plans/2026-09-13-full-shell-spec.md) documenta la +progettazione, non sostituisce i vincoli verificati nel codice e riportati qui. ## Scegliere il contenitore @@ -9,6 +13,16 @@ La modalità della shell è indipendente dal profilo di distribuzione e dal meto di autenticazione. Un server può ospitare full; un ambiente locale può ospitare embedded per provare un'integrazione. +| Destinazione | Shell | Autorità di accesso | Login/logout visibile | +| --- | --- | --- | --- | +| Mac attuale | full, default en | `auth.yaml` local | ThothII | +| Server autonomo | full | `auth.yaml` OIDC | ThothII, con redirect al provider | +| Datamart Builder in Omics | embedded, adapter Omics | core `AUTH_MODE=upstream`, sessione Omics al proxy | Solo Omics | + +Non confondere la lingua inglese iniziale del Mac con quella del workspace o +delle sessioni già create. Non copiare sul server l'intero descrittore del Mac: +contiene percorsi e scelte locali, oltre a full. + Per questo Mac, nel descrittore installato: ```yaml @@ -22,6 +36,7 @@ Per il server Omics: ```yaml shell: mode: embedded + defaultLocale: en adapter: omics-portal ``` @@ -36,6 +51,17 @@ Omics. Le preferenze non modificano il descrittore installato. ## Applicare una modifica all'installazione +Per una nuova installazione autonoma, selezionare esplicitamente full: + +```bash +tht setup --profile local --shell-mode full --shell-default-locale en +``` + +Il setup senza opzioni shell conserva per compatibilità il default embedded. +Per un'installazione esistente non rilanciare setup per sovrascrivere il +descrittore: registrare la configurazione attuale, modificarne la sezione shell +e usare la generazione seguente. Le credenziali rimangono nei file protetti. + Aggiornare prima il binario nativo `tht`: le versioni precedenti rifiutano la sezione `shell`. Modificare poi il descrittore e generare le proiezioni: @@ -54,10 +80,40 @@ Compose generata e ricreare il frontend quando cambia la configurazione. Il fingerprint della configurazione pubblica permette a Compose di rilevare il cambio. La stessa immagine frontend supporta entrambe le modalità. +Nel percorso standard del CLI, dopo avere approvato l'aggiornamento: + +```bash +tht --installation /percorso/assoluto/thothii-installation.yaml start +tht --installation /percorso/assoluto/thothii-installation.yaml status +tht --installation /percorso/assoluto/thothii-installation.yaml doctor --json +``` + +Usare `start --build` per una revisione di codice che richiede nuove immagini, +non per la sola modifica della shell. Questo è un lifecycle dell'installazione, +non un comando garantito frontend-only. Un launcher personalizzato deve conservare +tutti gli override di rete, autenticazione, workspace e modelli già approvati. +Non usare `down --volumes`. Registrare gli identificatori delle immagini prima +dell'aggiornamento e conservare il descrittore precedente per il rollback. + Controllare il `config.js` effettivamente servito, che non deve essere memorizzato in cache. In full la route API ordinaria è `/api`; Omics imposta nel template il prefisso same-origin `/datamart-builder/api`, mantenendo le altre impostazioni. +Il file pubblico standalone deve essere equivalente a: + +```javascript +window.__THOTHII_CONFIG__ = { + backendBaseUrl: "/api", + shell: { mode: "full", defaultLocale: "en" } +}; +``` + +È un risultato da controllare, non un file da mantenere a mano. In Omics il +template carica `/datamart-builder/config.js`, conserva l'oggetto con +`Object.assign` cambiando solo `backendBaseUrl` in `/datamart-builder/api`, poi +carica gli asset dal manifest. Il config senza cache deve precedere ogni modulo +React; verificare nella rete del browser l'URL finale `/datamart-builder/api/me`. + ## Accesso in parole semplici In Omics l'utente effettua l'accesso al portale come oggi. Quando sceglie @@ -72,6 +128,11 @@ la configurazione di accesso dell'installazione. Full supporta anche un'eventual autenticazione OIDC configurata; il suo logout termina la sessione ThothII, non promette di disconnettere l'utente da tutti gli altri servizi OIDC. +Full/upstream non può terminare una sessione posseduta dal proxy e non mostra +quel comando logout. Embedded non presenta mai il login ThothII, neppure per +recuperare un errore di configurazione. Per un server autonomo con login/logout +ThothII usare full/OIDC, non full/upstream. + I controlli server restano autorevoli. Un errore su una singola operazione non deve cancellare automaticamente l'accesso all'intera applicazione. Un rifiuto della verifica dell'utente chiude invece lo stato protetto. L'accesso viene @@ -93,6 +154,12 @@ di autorizzazione. Non esporre un percorso alternativo che permetta al browser di raggiungerlo aggirando quel controllo. Non introdurre token nel documento, negli eventi UI o nella configurazione pubblica. +La [guida upstream](../install/authentication-upstream.md) riporta i vincoli +esatti: `AUTH_MODE=upstream` nel core, nessun `auth.yaml` o runtime projection +contemporaneo, capability Django, quattro header obbligatori/facoltativi, percorso +diretto Omics distinto dal proxy generico a due hop, origine e SSE. Non usare +`tht auth configure --mode oidc` per «completare» l'accesso Omics già funzionante. + ## Come funziona l'adapter `OmicsPortalAdapter` è il solo modulo frontend che conosce il documento Omics. @@ -206,8 +273,73 @@ documentato nella guida. Non usare `git pull` nel checkout condiviso né richiedono una successiva approvazione, con revisione/immagini di rollback registrate e rilascio coordinato con ThothII embedded/upstream. +Dopo il confronto positivo con +`fca10901a73666ca257d8f4cc4b77066295c400a`, il trasferimento verso Gitea si +completa **sempre dal repository Omics sul server** con: + +```bash +cd /home/chirone/omics_portal +git ls-remote ssh://git@localhost:2222/aritmolab/omics_portal.git \ + HEAD refs/heads/codex/thothii-embedded-shell +git push ssh://git@localhost:2222/aritmolab/omics_portal.git \ + refs/remotes/github-relay/codex/thothii-embedded-shell:refs/heads/codex/thothii-embedded-shell +git ls-remote ssh://git@localhost:2222/aritmolab/omics_portal.git \ + refs/heads/codex/thothii-embedded-shell +git status --short --branch +git rev-parse HEAD +``` + +Lo SHA Gitea deve coincidere; branch, HEAD e modifiche del checkout devono +rimanere quelli registrati prima del fetch. Se diverge o il push viene rifiutato, +fermarsi senza force push, reset, modifica di credenziali o merge improvvisato. +Questo passaggio non pubblica ThothII, non cambia `master` e non fa deploy. + +### Preparare il rilascio coordinato + +1. Registrare SHA approvati di **entrambi** i repository, immagini precedenti, + descriptor ThothII, file Compose/override e progetto realmente in uso. La testa + del branch di lavoro non è automaticamente una revisione approvata di produzione. +2. In un checkout di revisione separato, integrare Omics con il branch di rilascio + concordato. Non fare merge nel checkout operativo con modifiche altrui. + I file Omics da includere sono template Datamart Builder/topbar/base, asset + fullscreen e cataloghi Django del branch; conservare la verifica server + esistente in `kokoro/datamart_catalog_views.py` e le location Nginx protette. +3. Eseguire dal checkout Omics i test isolati, non i test contro il database operativo: + + ```bash + docker build -f test_support/thothii/Dockerfile -t omics-portal:thothii-shell-tests . + docker run --rm --network none omics-portal:thothii-shell-tests + ``` + +4. Predisporre il descrittore ThothII embedded e il core upstream secondo la guida. + Verificare che Nginx Omics possa raggiungere gli alias privati `thothii-core:8787` + e `thothii-frontend:8080` e che non esista un ingresso non protetto al core. + Non sovrascrivere rete, mount o autenticazione usando il Compose locale del Mac. +5. Solo dopo il gate operatore, applicare le revisioni approvate seguendo il + lifecycle dei due progetti. In Omics i servizi sono `web` e `nginx`: includere + nel rebuild template, statici e cataloghi, mantenendo tutti gli override del + server. Verificare la configurazione Nginx con `nginx -t` nel servizio e lo + stato di entrambi. Non inventare opzioni Compose/progetto: usare quelle + registrate al punto 1. Gli entrypoint del portale possono avere altri effetti + operativi: questa modifica non richiede nuove migrazioni DB, ma non autorizza + a bypassare i controlli del suo rilascio. +6. Dopo l'aggiornamento del frontend, attendere la cache manifest Django (30 s) + oppure usare l'invalidazione prevista dal portale; ricaricare e controllare + config/asset/prefisso API prima di giudicare il risultato. +7. Compilare la matrice seguente. In caso di errore ripristinare revisioni, + immagini e configurazioni registrate, senza cancellare volumi. Il rollback + deve conservare una coppia compatibile di template Omics e frontend ThothII. + +La consegna GitHub è verificata; il push Gitea PSD e il deploy del nuovo branch +Omics rimangono da confermare dall'operatore. I test locali non attestano lo stato +attuale del server remoto. + ### Accettazione dell'integrazione +Usare la [matrice completa full/embedded e autenticazione](../testing/authentication-manual-acceptance.md), +registrando per ogni prova revisione, ambiente e risultato. Non spuntare i casi +IdP/Omics reali soltanto perché passano i test con risposte simulate. + Provare l'apertura dal menu Omics con un utente autorizzato e uno senza accesso; verificare assenza di un secondo login e di header ThothII, italiano/inglese già selezionati prima dell'apertura, tema, fullscreen e uscita con Esc. Ripetere con diff --git a/docs/testing/authentication-manual-acceptance.md b/docs/testing/authentication-manual-acceptance.md new file mode 100644 index 00000000..f07bbbe4 --- /dev/null +++ b/docs/testing/authentication-manual-acceptance.md @@ -0,0 +1,86 @@ +# Accettazione di shell e autenticazione + +Questa matrice è un gate di rilascio, non una dichiarazione che le prove server +siano già state eseguite. Registrare ambiente, data, SHA ThothII/portale, immagini, +modalità effettive e risultato di ogni caso. Usare account di prova autorizzati; +non incollare token, cookie, password o dati clinici nelle evidenze. + +## Configurazione prima della prova + +- Full/local: descrittore `shell.mode: full`, default en, `auth.yaml` local; + `AUTH_MODE` non impostato. Scegliere browser/origin coerenti con `publicUrl`. +- Full/OIDC: full, configurazione OIDC valida e callback esatta + `PUBLIC_URL/api/auth/oidc/callback`; `AUTH_MODE` non impostato. +- Embedded/Omics: embedded/omics-portal, core upstream senza auth.yaml/runtime + projection, sessione portale e capability; API attraverso il solo proxy fidato. +- Config pubblico caricato prima del modulo React, no-store e senza segreti; + connessioni private del core non raggiungibili da client non fidati. + +## Full, senza documento Omics + +| Prova | Risultato atteso | +| --- | --- | +| Primo accesso con preferenze browser assenti | Header ThothII; inglese e light; nessun errore per elementi Omics mancanti | +| Login locale valido/errato | Identità verificata nel primo caso; errore generico e nessun contenuto protetto nel secondo | +| Remember me | Sessione persistente secondo TTL local; senza Remember me cookie non persistente | +| OIDC con provider raggiungibile | Redirect, callback validata, nome e permessi dall'identità verificata | +| OIDC con claim gruppi invalido | Login rifiutato; nessuna informazione sensibile nel browser | +| OIDC con gruppi validi ma non mappati | Nessun ruolo, accesso alle route protette negato | +| Nome → Log out | Sessione ThothII revocata; una nuova richiesta protetta con quella sessione non accede | +| Nuovo login OIDC dopo logout | Può riusare SSO provider; nessuna promessa di logout globale | +| Disabilitazione/ruolo/password/logout-all locale | La sessione precedente viene invalidata al controllo server | +| Cambio lingua e tema | Etichette aggiornate, preferenze ricordate, leggibilità anche di popup e griglie | +| Fullscreen, Esc, rifiuto del browser | Stato/icona coerenti; errore visibile su rifiuto, nessun falso fullscreen | +| Schermo stretto/largo | Margini simmetrici almeno 20px; header adattivo; nessuna rotellina amministrativa | + +## Embedded, dal portale reale + +| Prova | Risultato atteso | +| --- | --- | +| Utente già autenticato e autorizzato → Datamart Builder | Nessun secondo login e un solo header, quello Omics | +| Utente senza capability o sessione scaduta | Pagina/API protette rifiutate, non UI autenticata ottenuta da eventi DOM | +| `/datamart-builder/api/me` autorizzato | Issuer `portal`, subject stabile, ruoli attesi; session/CSRF ThothII null | +| Utente normale vs amministratore | Azioni amministrative protette server-side; flag admin non controllabile dal client | +| Header identità inventati dal client, anche admin | Non concedono accesso né elevazione; il proxy usa soltanto la verifica Django | +| Richiesta cross-origin a un'operazione di prova | Rifiutata senza modificare dati; testare con risorse fittizie in ambiente isolato | +| IT/EN selezionato prima dell'apertura | Locale iniziale uguale a quello Django confermato | +| Cambio lingua dal form Omics | Reload normale con CSRF/next; selezione sessione conservata, nessuna generazione automatica | +| Cambio tema con menu/form aperti | UI, popup e griglia seguono Omics, senza controlli locali duplicati | +| Fullscreen dall'header e uscita con Esc | Stato reale sincronizzato anche dentro ThothII | +| Logout Omics e ritorno in una seconda scheda | Al ricontrollo `/me` lo stato protetto viene rimosso; rientro tramite Omics | +| Riconnessione SSE dopo scadenza | Verifica accesso prima di riprendere; nessun aggiramento del proxy | +| 403 su una sola operazione con `/me` ancora valido | Errore operativo, non logout indiscriminato | +| Contesto host mancante/tema invalido | Errore d'integrazione; niente fallback full o login autonomo | +| API, config e asset dopo rebuild | Prefissi corretti, config no-store, manifest aggiornato dopo la sua cache di 30 s | + +Le prove con header inventati devono attraversare l'ingresso pubblico protetto, +non certificare la sicurezza inviando header direttamente al core che per +contratto si fida del proxy. L'isolamento di rete del core va verificato a parte. +Non promettere che il logout chiuda immediatamente tutti gli SSE già aperti: il +proxy autorizza all'apertura e i ricontrolli avvengono sulle nuove richieste. + +## Continuità del workflow, entrambe le modalità + +| Prova | Risultato atteso | +| --- | --- | +| Nuova sessione con UI italiana/inglese | `interaction_language` acquisita alla creazione; domande e scelte nella lingua salvata | +| Cambio UI dopo creazione e ripresa | La lingua della sessione resta invariata | +| Vecchio manifest senza lingua | Prima ripresa fissa la lingua workspace secondo il criterio di compatibilità | +| Bozza/modifica amministrativa e navigazione | Conferma prima della perdita; annullamento conserva la modifica | +| Reload con selezione esistente | Riapre documenti senza avviare Pi/generazione automaticamente | +| Cambio utente | Nessuno stato protetto della precedente identità riutilizzato | +| SQL, identificatori, Evidence e Memory | Contenuti originali non tradotti/riscritti dal cambio UI | + +## Copertura automatica e limiti + +Frontend: `AuthGate.test.tsx`, `authState.test.ts`, `OmicsPortalAdapter.test.ts`, +`AppShell.host.test.tsx`, test di stream/sessioni e +`e2e/ui-visual-review.spec.ts`. Backend: test di auth, principal, route e +isolamento della configurazione. CLI: normalizzazione shell e proiezioni. +I test Omics isolati sono descritti nel suo `docs/thothii-integration.md`. + +I test automatici con API/IdP simulati non sostituiscono callback reali, +sessioni Omics, permessi di rete, TLS, cookie reali e interazioni fra schede sul +server. Prima di chiudere il rilascio indicare esplicitamente prove superate, +non eseguite e motivi del rinvio. Procedure e rollback: +[shell e deploy](../operations/shell-and-localization.md). diff --git a/mkdocs.yml b/mkdocs.yml index 77cc1cd2..8799df16 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,6 +50,7 @@ nav: - Preprocessing-complete server handoff: operations/server-handoff-260906-preprocessing-complete.md - Local authentication: install/authentication-local.md - Generic OIDC: install/authentication-oidc.md + - Portal upstream authentication: install/authentication-upstream.md - Authentik: install/authentik.md - Workspace operations: operations/workspaces.md - Shell and localization: operations/shell-and-localization.md @@ -69,6 +70,7 @@ nav: - Overview: architecture/overview.md - Components, modules, and flows: architecture/components.md - Authentication and authorization: architecture/authentication.md + - Full and embedded rendering: architecture/application-shell.md - Contracts and integration: - Portal Shell Adapter v1: contracts/portal-shell-adapter-v1.md - Catalog schema snapshot RPC: contracts/catalog-schema-snapshot.md @@ -81,6 +83,7 @@ nav: - DWH client enrollment: install/dwh-auth-client-enrollment.md - DWH REST TLS: install/dwh-auth-tls.md - Decisions and acceptance: + - Shell and authentication acceptance: testing/authentication-manual-acceptance.md - Architecture decisions: - 0001 Metadata catalog: adr/0001-postgres-metadata-catalog.md - 0002 Workspace database secrets: adr/0002-workspace-database-secret-references.md diff --git a/tools/tht/README.md b/tools/tht/README.md index 96e6ed62..eb3f0fca 100644 --- a/tools/tht/README.md +++ b/tools/tht/README.md @@ -23,6 +23,11 @@ Invalid values and unknown descriptor fields are rejected. In full mode, a known adapter setting is ignored and omitted from the resolved public configuration. Shell selection is independent of `profile` and authentication. +Operational guide: [shell configuration and deployment](../../docs/operations/shell-and-localization.md). +For Omics server identity, use [upstream integration](../../docs/install/authentication-upstream.md): +the CLI's `auth configure` configures local/OIDC, not an upstream login. A mounted +auth.yaml/runtime projection cannot coexist with core `AUTH_MODE=upstream`. + New installations can select these values with `tht setup --shell-mode full --shell-default-locale en`. The optional `--shell-adapter omics-portal` selects the embedded adapter explicitly. Corresponding environment answers are