Compare commits
2
Commits
67ee52624c
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f53512e4d | ||
|
|
497ab84031 |
+7
-1
@@ -1,6 +1,6 @@
|
||||
# Project state
|
||||
|
||||
Updated: 2026-09-15. This is a current snapshot, not a release diary. Stable commands
|
||||
Updated: 2026-09-27. This is a current snapshot, not a release diary. Stable commands
|
||||
and invariants are in [AGENTS.md](AGENTS.md); prior snapshots remain in Git.
|
||||
|
||||
## Current contracts
|
||||
@@ -56,6 +56,12 @@ embedded/upstream identity, not another ThothII OIDC login. Read
|
||||
|
||||
Last recorded application deliveries (not a fresh runtime attestation):
|
||||
|
||||
- [Coordinated ThothII/Omics release](docs/reports/2026-09-26-server-release-execution.md):
|
||||
core/frontend `497ab840-preflight`, Omics proxy fix `928f7e9f` with existing web
|
||||
image retained. Automated acceptance passed; on September 27 the operator confirmed
|
||||
browser access, UI controls and session start/stop/resume. Functional browser
|
||||
acceptance passed; remaining extended checks are handed off in the
|
||||
[server acceptance follow-up](docs/reports/2026-09-27-server-acceptance-handoff.md).
|
||||
- [Session dialogs](docs/reports/2026-09-14-session-dialogs-release.md):
|
||||
`b1723c34-session-dialogs-20260914`, frontend-only.
|
||||
- [Session layout/Memory fix](docs/reports/2026-09-14-session-layout-memory-fix.md):
|
||||
|
||||
@@ -34,12 +34,11 @@ for the executed consolidation and the inventory of historical sources retained
|
||||
|
||||
## Docker Compose and installation
|
||||
|
||||
For a fresh installation, follow the guided terminal procedure in
|
||||
For a fresh installation, follow the complete manual procedure in
|
||||
[Italian](docs/install/standalone-manual-it.md) or
|
||||
[English](docs/install/standalone-manual-en.md). The single
|
||||
`tht setup --complete` command validates protected files, builds the images, runs
|
||||
Catalog migration, starts the stack and imports the configured workspace repository.
|
||||
There is no graphical installer or native launcher.
|
||||
[English](docs/install/standalone-manual-en.md). Configure protected files first;
|
||||
then run the documented build, explicit migrations and startup commands with the
|
||||
same installation descriptor and Compose project. There is no installer or launcher.
|
||||
|
||||
The mandatory stack includes frontend, core, PostgreSQL catalog, Qdrant, Ollama
|
||||
and the embedding initializer. DWH and LLM endpoints remain external dependencies.
|
||||
|
||||
@@ -16,16 +16,12 @@ import { loadSettings } from "./settings/settings-store.js";
|
||||
import { ThtRunner, type SessionRow } from "./tht/tht-runner.js";
|
||||
import { WorkspaceRegistry } from "./workspaces/registry.js";
|
||||
import { WorkspaceSecretStore } from "./workspaces/secret-store.js";
|
||||
import { createProductionWorkspaceDiagnoser } from "./workspaces/diagnostics.js";
|
||||
import { resolveCatalogRuntimeBinding } from "./catalog/runtime-binding.js";
|
||||
import { CatalogService } from "./catalog/service.js";
|
||||
import { validateOperationalWorkspace } from "./workspaces/schema.js";
|
||||
import { createCatalogRepository } from "./catalog/repository.js";
|
||||
import type { CatalogRepository } from "./catalog/types.js";
|
||||
|
||||
type OperatorAction = "maintenance-activate" | "maintenance-deactivate" | "maintenance-status"
|
||||
| "session-inventory" | "workflow-doctor" | "workspace-integrity"
|
||||
| "workspace-pull" | "workspace-test" | "pi-test" | "effective-settings";
|
||||
| "pi-test" | "effective-settings";
|
||||
|
||||
const lifecyclePrincipal: PrincipalContext = {
|
||||
issuer: "tht-operator-command",
|
||||
@@ -123,119 +119,6 @@ async function workspaceIntegrity(config: AppConfig): Promise<{
|
||||
return { ready: true, ...integrity };
|
||||
}
|
||||
|
||||
async function workspacePull(config: AppConfig): Promise<{
|
||||
ready: boolean;
|
||||
status: "succeeded" | "degraded";
|
||||
branch: string;
|
||||
head?: string;
|
||||
degraded: boolean;
|
||||
}> {
|
||||
const status = await new WorkspaceRegistry(config.workspaceRegistry).pull();
|
||||
return {
|
||||
ready: !status.degraded,
|
||||
status: status.degraded ? "degraded" : "succeeded",
|
||||
branch: status.branch,
|
||||
...(status.head ? { head: status.head } : {}),
|
||||
degraded: status.degraded,
|
||||
};
|
||||
}
|
||||
|
||||
interface WorkspaceTestReport {
|
||||
id: string;
|
||||
status: "ready" | "failed";
|
||||
database: "reachable" | "not_configured" | "failed";
|
||||
diagnostics: string[];
|
||||
}
|
||||
|
||||
async function workspaceTest(config: AppConfig): Promise<{
|
||||
ready: boolean;
|
||||
workspaces: WorkspaceTestReport[];
|
||||
}> {
|
||||
if (!config.catalogDatabase) throw new Error("Catalog database is not configured");
|
||||
const registry = new WorkspaceRegistry(config.workspaceRegistry);
|
||||
const revisions = await registry.list();
|
||||
const repository = createCatalogRepository(config.catalogDatabase);
|
||||
try {
|
||||
const secretStore = new WorkspaceSecretStore({
|
||||
root: config.workspaceSecretStoreRoot,
|
||||
runtimeRoot: config.workspaceSecretRuntimeRoot,
|
||||
installationId: config.workspaceRegistry.installationId,
|
||||
});
|
||||
const catalogService = new CatalogService(
|
||||
repository,
|
||||
registry,
|
||||
secretStore,
|
||||
config.workspaceRegistry.secretRoots,
|
||||
config.workspaceDiagnosticTimeoutMs,
|
||||
);
|
||||
const diagnose = createProductionWorkspaceDiagnoser(config.workspaceDiagnosticTimeoutMs, undefined, {
|
||||
internalQdrantUrl: config.internalQdrantUrl,
|
||||
internalEmbeddingUrl: config.internalEmbeddingUrl,
|
||||
internalEmbeddingId: config.internalEmbeddingId,
|
||||
internalEmbeddingModel: config.internalEmbeddingModel,
|
||||
internalEmbeddingDimensions: config.internalEmbeddingDimensions,
|
||||
});
|
||||
const databases = await repository.list();
|
||||
const reports: WorkspaceTestReport[] = [];
|
||||
for (const revision of revisions) {
|
||||
const diagnostics: string[] = [];
|
||||
let workspace: ReturnType<typeof validateOperationalWorkspace>;
|
||||
try {
|
||||
workspace = validateOperationalWorkspace((await registry.read(revision.id)).workspace);
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "not_configured", diagnostics: ["workspace_invalid"] });
|
||||
continue;
|
||||
}
|
||||
const database = databases.find((candidate) => candidate.workspaceId === revision.id);
|
||||
if (!database) {
|
||||
reports.push({ id: revision.id, status: "failed", database: "not_configured", diagnostics: ["database_binding_missing"] });
|
||||
continue;
|
||||
}
|
||||
let tested;
|
||||
try {
|
||||
tested = await catalogService.test(database);
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "failed", diagnostics: ["database_unreachable"] });
|
||||
continue;
|
||||
}
|
||||
if (!tested || tested.connectionStatus !== "reachable") {
|
||||
reports.push({ id: revision.id, status: "failed", database: "failed", diagnostics: ["database_unreachable"] });
|
||||
continue;
|
||||
}
|
||||
let lease: ReturnType<typeof resolveCatalogRuntimeBinding>;
|
||||
try {
|
||||
lease = resolveCatalogRuntimeBinding({
|
||||
workspace,
|
||||
database: tested,
|
||||
environment: process.env,
|
||||
secretRoots: config.workspaceRegistry.secretRoots,
|
||||
secretStore,
|
||||
});
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "reachable", diagnostics: ["binding_missing"] });
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
// CatalogService.test() above is the authoritative database probe and records its
|
||||
// outcome. The remaining diagnoser pass checks Evidence and internal semantic services;
|
||||
// skipping its legacy DWH probe avoids requiring a second response-shape contract for a
|
||||
// REST health endpoint.
|
||||
const result = await diagnose(lease.workspace, lease.bindings, { writeProbe: false, skipDwh: true });
|
||||
diagnostics.push(...result.diagnostics.map((diagnostic) => diagnostic.code));
|
||||
const ready = result.activatable;
|
||||
reports.push({ id: revision.id, status: ready ? "ready" : "failed", database: "reachable", diagnostics });
|
||||
} catch {
|
||||
reports.push({ id: revision.id, status: "failed", database: "reachable", diagnostics: ["connector_unavailable"] });
|
||||
} finally {
|
||||
lease.release();
|
||||
}
|
||||
}
|
||||
return { ready: reports.length > 0 && reports.every((report) => report.status === "ready"), workspaces: reports };
|
||||
} finally {
|
||||
await repository.close?.();
|
||||
}
|
||||
}
|
||||
|
||||
export async function runOperatorAction(
|
||||
action: OperatorAction,
|
||||
config: AppConfig,
|
||||
@@ -249,8 +132,6 @@ export async function runOperatorAction(
|
||||
if (action === "session-inventory") return await sessionInventory(config);
|
||||
if (action === "workflow-doctor") return await workflowDiagnostics(config);
|
||||
if (action === "workspace-integrity") return await workspaceIntegrity(config);
|
||||
if (action === "workspace-pull") return await workspacePull(config);
|
||||
if (action === "workspace-test") return await workspaceTest(config);
|
||||
const modelCatalog = loadRuntimeModelCatalog(config.modelCatalogFile);
|
||||
if (action === "effective-settings") {
|
||||
return effectiveSettings(config, loadSettings(config), modelCatalog);
|
||||
@@ -265,7 +146,6 @@ async function main(): Promise<void> {
|
||||
if (!action || ![
|
||||
"maintenance-activate", "maintenance-deactivate", "maintenance-status", "session-inventory",
|
||||
"workflow-doctor", "workspace-integrity", "pi-test", "effective-settings",
|
||||
"workspace-pull", "workspace-test",
|
||||
].includes(action)) throw new Error("invalid operator action");
|
||||
const result = await runOperatorAction(action, loadConfig(process.env));
|
||||
process.stdout.write(`${JSON.stringify(result)}\n`);
|
||||
|
||||
@@ -36,10 +36,6 @@ vi.mock("../src/tht/tht-runner.js", () => ({
|
||||
|
||||
vi.mock("../src/workspaces/registry.js", () => ({
|
||||
WorkspaceRegistry: class {
|
||||
async pull() {
|
||||
return { branch: "main", head: "a".repeat(40), ahead: 0, behind: 0, degraded: false };
|
||||
}
|
||||
|
||||
async listRetainedSnapshots() {
|
||||
return [{ snapshotPath: "/data/workspace-registry/snapshots/revision/workspace.yaml" }];
|
||||
}
|
||||
@@ -102,13 +98,3 @@ test("workflow doctor gives schema-v4 runtime rendering a live Catalog repositor
|
||||
expect(fakes.releaseWorkspaceRuntime).toHaveBeenCalledOnce();
|
||||
expect(fakes.catalogRepository.close).toHaveBeenCalledOnce();
|
||||
});
|
||||
|
||||
test("workspace pull exposes only safe Git status", async () => {
|
||||
await expect(runOperatorAction("workspace-pull", config)).resolves.toEqual({
|
||||
ready: true,
|
||||
status: "succeeded",
|
||||
branch: "main",
|
||||
head: "a".repeat(40),
|
||||
degraded: false,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,11 +8,6 @@ cp deploy/secrets/thothii.secrets.example deploy/secrets/thothii.secrets
|
||||
chmod 600 deploy/secrets/thothii.secrets
|
||||
```
|
||||
|
||||
For a normal local installation, `tht setup --complete` creates the active bundle at
|
||||
`deploy/local/secrets/thothii.secrets` and creates the two Catalog password files beside it. The
|
||||
generated `deploy/local/operator.env` contains only absolute paths to those files; never copy
|
||||
secret values into `operator.env`.
|
||||
|
||||
The file uses strict `KEY=VALUE` lines (comments and blank lines are allowed). The supported
|
||||
installation keys are `THT_MODEL_API_KEY`, `THT_DWH_API_KEY`, `THT_CA`, `THT_SSL_CA`,
|
||||
`THT_OIDC_CLIENT_SECRET`, and `THT_AUTHENTIK_API_TOKEN`. Installation Model Catalog providers may
|
||||
@@ -34,11 +29,6 @@ Session and metadata-generation runtimes read only the provider key named by
|
||||
credential reference, not their execution lifecycle. Pi-owned authentication remains available only
|
||||
to session-only built-in providers through `authentication.mode: pi_auth`.
|
||||
|
||||
Workspace database credentials are intentionally not part of this global bundle. Configure each
|
||||
workspace's database binding, password/token, tunnel key and CA in Database Management; the
|
||||
installation stores those values in its encrypted workspace secret store. The workspace Git
|
||||
repository may declare database identity and Evidence, but must never contain these credentials.
|
||||
|
||||
Do not add vector or embedding endpoint credentials to the bundle. Active operator manuals use
|
||||
internal Qdrant and Ollama services, so vector/embedding runtime endpoint secrets are not part of
|
||||
the supported installation contract.
|
||||
|
||||
+42
-41
@@ -1,63 +1,64 @@
|
||||
# Install and first start
|
||||
|
||||
Use the guided procedure for a fresh installation:
|
||||
Use one complete procedure for a fresh installation:
|
||||
|
||||
- [Italian guided installation](standalone-manual-it.md)
|
||||
- [English guided installation](standalone-manual-en.md)
|
||||
- [Italian manual installation](standalone-manual-it.md)
|
||||
- [English manual installation](standalone-manual-en.md)
|
||||
|
||||
The procedure covers Windows through Ubuntu WSL2, macOS, and Linux including an Omarchy/Arch-like
|
||||
host. It uses the application clone, one installation secret bundle, protected repository
|
||||
credentials when needed, and a terminal command. No host Node.js, Python or Pi installation is
|
||||
required.
|
||||
Both cover macOS, Windows through Ubuntu WSL2, and Linux. They use a Gitea clone,
|
||||
protected local configuration and manual terminal commands, without an application
|
||||
installer or launcher. See their verification matrix for tests still pending.
|
||||
|
||||
## What must be ready
|
||||
|
||||
You need Docker with Compose v2, Git, Bash, curl, OpenSSL and shasum. You also need access to the
|
||||
workspace repository and the values supplied by its owner: repository URL/branch, DWH endpoint,
|
||||
database/schema, transport, credentials or certificates, Evidence credentials when applicable,
|
||||
and LLM provider/API-key information.
|
||||
You need Docker with Compose, the host operator command `tht`, access to the workspace
|
||||
repository, and the credentials and network routes for the configured DWH and model
|
||||
providers. Pi runs inside the application runtime; no host Pi installation is needed.
|
||||
|
||||
The workspace repository and the THothII application repository are different. A workspace
|
||||
descriptor may declare Evidence, but database passwords and installation bindings are stored in
|
||||
the installation Catalog, not in Git.
|
||||
The stack includes `frontend`, `core`, `catalog-db`, `qdrant`, `embedding`, plus the
|
||||
one-shot `embedding-model-init` and `catalog-migrate` services. DWH and generative-model
|
||||
endpoints remain separate installation settings.
|
||||
|
||||
## One guided command
|
||||
Secrets, certificates, Pi authentication and endpoint bindings are protected local files.
|
||||
Do not commit them or copy the configuration of another machine unchanged.
|
||||
|
||||
After cloning THothII, checking prerequisites and installing tht, run:
|
||||
## Follow the ordered procedure
|
||||
|
||||
~~~
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
~~~
|
||||
The bilingual guides provide the exact commands for:
|
||||
|
||||
The first run creates protected placeholders under deploy/local/secrets/. Fill the required
|
||||
credential files and rerun the same command. The command validates the local files and paths,
|
||||
renders Compose, builds the images, starts catalog-db, runs catalog-migrate, starts the full
|
||||
stack, and pulls/activates the workspace repository. Evidence source files declared by the
|
||||
workspace are imported during activation.
|
||||
1. Cloning the selected revision and checking prerequisites.
|
||||
2. Bootstrapping the native host command.
|
||||
3. Preparing catalog passwords and using
|
||||
`tht setup --profile local --shell-mode full --shell-default-locale en --configure-only`.
|
||||
4. Completing model, authentication and workspace credentials.
|
||||
5. Generating configuration, building images and explicitly running `catalog-migrate`.
|
||||
6. Starting the installation and checking health and readiness.
|
||||
|
||||
Do not run setup alone as a substitute for that sequence. Migrations are not an
|
||||
implicit effect of backend startup or `tht start`. Do not mix this installation's
|
||||
descriptor/project with a different low-level Compose environment.
|
||||
|
||||
For an already configured installation:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
tht --installation /absolute/path/thothii-installation.yaml status
|
||||
tht --installation /absolute/path/thothii-installation.yaml doctor --json
|
||||
tht --installation /absolute/path/thothii-installation.yaml workspace test --json
|
||||
~~~
|
||||
```
|
||||
|
||||
doctor --json is the non-destructive general core test. workspace test also probes the configured
|
||||
database, Evidence, Qdrant and embedding service for every active workspace. It requires the
|
||||
workspace database to have been configured in Database Management first.
|
||||
`/health` checks application-process readiness. Doctor also checks configuration,
|
||||
workspace, workflow and Pi prerequisites; a healthy web page alone does not prove
|
||||
that a real database question can complete.
|
||||
|
||||
## Installer-only completion
|
||||
## After startup
|
||||
|
||||
The installer must still decide which LLMs and API keys are approved, configure and test each
|
||||
workspace database, synchronize its schema, generate and consolidate descriptions, create Qdrant
|
||||
entries, review naming-based FK suggestions alongside schema FKs, and load the approved
|
||||
relationships. The final declaration of completeness requires green doctor and workspace test
|
||||
results plus one real natural-language question completed through final SQL.
|
||||
Prepare [workspaces](../operations/workspaces.md), configure a database in
|
||||
[Database Management](../operations/database-management.md), and complete the functional
|
||||
checks in the installation guide before using real data.
|
||||
|
||||
Migrations are part of setup --complete. Do not mix this installation’s descriptor or volumes with
|
||||
a different Compose environment. Preserve the descriptor, credentials, Catalog and persistent
|
||||
volumes; do not use docker compose down --volumes as a routine stop.
|
||||
See [display mode and language](shell-and-language.md), [local authentication](authentication-local.md),
|
||||
[OIDC](authentication-oidc.md) and [model configuration](../general/pi-configuration.md)
|
||||
for later changes. Embedded portal integration is separate from a fresh standalone setup.
|
||||
|
||||
See the guides for the Windows/macOS/Linux prerequisite matrix, workspace repository explanation,
|
||||
secret layout and Gate A/Gate B acceptance checks.
|
||||
Use the installation's normal `tht start`, `tht stop` and diagnostic commands.
|
||||
Preserve its descriptor, credentials, database and persistent volumes; do not use
|
||||
`down --volumes` as a routine stop or upgrade.
|
||||
|
||||
@@ -1,256 +1,324 @@
|
||||
# Guided standalone installation
|
||||
# Manual standalone installation
|
||||
|
||||
[Versione italiana](standalone-manual-it.md)
|
||||
|
||||
This is the fresh-machine installation procedure for THothII. THothII receives a natural-language
|
||||
question, queries an enterprise database read-only, and guides the user through SQL review. The
|
||||
core, PostgreSQL catalog, Qdrant, embedding service, and Pi run in Docker; Node.js, Python, and Pi
|
||||
are not required on the host.
|
||||
This is the verification procedure for preparing THothII as a standalone application in `full`
|
||||
mode on macOS, Windows, and Linux.
|
||||
|
||||
## Before you start: the two repositories
|
||||
In this document, “standalone” means that the user does not need to install Node.js, Python or Pi
|
||||
on the host: the application services and local semantic
|
||||
services run through Docker. DWH and LLM providers remain external endpoints configured by the
|
||||
installation; this is not an offline package.
|
||||
|
||||
There are two separate repositories:
|
||||
This path uses no graphical installer, native launcher, or Docker Hub image. It starts from a Gitea
|
||||
clone and uses explicit terminal commands. Publishing pre-built images is a later step.
|
||||
|
||||
1. the application repository cloned by the user:
|
||||
https://git.tylconsulting.it/mptyl/ThothII.git;
|
||||
2. the workspace repository supplied by the curator/installer. It is not the THothII repository
|
||||
and must not be cloned inside the application directory.
|
||||
## Verification matrix
|
||||
|
||||
The workspace repository normally contains:
|
||||
| System | Recommended terminal | Runtime | Test architecture |
|
||||
| --- | --- | --- | --- |
|
||||
| macOS supported by the installed Docker Desktop version | Bash in Terminal | Docker Desktop | Apple Silicon (`arm64`) |
|
||||
| Windows 11 | Ubuntu inside WSL2 | Docker Desktop with WSL2 integration | x64 (`amd64`) |
|
||||
| Ubuntu Linux 22.04 or 24.04 | Bash | Docker Engine + Compose v2 | x64 (`amd64`) |
|
||||
|
||||
~~~
|
||||
thoth-workspaces.yaml
|
||||
<workspace-id>/workspace.yaml
|
||||
<workspace-id>/evidence/** # when Evidence is declared
|
||||
~~~
|
||||
Intel macOS is excluded from the first verification campaign. ARM Linux may be tested when the
|
||||
machine’s Docker runtime reports `arm64`, but it is not part of the minimum matrix.
|
||||
|
||||
workspace.yaml contains workspace identity, language and optional Evidence source. By design it does
|
||||
not contain database passwords. Database identity, transport (PostgreSQL, REST, or tunnel), user,
|
||||
password, token and certificates are installation-local settings stored encrypted by the Catalog.
|
||||
This prevents credentials from being committed to the workspace repository.
|
||||
Documentation and Mac prerequisite checks have passed. Complete fresh installations on all three
|
||||
systems remain pending; this matrix describes the tests to perform, not completed certification.
|
||||
|
||||
## 0. Machine prerequisites
|
||||
## Before you start
|
||||
|
||||
### Windows
|
||||
You need:
|
||||
|
||||
- Windows 10/11 with Docker Desktop running and the WSL2 backend enabled.
|
||||
- Ubuntu in WSL2, with Docker Desktop integration enabled for that distribution.
|
||||
- Git, Bash, curl, OpenSSL and shasum inside WSL2.
|
||||
- Do not install Node.js, Python or Pi on the host for this procedure.
|
||||
- access to the THothII Gitea repository and the workspace Git repository;
|
||||
- Git;
|
||||
- Docker Desktop on macOS and Windows, or Docker Engine with the Compose v2 plugin on Linux;
|
||||
- Bash, `curl`, OpenSSL and `shasum` (Ubuntu package: `libdigest-sha-perl`);
|
||||
- enough disk space to build the images and download the embedding model;
|
||||
- the DWH and LLM endpoints, plus the credentials required by the installation.
|
||||
|
||||
If WSL2 is not installed, use the company procedure or, in PowerShell:
|
||||
On Linux, the current user must be able to run Docker. If the system requires `sudo`, add the user
|
||||
to the Docker group according to local policy and open a new session before continuing.
|
||||
|
||||
~~~
|
||||
wsl --install -d Ubuntu
|
||||
~~~
|
||||
On Windows, run every command in this guide from Ubuntu under WSL2. In Docker Desktop, enable WSL2
|
||||
integration for that distribution. Clone the project inside the WSL2 Linux filesystem, for example
|
||||
under `~/src`, rather than under `/mnt/c`: this avoids slow builds and path/line-ending issues. Pi
|
||||
does not need to be installed on the host.
|
||||
|
||||
Run all commands inside Ubuntu WSL2, in a Linux directory such as $HOME/src, not under /mnt/c.
|
||||
scripts/install-tht.ps1 exists for advanced native PowerShell scenarios; use WSL2 for the
|
||||
reproducible test.
|
||||
Check the runtime before or immediately after cloning:
|
||||
|
||||
### macOS
|
||||
|
||||
- Docker Desktop installed and running, with several GB free for images and the embedding model.
|
||||
- Git, Bash, curl, OpenSSL and shasum.
|
||||
- Intel and Apple Silicon Macs are supported when Docker Desktop supports the architecture
|
||||
reported by the Docker server.
|
||||
- Do not install Node.js, Python or Pi on the host for this procedure.
|
||||
|
||||
### Linux, including Omarchy
|
||||
|
||||
- Git, Bash, curl, OpenSSL and shasum.
|
||||
- Docker Engine and the Docker Compose v2 plugin. On Omarchy, check first:
|
||||
|
||||
~~~
|
||||
command -v docker
|
||||
```sh
|
||||
docker version
|
||||
docker compose version
|
||||
docker info
|
||||
~~~
|
||||
|
||||
If Docker is missing, install Docker and Compose using the distribution-approved package procedure,
|
||||
then start the service. On an Arch-like distribution the typical route is:
|
||||
|
||||
~~~
|
||||
sudo pacman -S docker docker-compose
|
||||
sudo systemctl enable --now docker
|
||||
sudo usermod -aG docker "$USER"
|
||||
~~~
|
||||
|
||||
After adding the group, open a new session and repeat docker info. Node.js, Python and Pi are not
|
||||
needed on the host: they are in the Docker images.
|
||||
|
||||
On every system run:
|
||||
|
||||
~~~
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
docker version --format '{{.Server.Arch}}'
|
||||
~~~
|
||||
```
|
||||
|
||||
The architecture must be amd64, x86_64, arm64, or aarch64. You also need access to the
|
||||
application Gitea repository, the workspace repository URL/branch and credentials, container
|
||||
reachability to DWH/LLM endpoints, and the credentials, tokens or certificates associated with
|
||||
the databases.
|
||||
The last command must return `amd64`, `x86_64`, `arm64`, or `aarch64`.
|
||||
|
||||
## 1. What to clone
|
||||
## 1. Clone a project revision
|
||||
|
||||
Clone only the application:
|
||||
Use the project repository on Gitea:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
mkdir -p "$HOME/src"
|
||||
cd "$HOME/src"
|
||||
git clone https://git.tylconsulting.it/mptyl/ThothII.git
|
||||
cd ThothII
|
||||
git rev-parse --short HEAD
|
||||
~~~
|
||||
```
|
||||
|
||||
Record the revision. tht setup --complete downloads the workspace repository into a persistent
|
||||
Docker volume using the URL, branch and transport supplied during setup.
|
||||
For an SSH clone, when the key is already authorized on Gitea:
|
||||
|
||||
## 2. Install the terminal command
|
||||
```sh
|
||||
git clone git@git.tylconsulting.it:mptyl/ThothII.git
|
||||
```
|
||||
|
||||
Record the hash printed by `git rev-parse` for a repeatable test. In a later campaign, use the
|
||||
maintainer-approved revision/tag rather than implicitly following a mutable `main` branch.
|
||||
|
||||
## 2. Check prerequisites and install the operator command
|
||||
|
||||
From the clone root:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
THT_INSTALL_DIRECTORY="$HOME/.local/bin" bash scripts/install-tht.sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
THT_INSTALL_DIRECTORY="$HOME/.local/bin" bash scripts/install-tht.sh
|
||||
tht version
|
||||
~~~
|
||||
```
|
||||
|
||||
tht is the only native component to install. It builds the binary with Docker and orchestrates
|
||||
Compose; it is not a second application runtime.
|
||||
`install-tht.sh` bootstraps only the native `tht` operator command; it does not install a desktop
|
||||
version of THothII. It uses the repository’s Docker builder, installs the binary for the current
|
||||
terminal environment, and installs it in the user directory. Persist `$HOME/.local/bin` in your
|
||||
shell PATH for new terminals too. An existing `tht` in this directory will be updated.
|
||||
|
||||
## 3. Prepare a few secrets and run complete setup
|
||||
On Windows, run these commands inside WSL2. The installed `tht` binary is the Linux binary inside
|
||||
WSL2; the application runtime remains Docker Desktop. Do not use `scripts/install-tht.ps1` as the
|
||||
primary path for this test.
|
||||
|
||||
The first execution creates protected placeholders under deploy/local/secrets/ and stops if a
|
||||
required credential is missing. Fill in the requested files and rerun the same command; compatible
|
||||
configuration files are reused.
|
||||
## 3. Configure and start the local installation
|
||||
|
||||
~~~
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
~~~
|
||||
Run the remaining blocks in one Bash session from the physical clone root (`pwd -P`).
|
||||
First create two distinct catalog passwords, preserving any existing files:
|
||||
|
||||
The setup asks only for information the computer cannot know:
|
||||
```bash
|
||||
umask 077
|
||||
mkdir -p deploy/local/secrets
|
||||
for name in catalog-runtime-password catalog-migrator-password; do
|
||||
target="deploy/local/secrets/$name"
|
||||
if [ ! -e "$target" ]; then
|
||||
(set -C; openssl rand -hex 32 > "$target") || exit 1
|
||||
fi
|
||||
done
|
||||
export THT_CATALOG_RUNTIME_PASSWORD_SOURCE="$(pwd -P)/deploy/local/secrets/catalog-runtime-password"
|
||||
export THT_CATALOG_MIGRATOR_PASSWORD_SOURCE="$(pwd -P)/deploy/local/secrets/catalog-migrator-password"
|
||||
```
|
||||
|
||||
| Request | What to provide |
|
||||
Do not regenerate passwords for an initialized catalog. Configure without starting services:
|
||||
|
||||
```sh
|
||||
tht setup --profile local --shell-mode full --shell-default-locale en --configure-only
|
||||
```
|
||||
|
||||
Answer the prompts as follows:
|
||||
|
||||
| Prompt | Value or rule |
|
||||
| --- | --- |
|
||||
| Workspace repository | Data/configuration repository URL, not ThothII.git |
|
||||
| Branch | normally main |
|
||||
| Access | ssh with key and known_hosts, or https with credential file and CA |
|
||||
| DWH/LLM URL | endpoint without a token in the URL |
|
||||
| Local login | initial user and password requested by the prompt |
|
||||
| Installation ID | `local`, unless one clone hosts multiple installations |
|
||||
| Deployment profile | `local` |
|
||||
| DWH API endpoint | An `http(s)` URL without user, password, query, or fragment; may be empty for a smoke-only test |
|
||||
| LLM API endpoint | An `http(s)` URL without credentials; may be empty for a smoke-only test |
|
||||
| Workspace repository URL | The workspace repository URL, not the THothII source clone |
|
||||
| Workspace branch | Normally `main` |
|
||||
| Workspace access | `ssh` with a deploy key, or `https` with a protected credential file |
|
||||
| File paths | Accept the default paths under `deploy/local/secrets/` for the first test |
|
||||
| Secret templates | Answer `yes` when protected files do not exist yet |
|
||||
| Authentication | Configure the local login required by the installation; never put passwords on a command line |
|
||||
|
||||
The setup generates random Catalog passwords and writes their paths, never their values, to
|
||||
operator.env. It runs docker compose config, builds images, starts the Catalog, runs
|
||||
catalog-migrate, starts the stack, and pulls the workspace repository. The pull also activates
|
||||
declared Evidence; at minimum source files present in the workspace are materialized locally.
|
||||
The generated configuration is local and ignored by Git:
|
||||
|
||||
### The file the user fills in
|
||||
```text
|
||||
deploy/local/thothii-installation.yaml
|
||||
deploy/local/operator.env
|
||||
deploy/local/auth/
|
||||
deploy/local/secrets/
|
||||
```
|
||||
|
||||
The main file is:
|
||||
Edit secrets only in protected local files; never commit them. `deploy/env/local.env.example` is a tracked reference; the
|
||||
generated path `deploy/local/operator.env` is the active path for this installation.
|
||||
|
||||
~~~
|
||||
deploy/local/secrets/thothii.secrets
|
||||
~~~
|
||||
### Complete protected files
|
||||
|
||||
Add only NAME=VALUE lines needed by modelCatalog and installation adapters, such as an LLM API key
|
||||
(DEEPSEEK_API_KEY, OPENAI_API_KEY, or the key declared by the catalog) and, when applicable,
|
||||
THT_DWH_API_KEY. Allowed names are documented in deploy/secrets/README.md. Never put tokens in
|
||||
URLs, the repository, or copied shell commands.
|
||||
If setup created blank templates, enter the values with a local editor:
|
||||
|
||||
Two distinctions prevent common errors:
|
||||
```sh
|
||||
chmod 600 deploy/local/secrets/*
|
||||
"${EDITOR:-vi}" deploy/local/secrets/thothii.secrets
|
||||
```
|
||||
|
||||
- when the catalog uses pi_auth, the LLM token belongs in the Pi pi-auth.json file created by
|
||||
setup; {} is only a placeholder and does not enable a model;
|
||||
- workspace database credentials (PostgreSQL password, REST API token, tunnel SSH key,
|
||||
known_hosts, CA) do not belong in the workspace repository. Enter them per workspace in
|
||||
Database Management, which stores them encrypted in the Catalog. The workspace declares
|
||||
database/schema and transport; the installer must obtain the actual values from the database owner.
|
||||
The bundle must contain only `KEY=VALUE` lines for credentials actually used by `modelCatalog`. The
|
||||
allowed names and credential boundary are documented in the local file
|
||||
`deploy/secrets/README.md`. Do not put tokens in URLs, the YAML
|
||||
descriptor, the Git repository, or commands copied into the shell.
|
||||
|
||||
A private workspace repository also needs the Git files required by its transport: an SSH key and
|
||||
known_hosts, or an HTTPS credential file and CA. These are transport files, not a second bundle to
|
||||
commit. To minimize manual files, use SSH with an already-authorized deploy key.
|
||||
For SSH workspace access, also provide the private key and `known_hosts` file requested by setup.
|
||||
For HTTPS access, provide the Git credential file and any required CA. Both must remain protected
|
||||
and outside version control.
|
||||
|
||||
## 4. Automatic checks and terminal tests
|
||||
Before starting, complete these additional configuration steps:
|
||||
|
||||
Setup verifies files, permissions, descriptor, Compose, Docker, authentication, services, Pi and
|
||||
the workspace. After startup, run these commands at any time:
|
||||
1. Add `THT_CATALOG_RUNTIME_PASSWORD_SOURCE` and `THT_CATALOG_MIGRATOR_PASSWORD_SOURCE` to
|
||||
`deploy/local/operator.env`, with the same absolute paths exported above. Setup does not persist
|
||||
these two variables. Store paths, not passwords.
|
||||
2. Replace the descriptor's generic `modelCatalog` with the approved provider/model configuration.
|
||||
The generated defaults do not replicate the existing Mac. See [Pi/model configuration](../general/pi-configuration.md)
|
||||
and the local example `deploy/psd/thothii-installation.yaml.example`.
|
||||
3. Populate the keys referenced by `authentication.apiKeyEnv` in `thothii.secrets`. Providers using
|
||||
`pi_auth` need valid credentials at `PI_AUTH_FILE`; the `{}` template is not authentication.
|
||||
4. Complete the workspace Git files. SSH requires an authorized deploy key and verified known-hosts;
|
||||
HTTPS requires the credential file and CA bundle expected by the overlay. Blank templates cannot
|
||||
provide repository access.
|
||||
|
||||
~~~
|
||||
INSTALLATION="$PWD/deploy/local/thothii-installation.yaml"
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace pull --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
~~~
|
||||
After editing generated configuration, do not rerun setup: it rejects different existing content.
|
||||
Generate the projections and run the explicit migration below. Use `THT_GIT_ACCESS=https` if that
|
||||
was selected during setup. This block targets the fresh `local` descriptor with only the Git overlay;
|
||||
custom installations must include their extra descriptor overlays in the same order.
|
||||
|
||||
workspace test checks, for every active workspace, database binding and credentials, Evidence,
|
||||
Qdrant, and the embedding service. It exits non-zero when the database binding is missing or a
|
||||
connection is unusable. Before running it, the installer must configure the database in Database
|
||||
Management: the workspace repository cannot contain the password by itself.
|
||||
```bash
|
||||
INSTALLATION="$(pwd -P)/deploy/local/thothii-installation.yaml"
|
||||
tht --installation "$INSTALLATION" installation generate
|
||||
THT_PROJECT="thothii-$(printf '%s' "$INSTALLATION" | shasum -a 256 | cut -c 1-12)"
|
||||
THT_GIT_ACCESS=ssh
|
||||
compose=(
|
||||
docker compose --project-name "$THT_PROJECT" --project-directory "$(pwd -P)"
|
||||
--env-file "$(pwd -P)/deploy/local/operator.env"
|
||||
-f compose.yaml -f deploy/compose.local.yaml
|
||||
-f "deploy/compose.git-$THT_GIT_ACCESS.yaml"
|
||||
-f deploy/local/generated/compose.models.yaml
|
||||
)
|
||||
"${compose[@]}" config --quiet
|
||||
"${compose[@]}" build core frontend
|
||||
"${compose[@]}" up -d catalog-db
|
||||
"${compose[@]}" run --rm catalog-migrate
|
||||
tht --installation "$INSTALLATION" start
|
||||
```
|
||||
|
||||
doctor --json is the repeatable, non-destructive core verification. The final functional test must
|
||||
also open http://127.0.0.1:8080, sign in, and complete a real question through final SQL.
|
||||
Stop if a command fails. The project name matches the hash used by `tht`, preserving volume
|
||||
identity. `catalog-migrate` applies Catalog and Memory migrations; `tht start` does not run it
|
||||
automatically. Initial embedding-model download may take time. Use this installation-specific
|
||||
sequence, not `run-stack.sh` with a different environment/project name.
|
||||
|
||||
## Activities only the installer can complete
|
||||
## 4. Verify the installation
|
||||
|
||||
The procedure automates bootstrap, but it cannot invent enterprise decisions or authorizations.
|
||||
The installer must complete and record:
|
||||
The descriptor generated for the default ID is:
|
||||
|
||||
1. usable LLMs, the modelCatalog, and linked API keys; then run tht pi test and tht doctor;
|
||||
2. database configuration, connection test, schema synchronization, and description generation;
|
||||
3. human consolidation of generated descriptions;
|
||||
4. Qdrant semantic entries through workspace preprocess run;
|
||||
5. naming-based FK suggestions as a complement to schema FKs, human review, and loading approved
|
||||
relationships into Qdrant;
|
||||
6. recurring tht doctor --json and tht workspace test --json checks;
|
||||
7. one real question completed successfully without connection or model errors.
|
||||
```sh
|
||||
INSTALLATION="$(pwd -P)/deploy/local/thothii-installation.yaml"
|
||||
test -f "$INSTALLATION"
|
||||
bash scripts/verify-standalone-install.sh "$INSTALLATION"
|
||||
```
|
||||
|
||||
Configuration is complete only when all applicable activities are done, decisions are recorded, and
|
||||
the two terminal tests are green. The core is usable only after the real question, not merely
|
||||
because the frontend answers /health.
|
||||
The verifier is read-only: it runs `tht doctor --json` and `tht status` without restarting the
|
||||
stack, regenerating configuration, or printing secret contents.
|
||||
|
||||
## Gate A and Gate B
|
||||
### Gate A — platform smoke test on all three computers
|
||||
|
||||
### Gate A — platform
|
||||
Record the following for each machine:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
uname -a
|
||||
docker version --format '{{.Server.Version}} {{.Server.Arch}}'
|
||||
tht version
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
bash scripts/verify-standalone-install.sh "$INSTALLATION"
|
||||
~~~
|
||||
```
|
||||
|
||||
### Gate B — usability
|
||||
The gate passes when the clone is intact, Docker and Compose are reachable, `tht doctor` is OK, the
|
||||
stack is running, and the frontend responds at the default local URL `http://127.0.0.1:8080`.
|
||||
Doctor also checks workspace and Pi: record their failures separately rather than labeling every
|
||||
failure as a platform problem. Check HTTP readiness with:
|
||||
|
||||
~~~
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
```sh
|
||||
curl --fail --silent --show-error http://127.0.0.1:8080/health
|
||||
~~~
|
||||
```
|
||||
|
||||
Then run a real question and stop/restart with tht stop and tht start. Do not use docker compose
|
||||
down --volumes: it deletes the Catalog, sessions, Qdrant data and the embedding model.
|
||||
### Gate B — functional verification
|
||||
|
||||
Run this on at least one machine with available endpoints and credentials:
|
||||
|
||||
First follow [Workspace operations](../operations/workspaces.md) to import/prepare the workspace
|
||||
and configure the Database and local binding. The source clone does not transfer catalog data,
|
||||
secrets or sessions from the Mac. Connect any VPN required by DWH/model endpoints and verify
|
||||
that their names are reachable from containers too.
|
||||
|
||||
1. open `http://127.0.0.1:8080`;
|
||||
2. sign in with the configured local account;
|
||||
3. verify that the configured workspace is readable;
|
||||
4. start a real question and complete the review gates through final SQL;
|
||||
5. stop and restart the installation, then run `verify-standalone-install.sh` again.
|
||||
|
||||
A Gate B failure involving DWH, the LLM provider, workspace Git, or credentials does not by itself
|
||||
prove a Docker portability problem: record the failed endpoint or component separately.
|
||||
|
||||
## Daily lifecycle
|
||||
|
||||
Use the explicit descriptor when more than one installation may be discoverable:
|
||||
|
||||
```sh
|
||||
INSTALLATION="$PWD/deploy/local/thothii-installation.yaml"
|
||||
|
||||
tht --installation "$INSTALLATION" status
|
||||
tht --installation "$INSTALLATION" start
|
||||
tht --installation "$INSTALLATION" start --build
|
||||
tht --installation "$INSTALLATION" logs
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" stop
|
||||
```
|
||||
|
||||
Use `start --build` after source changes or to rebuild images from the current checkout. `stop`
|
||||
preserves volumes, sessions, the catalog, Pi state, Qdrant data, and the embedding model. Do not
|
||||
use `docker compose down --volumes` during a normal test: it is destructive and removes local data.
|
||||
For upgrades requiring migrations, follow the release runbook before starting the new application.
|
||||
|
||||
## Quick diagnosis
|
||||
|
||||
| Symptom | Action |
|
||||
| Symptom | Check |
|
||||
| --- | --- |
|
||||
| Docker Engine is not reachable | start Docker Desktop or systemctl and repeat docker info |
|
||||
| Omarchy cannot find docker | install Docker/Compose, enable the service and open a new session |
|
||||
| Windows sees Docker but Bash fails | use Ubuntu WSL2 and enable its Docker Desktop integration |
|
||||
| workspace pull fails | check URL, branch, key/credential file and known_hosts from the container |
|
||||
| workspace test reports a missing binding | configure database, token/password and CA in Database Management |
|
||||
| Pi is not ready | fill pi-auth.json or the key declared by modelCatalog, then run tht pi test |
|
||||
| `Docker Engine is not reachable` | start Docker Desktop or the Docker service and rerun `docker info` |
|
||||
| Windows sees Docker but Bash fails | run the guide inside Ubuntu WSL2 and enable that distribution in Docker Desktop |
|
||||
| `tht: command not found` | open a new shell and check `command -v tht`; rerun the bootstrap if needed |
|
||||
| line-ending or executable-script errors | use a clone in the WSL2/Linux filesystem and rerun `bash scripts/...` |
|
||||
| unsupported architecture | check `docker version --format '{{.Server.Arch}}'`; the test requires `amd64` or `arm64` |
|
||||
| missing descriptor or env file | use `deploy/local/...` generated by `tht setup`, not an arbitrary copied file |
|
||||
| healthy stack but workflow failure | check external URLs, the credential bundle, workspace Git, and authentication separately |
|
||||
| data appears missing | check that `down --volumes` was not used; `stop` does not remove volumes |
|
||||
|
||||
## Acceptance checklist
|
||||
|
||||
- [ ] The clone comes from the expected Gitea repository and the revision is recorded.
|
||||
- [ ] Docker Desktop/Engine and Compose v2 are available.
|
||||
- [ ] The runtime reports an allowed architecture.
|
||||
- [ ] `tht` was built from the repository and responds to `tht version`.
|
||||
- [ ] Setup uses `profile: local`, `shell.mode: full`, and `shell.defaultLocale: en`.
|
||||
- [ ] The descriptor, `operator.env`, authentication, and secrets exist only under `deploy/local/`.
|
||||
- [ ] No secret appears in Git, URLs, public YAML, or recorded commands.
|
||||
- [ ] Gate A passes on Apple Silicon macOS, x64 Windows WSL2, and x64 Linux.
|
||||
- [ ] Gate B runs on at least one machine with DWH and LLM available.
|
||||
- [ ] Stop/start and final verification complete without deleting volumes.
|
||||
|
||||
## Out of scope for this release
|
||||
|
||||
The following remain future work:
|
||||
|
||||
- publishing pre-built images on Docker Hub;
|
||||
- reducing prompts through a dedicated non-interactive configuration;
|
||||
- creating DMG, MSI/EXE, AppImage, or other native installers;
|
||||
- providing an offline runtime or bundling a local DWH/LLM into the application.
|
||||
|
||||
## Related documents
|
||||
|
||||
- [Install and first start](first-start.md)
|
||||
- [Shell and localization](shell-and-language.md)
|
||||
- [Workspace operations](../operations/workspaces.md)
|
||||
- [Database Management](../operations/database-management.md)
|
||||
- [Model configuration](../general/pi-configuration.md)
|
||||
- deploy/secrets/README.md
|
||||
|
||||
Publishing images on Docker Hub and native DMG/MSI/AppImage installers remain later work: this
|
||||
procedure starts from the Gitea clone and does not require pre-published Docker Hub images.
|
||||
- `deploy/secrets/README.md` (runtime secrets)
|
||||
|
||||
@@ -1,262 +1,329 @@
|
||||
# Installazione standalone guidata
|
||||
# Installazione manuale standalone
|
||||
|
||||
[English version](standalone-manual-en.md)
|
||||
|
||||
Questa è la procedura per installare THothII da zero. THothII riceve una domanda in linguaggio
|
||||
naturale, interroga in sola lettura un database aziendale e accompagna l’utente nella revisione
|
||||
della SQL risultante. Il core, il catalogo PostgreSQL, Qdrant, il servizio di embedding e Pi vengono
|
||||
eseguiti in Docker; sul computer non servono Node.js, Python o Pi.
|
||||
Questa è la procedura di prova per predisporre THothII come applicazione autonoma in modalità
|
||||
`full` su macOS, Windows e Linux.
|
||||
|
||||
## Prima di iniziare: i due repository
|
||||
In questo documento “autonoma” significa che l’utente non deve installare Node.js, Python o Pi
|
||||
sull'host: i servizi applicativi e i servizi semantici
|
||||
locali vengono eseguiti con Docker. DWH e provider LLM restano endpoint esterni configurati
|
||||
dall’installazione; questa procedura non è un pacchetto offline.
|
||||
|
||||
Servono due repository distinti:
|
||||
Il percorso non usa installer grafici, launcher nativi o immagini Docker Hub. Si parte da un clone
|
||||
Gitea e si usano comandi espliciti da terminale. La pubblicazione di immagini pre-costruite è una
|
||||
fase successiva.
|
||||
|
||||
1. il repository dell’applicazione, che l’utente clona:
|
||||
https://git.tylconsulting.it/mptyl/ThothII.git;
|
||||
2. il repository dei workspace, indicato dal curatore/installatore. Non è il repository di
|
||||
THothII e non va clonato manualmente nella directory dell’applicazione.
|
||||
## Matrice di verifica
|
||||
|
||||
Il repository workspace contiene il catalogo e una directory per ogni workspace, normalmente:
|
||||
| Sistema | Terminale raccomandato | Runtime | Architettura della prova |
|
||||
| --- | --- | --- | --- |
|
||||
| macOS supportato dalla versione Docker Desktop installata | Bash nel Terminale | Docker Desktop | Apple Silicon (`arm64`) |
|
||||
| Windows 11 | Ubuntu dentro WSL2 | Docker Desktop con integrazione WSL2 | x64 (`amd64`) |
|
||||
| Linux Ubuntu 22.04 o 24.04 | Bash | Docker Engine + Compose v2 | x64 (`amd64`) |
|
||||
|
||||
~~~
|
||||
thoth-workspaces.yaml
|
||||
<workspace-id>/workspace.yaml
|
||||
<workspace-id>/evidence/** # se il workspace dichiara Evidence
|
||||
~~~
|
||||
Intel macOS non fa parte della prima campagna di verifica. ARM Linux può essere provato quando il
|
||||
runtime Docker della macchina restituisce `arm64`, ma non è un requisito della matrice minima.
|
||||
|
||||
Il file workspace.yaml descrive identità, lingua e, opzionalmente, la sorgente Evidence. Per scelta
|
||||
architetturale non contiene password del database. L’identità del database, il trasporto
|
||||
(PostgreSQL, REST o tunnel), username, password, token e certificati sono configurazione locale
|
||||
dell’installazione, conservata cifrata dal Catalog. Questo evita di committare credenziali nel
|
||||
repository workspace.
|
||||
Le verifiche documentali e dei prerequisiti Mac sono passate. Le installazioni complete da zero
|
||||
sui tre sistemi restano da eseguire: la matrice indica le prove previste, non una certificazione.
|
||||
|
||||
## 0. Prerequisiti della macchina
|
||||
## Cosa serve prima di iniziare
|
||||
|
||||
### Windows
|
||||
Servono:
|
||||
|
||||
- Windows 10/11 con Docker Desktop avviato e backend WSL2 abilitato.
|
||||
- Ubuntu in WSL2, con integrazione Docker Desktop abilitata per quella distribuzione.
|
||||
- Git, Bash, curl, OpenSSL e shasum nella distribuzione WSL2.
|
||||
- Non installare Node.js, Python o Pi sull’host per questa procedura.
|
||||
- accesso al repository Gitea di THothII e al repository Git dei workspace;
|
||||
- Git;
|
||||
- Docker Desktop su macOS e Windows, oppure Docker Engine con il plugin Compose v2 su Linux;
|
||||
- Bash, `curl`, OpenSSL e `shasum` (su Ubuntu, pacchetto `libdigest-sha-perl`);
|
||||
- spazio disco sufficiente per compilare le immagini e scaricare il modello di embedding;
|
||||
- gli endpoint DWH e LLM, più le credenziali che l’installazione deve usare.
|
||||
|
||||
In PowerShell, se WSL2 non esiste ancora, usare la procedura aziendale oppure:
|
||||
Su Linux l’utente corrente deve poter eseguire Docker. Se il sistema richiede `sudo`, aggiungere
|
||||
l’utente al gruppo Docker secondo la policy locale e aprire una nuova sessione prima di continuare.
|
||||
|
||||
~~~
|
||||
wsl --install -d Ubuntu
|
||||
~~~
|
||||
Su Windows usare Ubuntu in WSL2 per tutti i comandi di questa guida. In Docker Desktop attivare
|
||||
l’integrazione WSL2 per quella distribuzione. Clonare il progetto nel filesystem Linux di WSL2,
|
||||
per esempio sotto `~/src`, e non sotto `/mnt/c`: si evitano rallentamenti e problemi di permessi o
|
||||
line ending. Non è necessario installare Pi sull’host.
|
||||
|
||||
Eseguire poi tutti i comandi dentro Ubuntu WSL2, in una directory Linux come $HOME/src, non sotto
|
||||
/mnt/c. Il percorso nativo scripts/install-tht.ps1 esiste per scenari PowerShell avanzati; per la
|
||||
prova riproducibile usare WSL2.
|
||||
Verificare il runtime prima del clone o subito dopo:
|
||||
|
||||
### macOS
|
||||
|
||||
- Docker Desktop installato, avviato e con alcuni GB liberi per immagini e modello di embedding.
|
||||
- Git, Bash, curl, OpenSSL e shasum.
|
||||
- Sono supportati Mac Intel e Apple Silicon se Docker Desktop supporta l’architettura restituita
|
||||
dal Docker server.
|
||||
- Non installare Node.js, Python o Pi sull’host per questa procedura.
|
||||
|
||||
### Linux, incluso Omarchy
|
||||
|
||||
- Git, Bash, curl, OpenSSL e shasum.
|
||||
- Docker Engine e il plugin Docker Compose v2. Su Omarchy verificare prima:
|
||||
|
||||
~~~
|
||||
command -v docker
|
||||
```sh
|
||||
docker version
|
||||
docker compose version
|
||||
docker info
|
||||
~~~
|
||||
|
||||
Se Docker manca, installare Docker e Compose con il gestore pacchetti/procedura approvata dalla
|
||||
distribuzione, poi avviare il servizio. Su una distribuzione Arch-like il percorso tipico è:
|
||||
|
||||
~~~
|
||||
sudo pacman -S docker docker-compose
|
||||
sudo systemctl enable --now docker
|
||||
sudo usermod -aG docker "$USER"
|
||||
~~~
|
||||
|
||||
Dopo l’aggiunta al gruppo aprire una nuova sessione e ripetere docker info. Non installare Node.js,
|
||||
Python o Pi sull’host: sono dentro le immagini Docker.
|
||||
|
||||
Su tutti i sistemi il controllo finale è:
|
||||
|
||||
~~~
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
docker version --format '{{.Server.Arch}}'
|
||||
~~~
|
||||
```
|
||||
|
||||
L’architettura deve essere amd64, x86_64, arm64 o aarch64. Servono inoltre accesso al repository
|
||||
Gitea dell’applicazione, URL/branch e credenziali del repository workspace, raggiungibilità dal
|
||||
container degli endpoint DWH/LLM e le credenziali, token o certificati associati ai database.
|
||||
L’ultima istruzione deve restituire `amd64`, `x86_64`, `arm64` o `aarch64`.
|
||||
|
||||
## 1. Cosa clonare
|
||||
## 1. Clonare una revisione del progetto
|
||||
|
||||
Clonare solo l’applicazione:
|
||||
Usare il repository di progetto su Gitea:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
mkdir -p "$HOME/src"
|
||||
cd "$HOME/src"
|
||||
git clone https://git.tylconsulting.it/mptyl/ThothII.git
|
||||
cd ThothII
|
||||
git rev-parse --short HEAD
|
||||
~~~
|
||||
```
|
||||
|
||||
Annotare la revisione. Il repository workspace verrà scaricato da tht setup --complete dentro un
|
||||
volume Docker persistente, usando URL, branch e trasporto indicati durante il setup.
|
||||
Per un clone SSH usare, se la chiave è già autorizzata su Gitea:
|
||||
|
||||
## 2. Installare il comando terminale
|
||||
```sh
|
||||
git clone git@git.tylconsulting.it:mptyl/ThothII.git
|
||||
```
|
||||
|
||||
Per una prova ripetibile annotare l’hash stampato da `git rev-parse`. In una campagna successiva
|
||||
usare la revisione/tag approvata dal maintainer invece di seguire implicitamente una `main` che
|
||||
può cambiare.
|
||||
|
||||
## 2. Verificare i prerequisiti e installare il comando operatore
|
||||
|
||||
Dal root del clone:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
THT_INSTALL_DIRECTORY="$HOME/.local/bin" bash scripts/install-tht.sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
THT_INSTALL_DIRECTORY="$HOME/.local/bin" bash scripts/install-tht.sh
|
||||
tht version
|
||||
~~~
|
||||
```
|
||||
|
||||
Il comando tht è l’unico componente nativo da installare. Costruisce il binario con Docker e
|
||||
orchestra Compose; non è un secondo runtime dell’applicazione.
|
||||
`install-tht.sh` è un bootstrap del solo comando operatore nativo `tht`; non installa una versione
|
||||
desktop di THothII. Usa il builder Docker del repository, installa il binario adatto all’ambiente
|
||||
del terminale e lo installa nella directory utente. Aggiungere `$HOME/.local/bin` al PATH della
|
||||
shell anche per i terminali successivi. Un `tht` già presente in quella directory viene aggiornato.
|
||||
|
||||
## 3. Preparare pochi segreti e avviare il setup completo
|
||||
Su Windows, eseguire questi comandi dentro WSL2. Il binario `tht` installato è quello Linux di WSL2;
|
||||
il runtime dell’applicazione rimane Docker Desktop. Non usare `scripts/install-tht.ps1` come percorso
|
||||
principale di questa prova.
|
||||
|
||||
La prima esecuzione crea i placeholder protetti sotto deploy/local/secrets/ e si ferma se manca
|
||||
una credenziale necessaria. Compilare i file indicati e rilanciare lo stesso comando: i file di
|
||||
configurazione già compatibili vengono riutilizzati.
|
||||
## 3. Configurare e avviare l’installazione locale
|
||||
|
||||
~~~
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
~~~
|
||||
Eseguire i blocchi successivi nella stessa sessione Bash dal root fisico del clone (`pwd -P`).
|
||||
Creare prima le due password distinte del catalogo, conservando eventuali file già esistenti:
|
||||
|
||||
Durante il setup servono solo le informazioni operative che il computer non può conoscere:
|
||||
```bash
|
||||
umask 077
|
||||
mkdir -p deploy/local/secrets
|
||||
for name in catalog-runtime-password catalog-migrator-password; do
|
||||
target="deploy/local/secrets/$name"
|
||||
if [ ! -e "$target" ]; then
|
||||
(set -C; openssl rand -hex 32 > "$target") || exit 1
|
||||
fi
|
||||
done
|
||||
export THT_CATALOG_RUNTIME_PASSWORD_SOURCE="$(pwd -P)/deploy/local/secrets/catalog-runtime-password"
|
||||
export THT_CATALOG_MIGRATOR_PASSWORD_SOURCE="$(pwd -P)/deploy/local/secrets/catalog-migrator-password"
|
||||
```
|
||||
|
||||
| Richiesta | Cosa inserire |
|
||||
Non rigenerare le password di un catalogo già inizializzato. Configurare senza avviare i servizi:
|
||||
|
||||
```sh
|
||||
tht setup --profile local --shell-mode full --shell-default-locale en --configure-only
|
||||
```
|
||||
|
||||
Rispondere ai prompt nel seguente modo:
|
||||
|
||||
| Prompt | Valore o regola |
|
||||
| --- | --- |
|
||||
| Repository workspace | URL del repository dati/configurazione, non ThothII.git |
|
||||
| Branch | normalmente main |
|
||||
| Accesso | ssh con chiave e known_hosts, oppure https con credential file e CA |
|
||||
| DWH/LLM URL | endpoint senza token nella URL |
|
||||
| Login locale | utente e password iniziale richiesti dal prompt |
|
||||
| Installation ID | `local`, salvo necessità di più installazioni nello stesso clone |
|
||||
| Deployment profile | `local` |
|
||||
| DWH API endpoint | URL `http(s)` senza user, password, query o fragment; può restare vuoto per il solo smoke test |
|
||||
| LLM API endpoint | URL `http(s)` senza credenziali; può restare vuoto per il solo smoke test |
|
||||
| Workspace repository URL | URL del repository dei workspace, non il clone sorgente di THothII |
|
||||
| Workspace branch | normalmente `main` |
|
||||
| Workspace access | `ssh` se si usa una chiave deploy; altrimenti `https` con credential file protetto |
|
||||
| Percorsi dei file | accettare i percorsi predefiniti sotto `deploy/local/secrets/` nella prima prova |
|
||||
| Secret templates | rispondere `yes` quando i file protetti non esistono ancora |
|
||||
| Autenticazione | configurare il login locale richiesto dall’installazione; non inserire password in una riga di comando |
|
||||
|
||||
Il setup crea automaticamente le password casuali del Catalog e le scrive in operator.env come
|
||||
percorsi, non come valori. Esegue docker compose config, costruisce le immagini, avvia il Catalog,
|
||||
esegue catalog-migrate, avvia lo stack e importa il repository workspace. L’import attiva anche
|
||||
l’Evidence dichiarata: almeno i file source presenti nel workspace vengono materializzati nel
|
||||
registro locale.
|
||||
La configurazione generata è locale e ignorata da Git:
|
||||
|
||||
### Il file da compilare
|
||||
```text
|
||||
deploy/local/thothii-installation.yaml
|
||||
deploy/local/operator.env
|
||||
deploy/local/auth/
|
||||
deploy/local/secrets/
|
||||
```
|
||||
|
||||
Il file principale è:
|
||||
Modificare i segreti solo nei file locali protetti; non committarli. Il file `deploy/env/local.env.example` è un riferimento
|
||||
tracciato; il percorso generato da `tht setup`, `deploy/local/operator.env`, è quello da usare per
|
||||
questa installazione.
|
||||
|
||||
~~~
|
||||
deploy/local/secrets/thothii.secrets
|
||||
~~~
|
||||
### Completare i file protetti
|
||||
|
||||
Inserire solo righe NOME=VALORE necessarie al modelCatalog e agli adapter, per esempio una API key
|
||||
LLM (DEEPSEEK_API_KEY, OPENAI_API_KEY o quella dichiarata dal catalogo) ed eventualmente
|
||||
THT_DWH_API_KEY. I nomi ammessi sono documentati in deploy/secrets/README.md. Non mettere token
|
||||
nelle URL, nel repository o nei comandi.
|
||||
Se il setup ha creato template vuoti, inserire i valori con un editor locale:
|
||||
|
||||
Due precisazioni evitano gli errori più comuni:
|
||||
```sh
|
||||
chmod 600 deploy/local/secrets/*
|
||||
"${EDITOR:-vi}" deploy/local/secrets/thothii.secrets
|
||||
```
|
||||
|
||||
- se il catalogo usa pi_auth, il token LLM va nel file Pi pi-auth.json creato dal setup; {} è solo
|
||||
un placeholder e non abilita alcun modello;
|
||||
- le credenziali specifiche di un database workspace (password PostgreSQL, API token REST, chiave
|
||||
SSH del tunnel, known_hosts, CA) non vanno nel repository workspace: si inseriscono per workspace
|
||||
in Database Management, che le conserva nel Catalog cifrato. Il workspace indica database/schema
|
||||
e trasporto; l’installatore deve ottenere dal proprietario il valore corretto.
|
||||
Il bundle deve contenere solo righe `KEY=VALUE` per le credenziali effettivamente usate dal
|
||||
`modelCatalog`. I nomi ammessi e il confine delle credenziali sono descritti nel file locale
|
||||
`deploy/secrets/README.md`. Non mettere token nelle URL, nel
|
||||
descriptor YAML, nel repository Git o nei comandi copiati nella shell.
|
||||
|
||||
Per un repository workspace privato sono inoltre indispensabili i file Git richiesti dal trasporto:
|
||||
una chiave SSH e known_hosts, oppure credential file HTTPS e CA. Sono file di trasporto, non un
|
||||
secondo bundle da committare. Per ridurre i file da compilare, usare SSH con una deploy key già
|
||||
autorizzata.
|
||||
Per accesso workspace SSH, predisporre anche la chiave privata e il file `known_hosts` indicati dal
|
||||
setup. Per accesso HTTPS, predisporre il credential file Git e l’eventuale CA. Entrambi devono
|
||||
restare protetti e fuori dal controllo versione.
|
||||
|
||||
## 4. Controlli automatici e test da terminale
|
||||
Prima dell'avvio completare anche questi passaggi:
|
||||
|
||||
Il setup verifica file, permessi, descriptor, Compose, Docker, autenticazione, servizi, Pi e
|
||||
workspace. Dopo l’avvio usare questi comandi in qualunque momento:
|
||||
1. Aggiungere `THT_CATALOG_RUNTIME_PASSWORD_SOURCE` e `THT_CATALOG_MIGRATOR_PASSWORD_SOURCE` a
|
||||
`deploy/local/operator.env`, con gli stessi percorsi assoluti esportati sopra. Il setup non salva
|
||||
queste due variabili. Inserire i percorsi, non le password.
|
||||
2. Sostituire il `modelCatalog` generico nel descriptor con la configurazione provider/modelli
|
||||
approvata. I default generati non replicano il Mac esistente. Vedere [configurazione Pi/modelli](../general/pi-configuration.md)
|
||||
e l'esempio locale `deploy/psd/thothii-installation.yaml.example`.
|
||||
3. Inserire in `thothii.secrets` le chiavi referenziate da `authentication.apiKeyEnv`. I provider
|
||||
`pi_auth` richiedono credenziali valide nel file `PI_AUTH_FILE`; il template `{}` non autentica.
|
||||
4. Completare i file Git del workspace. SSH richiede una chiave deploy autorizzata e known-hosts
|
||||
verificato; HTTPS richiede il credential file e il bundle CA previsti dall'overlay. I template
|
||||
vuoti non consentono l'accesso al repository.
|
||||
|
||||
~~~
|
||||
INSTALLATION="$PWD/deploy/local/thothii-installation.yaml"
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace pull --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
~~~
|
||||
Dopo aver modificato la configurazione generata, non rilanciare setup: rifiuta file esistenti con
|
||||
contenuti diversi. Generare le proiezioni ed eseguire la migrazione esplicita indicata sotto.
|
||||
Impostare `THT_GIT_ACCESS=https` se scelto nel setup. Il blocco usa il nuovo descriptor `local`
|
||||
con il solo overlay Git; per installazioni personalizzate includere gli overlay aggiuntivi
|
||||
nello stesso ordine del descriptor.
|
||||
|
||||
workspace test prova, per ogni workspace attivo, il binding del database e le credenziali, Evidence,
|
||||
Qdrant e il servizio embedding. Restituisce exit code diverso da zero se manca il binding del
|
||||
database o una connessione non è utilizzabile. Prima di eseguirlo l’installatore deve aver
|
||||
configurato il database in Database Management: il workspace repository da solo non può contenere
|
||||
la password.
|
||||
```bash
|
||||
INSTALLATION="$(pwd -P)/deploy/local/thothii-installation.yaml"
|
||||
tht --installation "$INSTALLATION" installation generate
|
||||
THT_PROJECT="thothii-$(printf '%s' "$INSTALLATION" | shasum -a 256 | cut -c 1-12)"
|
||||
THT_GIT_ACCESS=ssh
|
||||
compose=(
|
||||
docker compose --project-name "$THT_PROJECT" --project-directory "$(pwd -P)"
|
||||
--env-file "$(pwd -P)/deploy/local/operator.env"
|
||||
-f compose.yaml -f deploy/compose.local.yaml
|
||||
-f "deploy/compose.git-$THT_GIT_ACCESS.yaml"
|
||||
-f deploy/local/generated/compose.models.yaml
|
||||
)
|
||||
"${compose[@]}" config --quiet
|
||||
"${compose[@]}" build core frontend
|
||||
"${compose[@]}" up -d catalog-db
|
||||
"${compose[@]}" run --rm catalog-migrate
|
||||
tht --installation "$INSTALLATION" start
|
||||
```
|
||||
|
||||
Per una verifica generale del core, doctor --json è il test ripetibile e non distruttivo. Il test
|
||||
funzionale finale deve inoltre aprire http://127.0.0.1:8080, autenticarsi e completare una domanda
|
||||
reale fino alla SQL finale.
|
||||
Fermarsi se un comando fallisce. Il nome progetto coincide con l'hash usato da `tht`, preservando
|
||||
l'identità dei volumi. `catalog-migrate` applica le migrazioni Catalog e Memory; `tht start` non
|
||||
lo esegue automaticamente. Il primo download del modello embedding può richiedere tempo.
|
||||
Usare questa sequenza legata all'installazione, non `run-stack.sh` con env/progetto diversi.
|
||||
|
||||
## Attività che può svolgere solo l’installatore
|
||||
## 4. Verificare l’installazione
|
||||
|
||||
La procedura automatizza il bootstrap, non può inventare decisioni o autorizzazioni aziendali.
|
||||
L’installatore deve completare e registrare:
|
||||
Il descriptor generato per l’ID predefinito è:
|
||||
|
||||
1. quali LLM sono utilizzabili, il relativo modelCatalog e le API key collegate; poi eseguire
|
||||
tht pi test e tht doctor;
|
||||
2. per ogni database: configurazione, test connessione, sincronizzazione dello schema e
|
||||
generazione delle descrizioni;
|
||||
3. consolidamento umano delle descrizioni generate;
|
||||
4. generazione delle entry semantiche in Qdrant tramite workspace preprocess run;
|
||||
5. generazione delle FK suggerite dal naming, come complemento alle FK lette dallo schema, revisione
|
||||
umana delle proposte e caricamento delle relazioni approvate in Qdrant;
|
||||
6. verifica periodica con tht doctor --json e tht workspace test --json;
|
||||
7. una domanda reale completata con successo, senza errori di connessione o modello.
|
||||
```sh
|
||||
INSTALLATION="$(pwd -P)/deploy/local/thothii-installation.yaml"
|
||||
test -f "$INSTALLATION"
|
||||
bash scripts/verify-standalone-install.sh "$INSTALLATION"
|
||||
```
|
||||
|
||||
La configurazione è dichiarata completa solo quando tutti i punti applicabili sono stati eseguiti,
|
||||
le decisioni sono state registrate e i due test terminali sono verdi. Il core è dichiarato usabile
|
||||
solo dopo la domanda reale, non perché il frontend risponde a /health.
|
||||
Il verificatore è read-only: esegue `tht doctor --json` e `tht status`, senza ristartare lo stack,
|
||||
rigenerare la configurazione o stampare il contenuto dei segreti.
|
||||
|
||||
## Gate A e Gate B
|
||||
### Gate A — smoke di piattaforma, su tutti e tre i computer
|
||||
|
||||
### Gate A — piattaforma
|
||||
Registrare per ogni macchina:
|
||||
|
||||
~~~
|
||||
```sh
|
||||
uname -a
|
||||
docker version --format '{{.Server.Version}} {{.Server.Arch}}'
|
||||
tht version
|
||||
bash scripts/check-standalone-prerequisites.sh
|
||||
bash scripts/verify-standalone-install.sh "$INSTALLATION"
|
||||
~~~
|
||||
```
|
||||
|
||||
### Gate B — usabilità
|
||||
Il gate passa quando il clone è integro, Docker e Compose sono raggiungibili, `tht doctor` è OK,
|
||||
lo stack è avviato e il frontend risponde sulla porta locale predefinita `http://127.0.0.1:8080`.
|
||||
Il doctor controlla anche workspace e Pi: registrare separatamente i loro errori senza attribuire
|
||||
ogni fallimento alla piattaforma. Verificare la disponibilità HTTP con:
|
||||
|
||||
~~~
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" workspace test --json
|
||||
```sh
|
||||
curl --fail --silent --show-error http://127.0.0.1:8080/health
|
||||
~~~
|
||||
```
|
||||
|
||||
Poi eseguire una domanda reale e fermare/riavviare con tht stop e tht start. Non usare docker
|
||||
compose down --volumes: cancella Catalog, sessioni, Qdrant e il modello embedding.
|
||||
### Gate B — verifica funzionale
|
||||
|
||||
Eseguire almeno su una macchina con endpoint e credenziali disponibili:
|
||||
|
||||
Seguire prima [Workspace operations](../operations/workspaces.md) per importare/preparare il
|
||||
workspace e configurare Database e binding locale. Il clone sorgente non trasferisce catalogo,
|
||||
segreti o sessioni del Mac. Connettere l'eventuale VPN richiesta da DWH/modelli e verificare
|
||||
che i relativi nomi siano raggiungibili anche dai container.
|
||||
|
||||
1. aprire `http://127.0.0.1:8080`;
|
||||
2. autenticarsi con l’account locale configurato;
|
||||
3. verificare che il workspace configurato sia leggibile;
|
||||
4. avviare una domanda reale e completare i gate di revisione fino alla SQL finale;
|
||||
5. fermare e riavviare l’installazione, poi ripetere `verify-standalone-install.sh`.
|
||||
|
||||
Un fallimento del Gate B per DWH, provider LLM, Git workspace o credenziali non dimostra da solo un
|
||||
problema di portabilità Docker: registrare separatamente l’endpoint o il componente fallito.
|
||||
|
||||
## Ciclo di vita quotidiano
|
||||
|
||||
Usare il descriptor esplicito quando più installazioni possono essere scoperte:
|
||||
|
||||
```sh
|
||||
INSTALLATION="$PWD/deploy/local/thothii-installation.yaml"
|
||||
|
||||
tht --installation "$INSTALLATION" status
|
||||
tht --installation "$INSTALLATION" start
|
||||
tht --installation "$INSTALLATION" start --build
|
||||
tht --installation "$INSTALLATION" logs
|
||||
tht --installation "$INSTALLATION" doctor --json
|
||||
tht --installation "$INSTALLATION" stop
|
||||
```
|
||||
|
||||
`start --build` è necessario dopo una modifica al codice o per ricostruire le immagini dal clone
|
||||
corrente. `stop` conserva volumi, sessioni, catalogo, stato Pi, dati Qdrant e modello embedding.
|
||||
Non usare `docker compose down --volumes` durante una prova normale: è un’operazione distruttiva
|
||||
che cancella i dati locali.
|
||||
Per aggiornamenti che richiedono migrazioni, seguire il runbook della release prima dell'avvio.
|
||||
|
||||
## Diagnosi rapida
|
||||
|
||||
| Sintomo | Azione |
|
||||
| Sintomo | Controllo |
|
||||
| --- | --- |
|
||||
| Docker Engine is not reachable | avviare Docker Desktop o systemctl e ripetere docker info |
|
||||
| Omarchy non trova docker | installare Docker/Compose, abilitare il servizio e riaprire la sessione |
|
||||
| Windows vede Docker ma Bash fallisce | usare Ubuntu WSL2 e abilitarne l’integrazione in Docker Desktop |
|
||||
| pull workspace fallisce | controllare URL, branch, chiave/credential file e known_hosts dal container |
|
||||
| workspace test segnala binding mancante | configurare database, token/password e CA in Database Management |
|
||||
| Pi non è pronto | compilare pi-auth.json o la chiave dichiarata dal modelCatalog, poi eseguire tht pi test |
|
||||
| `Docker Engine is not reachable` | avviare Docker Desktop oppure il servizio Docker e ripetere `docker info` |
|
||||
| Windows vede Docker ma Bash fallisce | eseguire la guida dentro Ubuntu WSL2 e abilitare l’integrazione della distribuzione in Docker Desktop |
|
||||
| `tht: command not found` | aprire una nuova shell e verificare `command -v tht`; se necessario ripetere il bootstrap |
|
||||
| line ending o script non eseguibile | usare un clone nel filesystem WSL2/Linux e rieseguire `bash scripts/...` |
|
||||
| architettura non supportata | verificare `docker version --format '{{.Server.Arch}}'`; la prova richiede `amd64` o `arm64` |
|
||||
| descriptor o env file mancanti | usare il percorso `deploy/local/...` generato da `tht setup`, non un file copiato casualmente |
|
||||
| stack sano ma workflow fallisce | controllare separatamente URL, credential bundle, workspace Git e autenticazione |
|
||||
| dati apparentemente persi | verificare che non sia stato usato `down --volumes`; `stop` non rimuove i volumi |
|
||||
|
||||
## Checklist di accettazione
|
||||
|
||||
- [ ] Il clone proviene dal repository Gitea atteso e la revisione è stata annotata.
|
||||
- [ ] Docker Desktop/Engine e Compose v2 sono disponibili.
|
||||
- [ ] Il runtime restituisce un’architettura ammessa.
|
||||
- [ ] `tht` è stato costruito dal repository e risponde a `tht version`.
|
||||
- [ ] Il setup usa `profile: local`, `shell.mode: full` e `shell.defaultLocale: en`.
|
||||
- [ ] Descriptor, `operator.env`, autenticazione e segreti sono presenti solo in `deploy/local/`.
|
||||
- [ ] Nessun segreto compare in Git, URL, YAML pubblico o comandi registrati.
|
||||
- [ ] Gate A superato su macOS Apple Silicon, Windows WSL2/x64 e Linux x64.
|
||||
- [ ] Gate B eseguito almeno su una macchina con DWH e LLM disponibili.
|
||||
- [ ] Stop/start e verifica finale completati senza cancellare i volumi.
|
||||
|
||||
## Fuori perimetro di questa release
|
||||
|
||||
Restano attività successive:
|
||||
|
||||
- pubblicare immagini pre-costruite su Docker Hub;
|
||||
- ridurre ulteriormente i prompt tramite una configurazione non interattiva dedicata;
|
||||
- creare pacchetti DMG, MSI/EXE, AppImage o altri installer nativi;
|
||||
- fornire un runtime offline o un DWH/LLM locale incluso nell’applicazione.
|
||||
|
||||
## Documenti collegati
|
||||
|
||||
- [Installazione e primo avvio](first-start.md)
|
||||
- [Operazioni sui workspace](../operations/workspaces.md)
|
||||
- [Database Management](../operations/database-management.md)
|
||||
- [Configurazione dei modelli](../general/pi-configuration.md)
|
||||
- deploy/secrets/README.md
|
||||
|
||||
La pubblicazione di immagini su Docker Hub e gli installer nativi DMG/MSI/AppImage restano attività
|
||||
successive: questa procedura parte dal clone Gitea e non richiede immagini Docker Hub pre-pubblicate.
|
||||
- [Install and first start](first-start.md)
|
||||
- [Shell and localization](shell-and-language.md)
|
||||
- [Workspace operations](../operations/workspaces.md)
|
||||
- `deploy/secrets/README.md` (runtime secrets)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Consegna a Codex sul server: ThothII e Omics Portal
|
||||
|
||||
Revisione: **14 settembre 2026**. Destinazione: Datamart Builder nel portale
|
||||
Revisione: **26 settembre 2026**. Destinazione: Datamart Builder nel portale
|
||||
Omics esistente, non un nuovo sito standalone. Questo documento è la procedura
|
||||
di riferimento per questa consegna e sostituisce le precedenti istruzioni di
|
||||
trasporto/pubblicazione del codice Omics. La distribuzione parte dai sorgenti
|
||||
@@ -57,20 +57,27 @@ conservati in un percorso operativo stabile sul server.
|
||||
|
||||
### ThothII
|
||||
|
||||
Il checkout aggiornato deve essere su `main` e includere almeno
|
||||
`bdcd8fcd28f3011471d77224db9c3f5baf227995` e questo documento. Registra anche lo
|
||||
SHA effettivo di `main`, che include il commit di consegna e il merge successivi:
|
||||
Il checkout aggiornato deve essere sulla `main` di Gitea (`origin`) e includere almeno
|
||||
`0d2e573e` (correzione della vista sessione del 26 settembre) e questo documento.
|
||||
Il branch `codex/guided-standalone-install` contiene un processo di nuova installazione
|
||||
ancora in lavorazione: non usarlo per questo aggiornamento e non eseguire
|
||||
`tht setup --complete` sull'installazione server esistente. Registra lo SHA effettivo e
|
||||
confrontalo con `origin/main` senza modificare il checkout operativo:
|
||||
|
||||
```bash
|
||||
git fetch origin main
|
||||
git status --short --branch
|
||||
git rev-parse HEAD
|
||||
git merge-base --is-ancestor bdcd8fcd28f3011471d77224db9c3f5baf227995 HEAD
|
||||
git rev-parse origin/main
|
||||
git rev-list --left-right --count HEAD...origin/main
|
||||
git merge-base --is-ancestor 0d2e573e HEAD
|
||||
```
|
||||
|
||||
Se il controllo fallisce, completa l'acquisizione della revisione approvata
|
||||
prima di toccare l'installazione. Non ricostruire a mano le singole modifiche UI:
|
||||
questa revisione contiene shell, autenticazione, i18n, workflow bilingue,
|
||||
amministrazione, typography e navigazione aggiornate.
|
||||
La divergenza ideale è `0 0` e la working tree è pulita. Se il controllo dell'antenato
|
||||
fallisce, o se il server ha commit o modifiche locali, prepara e verifica la revisione
|
||||
approvata prima di toccare l'installazione; non usare reset o force push. Non ricostruire
|
||||
a mano le singole modifiche UI: la revisione di `main` contiene shell, autenticazione,
|
||||
i18n, workflow bilingue, amministrazione, typography e navigazione aggiornate.
|
||||
|
||||
### Omics Portal
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ Omics. Le preferenze non modificano il descrittore installato.
|
||||
Per una nuova installazione autonoma, selezionare esplicitamente full:
|
||||
|
||||
```bash
|
||||
tht setup --complete --profile local --shell-mode full --shell-default-locale en
|
||||
tht setup --profile local --shell-mode full --shell-default-locale en
|
||||
```
|
||||
|
||||
Il setup senza opzioni shell conserva per compatibilità il default embedded.
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
# Rilascio server ThothII embedded in Omics — 2026-09-14
|
||||
|
||||
## Esito
|
||||
|
||||
Il rilascio tecnico è stato eseguito il 2026-09-14 e i controlli automatici e
|
||||
server-side descritti sotto sono superati. L'accettazione funzionale non è ancora
|
||||
chiusa: lingua, tema, fullscreen, logout, ruoli e continuità SSE devono essere
|
||||
provati da browser con account Omics autorizzati.
|
||||
|
||||
Finestra autorizzata dall'operatore e conclusa alle 16:17 CEST. Le ammissioni
|
||||
ThothII sono state riaperte dopo il collaudo (`active: false`, `admissions: 0`).
|
||||
|
||||
## Revisioni e immagini distribuite
|
||||
|
||||
- ThothII, checkout operativo `/srv/thothii-v2/source/ThothII`:
|
||||
`49333a2d35664b7237c3ddc2a9f10a605dcc84ce`, branch `main`, pulito e allineato
|
||||
a `origin/main`.
|
||||
- Omics Portal, checkout `/home/chirone/omics_portal`:
|
||||
`fca10901a73666ca257d8f4cc4b77066295c400a`, branch `master`, pulito e due
|
||||
commit avanti a `origin/master`. Include la consegna funzionale
|
||||
`95154e179144e2453b37ef2a63a65d6f377e4cf8`.
|
||||
- CLI nativo `/usr/local/bin/tht`: commit
|
||||
`49333a2d35664b7237c3ddc2a9f10a605dcc84ce`, build
|
||||
`2026-09-14T15:08:47+02:00`, `linux/amd64`.
|
||||
- Core: `thothii-v2-core:49333a2d`, image ID
|
||||
`sha256:d62bf17dd1345e6a459edabe4b559333b396ef30c523dedf1b842506c147efbd`.
|
||||
- Frontend: `thothii-v2-frontend:49333a2d`, image ID
|
||||
`sha256:dd57745143fc282562ec6d4c2cd8fc493eb2078494eeb17099d49bea8eae218b`.
|
||||
- Omics web: `omics_portal-web`, image ID
|
||||
`sha256:11e99905c41b38cd68d0e726f25a4174b8eb65db27fb1d887238a7bd255074da`.
|
||||
- Nginx: image invariata `sha256:b3c656d55d7ad751196f21b7fd2e8d4da9cb430e32f646adcf92441b72f82b14`.
|
||||
|
||||
## Configurazioni modificate
|
||||
|
||||
- `deploy/psd-server-v2/thothii-installation.yaml`: Installation Model Catalog
|
||||
schema v2; shell `embedded`, locale predefinito `en`, adapter `omics-portal`;
|
||||
provider DeepSeek unificato e default interaction `zai/glm-5.3`. Percorsi,
|
||||
profilo server, workspace, DWH e provider reali del server sono stati
|
||||
preservati.
|
||||
- `/srv/thothii-v2/operator/compose.portal-upstream.yaml`: `AUTH_MODE=upstream`,
|
||||
alias `thothii-core` e `thothii-frontend` sulla rete Omics; eliminato il mount
|
||||
della copia manuale di `config.js`. Nessun `auth.yaml` e nessuna runtime auth
|
||||
projection.
|
||||
- `/srv/thothii-v2/operator/operator.env`: tag applicativo aggiornato a
|
||||
`49333a2d`; nessun valore segreto copiato dal Mac o riportato in questo report.
|
||||
- `deploy/psd-server-v2/generated/`: proiezioni rigenerate dal descriptor. Il
|
||||
frontend riceve in sola lettura `generated/frontend/config.js`, che espone
|
||||
soltanto `backendBaseUrl: /api` e il contratto shell embedded.
|
||||
- Omics: integrati template embedded, lingua Django, topbar/fullscreen, adapter
|
||||
JavaScript, traduzioni e test della consegna GitHub.
|
||||
- `nginx/nginx.conf`: non modificato. La configurazione già presente conteneva
|
||||
l'`auth_request` Django, derivazione server-side degli header `X-Thoth-*`,
|
||||
rimozione di cookie/Authorization/header client, origin esatta e SSE senza
|
||||
buffering.
|
||||
|
||||
Configurazione risolta verificata:
|
||||
|
||||
- core e frontend usano le immagini `49333a2d`;
|
||||
- `AUTH_MODE=upstream`;
|
||||
- core senza porta host pubblicata;
|
||||
- frontend pubblicato soltanto su `127.0.0.1:18020`;
|
||||
- alias Omics risolti rispettivamente a `thothii-core` e `thothii-frontend`;
|
||||
- `config.js` generated montato read-only;
|
||||
- `THOTH_PUBLIC_EXPOSURE=false` e storage sessioni locale, preservando la
|
||||
topologia server già approvata.
|
||||
|
||||
## Backup e rollback
|
||||
|
||||
Backup protetto:
|
||||
`/srv/thothii-v2/backups/20260914-pre-embedded-release`, directory `0700`, tutti
|
||||
i file `0600` e owner `root:root`.
|
||||
|
||||
Contiene:
|
||||
|
||||
- immagini applicative precedenti core/frontend/Omics;
|
||||
- binario CLI precedente;
|
||||
- descriptor, override, config manuale e proiezioni precedenti;
|
||||
- bind `data`, `workspace-registry`, `pi-state`, `operator` e `secrets`;
|
||||
- snapshot raw dei volumi catalogo, Qdrant ed embedding;
|
||||
- dump logico PostgreSQL del catalogo ThothII;
|
||||
- dump logico PostgreSQL del database usato da Omics;
|
||||
- snapshot dei volumi statici e media Omics;
|
||||
- `SHA256SUMS`.
|
||||
|
||||
Tutti i checksum sono risultati validi. Gli archivi tar sono stati elencati
|
||||
integralmente senza errori e i due dump sono stati validati con
|
||||
`pg_restore --list`. Le vecchie immagini restano disponibili; Omics precedente
|
||||
è inoltre etichettata `omics_portal-web:pre-fca1090-aff75817`.
|
||||
|
||||
Non sono state eseguite migrazioni ThothII: tra `82e2c91f` e `49333a2d` non
|
||||
esistono nuove migrazioni catalogo, Memory o sessioni. L'entrypoint Omics ha
|
||||
eseguito `migrate` con risultato `No migrations to apply`. Il rollback normale
|
||||
è quindi applicativo e non richiede ripristino dati; dump e snapshot raw sono
|
||||
conservati per un recupero separato solo in presenza di corruzione accertata.
|
||||
|
||||
## Verifiche superate
|
||||
|
||||
### Prima del rilascio
|
||||
|
||||
- frontend ThothII: 768/768 test;
|
||||
- backend auth/config/session/model: 205/205 test mirati;
|
||||
- estensione Pi, lingua e ripresa: 7/7;
|
||||
- harness lingua sessione e repository PostgreSQL: 24/24;
|
||||
- CLI Go: tutte le package superate;
|
||||
- Omics embedded shell isolata: 15/15;
|
||||
- build delle tre immagini candidate completata;
|
||||
- generazione delle proiezioni validata prima in staging isolato;
|
||||
- build documentale strict completata dopo la scrittura di questo report.
|
||||
|
||||
### Sul server distribuito
|
||||
|
||||
- `tht status`: exit 0;
|
||||
- `tht doctor --json`: `ok: true`, 13/13 controlli superati, inclusi descriptor,
|
||||
proiezioni, permessi, Docker/Compose, autenticazione, health, HTTP, registry,
|
||||
workflow e Pi;
|
||||
- core, frontend, catalog-db, Qdrant, embedding e Omics web in stato healthy;
|
||||
- `nginx -t` superato prima e dopo la ricreazione;
|
||||
- catalogo Superset Omics valido: 32 dashboard;
|
||||
- `migrate --check` post-rilascio: exit 0;
|
||||
- nessun traceback, fatal, panic, HTTP 500 o errore nginx nei log recenti;
|
||||
- pagina senza sessione: `302` verso `/accounts/login/`;
|
||||
- `/datamart-builder/api/me` senza sessione: `403`;
|
||||
- richiesta pubblica con header principal/admin falsificati: ancora `403`;
|
||||
- `config.js`: `200`, `Cache-Control: no-store`, contenuto embedded corretto;
|
||||
- manifest Vite risolto da Django: 368 entry; entrypoint corrente
|
||||
`index-ktEFlKPi.js` e stylesheet `index-BtNkA4QL.css`;
|
||||
- asset JavaScript attraverso `/datamart-builder/assets/`: `200` e cache
|
||||
`public, immutable`;
|
||||
- il core non ascolta sulla porta host 8787; dalla rete interna senza principal
|
||||
risponde `401`;
|
||||
- nginx risolve i nuovi indirizzi degli alias, senza dipendere dai precedenti IP
|
||||
Docker.
|
||||
|
||||
Il probe HTTPS verso l'hostname pubblico, eseguito dal server stesso, è andato
|
||||
in timeout prima della connessione (`HTTP 000`): è un limite di raggiungibilità
|
||||
hairpin/rete e non viene contato come verifica superata. I probe equivalenti
|
||||
attraverso nginx locale con Host e forwarded protocol reali sono invece passati.
|
||||
|
||||
È rimasto intenzionalmente intatto il container orphan storico
|
||||
`omics_portal-web-run-a0bc36025e52`, creato circa tre mesi prima del rilascio ed
|
||||
exited da due settimane; non è stato rimosso perché estraneo alla consegna.
|
||||
|
||||
## Prove manuali ancora necessarie
|
||||
|
||||
Usare account di prova autorizzati e dati non operativi:
|
||||
|
||||
1. utente Omics autorizzato apre Datamart Builder senza secondo login e vede un
|
||||
solo header, quello Omics;
|
||||
2. `/datamart-builder/api/me` restituisce issuer `portal`, subject Django stabile,
|
||||
ruoli corretti e `session`/`csrfToken` null;
|
||||
3. confronto utente normale/amministratore e rifiuto utente senza capability;
|
||||
4. IT/EN prima dell'apertura e cambio tramite form Omics, senza tradurre SQL o
|
||||
contenuti authored;
|
||||
5. light/dark con popup, menu e griglia aperti;
|
||||
6. ingresso/uscita fullscreen, compresa uscita con Esc e rifiuto browser;
|
||||
7. logout Omics, seconda scheda e nuova verifica `/me`;
|
||||
8. nuova sessione, flusso SSE, riconnessione dopo scadenza, reload senza avvio
|
||||
automatico e ripresa con `interaction_language` invariata;
|
||||
9. richiesta cross-origin autenticata su operazione fittizia e comportamento
|
||||
distinto di un singolo `403` operativo;
|
||||
10. accesso HTTPS reale da una postazione client, perché il server non raggiunge
|
||||
l'hostname pubblico in hairpin.
|
||||
|
||||
L'installazione non va dichiarata funzionalmente accettata finché questa matrice
|
||||
manuale non è stata eseguita e registrata.
|
||||
@@ -0,0 +1,142 @@
|
||||
# Rilascio coordinato ThothII / Omics — 26 settembre 2026
|
||||
|
||||
**Distribuito; accettazione automatica superata. Collaudo browser positivo per accesso, interfaccia e avvio/interruzione/ripresa sessione; prove estese residue sotto.**
|
||||
Finestra esplicitamente confermata dall’utente in chat («confermo»), avvio alle
|
||||
19:28 Europe/Rome. Riferimento: [piano approvato](2026-09-26-server-release-plan.md).
|
||||
Maintenance disattivata alle **19:35:27** dopo tutti i controlli automatici.
|
||||
|
||||
## Versioni e stato finale
|
||||
|
||||
| Componente | Risultato |
|
||||
| --- | --- |
|
||||
| ThothII sorgente | Main `497ab84031e285464fdbb73e6e0ce9252687e3ab`, checkout pulito in `/srv/thothii-v2/releases/497ab84031e285464fdbb73e6e0ce9252687e3ab` |
|
||||
| Core | `thothii-v2-core:497ab840-preflight`, ID `sha256:182f4e0d63404cb7ed6a0e272441e9c55ed27e2bb16fdbf4d7162f892ac76dc7`, healthy |
|
||||
| Frontend | `thothii-v2-frontend:497ab840-preflight`, ID `sha256:5f5a4f81139432d0ac41025c3006edaf1258b623ce388242700b1b20fcce6421`, healthy |
|
||||
| Omics checkout | Fast-forward a `928f7e9fff2aba895416776fecf5668ee957d237`; nessuna modifica tracciata, file locali preservati |
|
||||
| Omics web | Stesso container e immagine `sha256:27aa100690b110bf596322b1b0a31acc178ca9d1c709bc10382cbeecbfb5aeca`, riavviato e healthy; risposta HTTP Django verificata |
|
||||
| Omics nginx | Ricreato col fix asset e immagine precedente fissata `sha256:b3c656d55d7ad751196f21b7fd2e8d4da9cb430e32f646adcf92441b72f82b14`; `nginx -t` positivo |
|
||||
| Supporti | Catalogo PostgreSQL, Qdrant e Ollama healthy; immagini e volumi invariati |
|
||||
| CLI host | `/usr/local/bin/tht` aggiornato; SHA256 `0d39a93fb0a3b2147541a746c75832db20302f3a604bf6510da69d3731bcd783` |
|
||||
| Maintenance / Pi | Maintenance inattiva, zero processi Pi RPC al controllo finale delle 19:36 |
|
||||
|
||||
Descrittore mantenuto nel percorso originale:
|
||||
`/srv/thothii-v2/source/ThothII/deploy/psd-server-v2/thothii-installation.yaml`.
|
||||
Project Compose sempre `thothii-7f901b48fe35`; shell embedded/en/omics-portal,
|
||||
auth upstream e storage locale invariati. Cambiati solo projectDirectory e
|
||||
percorso dell’overlay git-ssh nel descrittore, tag immagini in env/overlay.
|
||||
Proiezioni rigenerate col nuovo CLI e UID 10001. Descriptor/env 10001:10001 0600;
|
||||
overlay 1013:1014 0640; CLI root:root 0755.
|
||||
|
||||
Il vecchio checkout ThothII dirty resta al suo posto per rollback. Nessun reset,
|
||||
force push, eliminazione di volumi, cambio identità, credenziali, DWH o Authentik.
|
||||
Nessun push Omics eseguito. Nessuna nuova migrazione applicata; i controlli Django
|
||||
prima e dopo il riavvio non rilevano migrazioni o modifiche dei modelli pendenti.
|
||||
L’entrypoint web ha rieseguito i normali comandi di startup, statici e traduzioni.
|
||||
|
||||
## Backup ed esecuzione
|
||||
|
||||
Backup protetto root 0700:
|
||||
`/srv/thothii-v2/backups/20260926-coordinated-release`.
|
||||
Completato e **VERIFIED alle 19:31:57**, circa **2,89 GiB**, **23 checksum**,
|
||||
archivi tar leggibili e indici dei dump verificati. Non è una prova di restore.
|
||||
|
||||
Include configurazioni/CLI/generated, sorgenti e Git con file locali,
|
||||
immagini precedenti, bind data/registry/Evidence/Pi/segreti, volumi
|
||||
catalogo/Qdrant/Ollama/static/media, dump catalogo e dump PostgreSQL condiviso.
|
||||
Il DB condiviso è rimasto operativo: il suo dump è una snapshot transazionale,
|
||||
non un backup raw del database fermo. Il volume raw del catalogo ThothII è stato
|
||||
archiviato a servizio fermo. Nessun restore dati eseguito.
|
||||
|
||||
Cronologia Europe/Rome:
|
||||
|
||||
- 19:28: controllo del piano approvato positivo; riserva 20,9 GiB, liberi 27,8 GiB.
|
||||
- 19:29:21: configurazione di rollback salvata e verificata prima delle mutazioni.
|
||||
- 19:29:42: maintenance e chiusura nginx Omics; due controlli Pi negativi.
|
||||
- 19:30:03: applicazioni ferme; dump, fermo supporti e archiviazione dati.
|
||||
- 19:31:57: backup verificato.
|
||||
- 19:32:10: deploy avviato; core 19:32:17, frontend 19:32:23,
|
||||
web Omics 19:32:29, nginx 19:32:36.
|
||||
- 19:35:27: accettazione automatica completata e maintenance disattivata.
|
||||
|
||||
Il periodo tra chiusura e riavvio nginx è stato circa tre minuti; le nuove
|
||||
ammissioni sessione sono rimaste bloccate fino al completamento dei controlli.
|
||||
|
||||
## Correzione del controllo durante il rilascio
|
||||
|
||||
L’accettazione iniziale si è fermata su un falso negativo nello script:
|
||||
`config.js` invia due header `Cache-Control`, `no-cache` e `no-store`; il controllo
|
||||
leggeva solo il primo. Configurazione e risposta HTTP erano corrette.
|
||||
|
||||
Riproduzione isolata rossa, correzione di una riga con `get_all`, **16 test verdi**,
|
||||
compreso il rifiuto quando `no-store` manca davvero. Nessuna modifica applicativa
|
||||
necessaria. Maintenance mantenuta attiva fino alla ripetizione completa
|
||||
dell’accettazione. Non sono stati ripetuti backup, fast-forward o ricreazione.
|
||||
|
||||
Directory script/evidenze:
|
||||
`/srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/`.
|
||||
|
||||
- Script inizialmente approvato conservato in `release.approved.py`, SHA256
|
||||
`eb2c677c8adbee0c9febf919001f654c8535e71f064d9fb7c7883afd02383a41`.
|
||||
- Script corretto `release.py`, SHA256
|
||||
`20314e68a6a42701456d454d2a0881652cfdbe5e00e9a912a22df9e78129aa00`.
|
||||
- Test di regressione: `test_release_reviewed.py`, `reviewed-tests-cache-fix.log`.
|
||||
- Stato finale filtrato: `deployed-evidence.json`; avanzamento nel
|
||||
`journal.jsonl` del backup. Manifest degli artefatti aggiornato, originale conservato.
|
||||
|
||||
## Accettazione automatica
|
||||
|
||||
| Verifica | Esito |
|
||||
| --- | --- |
|
||||
| Digest reali dei container, readiness, doctor | Positivi |
|
||||
| Alias Docker | Univoci e risolti ai container attuali; manifest raggiungibile da Omics |
|
||||
| API senza cookie e con principal falsificati | 403 su HTTP e HTTPS locale verificato |
|
||||
| Bypass asset e traversal codificati | Negati; `/datamart-builder/assets/api/me` restituisce 404 |
|
||||
| Config | 200, embedded e no-store su entrambi i percorsi |
|
||||
| Asset | Tutti i file elencati dal manifest disponibili su HTTP/HTTPS |
|
||||
| Esposizione core | Nessuna porta pubblicata sull’host |
|
||||
| Modelli, Pi e credenziali | Hash invariati rispetto alla baseline |
|
||||
| Documenti persistiti | 2 manifest sessione, 51 file sessione/artifact e 221 file workspace/Evidence confrontati col backup: nessuna differenza |
|
||||
| Migrazioni e catalogo Omics | Nessuna migrazione pendente; catalogo Superset valido |
|
||||
| Log startup | Zero occorrenze nelle categorie fatal/config/auth/permessi controllate; nessun contenuto sensibile riportato |
|
||||
|
||||
Le prove HTTPS usano la CA interna e risoluzione locale del nome pubblico;
|
||||
non sostituiscono il collaudo dalla postazione esterna. Il controllo degli hash
|
||||
riguarda i file elencati, non certifica da solo l’intera semantica degli archivi.
|
||||
|
||||
## Rollback disponibile
|
||||
|
||||
Usare lo script corretto, dopo controllo di eventuali sessioni Pi attive:
|
||||
|
||||
```bash
|
||||
sudo -n python3 /srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py rollback --window-confirmed
|
||||
```
|
||||
|
||||
Il rollback previsto dalla finestra approvata ripristina CLI/config/proiezioni e
|
||||
immagini ThothII precedenti, mantiene il fix proxy Omics, riavvia e verifica le
|
||||
applicazioni. Conserva dati e volumi; nessun restore del DB condiviso, reset Git
|
||||
o ritorno al nginx vulnerabile. Se l’utente ha avviato sessioni, prima salvarle e
|
||||
fermarle. Il rollback non è stato necessario né eseguito durante questo rilascio.
|
||||
|
||||
## Collaudo browser — aggiornamento 27 settembre 2026
|
||||
|
||||
Conferme dell’utente:
|
||||
|
||||
- Omics → Datamart Builder si carica senza problemi, in risposta alla prova di
|
||||
apertura senza secondo login.
|
||||
- Il 27 settembre: «tutto bene, compreso l’avvio e l’interruzione di una sessione».
|
||||
Nel contesto dei controlli richiesti, registrato esito positivo per IT/EN,
|
||||
tema, fullscreen/Esc e per avvio/interruzione di una sessione.
|
||||
- Successivamente, sempre il 27 settembre: «ho anche ripreso una sessione interrotta.
|
||||
tutto ok». Confermata anche la ripresa riuscita; il ciclo funzionale
|
||||
avvio → interruzione → ripresa è collaudato dall’utente.
|
||||
|
||||
Il collaudo funzionale richiesto ha esito positivo. Su richiesta dell’utente,
|
||||
le verifiche estese sono trasferite a un’attività successiva nel
|
||||
[handoff del 27 settembre](2026-09-27-server-acceptance-handoff.md): lingua
|
||||
persistita, identità/ruoli, logout, origine delle scritture, amministrazione,
|
||||
reload e HTTPS esterno. Il documento contiene passi, responsabili, risultati
|
||||
attesi e registro delle prove; nessuno di questi casi è dichiarato già superato.
|
||||
|
||||
La [matrice di accettazione](../testing/authentication-manual-acceptance.md)
|
||||
resta il riferimento. Nessuna ulteriore modifica ai servizi è stata eseguita
|
||||
per registrare il collaudo o preparare l’handoff del 27 settembre.
|
||||
@@ -0,0 +1,246 @@
|
||||
# Handoff — rilascio coordinato ThothII / Omics
|
||||
|
||||
**Rilasciato il 26 settembre 2026; accettazione automatica superata alle 19:35 Europe/Rome.**
|
||||
Per riprendere, leggere il [report di esecuzione](2026-09-26-server-release-execution.md):
|
||||
servizi avviati, maintenance inattiva, backup verificato e rollback disponibile.
|
||||
La finestra era stata confermata esplicitamente dall’utente; non richiederla di
|
||||
nuovo per completare il collaudo già autorizzato. Il 27 settembre l’utente ha
|
||||
confermato accesso, controlli dell’interfaccia e avvio/interruzione/ripresa di una
|
||||
sessione: collaudo funzionale positivo. Per le verifiche residue usare il
|
||||
[nuovo handoff del 27 settembre](2026-09-27-server-acceptance-handoff.md), con
|
||||
passi e registro delle prove. L’utente le ha affidate a un’attività successiva.
|
||||
|
||||
Usare lo script corretto documentato nel report: durante il rilascio è stata
|
||||
corretta soltanto la lettura degli header Cache-Control ripetuti nel controllo.
|
||||
Non rieseguire le fasi pre-deploy sullo stato già rilasciato.
|
||||
|
||||
## Snapshot storico della sospensione delle 17:40
|
||||
|
||||
Il resto di questo file conserva lo stato precedente alla ripresa e al rilascio.
|
||||
Il report di esecuzione sostituisce le indicazioni operative e le attività residue
|
||||
qui sotto; il [piano approvato](2026-09-26-server-release-plan.md) descrive le scelte.
|
||||
|
||||
## Prima azione alla ripresa
|
||||
|
||||
Leggere questo handoff, quindi `AGENTS.md`, `PROJECT_STATE.md`,
|
||||
`docs/operations/server-codex-handoff.md`, `docs/install/authentication-upstream.md`
|
||||
e `docs/testing/authentication-manual-acceptance.md`. Per l'inventario completo
|
||||
e i digest delle immagini operative, leggere
|
||||
`docs/reports/2026-09-26-server-release-preflight.md`.
|
||||
Quel preflight è storico: la correzione proxy allora mancante è ora preparata e
|
||||
testata **soltanto in isolamento**, come descritto sotto.
|
||||
|
||||
La prossima attività è **revisionare e completare lo script di rilascio in bozza**,
|
||||
validare il piano senza mutazioni operative e presentarlo all'utente con backup
|
||||
e rollback. Solo dopo la sua conferma eseguire le fasi operative e il collaudo.
|
||||
|
||||
## Richiesta dell'utente e confini
|
||||
|
||||
- Aggiornare ThothII e Omics secondo il runbook, preservando dati, workspace,
|
||||
Pi, provider, modelli e credenziali già presenti sul server.
|
||||
- Usare main ThothII includente `497ab84031e285464fdbb73e6e0ce9252687e3ab`;
|
||||
conservare i progressi server Omics successivi alla consegna GitHub `fca10901…`.
|
||||
- Conservare checkout sporchi e file locali. Nessun reset, force push, rimozione
|
||||
volumi o `tht setup --complete`; non usare `codex/guided-standalone-install`.
|
||||
- L'utente ha autorizzato preparazione, correzione e test isolati. Prima del
|
||||
fermo/proxy/migrazioni/recreate operativi vuole vedere il piano risolto e
|
||||
confermare la finestra. Il suo «procediamo, fai la tua parte» ha avviato la
|
||||
preparazione, non approvato uno script ancora inesistente/incompleto.
|
||||
- L'utente può fare il collaudo da browser: avvisarlo quando sarà il momento
|
||||
e fornire prove precise. Non chiedergli password in chat.
|
||||
- Ha autorizzato a cercare credenziali di `akadmin` / `mpancotti`: trovata solo
|
||||
la presenza di `AUTHENTIK_BOOTSTRAP_PASSWORD` in
|
||||
`/home/chirone/chirone-authentik/docker/.env`. Valore non mostrato, non copiato,
|
||||
**nessun login tentato e validità attuale non verificata**. Nessuna password
|
||||
mpancotti trovata. I due utenti sono locali Authentik, non LDAP.
|
||||
|
||||
## Stato operativo, invariato
|
||||
|
||||
- Checkout di lavoro `/home/chirone/Thoth`: main `497ab840…`, allineata Gitea;
|
||||
il report `2026-09-14-server-embedded-omics-release.md` era già non tracciato.
|
||||
Sono stati aggiunti solo i report locali di questa attività.
|
||||
- Checkout ThothII operativo `/srv/thothii-v2/source/ThothII`: main
|
||||
`b1723c34c467980d007094af078d966d460cde2b`, 30 file modificati + due non tracciati,
|
||||
preservato integralmente. Le modifiche sono già recepite dalla nuova main,
|
||||
che contiene anche le correzioni successive.
|
||||
- Omics operativo `/home/chirone/omics_portal`: master pulito
|
||||
`1cf7ea90a669a26bf3bc51749eab4d07981da472`. Comprende la consegna shell GitHub
|
||||
`fca10901a73666ca257d8f4cc4b77066295c400a` e la correzione Superset successiva.
|
||||
**Non ripetere l'integrazione e non tornare a fca10901.**
|
||||
- Core ancora `thothii-v2-core:49333a2d-session-memory-fix`; frontend ancora
|
||||
`thothii-v2-frontend:b1723c34-session-dialogs-20260914`; Omics web ancora
|
||||
`omics_portal-web` image ID `sha256:27aa100690b110bf596322b1b0a31acc178ca9d1c709bc10382cbeecbfb5aeca`.
|
||||
- Ultimo controllo: zero processi Pi RPC, maintenance `active=false`, admissions 0.
|
||||
Ricontrollare alla ripresa e prima del fermo.
|
||||
- Backup nuovo `/srv/thothii-v2/backups/20260926-coordinated-release` **non esiste**.
|
||||
Backup storico 14 settembre verificato (14 checksum, tar e indici dump), non
|
||||
un backup dello stato odierno, nessuna prova di restore eseguita.
|
||||
|
||||
## Installazione e preservazione comprovata
|
||||
|
||||
Descrittore effettivo, il cui **percorso va mantenuto** per preservare project identity:
|
||||
`/srv/thothii-v2/source/ThothII/deploy/psd-server-v2/thothii-installation.yaml`.
|
||||
Project `thothii-7f901b48fe35`, schema 2, profile server, embedded/en/omics-portal,
|
||||
upstream, session storage local, `THOTH_PUBLIC_EXPOSURE=false` già preesistente.
|
||||
Non cambiare modalità auth o disattivare controlli per far partire l'app.
|
||||
|
||||
Preservati e confrontati:
|
||||
|
||||
- default interaction `zai/glm-5.3`;
|
||||
- `deepseek/deepseek-v4-pro`, `deepseek/deepseek-v4-flash`;
|
||||
- `local-qwen/qwen3.6-35b-a3b`;
|
||||
- embedding `ollama/qwen3-embedding:0.6b`, dimensione 1024;
|
||||
- `catalog.json`, `pi/models.json`, `pi/settings.json`, `frontend/config.js`:
|
||||
proiezioni nuove **identiche byte per byte** a quelle operative;
|
||||
- Compose candidato: environment, reti, porte, secret/config mount e mount
|
||||
persistenti uguali. Solo due bind di script versionati identici cambiano
|
||||
percorso seguendo il nuovo checkout (`catalog-db-init.sql`, `embedding-model-init.sh`).
|
||||
|
||||
Il CLI rifiuta correttamente i segreti se eseguito da UID diverso da 10001.
|
||||
Per diagnostica usare UID 10001 con gruppi operator/Docker e DOCKER_CONFIG
|
||||
leggibile; non cambiare ownership dei segreti. Esempio verificato:
|
||||
|
||||
```bash
|
||||
sudo -n setpriv --reuid=10001 --regid=10001 --groups=1014,988 \
|
||||
env DOCKER_CONFIG=/srv/thothii-v2/operator/releases/20260926-coordinated/docker-config \
|
||||
/usr/local/bin/tht \
|
||||
--installation /srv/thothii-v2/source/ThothII/deploy/psd-server-v2/thothii-installation.yaml \
|
||||
doctor --json
|
||||
```
|
||||
|
||||
## Correzione proxy pronta, non applicata
|
||||
|
||||
Il proxy operativo è ancora vulnerabile: senza cookie,
|
||||
`/datamart-builder/assets/api/me` con header `X-Thoth-Trusted-*` inventati
|
||||
restituisce 200 e principal sintetico. API canonica restituisce 403.
|
||||
Confermato anche via nginx HTTPS host con CA verificata e DNS locale.
|
||||
Il test ha usato un soggetto inesistente, nessun dato reale o scrittura.
|
||||
|
||||
Causa: il prefisso pubblico degli asset inoltra alla radice del frontend,
|
||||
che espone `/api/` e converte gli header Trusted in principal del core.
|
||||
|
||||
Correzione candidata Omics:
|
||||
|
||||
- branch `codex/thothii-assets-proxy-isolation`;
|
||||
- commit locale **`928f7e9fff2aba895416776fecf5668ee957d237`**;
|
||||
- parte da `1cf7ea90…`, nessun push eseguito;
|
||||
- checkout stabile pulito:
|
||||
`/srv/thothii-v2/releases/omics-928f7e9fff2aba895416776fecf5668ee957d237`;
|
||||
- clone di lavoro: `/tmp/thothii-release-20260926/omics-source`;
|
||||
- sei file cambiati: nginx, test statico, tre file di test dinamico, docs integrazione.
|
||||
|
||||
Il filtro accetta solo file Vite con hash ed estensioni previste, alla radice
|
||||
o sotto `assets/` per compatibilità. Le route pubbliche config/asset rimuovono
|
||||
Cookie, Authorization e tutte le famiglie di header identità; solo GET/HEAD.
|
||||
Il frontend attuale emette file alla **radice**, non tutti in `assets/`:
|
||||
il primo filtro eccessivamente stretto è stato corretto grazie al test reale.
|
||||
|
||||
Test completati:
|
||||
|
||||
- test dinamico nuovo riproduceva il difetto prima della correzione;
|
||||
- **6/6** test della catena nginx Omics → nginx frontend reale → core/Django
|
||||
sintetici, rete Docker interna, senza porte host o volumi operativi;
|
||||
- verificati traversal codificati, canonical auth, Origin esatta, config,
|
||||
tutti i file del manifest reale, diniego scritture alle route statiche;
|
||||
- gli stessi **6/6** passano anche con l'immagine frontend precedente:
|
||||
il rollback può e deve mantenere la correzione del proxy;
|
||||
- suite Omics shell/auth/nginx/Superset **28/28** dopo la modifica;
|
||||
- nessun container/rete `omics-proxy-check-*` rimasto al momento della sospensione.
|
||||
|
||||
Esecuzione test ripetibile, solo se necessaria per nuove modifiche:
|
||||
|
||||
```bash
|
||||
cd /srv/thothii-v2/releases/omics-928f7e9fff2aba895416776fecf5668ee957d237
|
||||
THOTHII_TEST_FRONTEND_IMAGE=thothii-v2-frontend:497ab840-preflight \
|
||||
OMICS_TEST_IMAGE=omics-portal:proxy-isolation-tests \
|
||||
OMICS_TEST_NGINX_IMAGE=sha256:b3c656d55d7ad751196f21b7fd2e8d4da9cb430e32f646adcf92441b72f82b14 \
|
||||
python3 test_support/thothii/run_proxy_integration.py
|
||||
```
|
||||
|
||||
## Artefatti pronti e bozza da revisionare
|
||||
|
||||
Directory stabile: `/srv/thothii-v2/operator/releases/20260926-coordinated`.
|
||||
Contiene:
|
||||
|
||||
- `descriptor.next.yaml`: cambia soltanto projectDirectory verso la nuova main
|
||||
e il percorso del suo overlay git-ssh; modelCatalog/auth/shell/workspace invariati.
|
||||
- `operator.next.env`: cambia soltanto tag immagini in `497ab840-preflight`.
|
||||
- `compose.portal-upstream.next.yaml`: aggiorna anche il tag frontend letterale,
|
||||
che non seguiva la variabile del core.
|
||||
- `baseline.json`: hash protetti dei file operativi per rilevare drift prima
|
||||
della finestra; non contiene valori segreti.
|
||||
- `compose-preservation.json`: esito positivo del confronto Compose candidato.
|
||||
- `tht.next`: nuovo binario non installato; SHA256
|
||||
`0d39a93fb0a3b2147541a746c75832db20302f3a604bf6510da69d3731bcd783`.
|
||||
- `nginx.safe.conf`: copia della configurazione candidata testata.
|
||||
- `proxy-green.log`, `proxy-rollback-test.log`, `omics-proxy-tests.log`.
|
||||
- **`release.DRAFT.py`**: bozza appena scritta, **non revisionata, non compilata,
|
||||
non eseguita neppure in modalità check**. Non lanciarla prima di una revisione
|
||||
completa e della conferma della finestra per le fasi mutanti.
|
||||
|
||||
Originale della bozza: `/tmp/thothii-release-20260926/release.py`.
|
||||
Non trattare il flag `--window-confirmed` come un'approvazione dell'utente.
|
||||
|
||||
Sorgenti ThothII pronti, main pulita e fetch Gitea con divergenza 0/0:
|
||||
`/srv/thothii-v2/releases/497ab84031e285464fdbb73e6e0ce9252687e3ab`.
|
||||
Vecchio checkout dirty lasciato al suo posto per rollback.
|
||||
|
||||
Immagini candidate già costruite, non distribuite:
|
||||
|
||||
- core `thothii-v2-core:497ab840-preflight`,
|
||||
`sha256:182f4e0d63404cb7ed6a0e272441e9c55ed27e2bb16fdbf4d7162f892ac76dc7`;
|
||||
- frontend `thothii-v2-frontend:497ab840-preflight`,
|
||||
`sha256:5f5a4f81139432d0ac41025c3006edaf1258b623ce388242700b1b20fcce6421`.
|
||||
|
||||
Test ThothII già superati: 782 frontend, 152 backend su Node 24.16, 31 browser,
|
||||
build/typecheck core/frontend, build CLI e generazione isolata, doctor attuale 13/13.
|
||||
Log in `/tmp/thothii-release-20260926`. La sottodirectory `generation` contiene
|
||||
copie sensibili protette root:root 0600 sotto directory 0700: non pubblicarla.
|
||||
|
||||
## Lavoro residuo e criteri per avanzare
|
||||
|
||||
1. **Revalidare solo ciò che può essere cambiato** durante la pausa: immagini,
|
||||
SHA/stato checkout operativo, configurazioni contro baseline, processi Pi,
|
||||
migrazioni Omics pendenti e raggiungibilità. Se c'è drift, preservarlo e
|
||||
aggiornare il piano prima di proseguire.
|
||||
2. **Revisionare lo script DRAFT**, inclusi escaping del controllo processi Pi,
|
||||
gestione errori/parzialità backup, health/readiness reale Omics (il suo
|
||||
healthcheck verifica solo catalogo, non Gunicorn), generazione con UID corretto,
|
||||
digest image vs container, conservazione proprietari e dati, rollout/rollback
|
||||
della correzione proxy. Validare sintassi e fase read-only solo dopo revisione.
|
||||
Aggiungere prove HTTPS locali, risoluzione alias dopo recreate e controllo
|
||||
log redatto: la bozza non copre ancora integralmente il runbook.
|
||||
3. **Finalizzare scelta lifecycle Omics.** La bozza mantiene l'esatta immagine
|
||||
web operativa perché l'unica modifica applicabile è nginx (shell/Superset
|
||||
già presenti); fa fast-forward del checkout al fix, stop/start web per backup
|
||||
consistente e recreate nginx. Lo start riesegue il suo entrypoint, compresi
|
||||
migrate/compilemessages/collectstatic. Spiegare questa scelta nel piano finale.
|
||||
Se si decide di ricostruire web, il suo `.dockerignore` è minimale: creare un
|
||||
contesto pulito, aggiungere il catalogo Superset reale valido, escludere segreti.
|
||||
4. **Finalizzare backup odierno.** La bozza salva immagini/code/config, ferma
|
||||
ingressi e applicativi dopo maintenance e controllo Pi, crea dump catalogo
|
||||
e PostgreSQL Omics condiviso, ferma supporti ThothII per snapshot raw coerenti,
|
||||
archivia bind/volumi e verifica checksum/tar/indici dump. Valutare spazio e
|
||||
interruzioni; il vecchio backup verificato non basta. Il DB Omics è condiviso
|
||||
(`postgres` su `supabase-db`, app in `kokoro`, metadata in `chirone_meta`):
|
||||
un restore dell'intero DB non fa parte del rollback ordinario.
|
||||
5. **Presentare piano risolto, comandi, backup e rollback all'utente**, chiedendo
|
||||
conferma della finestra. Solo allora installare CLI/config, generare proiezioni,
|
||||
ricreare le app e applicare nginx. Nessuna migrazione nuova rilevata finora.
|
||||
6. **Collaudare e poi coinvolgere l'utente.** Login unico, `/me` e ruoli,
|
||||
IT/EN, tema/fullscreen, logout/seconda scheda, sessione fittizia con Pi/SSE,
|
||||
stop/save/ripresa e lingua immutabile, diniego cross-origin autenticato,
|
||||
Database/Memory/Evidence e accesso HTTPS da postazione esterna.
|
||||
|
||||
Rollback: ripristinare immagini ThothII, CLI, descriptor/env/override e
|
||||
proiezioni salvati; preservare dati e **mantenere il fix proxy**, già testato
|
||||
col frontend precedente. Ripristinare il vecchio nginx riaprirebbe il bypass.
|
||||
Nessun restore dati automatico, reset Git o eliminazione volumi.
|
||||
|
||||
## Ambiente strumenti
|
||||
|
||||
La sandbox exec fallisce prima dell'avvio (`bwrap: loopback … Operation not
|
||||
permitted`): i comandi sono stati eseguiti con `require_escalated` e motivazione.
|
||||
Auto-review li ha consentiti; nessun rifiuto pendente. Non sono stati usati
|
||||
subagenti. Skill applicate: `diagnosing-bugs`, `writing-for-agents` per questo handoff.
|
||||
Nessun goal formale attivo. Per lo stato successivo alla ripresa, usare il piano revisionato collegato in apertura.
|
||||
@@ -0,0 +1,184 @@
|
||||
# Piano eseguibile — rilascio coordinato ThothII / Omics
|
||||
|
||||
Data: 26 settembre 2026. Ripresa del [passaggio di consegne](2026-09-26-server-release-handoff.md).
|
||||
**Piano approvato dall’utente; esecuzione avviata il 26 settembre 2026 alle 19:28 Europe/Rome.**
|
||||
Stato operativo e risultati successivi nel [report di esecuzione](2026-09-26-server-release-execution.md).
|
||||
Il testo seguente registra la preparazione precedente alla conferma.
|
||||
Nessun fermo, modifica di configurazione operativa, migrazione, ricreazione,
|
||||
login di prova o cambio credenziali eseguito durante questa ripresa.
|
||||
|
||||
## Risultato proposto
|
||||
|
||||
- ThothII: distribuire core/frontend già costruiti dalla main
|
||||
`497ab84031e285464fdbb73e6e0ce9252687e3ab`, conservando percorso del descrittore,
|
||||
project identity, dati e configurazione server.
|
||||
- Omics: fast-forward da `1cf7ea90a669a26bf3bc51749eab4d07981da472` al commit locale
|
||||
`928f7e9fff2aba895416776fecf5668ee957d237`, che aggiunge il filtro proxy degli asset.
|
||||
Conservare la stessa immagine e lo stesso container web: shell embedded e fix
|
||||
Superset sono già operativi. Riavviare web dopo il backup e ricreare soltanto
|
||||
nginx Omics, fissandone l'immagine all'ID esistente.
|
||||
- Mantenere il fix proxy anche nel rollback: la configurazione precedente consente
|
||||
il bypass documentato nell'handoff e non deve essere ripristinata.
|
||||
|
||||
L'entrypoint web rieseguirà `makemigrations`, `migrate`, controllo superuser,
|
||||
`compilemessages` e `collectstatic`. Verificati `makemigrations --check --dry-run`
|
||||
e `migrate --check`: nessuna modifica o migrazione pendente. L'utente che lo
|
||||
script creerebbe automaticamente esiste già. Questi controlli saranno ripetuti
|
||||
prima del fermo. Nessuna nuova migrazione di catalogo, Memory o sessioni emerge
|
||||
anche dal confronto ThothII `49333a2d..497ab840`; nessun job di migrazione è previsto.
|
||||
|
||||
## Rivalidazione alla ripresa
|
||||
|
||||
| Controllo | Esito |
|
||||
| --- | --- |
|
||||
| Immagini/container operativi | Stessi ID e date di avvio registrati nell'handoff |
|
||||
| Baseline descriptor/env/override/Pi/modelli/segreti | Tutti gli hash invariati |
|
||||
| Checkout ThothII candidato e Omics candidato | SHA attesi, puliti |
|
||||
| Checkout ThothII operativo | Sempre dirty; preservato, 30 modifiche e due file non tracciati |
|
||||
| Checkout Omics operativo | Tracciati invariati; nuovi file locali sotto `docs/prd/.claude/`, preservati |
|
||||
| Checkout di lavoro ThothII | Nuova directory locale `.claude/`, estranea al rilascio e preservata |
|
||||
| Pi RPC | Zero processi, rilevamento effettivo in `/proc` |
|
||||
| Maintenance | Inattiva; il contatore `admissions` del CLI è locale a quel processo e non certifica il drenaggio del server |
|
||||
| Doctor | Positivo con UID 10001 e gruppi operator/Docker |
|
||||
| Omics | Gunicorn/Django rispondono; catalogo Superset valido; nessuna migrazione pendente |
|
||||
| HTTPS locale | Certificato verificato con CA interna e risoluzione del nome a 127.0.0.1; config 200, API anonima 403 |
|
||||
| Alias Docker | Univoci; nginx risolve core/frontend/web; Omics legge il manifest |
|
||||
| Compose candidato | Environment, reti, porte, mount persistenti/segreti invariati; cambiano immagini, contesti build e due script con contenuto identico |
|
||||
| Descrittore candidato | Cambiano solo `projectDirectory` e il percorso dell'overlay git-ssh |
|
||||
| Spazio | 27,8 GiB liberi; stima non compressa 12,6 GiB; riserva richiesta 20,9 GiB |
|
||||
|
||||
Il bypass asset operativo non è stato ritestato in questa ripresa: resta quello
|
||||
accertato nell'handoff; il fix resta non distribuito. Le prove HTTPS locali non
|
||||
sostituiscono l'accesso da una postazione esterna o un login reale.
|
||||
|
||||
## Script revisionato e verifiche
|
||||
|
||||
Percorso definitivo di preparazione:
|
||||
`/srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py`.
|
||||
SHA256: `eb2c677c8adbee0c9febf919001f654c8535e71f064d9fb7c7883afd02383a41`.
|
||||
La precedente `release.DRAFT.py` resta conservata e non va eseguita.
|
||||
|
||||
Correzioni principali:
|
||||
|
||||
- Parsing NUL degli argomenti Pi, rilevamento `--mode rpc` e `--mode=rpc`, esclusione
|
||||
del processo di controllo; test reale in container isolato.
|
||||
- Gate espliciti anche con Python ottimizzato; lock tra esecuzioni; controllo
|
||||
dei digest dei tag, dei container e degli artefatti preparati.
|
||||
- Baseline estesa a CLI, configurazione Omics, CA/proxy host e file locali.
|
||||
- Checksum dedicati della configurazione di rollback, creati prima delle mutazioni;
|
||||
journal delle fasi, file parziali conservati e nessun marker VERIFIED su errore.
|
||||
- Preservazione proprietari/permessi, `.git`, file ignorati/non tracciati, ACL/xattr
|
||||
negli archivi. Solo cache dipendenze ricostruibili escluse.
|
||||
- Readiness HTTP di Omics, alias dopo ricreazione, controlli HTTPS con CA,
|
||||
tutti gli asset del manifest e riepilogo log per categorie senza contenuti sensibili.
|
||||
- Recupero `reopen` per rendere nuovamente raggiungibile una sessione Pi comparsa
|
||||
durante il drenaggio: riapre solo nginx con il fix, senza fermare web/core/Pi.
|
||||
|
||||
Validazione: sintassi Python, **14 test isolati**, fase `check` read-only positiva.
|
||||
I test coprono anche conferma mancante, backup parziale/corrotto, checksum con
|
||||
path traversal, ownership, readiness HTTP e recupero senza stop di Pi.
|
||||
Le fasi mutanti non sono state eseguite né rappresentano un restore provato.
|
||||
|
||||
Evidenze in `/srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/`:
|
||||
`reviewed-tests.log`, `reviewed-check.log`, script e test; manifest protetti
|
||||
`artifacts.json`, `baseline-extra.json`, `source-state.json`.
|
||||
Restano valide le prove precedenti: 6/6 proxy con ciascun frontend nuovo/vecchio,
|
||||
28/28 Omics, 782 frontend, 152 backend e 31 browser; nessuna modifica a quelle
|
||||
implementazioni durante questa ripresa.
|
||||
|
||||
## Comandi risolti per la finestra
|
||||
|
||||
Riservare indicativamente **30–45 minuti**, da confermare dall'operatore: la durata
|
||||
reale dipende soprattutto dal dump del database condiviso. L'interruzione interessa
|
||||
Omics e ThothII; non vengono fermati Authentik, il database condiviso o il DWH.
|
||||
La prima parte del backup (codice/config/immagini) avviene con le app ancora attive.
|
||||
|
||||
Eseguire ciascun comando solo dopo exit 0 del precedente, nella finestra approvata:
|
||||
|
||||
```bash
|
||||
sudo -n python3 /srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py check
|
||||
sudo -n python3 /srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py backup --window-confirmed
|
||||
sudo -n python3 /srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py deploy --window-confirmed
|
||||
```
|
||||
|
||||
`--window-confirmed` registra l'intenzione del comando, **non sostituisce il consenso**.
|
||||
Lo script contiene tutti i percorsi/ID e l'ordine Compose risolti; non usa pull,
|
||||
build implicite, setup completo, reset o cancellazione volumi.
|
||||
|
||||
Sequenza concreta:
|
||||
|
||||
1. Rivalidare baseline, assenza Pi e spazio. Salvare e verificare configurazioni,
|
||||
CLI, sorgenti e immagini correnti.
|
||||
2. Attivare maintenance, chiudere nginx Omics, attendere e controllare due volte
|
||||
Pi. In caso di sessioni attive fermare la procedura senza ucciderle.
|
||||
3. Fermare Omics web/core/frontend, creare i dump, fermare i soli supporti ThothII,
|
||||
archiviare bind e volumi. Verificare checksum, lettura tar e indici dump.
|
||||
4. Solo con backup VERIFIED: fast-forward Omics; aggiornare descriptor/env/overlay;
|
||||
installare CLI verificato e generare proiezioni con UID 10001. Controllare che
|
||||
modelli, Pi, shell e credenziali restino identici.
|
||||
5. Riavviare supporti; ricreare core/frontend con stesso progetto
|
||||
`thothii-7f901b48fe35`; avviare lo stesso web Omics; ricreare nginx col fix e
|
||||
immagine fissata. `--no-build --pull never --no-deps` limita il lifecycle.
|
||||
6. Verificare health/HTTP, DNS, `nginx -t`, attendere 31 secondi, eseguire prove
|
||||
automatiche HTTP/HTTPS e log. Disattivare maintenance solo dopo esito positivo.
|
||||
|
||||
## Backup e gestione delle interruzioni
|
||||
|
||||
Destinazione nuova, protetta root 0700:
|
||||
`/srv/thothii-v2/backups/20260926-coordinated-release`.
|
||||
**Non esiste ancora**: verrà creata nella finestra. Se esiste già, lo script si
|
||||
ferma senza riutilizzare o cancellare il contenuto.
|
||||
|
||||
Contiene CLI/descriptor/env/override/generated, sorgenti e Git, configurazioni
|
||||
Omics e proxy, immagini per ID, bind data/registry/Evidence/Pi/segreti,
|
||||
volumi catalogo/Qdrant/Ollama/static/media, dump catalogo e dump PostgreSQL condiviso.
|
||||
Il dump condiviso è una snapshot transazionale coerente mentre gli altri servizi
|
||||
che usano quel DB continuano a operare; non è un backup raw a database fermo.
|
||||
Il volume raw del catalogo ThothII viene copiato solo dopo averlo fermato.
|
||||
|
||||
Su errore: niente retry cieco né prosecuzione verso deploy. Leggere journal e stato
|
||||
container. Prima di una mutazione ai servizi, questi restano operativi; dopo la
|
||||
quiescenza possono rimanere fermi. Il manifest `rollback-config.json` permette
|
||||
il rollback applicativo anche quando il backup dati è incompleto. Nessun restore
|
||||
automatico dei dati; nessuna prova di restore dichiarata.
|
||||
|
||||
Se Pi compare dopo chiusura ingressi e prima del fermo applicativo:
|
||||
|
||||
```bash
|
||||
sudo -n python3 /srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py reopen --window-confirmed
|
||||
```
|
||||
|
||||
Questo applica il solo proxy sicuro, mantiene le applicazioni e Pi accesi e lascia
|
||||
maintenance attiva: l'utente può salvare/fermare la sessione. La procedura si arresta
|
||||
poi per rivalutare backup parziale e baseline; non tenta automaticamente un nuovo
|
||||
backup o deploy.
|
||||
|
||||
## Rollback applicativo
|
||||
|
||||
Se la nuova applicazione o i controlli falliscono, e non ci sono Pi da salvare:
|
||||
|
||||
```bash
|
||||
sudo -n python3 /srv/thothii-v2/operator/releases/20260926-coordinated/reviewed/release.py rollback --window-confirmed
|
||||
```
|
||||
|
||||
Ripristina configurazioni/CLI/generated e immagini core/frontend precedenti,
|
||||
riavvia lo stesso web Omics, mantiene il commit e il proxy corretto, quindi ripete
|
||||
il collaudo automatico. Ripristina UID/GID/mode originali. Non sovrascrive dati,
|
||||
non ripristina l'intero DB condiviso e non torna al nginx vulnerabile. Non fa reset
|
||||
Git. Rifiuta di interrompere Pi attivi. Dopo un backup parziale conserva gli
|
||||
artefatti per analisi: non li presenta come backup completo.
|
||||
|
||||
## Collaudo dell'operatore dopo il rilascio
|
||||
|
||||
Avvisare l'utente quando i controlli automatici saranno verdi, poi verificare
|
||||
con account autorizzati e dati fittizi:
|
||||
|
||||
1. Login unico Omics → Datamart Builder, `/me` con identità/ruoli corretti,
|
||||
nessun secondo login; utente normale e admin coerenti.
|
||||
2. IT/EN, tema, fullscreen/Esc e persistenza dopo reload.
|
||||
3. Sessione di prova, eventi SSE, stop/save/ripresa e lingua immutabile.
|
||||
4. Logout e seconda scheda; diniego cross-origin autenticato su risorse di prova.
|
||||
5. Database/Memory/Evidence leggibili, layout previsto, HTTPS da client esterno.
|
||||
|
||||
Queste prove restano aperte e sono necessarie prima di dichiarare concluso il
|
||||
rilascio, secondo la [matrice di accettazione](../testing/authentication-manual-acceptance.md).
|
||||
@@ -0,0 +1,285 @@
|
||||
# ThothII / Omics — preflight server del 26 settembre 2026
|
||||
|
||||
Stato: **rilascio fermo al gate di isolamento del proxy**. Nessuna finestra
|
||||
richiesta o autorizzata; nessun servizio fermato, ricreato o aggiornato, nessuna
|
||||
migrazione e nessuna modifica di proxy, descrittore, credenziali, DWH o IdP.
|
||||
Questo documento è un inventario e piano parziale, **non un piano eseguibile
|
||||
di rilascio approvato**. Applicare il runbook `docs/operations/server-codex-handoff.md`.
|
||||
|
||||
## Blocco verificato
|
||||
|
||||
Senza cookie/sessione Omics:
|
||||
|
||||
| Ingresso | Richiesta | Risultato |
|
||||
| --- | --- | --- |
|
||||
| Nginx Omics, localhost:8080 con Host pubblico | `/datamart-builder/api/me` | 403 |
|
||||
| Stesso ingresso, principal normalizzato inventato | `/datamart-builder/api/me` | 403 |
|
||||
| Stesso ingresso, header `X-Thoth-Trusted-*` sintetici | `/datamart-builder/assets/api/me` | **200, JSON `/me` con identità sintetica e permesso** |
|
||||
| Nginx TLS host, HTTPS con CA verificata e DNS locale | API canonica / percorso alternativo | 403 / **200** |
|
||||
|
||||
Il soggetto di prova era `release-probe-nonexistent`, con flag admin falso;
|
||||
non sono stati usati utenti reali o richieste di scrittura. La risposta alternativa
|
||||
conteneva issuer/subject, ruoli, permessi e session/CSRF null: non era il fallback HTML.
|
||||
|
||||
Causa circoscritta: la location pubblica `/datamart-builder/assets/` inoltra
|
||||
qualsiasi suffisso alla radice del frontend. Il suffisso `api/me` raggiunge quindi
|
||||
`/api/me` del frontend, che converte gli header Trusted in principal del core.
|
||||
Quel percorso non attraversa `auth_request`. La configurazione Omics operativa e
|
||||
quella della consegna mantengono questo percorso; la nuova immagine frontend
|
||||
conserva l'endpoint `/api/`. Un aggiornamento di ThothII da solo non corregge il difetto.
|
||||
|
||||
Riproduzione non mutante, exit 1 sul difetto:
|
||||
|
||||
```bash
|
||||
python3 /tmp/thothii-release-20260926/evidence/check-proxy.py
|
||||
```
|
||||
|
||||
Serve una revisione candidata Omics del proxy che impedisca l'accesso alle API
|
||||
attraverso gli asset e rimuova gli header di fiducia dai percorsi pubblici.
|
||||
Va preparata dal codice server `1cf7ea90…`, collaudata in isolamento includendo
|
||||
varianti dei percorsi, asset/manifest/config e dinieghi, quindi inclusa nel piano
|
||||
da approvare **prima** del reload operativo. Nessuna correzione è stata applicata.
|
||||
Non indebolire auth o Origin, né cambiare le identità degli utenti.
|
||||
|
||||
L'origine pubblica via DNS, dal server, va in timeout (HTTP 000, curl exit 28).
|
||||
Il probe TLS con `--resolve …:443:127.0.0.1` è invece riuscito. Resta da verificare
|
||||
il percorso completo dal client esterno/bilanciatore; non è attestato dal probe locale.
|
||||
|
||||
## Revisioni e conservazione delle modifiche
|
||||
|
||||
- Checkout di consegna `/home/chirone/Thoth`: branch `main`, HEAD e `origin/main`
|
||||
`497ab84031e285464fdbb73e6e0ce9252687e3ab`, fetch Gitea eseguito, divergenza `0 0`;
|
||||
entrambi gli ancestor richiesti (`497ab840…`, `0d2e573e`) presenti.
|
||||
- All'inizio non era pulito: solo `docs/reports/2026-09-14-server-embedded-omics-release.md`
|
||||
non tracciato. Quel file è stato conservato. Questo report è un ulteriore output locale.
|
||||
- Copia pulita per test `/tmp/thothii-release-20260926/source`, branch `main`, stesso SHA;
|
||||
clone locale senza hardlink e senza importare il report non tracciato.
|
||||
- Checkout ThothII operativo `/srv/thothii-v2/source/ThothII`: branch `main`,
|
||||
HEAD `b1723c34c467980d007094af078d966d460cde2b`, 30 file modificati e due file
|
||||
non tracciati. Nessun aggiornamento/reset/stash eseguito in questo checkout.
|
||||
Dei 32 file locali, 29 sono identici alla main approvata; le differenze negli
|
||||
altri tre sono le nuove correzioni di main a `AppShell.tsx`, al suo test di
|
||||
gestione sessioni e al test visuale dello scroll. Non occorre ricostruirle a mano.
|
||||
- Omics `/home/chirone/omics_portal`: `master`, pulito e coincidente col riferimento
|
||||
locale `origin/master`, HEAD `1cf7ea90a669a26bf3bc51749eab4d07981da472`.
|
||||
Non è stato eseguito fetch di master: questa coincidenza non attesta il master remoto attuale.
|
||||
- Fetch esplicito del branch GitHub `codex/thothii-embedded-shell`: esattamente
|
||||
`fca10901a73666ca257d8f4cc4b77066295c400a`; contiene `95154e179144e2453b37ef2a63a65d6f377e4cf8`
|
||||
ed è già antenato di HEAD Omics. **Non ripetere il merge e non tornare a fca10901.**
|
||||
Il commit successivo corregge la risoluzione delle dashboard Superset rispetto
|
||||
alla lingua. Gli 11 file verificati nel container (shell/auth e correzione
|
||||
Superset) hanno hash uguali al checkout operativo.
|
||||
- Il branch incompleto `codex/guided-standalone-install` non è stato usato;
|
||||
`tht setup --complete` non è stato eseguito.
|
||||
|
||||
## Immagini effettivamente operative, non candidate
|
||||
|
||||
| Servizio | Tag | Image ID |
|
||||
| --- | --- | --- |
|
||||
| core | `thothii-v2-core:49333a2d-session-memory-fix` | `sha256:ff4c435abd67c57e1e91e6e560dae73e67350ca499a5aedca3ffa517b9f59ee0` |
|
||||
| frontend | `thothii-v2-frontend:b1723c34-session-dialogs-20260914` | `sha256:d2ed3dec42f8a56536ebbc8d74f13892d4c42c9a7f2fb67c476ff39f43fe7af9` |
|
||||
| Omics web | `omics_portal-web` | `sha256:27aa100690b110bf596322b1b0a31acc178ca9d1c709bc10382cbeecbfb5aeca` |
|
||||
| Omics nginx | `nginx:alpine` | `sha256:b3c656d55d7ad751196f21b7fd2e8d4da9cb430e32f646adcf92441b72f82b14` |
|
||||
| catalog-db | PostgreSQL 17.6 bookworm | `sha256:f3bd19c606e442c3d7bdfa8002e03fe260a1023351e0ea4598032022b68dd6e3` |
|
||||
| qdrant | v1.18.2 | `sha256:75eab8c4ba42096724fdcfde8b4de0b5713d529dde32f285a1f86fdcb2c9e50c` |
|
||||
| embedding | Ollama 0.32.0 | `sha256:57f573b47f1f71ebb445789f279fe3e596a8beab182f7cf486db9205bad87c5a` |
|
||||
|
||||
Il frontend dichiara revision `b1723c34-working-tree`; core e Omics non hanno
|
||||
label OCI revision. Perciò lo SHA esatto del sorgente baked del core non può
|
||||
essere certificato dalla sola immagine: tag, ID e checkout sono evidenze distinte.
|
||||
CLI operativo `/usr/local/bin/tht`, binario root:root 0755; non sostituito.
|
||||
|
||||
## Installazione, Compose e persistenza
|
||||
|
||||
Descrittore invariato:
|
||||
`/srv/thothii-v2/source/ThothII/deploy/psd-server-v2/thothii-installation.yaml`.
|
||||
Schema 2, profile server, file 0600 owner UID/GID 10001, projectDirectory
|
||||
`/srv/thothii-v2/source/ThothII`, envFile `/srv/thothii-v2/operator/operator.env`.
|
||||
Shell già `embedded/en/omics-portal`. Project Compose `thothii-7f901b48fe35`.
|
||||
Ordine dei file applicativi, ricavato dalle label dei container:
|
||||
|
||||
1. `/srv/thothii-v2/source/ThothII/compose.yaml`
|
||||
2. `/srv/thothii-v2/source/ThothII/deploy/compose.server.yaml`
|
||||
3. `/srv/thothii-v2/source/ThothII/deploy/compose.git-ssh.yaml`
|
||||
4. `/srv/thothii-v2/operator/compose.portal-upstream.yaml`
|
||||
5. `/srv/thothii-v2/source/ThothII/deploy/psd-server-v2/generated/compose.models.yaml`
|
||||
|
||||
I supporti sono stati creati con i primi quattro file. Il percorso del descrittore
|
||||
determina l'identità Compose nel CLI: mantenerlo anche usando in futuro una
|
||||
directory sorgente pulita distinta. Non spostare il descrittore in un nuovo checkout.
|
||||
L'override contiene un tag frontend letterale: il solo cambio di
|
||||
`THTII_RELEASE_IMAGE_TAG` non aggiorna entrambe le immagini.
|
||||
|
||||
Core: `AUTH_MODE=upstream`, `THT_AUTH_CONFIG_FILE=/run/thothii-auth/upstream-disabled.yaml`,
|
||||
nessuno dei due file auth (`auth.yaml`, `upstream-disabled.yaml`) presente;
|
||||
directory host `/srv/thothii-v2/operator/auth`, nessuna runtime auth projection.
|
||||
`THOTH_PUBLIC_EXPOSURE=false`, `THT_SESSION_STORAGE=local`: configurazione
|
||||
preesistente, non modificata. Non è una prova di isolamento: il gate proxy è fallito.
|
||||
Se si decide di impostare public exposure true, serve prima un piano separato
|
||||
per storage sessioni PostgreSQL; non attivare l'overlay come falsa migrazione automatica.
|
||||
|
||||
Bind e archivi:
|
||||
|
||||
- `/srv/thothii-v2/data` → `/data`: settings, sessioni, artifact, indici e workspace secrets.
|
||||
- Sessioni PSD: `/data/sessions/psd-clinical/{sessions,artifacts,indexes,memory}`;
|
||||
snapshot catalogo `/data/sessions/psd-clinical/preprocessing/catalog-metadata.json`.
|
||||
- `/srv/thothii-v2/workspace-registry` → `/data/workspace-registry`; workspace
|
||||
`psd-clinical`, installation ID `psd-server-v2`. Evidence local archive
|
||||
`/data/workspace-registry/repo/psd-clinical`.
|
||||
- `/srv/thothii-v2/pi-state` → `/home/thoth/.pi`; auth provider read-only
|
||||
`/srv/thothii-v2/secrets/pi-auth.json` → `/home/thoth/.pi/agent/auth.json`.
|
||||
- Bundle `/srv/thothii-v2/secrets/thothii.secrets`; chiavi workspace SSH,
|
||||
known-hosts e password catalogo in `/srv/thothii-v2/secrets/`, valori mai riportati.
|
||||
- Generated catalog/Pi/frontend sotto il descrittore; `config.js` montato read-only.
|
||||
- Catalogo e Memory autorevoli PostgreSQL nel volume
|
||||
`thothii-7f901b48fe35_catalog-data`; indici derivati
|
||||
`thothii-7f901b48fe35_qdrant-data`; modelli `thothii-7f901b48fe35_embedding-models`.
|
||||
- Binding DWH diretto già operativo verso `host.docker.internal:5438`, utente
|
||||
read-only `thoth_dwh_reader`. Nessuna query DWH o sincronizzazione avviata.
|
||||
|
||||
Omics: project `omics_portal`, file ordinati
|
||||
`/home/chirone/omics_portal/docker-compose.yml`,
|
||||
`/home/chirone/omics_portal/docker-compose.override.yml`, env `.env.docker`.
|
||||
Volumi `omics_portal_static_volume` e `omics_portal_media_volume`; mount CA
|
||||
`/etc/nginx/ssl/policlinicosandonato.it.fullchain.crt` read-only.
|
||||
Database portale: `supabase-db`, database `postgres`, search_path `kokoro,public`,
|
||||
endpoint host 5438. Non confonderlo con il DWH o col catalogo ThothII.
|
||||
Il server PostgreSQL è condiviso: un eventuale restore dell'intero database
|
||||
non è un rollback ordinario di Omics e richiede un piano separato.
|
||||
|
||||
Reti: core su `thothii-7f901b48fe35_thothii`, `omics_portal_omics_network`
|
||||
(alias `thothii-core`) e `localllm_default`; frontend su prime due reti (alias
|
||||
`thothii-frontend`). Nessuna porta host core; frontend `127.0.0.1:18020`.
|
||||
Omics web solo porta interna 8000; nginx `0.0.0.0:8080`. TLS host nginx su 443
|
||||
per `https://aritmolab.policlinicosandonato.it`, poi localhost:8080.
|
||||
File host `/etc/nginx/sites-available/policlinicosandonato`, collegato in sites-enabled;
|
||||
SSE canonico con buffering disabilitato e timeout 86400 su entrambi gli nginx.
|
||||
La mappa Origin esatta HTTPS→HTTP è presente. Il tratto esterno non è verificato.
|
||||
|
||||
Inventario JSON filtrato completo (label, mount, reti, porte):
|
||||
`/tmp/thothii-release-20260926/inventory.json`.
|
||||
|
||||
## Verifiche eseguite e candidati
|
||||
|
||||
- ThothII frontend: **782/782** test, build/typecheck riusciti.
|
||||
- Browser isolato: **31/31** scenari visuali Playwright riusciti. Il primo
|
||||
tentativo non aveva il binario Chromium; installato soltanto nello staging
|
||||
`/tmp/thothii-release-20260926/browsers`, quindi suite rieseguita con successo.
|
||||
- Backend: build/typecheck riusciti; **152/152** test mirati su Node 24.16 in
|
||||
container senza rete o dati operativi. I tentativi host Node 23 fallivano
|
||||
per Argon2 non disponibile; i primi container di test avevano UID/mount
|
||||
incompleti. Il risultato valido è `backend-node24-tests.log`.
|
||||
- Omics shell/auth/nginx isolati: **15/15**; regressioni Superset: **12/12**,
|
||||
entrambe le esecuzioni con `--network none`, SQLite in-memory, nessun volume operativo.
|
||||
- Omics operativo: `migrate --check` exit 0, catalogo Superset valido (32 dashboard),
|
||||
`nginx -t` exit 0. Warning allauth deprecati presenti.
|
||||
- CLI corrente: status exit 0, doctor **13/13**, maintenance `active=false`, admissions 0.
|
||||
Il primo tentativo con sudo/root era rifiutato dal controllo ownership dei segreti.
|
||||
Con UID 10001 e gruppi 1014,988, più DOCKER_CONFIG leggibile, nessun errore:
|
||||
non mancavano credenziali e non sono stati cambiati permessi.
|
||||
- CLI aggiornato costruito in `/tmp/thothii-release-20260926/cli/tht-linux-amd64`;
|
||||
generazione riuscita su copie root:root 0600 in directory 0700
|
||||
`/tmp/thothii-release-20260926/generation` (contiene copie sensibili, non pubblicare).
|
||||
Proiezione frontend `/api`, shell embedded/en/omics-portal corretta.
|
||||
- Immagine core candidata `thothii-v2-core:497ab840-preflight`:
|
||||
`sha256:182f4e0d63404cb7ed6a0e272441e9c55ed27e2bb16fdbf4d7162f892ac76dc7`.
|
||||
- Immagine frontend candidata `thothii-v2-frontend:497ab840-preflight`:
|
||||
`sha256:5f5a4f81139432d0ac41025c3006edaf1258b623ce388242700b1b20fcce6421`.
|
||||
Entrambe portano la revision OCI `497ab84031e285464fdbb73e6e0ce9252687e3ab`.
|
||||
**Costruite, non distribuite**. Non è stata costruita una nuova immagine Omics operativa.
|
||||
|
||||
Log dei test e build in `/tmp/thothii-release-20260926/`; log Omics
|
||||
`/tmp/omics-release-tests-20260926.log` e `/tmp/omics-release-superset-tests-20260926.log`.
|
||||
Log browser: `/tmp/thothii-release-20260926/browser-tests.log`.
|
||||
|
||||
## Backup e rollback: stato e vincoli
|
||||
|
||||
Backup storico `/srv/thothii-v2/backups/20260914-pre-embedded-release`:
|
||||
directory root:root 0700, file 0600. Verificati **14 checksum**, leggibilità di
|
||||
sette archivi tar.gz e indice dei due dump con `pg_restore --list`: tutto exit 0.
|
||||
**Non è stata eseguita una prova di restore e non è un backup dello stato odierno.**
|
||||
Contiene anche dati condivisi/sensibili: accesso protetto, nessun contenuto mostrato.
|
||||
Altri backup presenti: `20260914-session-memory-fix`, `20260914-session-dialogs`,
|
||||
`memory-evidence-20260910`; non attestati dai controlli del primo backup.
|
||||
|
||||
Il nuovo punto di rollback andrà creato nella finestra, dopo gestione delle
|
||||
sessioni in corso e quiescenza delle scritture dei due applicativi. Percorso
|
||||
previsto `/srv/thothii-v2/backups/20260926-coordinated-release` (non creato).
|
||||
Deve includere:
|
||||
|
||||
1. Binario CLI, descriptor/env/override/generated, checkout operativo dirty
|
||||
completo o bundle Git + patch + file non tracciati, configurazioni Omics,
|
||||
catalogo Superset runtime e configurazione nginx host; proprietari/permessi preservati.
|
||||
2. Immagini attuali core/frontend/web/nginx per ID e checksum dell'archivio.
|
||||
3. Bind data, registry, Evidence, Pi, secrets/settings e volumi static/media Omics.
|
||||
4. Dump coerente del catalogo e backup portale con ambito esplicito rispetto
|
||||
al database PostgreSQL condiviso; snapshot Qdrant/Ollama e, se richiesto,
|
||||
snapshot raw catalogo **solo a database fermo**. Non archiviare un PGDATA live
|
||||
come se fosse un backup consistente.
|
||||
5. SHA256SUMS, elenco integrale archivi senza errori, `pg_restore --list` e
|
||||
restore isolato prima di eventuali migrazioni non reversibili.
|
||||
|
||||
Fra il riferimento operativo core `49333a2d` e la main approvata non risultano
|
||||
nuove migrazioni catalogo/sessioni; Omics `migrate --check` non segnala pendenti.
|
||||
Rivalutare dopo l'eventuale nuova revisione proxy: nessuna migrazione autorizzata ora.
|
||||
L'entrypoint Omics esegue anche `makemigrations`, `migrate`, creazione superuser,
|
||||
`compilemessages`, `collectstatic`: non usarlo come test preliminare su dati operativi.
|
||||
Il `.dockerignore` Omics è minimale: preparare un contesto di build pulito che
|
||||
includa il catalogo valido ed escluda env/backup/segreti prima della build operativa.
|
||||
|
||||
Rollback applicativo previsto: ripristino della coppia core/frontend e Omics
|
||||
sopra registrata, del CLI e dei file di configurazione/proiezione salvati,
|
||||
con gli stessi project name, bind e volumi; ricreazione mirata delle sole app,
|
||||
`nginx -t`, aggiornamento DNS/reload del proxy e collaudo accesso/manifest/SSE.
|
||||
Non fare downgrade dati, restore dell'intero Supabase o cancellazioni di volumi.
|
||||
**Il ritorno alla vecchia configurazione proxy ripristinerebbe il bypass noto:**
|
||||
il rollback approvato deve conservare una chiusura di sicurezza verificata,
|
||||
oppure mantenere indisponibile Datamart Builder fino alla correzione.
|
||||
|
||||
## Comandi ricostruiti e piano da completare
|
||||
|
||||
Queste funzioni ricostruiscono il lifecycle corrente; non sono state usate per mutazioni:
|
||||
|
||||
```bash
|
||||
thoth_compose() {
|
||||
sudo -n docker compose --project-name thothii-7f901b48fe35 \
|
||||
--project-directory /srv/thothii-v2/source/ThothII \
|
||||
--env-file /srv/thothii-v2/operator/operator.env \
|
||||
-f /srv/thothii-v2/source/ThothII/compose.yaml \
|
||||
-f /srv/thothii-v2/source/ThothII/deploy/compose.server.yaml \
|
||||
-f /srv/thothii-v2/source/ThothII/deploy/compose.git-ssh.yaml \
|
||||
-f /srv/thothii-v2/operator/compose.portal-upstream.yaml \
|
||||
-f /srv/thothii-v2/source/ThothII/deploy/psd-server-v2/generated/compose.models.yaml "$@"
|
||||
}
|
||||
omics_compose() {
|
||||
docker compose --project-name omics_portal \
|
||||
--project-directory /home/chirone/omics_portal \
|
||||
-f /home/chirone/omics_portal/docker-compose.yml \
|
||||
-f /home/chirone/omics_portal/docker-compose.override.yml "$@"
|
||||
}
|
||||
# Sola diagnostica, con identità del proprietario dei file protetti:
|
||||
sudo -n setpriv --reuid=10001 --regid=10001 --groups=1014,988 \
|
||||
env DOCKER_CONFIG=/tmp/thothii-release-20260926/docker-config \
|
||||
/usr/local/bin/tht \
|
||||
--installation /srv/thothii-v2/source/ThothII/deploy/psd-server-v2/thothii-installation.yaml \
|
||||
doctor --json
|
||||
```
|
||||
|
||||
Prima di chiedere la finestra occorre risolvere il gate proxy, selezionare la
|
||||
nuova revisione Omics, completare il contesto di build e il backup odierno,
|
||||
e verificare il rollback che non riapra il bypass. La revisione ThothII pulita
|
||||
può essere collocata in `/srv/thothii-v2/releases/497ab84031e285464fdbb73e6e0ce9252687e3ab`
|
||||
senza modificare il checkout dirty; mantenendo invariato il percorso del
|
||||
descrittore, il project name CLI resta uguale. Questo trasferimento e gli
|
||||
aggiornamenti del descriptor/override non sono stati eseguiti.
|
||||
|
||||
Solo dopo questi prerequisiti presentare comandi finali risolti (nuovo CLI,
|
||||
generazione, build/up mirati, proxy, verifiche e rollback) e chiedere conferma
|
||||
della finestra. La sospensione attuale deriva dall'istruzione dell'operatore
|
||||
e dal runbook: «Ferma il passaggio interessato se manca … un prerequisito;
|
||||
non aggirare i controlli» e «Nessuna route diretta aggira il proxy».
|
||||
|
||||
Restano aperti tutti i gate reali con account Omics autorizzati: login unico,
|
||||
ruoli/capability, tema/IT-EN/fullscreen, logout e seconda scheda, sessione di
|
||||
prova e SSE/ripresa, rifiuto cross-origin autenticato, lettura amministrazione
|
||||
e accesso HTTPS da client esterno. I test isolati non li sostituiscono.
|
||||
@@ -0,0 +1,90 @@
|
||||
# Handoff — verifiche estese ThothII / Omics
|
||||
|
||||
Aggiornato il 27 settembre 2026. L’utente ha chiesto di affidare a un’attività
|
||||
successiva le verifiche residue e di pubblicare la documentazione del rilascio.
|
||||
**Aggiornamento e collaudo funzionale conclusi con successo; matrice estesa aperta.**
|
||||
Questo documento è il punto di ripresa per le sole prove ancora da registrare.
|
||||
|
||||
## Stato acquisito e confini
|
||||
|
||||
Leggere [PROJECT_STATE.md](../../PROJECT_STATE.md), il
|
||||
[report del rilascio](2026-09-26-server-release-execution.md), la
|
||||
[matrice di accettazione](../testing/authentication-manual-acceptance.md) e il
|
||||
[contratto upstream](../install/authentication-upstream.md).
|
||||
|
||||
Il 26 settembre sono stati distribuiti ThothII `497ab840` e il fix proxy Omics
|
||||
`928f7e9f`, conservando l’immagine web Omics. Backup verificato e rollback sono
|
||||
registrati nel report. L’utente ha confermato accesso senza secondo login,
|
||||
controlli IT/EN, tema, fullscreen/Esc e avvio → interruzione → ripresa di una
|
||||
sessione. Le prove automatiche di health, proxy anonimo/header falsificati,
|
||||
asset, TLS locale e preservazione dati/configurazioni sono passate.
|
||||
|
||||
Queste sono evidenze del rilascio, non una nuova attestazione dello stato live.
|
||||
Non ripetere backup/deploy né attivare maintenance per questo collaudo. Usare
|
||||
account autorizzati e sessioni fittizie; DWH read-only. Non modificare ruoli,
|
||||
Authentik, credenziali, modelli, archivi o configurazioni per far passare una prova.
|
||||
Un problema che richieda un nuovo rilascio va prima diagnosticato e pianificato.
|
||||
|
||||
## Prima azione alla ripresa
|
||||
|
||||
1. Rileggere le conferme nel report: non chiedere all’utente di ripetere il ciclo
|
||||
funzionale già riuscito, salvo regressioni o cambio di versione.
|
||||
2. Verificare in sola lettura revisioni/container e stato dell’installazione.
|
||||
Distinguere eventuale drift dalla baseline pubblicata; preservare il lavoro
|
||||
e le sessioni in corso. Il `check` dello script di rilascio si aspetta lo stato
|
||||
**precedente** al deploy: non usarlo come controllo corrente.
|
||||
3. Concordare con l’operatore browser e account già disponibili: autorizzato,
|
||||
normale, amministratore e, se disponibile, senza capability Datamart Builder.
|
||||
Accedere dal normale login Omics; non chiedere password/cookie/token in chat.
|
||||
Se manca un profilo, registrare quel caso come non eseguito senza crearne uno.
|
||||
|
||||
**Completato quando:** sono registrati data, revisioni effettive, modalità
|
||||
embedded/upstream, browser e disponibilità dei profili, senza dati personali.
|
||||
L’agente può proseguire con le letture tecniche mentre attende l’operatore.
|
||||
|
||||
## Prove residue
|
||||
|
||||
Tutti i casi sotto partono da **non eseguito**. La colonna “chi” indica chi compie
|
||||
la parte principale; l’agente prepara i controlli tecnici e registra i risultati.
|
||||
|
||||
| ID | Chi | Azione concreta | Risultato necessario |
|
||||
| --- | --- | --- | --- |
|
||||
| V1 — lingua persistita | Operatore + agente | Creare una sessione fittizia con UI italiana, annotarne `interaction_language` tramite il normale stato sessione, interromperla, cambiare UI in inglese e riprendere **la stessa** sessione. | UI inglese, lingua della sessione ancora italiana; domande/scelte nella lingua persistita, SQL e contenuti authored invariati. La ripresa generica già provata non chiude questo caso. |
|
||||
| V2 — identità e ruoli | Operatore + agente | Aprire `/datamart-builder/api/me` dalla sessione Omics autenticata; confrontare profilo normale e admin con le capability attese. Provare una richiesta amministrativa di sola lettura con il profilo normale. Se disponibile, provare pagina/API con un account senza capability. | Issuer `portal`, subject Django stabile, ruoli coerenti, `session` e `csrfToken` null. Profilo normale senza accesso amministrativo anche lato server; account senza capability rifiutato. Registrare solo esiti e codici, non identità o payload completi. |
|
||||
| V3 — logout e riconnessione | Operatore | Aprire due schede Omics/Datamart Builder con una sessione fittizia; fare logout in una, tornare nell’altra e provocare un ricontrollo con reload/riconnessione. Rientrare attraverso Omics. | La nuova richiesta `/me` e le nuove aperture SSE non riusano l’accesso scaduto; UI protetta rimossa al ricontrollo. Non richiedere la chiusura istantanea di uno stream già aperto: non è il contratto. |
|
||||
| V4 — origine delle scritture | Agente, con login dell’operatore | Preparare una coppia di richieste autenticate equivalenti su una risorsa fittizia autorizzata: prima same-origin, poi con origine estranea, attraversando il proxy pubblico. Confrontare lo stato della risorsa prima/dopo. Usare un harness HTTP locale con credenziali solo in memoria o file protetto; non affidarsi a `fetch` per impostare manualmente `Origin`. | La scrittura same-origin riesce e quella cross-origin è negata senza mutazioni. Dimostrare che la seconda richiesta è autenticata: un 403 dovuto alla sola assenza di cookie non prova la difesa Origin. I test isolati già verdi sono evidenza complementare, non sostituiscono questo caso. |
|
||||
| V5 — lettura amministrazione | Operatore autorizzato | Aprire Database, Memory ed Evidence e controllare disponibilità dei dati preesistenti, selezione, pannelli e scroll. | Viste leggibili, nessun errore e nessuna scrittura/sincronizzazione necessaria per aprirle. Annotare quale area è stata verificata senza copiare contenuti clinici. |
|
||||
| V6 — reload e preferenze | Operatore | Con sessione selezionata e Pi fermo, scegliere lingua e tema dal portale e ricaricare. | Preferenze e selezione coerenti; i documenti si riaprono senza avviare automaticamente Pi o una nuova generazione. La lingua persistita della sessione resta quella originale. |
|
||||
| V7 — HTTPS esterno | Operatore | Confermare se le prove precedenti sono state svolte da una postazione esterna al server. Se non attestato, aprire il portale dal client abituale attraverso il nome pubblico e verificare config, asset e connessione eventi. | Accesso HTTPS senza avvisi di certificato, mixed content o errori di rete. Annotare browser e tipo di accesso, senza IP personali. Il curl locale con CA e risoluzione a 127.0.0.1 non chiude questo caso. |
|
||||
|
||||
Per V4 preparare e rendere verificabile il probe prima di eseguirlo: deve agire
|
||||
solo sulla risorsa di prova concordata e controllare l’assenza di mutazioni nel
|
||||
caso negato. In assenza di credenziali utilizzabili localmente, lasciare il caso
|
||||
non eseguito; non estrarre sessioni di altri utenti o cambiare le regole Origin.
|
||||
I comandi e gli endpoint concreti vanno derivati dalla versione effettivamente
|
||||
installata, non inventati a partire da questo elenco.
|
||||
|
||||
## Registrazione e criterio di chiusura
|
||||
|
||||
Aggiornare questa tabella dopo ogni prova, collegando evidenze redatte o una
|
||||
conferma esplicita dell’operatore. Un caso parziale resta aperto per i profili o
|
||||
scenari mancanti. In caso di difetto, annotare riproduzione, atteso/ottenuto e
|
||||
revisione; correggere e riprovare il caso interessato prima di dichiararlo superato.
|
||||
|
||||
| Caso | Stato iniziale | Data / versione / evidenza |
|
||||
| --- | --- | --- |
|
||||
| V1 | Non eseguito | — |
|
||||
| V2 | Non eseguito | — |
|
||||
| V3 | Non eseguito | — |
|
||||
| V4 | Non eseguito | — |
|
||||
| V5 | Non eseguito | — |
|
||||
| V6 | Non eseguito | — |
|
||||
| V7 | Non eseguito | — |
|
||||
|
||||
**Chiusura delle verifiche residue:** ogni caso V1–V7 ha esito e prova registrati;
|
||||
per dichiarare la matrice estesa superata devono essere tutti verdi. Un rinvio
|
||||
esplicito o un prerequisito mancante va riportato come tale, non come successo.
|
||||
Aggiornare quindi report di rilascio, questo handoff e PROJECT_STATE.md.
|
||||
|
||||
L’aggiornamento applicativo e il collaudo funzionale già confermati restano conclusi;
|
||||
questo follow-up non richiede di reinstallare né di ripetere il rilascio.
|
||||
@@ -79,7 +79,7 @@ verify_standalone_installation_guides() {
|
||||
'git clone https://git.tylconsulting.it/mptyl/ThothII.git' \
|
||||
'scripts/check-standalone-prerequisites.sh' \
|
||||
'scripts/install-tht.sh' \
|
||||
'tht setup --complete --profile local --shell-mode full --shell-default-locale en' \
|
||||
'tht setup --profile local --shell-mode full --shell-default-locale en' \
|
||||
'scripts/verify-standalone-install.sh' \
|
||||
'Docker Hub' \
|
||||
'Gate A' \
|
||||
@@ -99,7 +99,8 @@ verify_install_and_workspace_guides() {
|
||||
require_file "$workspace"
|
||||
|
||||
for text in \
|
||||
'tht setup --complete --profile local' \
|
||||
'tht setup --profile local' \
|
||||
'--configure-only' \
|
||||
'catalog-migrate' \
|
||||
'tht --installation /absolute/path/thothii-installation.yaml doctor --json'; do
|
||||
require_text "$install" "$text"
|
||||
|
||||
@@ -40,9 +40,9 @@ When --installation is omitted, tht uses THOTHII_INSTALLATION or discovers one v
|
||||
descriptor in the current project tree.
|
||||
|
||||
Commands:
|
||||
setup [--complete|--configure-only] [--installation-id ID] [--profile local|server]
|
||||
setup [--configure-only] [--installation-id ID] [--profile local|server]
|
||||
[--shell-mode full|embedded] [--shell-default-locale BCP47-TAG] [--shell-adapter omics-portal]
|
||||
Create, validate, and optionally complete the local installation.
|
||||
Create or validate the local non-secret installation configuration.
|
||||
installation migrate --output PATH --session-default PROVIDER/MODEL
|
||||
--embedding-id PROVIDER/MODEL --embedding-dimensions N
|
||||
Create a review-only schema-v2 candidate from all three legacy model sources.
|
||||
@@ -86,10 +86,6 @@ Commands:
|
||||
Verify a terminal installation, remove stale lifecycle files, and clear maintenance.
|
||||
pi logs Show the latest 200 sanitized core log lines (bounded; no follow mode).
|
||||
workspace inspect --workspace ID [--json]
|
||||
workspace pull [--json]
|
||||
Pull and activate the configured workspace repository.
|
||||
workspace test [--json]
|
||||
Test configured database, Evidence, Qdrant, and embedding connectivity.
|
||||
workspace evidence consolidate --workspace ID [--json]
|
||||
workspace evidence refresh --workspace ID [--json]
|
||||
workspace evidence decide --workspace ID --source-id SHA --revision SHA --decision keep|replace [--json]
|
||||
@@ -404,11 +400,6 @@ func parseSetupArgs(args []string) (setup.Request, error) {
|
||||
flag := args[0]
|
||||
args = args[1:]
|
||||
switch flag {
|
||||
case "--complete":
|
||||
if request.Complete {
|
||||
return setup.Request{}, errors.New("--complete may be supplied once")
|
||||
}
|
||||
request.Complete = true
|
||||
case "--configure-only":
|
||||
if request.ConfigureOnly {
|
||||
return setup.Request{}, errors.New("--configure-only may be supplied once")
|
||||
@@ -493,9 +484,6 @@ func parseSetupArgs(args []string) (setup.Request, error) {
|
||||
*target = value
|
||||
}
|
||||
}
|
||||
if request.Complete && request.ConfigureOnly {
|
||||
return setup.Request{}, errors.New("--complete and --configure-only cannot be combined")
|
||||
}
|
||||
return request, nil
|
||||
}
|
||||
|
||||
@@ -511,9 +499,6 @@ func writeRemovalTargets(outputWriter io.Writer, project string, targets []serve
|
||||
}
|
||||
|
||||
func workspaceCommand(ctx context.Context, installation config.Installation, runner compose.Runner, args []string, secretValues []string, stdout, stderr io.Writer) int {
|
||||
if len(args) > 0 && (args[0] == "pull" || args[0] == "test") {
|
||||
return workspaceOperatorCommand(ctx, installation, runner, args, secretValues, stdout, stderr)
|
||||
}
|
||||
request, err := workspaceops.Parse(args)
|
||||
if err != nil {
|
||||
return commandUsageError(stderr, err.Error())
|
||||
@@ -542,51 +527,6 @@ func workspaceCommand(ctx context.Context, installation config.Installation, run
|
||||
}
|
||||
}
|
||||
|
||||
func workspaceOperatorCommand(ctx context.Context, installation config.Installation, runner compose.Runner, args []string, secretValues []string, stdout, stderr io.Writer) int {
|
||||
action := "workspace-" + args[0]
|
||||
jsonMode := false
|
||||
for _, arg := range args[1:] {
|
||||
if arg != "--json" || jsonMode {
|
||||
return commandUsageError(stderr, "workspace pull/test accepts only --json")
|
||||
}
|
||||
jsonMode = true
|
||||
}
|
||||
result, err := runner.Run(ctx, installation.ComposeArgs("exec", "-T", "core", "node", "dist/operator-command.js", action), nil)
|
||||
if err != nil {
|
||||
return writeResult(result, err, secretValues, stdout, stderr)
|
||||
}
|
||||
var payload struct {
|
||||
Ready bool `json:"ready"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(result.Stdout), &payload); err != nil {
|
||||
fmt.Fprintln(stderr, "tht: workspace operator returned invalid JSON")
|
||||
return 1
|
||||
}
|
||||
if jsonMode {
|
||||
fmt.Fprintln(stdout, output.Sanitize(result.Stdout, secretValues))
|
||||
} else {
|
||||
fmt.Fprintf(stdout, "workspace %s: %s\n", args[0], output.Sanitize(workspaceOperatorSummary(payload), secretValues))
|
||||
}
|
||||
if !payload.Ready {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func workspaceOperatorSummary(payload struct {
|
||||
Ready bool `json:"ready"`
|
||||
Status string `json:"status"`
|
||||
}) string {
|
||||
if payload.Status != "" {
|
||||
return payload.Status
|
||||
}
|
||||
if payload.Ready {
|
||||
return "ready"
|
||||
}
|
||||
return "failed"
|
||||
}
|
||||
|
||||
func workspaceFailure(stderr io.Writer, err error, secretValues []string) int {
|
||||
message := output.Sanitize(err.Error(), secretValues)
|
||||
var operationErr *workspaceops.OperationError
|
||||
|
||||
@@ -3,8 +3,6 @@ package setup
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -15,7 +13,6 @@ import (
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/aritmolab/thothii/tools/tht/internal/config"
|
||||
"github.com/aritmolab/thothii/tools/tht/internal/safeio"
|
||||
@@ -29,7 +26,6 @@ const (
|
||||
)
|
||||
|
||||
var installationIDPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]*$`)
|
||||
var secretBundleKeyPattern = regexp.MustCompile(`^[A-Z][A-Z0-9_]{0,127}$`)
|
||||
|
||||
// atomicWriteNewFile is a seam for failure testing. Its implementation never replaces an existing
|
||||
// file and leaves no final target until all content is synced.
|
||||
@@ -48,7 +44,6 @@ type answers struct {
|
||||
secretsFile, piAuthFile string
|
||||
gitCredentialsFile, gitCAFile string
|
||||
gitSSHKeyFile, gitKnownHostsFile string
|
||||
complete bool
|
||||
createSecretTemplates bool
|
||||
}
|
||||
|
||||
@@ -121,11 +116,6 @@ func EnsureFiles(request Request, input io.Reader, output io.Writer) (FilesResul
|
||||
if err := validateOrCreateSecretFiles(values, output); err != nil {
|
||||
return FilesResult{}, err
|
||||
}
|
||||
if values.complete {
|
||||
if err := validateCompleteProtectedFiles(values); err != nil {
|
||||
return FilesResult{}, err
|
||||
}
|
||||
}
|
||||
|
||||
created := make([]string, 0, 2)
|
||||
cleanup := func() {
|
||||
@@ -173,27 +163,6 @@ func collectAnswers(request Request, input io.Reader, output io.Writer, root str
|
||||
value := answersFromRequest(request)
|
||||
value.installationID = firstNonEmpty(request.InstallationID, os.Getenv("THT_SETUP_INSTALLATION_ID"), "local")
|
||||
value.profile = firstNonEmpty(request.Profile, os.Getenv("THT_SETUP_PROFILE"), "local")
|
||||
value.complete = request.Complete
|
||||
if request.Complete {
|
||||
// The complete path has one predictable protected directory. The user only fills the
|
||||
// bundle and any repository credential that is genuinely required; catalog passwords
|
||||
// are generated below and never appear in the questionnaire.
|
||||
directory := filepath.Join(root, "deploy", value.installationID, "secrets")
|
||||
value.workspaceBranch = firstNonEmpty(value.workspaceBranch, "main")
|
||||
value.secretsFile = firstNonEmpty(value.secretsFile, filepath.Join(directory, "thothii.secrets"))
|
||||
value.piAuthFile = firstNonEmpty(value.piAuthFile, filepath.Join(directory, "pi-auth.json"))
|
||||
if request.NonInteractive {
|
||||
value.workspaceAccess = firstNonEmpty(value.workspaceAccess, accessForRemote(value.workspaceRemote))
|
||||
if value.workspaceAccess == "ssh" {
|
||||
value.gitSSHKeyFile = firstNonEmpty(value.gitSSHKeyFile, filepath.Join(directory, "workspace-git-key"))
|
||||
value.gitKnownHostsFile = firstNonEmpty(value.gitKnownHostsFile, filepath.Join(directory, "workspace-git-known-hosts"))
|
||||
} else {
|
||||
value.gitCredentialsFile = firstNonEmpty(value.gitCredentialsFile, filepath.Join(directory, "workspace-git-credentials"))
|
||||
value.gitCAFile = firstNonEmpty(value.gitCAFile, filepath.Join(directory, "workspace-git-ca.pem"))
|
||||
}
|
||||
}
|
||||
value.createSecretTemplates = true
|
||||
}
|
||||
if request.NonInteractive {
|
||||
return requireNonInteractiveAnswers(value)
|
||||
}
|
||||
@@ -221,18 +190,6 @@ func collectAnswers(request Request, input io.Reader, output io.Writer, root str
|
||||
return answers{}, err
|
||||
}
|
||||
directory := filepath.Join(root, "deploy", value.installationID, "secrets")
|
||||
if request.Complete {
|
||||
value.secretsFile = firstNonEmpty(value.secretsFile, filepath.Join(directory, "thothii.secrets"))
|
||||
value.piAuthFile = firstNonEmpty(value.piAuthFile, filepath.Join(directory, "pi-auth.json"))
|
||||
if value.workspaceAccess == "ssh" {
|
||||
value.gitSSHKeyFile = firstNonEmpty(value.gitSSHKeyFile, filepath.Join(directory, "workspace-git-key"))
|
||||
value.gitKnownHostsFile = firstNonEmpty(value.gitKnownHostsFile, filepath.Join(directory, "workspace-git-known-hosts"))
|
||||
} else {
|
||||
value.gitCredentialsFile = firstNonEmpty(value.gitCredentialsFile, filepath.Join(directory, "workspace-git-credentials"))
|
||||
value.gitCAFile = firstNonEmpty(value.gitCAFile, filepath.Join(directory, "workspace-git-ca.pem"))
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
if value.secretsFile, err = prompt(scanner, output, "Secret file location", firstNonEmpty(value.secretsFile, filepath.Join(directory, "thothii.secrets"))); err != nil {
|
||||
return answers{}, err
|
||||
}
|
||||
@@ -259,15 +216,11 @@ func collectAnswers(request Request, input io.Reader, output io.Writer, root str
|
||||
return answers{}, missingErr
|
||||
}
|
||||
if len(missing) > 0 {
|
||||
if request.Complete {
|
||||
value.createSecretTemplates = true
|
||||
} else {
|
||||
answer, promptErr := prompt(scanner, output, "Create blank secret-file templates for the missing locations? Type yes to confirm", "no")
|
||||
if promptErr != nil {
|
||||
return answers{}, promptErr
|
||||
}
|
||||
value.createSecretTemplates = strings.EqualFold(answer, "yes")
|
||||
answer, promptErr := prompt(scanner, output, "Create blank secret-file templates for the missing locations? Type yes to confirm", "no")
|
||||
if promptErr != nil {
|
||||
return answers{}, promptErr
|
||||
}
|
||||
value.createSecretTemplates = strings.EqualFold(answer, "yes")
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
@@ -426,13 +379,6 @@ func render(root, descriptorPath string, value answers) ([]byte, []byte, error)
|
||||
if value.llmURL != "" {
|
||||
lines = append(lines, "THT_LLM_URL="+dotenvValue(value.llmURL))
|
||||
}
|
||||
if value.complete {
|
||||
passwordDirectory := filepath.Dir(value.secretsFile)
|
||||
lines = append(lines,
|
||||
"THT_CATALOG_RUNTIME_PASSWORD_SOURCE="+dotenvValue(filepath.Join(passwordDirectory, "catalog-runtime-password")),
|
||||
"THT_CATALOG_MIGRATOR_PASSWORD_SOURCE="+dotenvValue(filepath.Join(passwordDirectory, "catalog-migrator-password")),
|
||||
)
|
||||
}
|
||||
if value.profile == "server" {
|
||||
installationDirectory := filepath.Dir(descriptorPath)
|
||||
lines = append(lines,
|
||||
@@ -528,7 +474,10 @@ func validateOrCreateSecretFiles(value answers, output io.Writer) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(missing) > 0 && !value.createSecretTemplates {
|
||||
if len(missing) == 0 {
|
||||
return nil
|
||||
}
|
||||
if !value.createSecretTemplates {
|
||||
return fmt.Errorf("secret files are missing: %s; create them yourself or explicitly confirm blank secret-file templates", strings.Join(missing, ", "))
|
||||
}
|
||||
for _, path := range missing {
|
||||
@@ -540,104 +489,6 @@ func validateOrCreateSecretFiles(value answers, output io.Writer) error {
|
||||
}
|
||||
fmt.Fprintf(output, "Created blank secret-file template: %s\n", path)
|
||||
}
|
||||
if value.complete {
|
||||
for _, path := range catalogPasswordPaths(value) {
|
||||
exists, err := inspectExistingSecretFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
continue
|
||||
}
|
||||
contents, err := generatedCatalogPassword()
|
||||
if err != nil {
|
||||
return fmt.Errorf("generate catalog password: %w", err)
|
||||
}
|
||||
if err := atomicWriteNewFile(path, contents, 0o600); err != nil {
|
||||
return fmt.Errorf("create catalog password %s: %w", path, err)
|
||||
}
|
||||
fmt.Fprintf(output, "Created generated catalog password file: %s\n", path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func catalogPasswordPaths(value answers) []string {
|
||||
directory := filepath.Dir(value.secretsFile)
|
||||
return []string{
|
||||
filepath.Join(directory, "catalog-runtime-password"),
|
||||
filepath.Join(directory, "catalog-migrator-password"),
|
||||
}
|
||||
}
|
||||
|
||||
func generatedCatalogPassword() ([]byte, error) {
|
||||
value := make([]byte, 32)
|
||||
if _, err := rand.Read(value); err != nil {
|
||||
return nil, errors.New("secure random source is unavailable")
|
||||
}
|
||||
return []byte(hex.EncodeToString(value) + "\n"), nil
|
||||
}
|
||||
|
||||
func validateCompleteProtectedFiles(value answers) error {
|
||||
if err := validateSecretBundle(value.secretsFile); err != nil {
|
||||
return err
|
||||
}
|
||||
// The generated catalog deliberately uses Pi's built-in provider. A syntactically empty
|
||||
// auth store would let Docker start only to fail at the first provider check, so catch it
|
||||
// before any image is built. Other model providers can be selected later in the descriptor.
|
||||
contents, err := safeio.ReadCanonicalRegular(value.piAuthFile, maxSecretBytes)
|
||||
if err != nil || strings.TrimSpace(string(contents)) == "" || strings.TrimSpace(string(contents)) == "{}" {
|
||||
return fmt.Errorf("complete setup requires usable Pi credentials in %s", value.piAuthFile)
|
||||
}
|
||||
if value.workspaceAccess == "ssh" {
|
||||
for name, path := range map[string]string{
|
||||
"workspace Git SSH key": value.gitSSHKeyFile,
|
||||
"workspace Git known-hosts": value.gitKnownHostsFile,
|
||||
} {
|
||||
contents, readErr := safeio.ReadCanonicalRegular(path, maxSecretBytes)
|
||||
if readErr != nil || strings.TrimSpace(string(contents)) == "" {
|
||||
return fmt.Errorf("complete setup requires usable %s in %s", name, path)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for name, path := range map[string]string{
|
||||
"workspace Git credentials": value.gitCredentialsFile,
|
||||
"workspace Git CA": value.gitCAFile,
|
||||
} {
|
||||
contents, readErr := safeio.ReadCanonicalRegular(path, maxSecretBytes)
|
||||
if readErr != nil || strings.TrimSpace(string(contents)) == "" {
|
||||
return fmt.Errorf("complete setup requires usable %s in %s", name, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSecretBundle(path string) error {
|
||||
contents, err := safeio.ReadCanonicalRegular(path, maxSecretBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("complete setup cannot read the secret bundle %s", path)
|
||||
}
|
||||
seen := make(map[string]struct{})
|
||||
for lineNumber, raw := range strings.Split(string(contents), "\n") {
|
||||
line := strings.TrimSuffix(raw, "\r")
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
continue
|
||||
}
|
||||
key, secret, found := strings.Cut(line, "=")
|
||||
invalid := !found || !secretBundleKeyPattern.MatchString(key) || strings.TrimSpace(key) != key ||
|
||||
secret == "" || strings.TrimSpace(secret) != secret ||
|
||||
strings.Contains(strings.ToLower(secret), "replace-me") ||
|
||||
strings.IndexFunc(secret, unicode.IsSpace) >= 0
|
||||
if invalid {
|
||||
return fmt.Errorf("complete setup found an invalid secret bundle entry at line %d", lineNumber+1)
|
||||
}
|
||||
if _, duplicate := seen[key]; duplicate {
|
||||
return fmt.Errorf("complete setup found a duplicate secret bundle key %s", key)
|
||||
}
|
||||
seen[key] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -207,50 +207,6 @@ func TestEnsureFilesRequiresExplicitNonInteractiveAnswers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompleteSetupCreatesProtectedPlaceholdersThenRequiresUsableCredentials(t *testing.T) {
|
||||
root := newProject(t, "complete setup")
|
||||
for name, value := range map[string]string{
|
||||
"THT_SETUP_WORKSPACE_REMOTE": "git@git.example.invalid:team/workspaces.git",
|
||||
"THT_SETUP_WORKSPACE_BRANCH": "main",
|
||||
"THT_SETUP_WORKSPACE_ACCESS": "ssh",
|
||||
} {
|
||||
t.Setenv(name, value)
|
||||
}
|
||||
request := Request{ProjectRoot: root, InstallationID: "local", Profile: "local", Complete: true, NonInteractive: true}
|
||||
if _, err := EnsureFiles(request, strings.NewReader(""), ioDiscard{}); err == nil || !strings.Contains(err.Error(), "usable Pi credentials") {
|
||||
t.Fatalf("first complete setup error = %v, want the placeholder guidance", err)
|
||||
}
|
||||
secretRoot := filepath.Join(root, "deploy", "local", "secrets")
|
||||
for path, contents := range map[string]string{
|
||||
filepath.Join(secretRoot, "pi-auth.json"): "{\"deepseek\":{\"apiKey\":\"configured\"}}\n",
|
||||
filepath.Join(secretRoot, "workspace-git-key"): "private-key\n",
|
||||
filepath.Join(secretRoot, "workspace-git-known-hosts"): "git.example.invalid ssh-ed25519 AAAA\n",
|
||||
} {
|
||||
if err := os.WriteFile(path, []byte(contents), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
result, err := EnsureFiles(request, strings.NewReader(""), ioDiscard{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
environment, err := os.ReadFile(result.EnvironmentPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, name := range []string{"THT_CATALOG_RUNTIME_PASSWORD_SOURCE", "THT_CATALOG_MIGRATOR_PASSWORD_SOURCE"} {
|
||||
if !strings.Contains(string(environment), name+"=") {
|
||||
t.Fatalf("complete environment misses %s: %s", name, environment)
|
||||
}
|
||||
}
|
||||
for _, name := range []string{"catalog-runtime-password", "catalog-migrator-password"} {
|
||||
contents, readErr := os.ReadFile(filepath.Join(secretRoot, name))
|
||||
if readErr != nil || len(strings.TrimSpace(string(contents))) < 32 {
|
||||
t.Fatalf("generated catalog password %s is unavailable or too short", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnsureFilesIncludesServerStorageLocations(t *testing.T) {
|
||||
requireProjectedServerTestHost(t)
|
||||
root := newProject(t, "server profile")
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
// Package setup creates the local, non-secret configuration selected by tht setup.
|
||||
package setup
|
||||
|
||||
// Request contains the stable setup-file inputs.
|
||||
// Request contains the stable setup-file inputs. Task 5 will use ConfigureOnly when it adds
|
||||
// Compose validation and lifecycle orchestration.
|
||||
type Request struct {
|
||||
ProjectRoot string
|
||||
InstallationID string
|
||||
Profile string
|
||||
// Complete runs the installation-only steps that are safe to automate: catalog migration,
|
||||
// stack startup, and the initial workspace pull. It intentionally does not invent database
|
||||
// bindings or credentials that belong to the installation operator.
|
||||
Complete bool
|
||||
ConfigureOnly bool
|
||||
NonInteractive bool
|
||||
Answers Answers
|
||||
|
||||
@@ -3,7 +3,6 @@ package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -36,8 +35,7 @@ type Result struct {
|
||||
}
|
||||
|
||||
// Run validates the host, creates or validates non-secret configuration, and by default builds,
|
||||
// starts, and verifies the current checkout. Complete additionally migrates the Catalog and
|
||||
// imports the configured workspace repository. ConfigureOnly stops after Compose rendering.
|
||||
// starts, and verifies the current checkout. ConfigureOnly stops after Compose rendering.
|
||||
func Run(ctx context.Context, runner compose.Runner, request Request, input io.Reader, output io.Writer) (Result, error) {
|
||||
if runner == nil {
|
||||
return Result{}, errors.New("setup requires a Docker command runner")
|
||||
@@ -73,33 +71,13 @@ func Run(ctx context.Context, runner compose.Runner, request Request, input io.R
|
||||
fmt.Fprintf(output, "Configuration is ready: %s\n", result.DescriptorPath)
|
||||
return result, nil
|
||||
}
|
||||
if request.Complete {
|
||||
if err := runCompose(ctx, runner, installation, "build"); err != nil {
|
||||
return Result{}, fmt.Errorf("setup image build: %w", err)
|
||||
}
|
||||
if err := runCompose(ctx, runner, installation, "up", "--detach", "catalog-db"); err != nil {
|
||||
return Result{}, fmt.Errorf("setup Catalog database start: %w", err)
|
||||
}
|
||||
if err := runCompose(ctx, runner, installation,
|
||||
"--profile", "catalog-maintenance", "run", "--rm", "catalog-migrate"); err != nil {
|
||||
return Result{}, fmt.Errorf("setup Catalog migration: %w", err)
|
||||
}
|
||||
}
|
||||
if err := service.Start(ctx, installation, runner, !request.Complete); err != nil {
|
||||
if err := service.Start(ctx, installation, runner, true); err != nil {
|
||||
if strings.Contains(err.Error(), "image build") {
|
||||
return Result{}, fmt.Errorf("setup %w", err)
|
||||
}
|
||||
return Result{}, withStartupRecovery(fmt.Errorf("setup %w", err), recoveryService(err))
|
||||
}
|
||||
result.Built, result.Started, result.Healthy = true, true, true
|
||||
if request.Complete {
|
||||
if err := runOperator(ctx, runner, installation, "workspace-pull"); err != nil {
|
||||
return Result{}, withStartupRecovery(fmt.Errorf("setup workspace import: %w", err), "core")
|
||||
}
|
||||
if err := runOperator(ctx, runner, installation, "pi-test"); err != nil {
|
||||
return Result{}, withStartupRecovery(fmt.Errorf("setup LLM credential test: %w", err), "core")
|
||||
}
|
||||
}
|
||||
report, err := doctor.Run(ctx, installation, runner)
|
||||
if err != nil {
|
||||
return Result{}, withStartupRecovery(fmt.Errorf("setup doctor: %w", err), "core")
|
||||
@@ -107,9 +85,6 @@ func Run(ctx context.Context, runner compose.Runner, request Request, input io.R
|
||||
if !report.OK {
|
||||
return Result{}, withStartupRecovery(errors.New("setup doctor reported failed checks"), "core")
|
||||
}
|
||||
if request.Complete {
|
||||
fmt.Fprintln(output, "Workspace repository pulled and activated; run 'tht workspace test' after configuring each workspace database.")
|
||||
}
|
||||
fmt.Fprintf(output, "ThothII is ready at %s\nInstallation descriptor: %s\nNext: tht status\n", frontendURL(installation), result.DescriptorPath)
|
||||
return result, nil
|
||||
}
|
||||
@@ -244,25 +219,6 @@ func runCompose(ctx context.Context, runner compose.Runner, installation config.
|
||||
return nil
|
||||
}
|
||||
|
||||
func runOperator(ctx context.Context, runner compose.Runner, installation config.Installation, action string) error {
|
||||
result, err := runner.Run(ctx, installation.ComposeArgs(
|
||||
"exec", "-T", "core", "node", "dist/operator-command.js", action,
|
||||
), nil)
|
||||
if err != nil {
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Docker exited with status %d", result.ExitCode)
|
||||
}
|
||||
return err
|
||||
}
|
||||
var payload struct {
|
||||
Ready *bool `json:"ready"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(result.Stdout), &payload); err != nil || payload.Ready == nil || !*payload.Ready {
|
||||
return fmt.Errorf("operator action %s reported failure", action)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func composeFailure(result compose.Result, cause error) error {
|
||||
if result.ExitCode != 0 {
|
||||
return fmt.Errorf("Docker exited with status %d", result.ExitCode)
|
||||
|
||||
@@ -68,34 +68,6 @@ func TestRunConfigureOnlyStopsAfterRenderedConfiguration(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunCompleteMigratesCatalogPullsWorkspaceAndTestsLLM(t *testing.T) {
|
||||
root, request := setupRunFixture(t, false)
|
||||
request.Complete = true
|
||||
secretRoot := filepath.Join(root, "deploy", "ci", "secrets")
|
||||
for path, contents := range map[string]string{
|
||||
filepath.Join(secretRoot, "pi-auth.json"): "{\"deepseek\":{\"apiKey\":\"configured\"}}\n",
|
||||
filepath.Join(secretRoot, "workspace-git-key"): "private-key\n",
|
||||
filepath.Join(secretRoot, "workspace-git-known-hosts"): "git.example.invalid ssh-ed25519 AAAA\n",
|
||||
} {
|
||||
if err := os.WriteFile(path, []byte(contents), 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
runner := &setupRunner{health: []string{healthyServicesJSON}}
|
||||
if _, err := Run(context.Background(), runner, request, strings.NewReader(""), io.Discard); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := []string{
|
||||
"docker engine", "docker compose", "architecture", "compose config", "compose build",
|
||||
"catalog db", "catalog migrate", "compose up", "health", "workspace pull", "pi doctor",
|
||||
"doctor docker", "doctor compose", "compose config", "doctor config", "health",
|
||||
"authentication", "core HTTP", "frontend HTTP", "workspace registry", "workflow doctor", "pi doctor",
|
||||
}
|
||||
if got := collapseStages(runner.stages); strings.Join(got, " | ") != strings.Join(want, " | ") {
|
||||
t.Fatalf("complete setup stages = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunConfiguresAndStaticallyValidatesLocalAuthBeforeComposeRender(t *testing.T) {
|
||||
projectRoot, request := setupRunFixture(t, true)
|
||||
passwordFile := filepath.Join(projectRoot, "initial-admin-password")
|
||||
@@ -449,10 +421,6 @@ func setupStage(args []string) (string, compose.Result) {
|
||||
return "architecture", compose.Result{Stdout: "arm64\n"}
|
||||
case strings.HasSuffix(joined, " config --quiet"):
|
||||
return "compose config", compose.Result{}
|
||||
case strings.HasSuffix(joined, " up --detach catalog-db"):
|
||||
return "catalog db", compose.Result{}
|
||||
case strings.HasSuffix(joined, " --profile catalog-maintenance run --rm catalog-migrate"):
|
||||
return "catalog migrate", compose.Result{}
|
||||
case strings.HasSuffix(joined, " build"):
|
||||
return "compose build", compose.Result{}
|
||||
case strings.HasSuffix(joined, " up --detach --remove-orphans"):
|
||||
@@ -465,8 +433,6 @@ func setupStage(args []string) (string, compose.Result) {
|
||||
return "authentication", compose.Result{Stdout: `{"ready":true,"mode":"oidc","checks":[{"level":"info","code":"auth_ready","message":"Authentication is ready."}]}`}
|
||||
case strings.Contains(joined, "exec -T core node dist/operator-command.js workflow-doctor"):
|
||||
return "workflow doctor", compose.Result{Stdout: `{"ready":true,"workspaces":1}`}
|
||||
case strings.Contains(joined, "operator-command.js workspace-pull"):
|
||||
return "workspace pull", compose.Result{Stdout: `{"ready":true,"status":"succeeded"}`}
|
||||
case strings.Contains(joined, "exec -T core curl -fsS --max-time 5 http://127.0.0.1:8787/health"):
|
||||
return "core HTTP", compose.Result{}
|
||||
case strings.Contains(joined, "exec -T frontend wget -q -T 5 -O /dev/null http://127.0.0.1:8080/"):
|
||||
|
||||
Reference in New Issue
Block a user