fix: harden workspace registry installation docs

This commit is contained in:
2026-08-04 08:11:28 +02:00
parent 72e16dd5ea
commit e5219deab1
8 changed files with 222 additions and 44 deletions
@@ -0,0 +1,13 @@
# Optional override for an HTTPS Git remote. Both source paths are required absolute paths to
# existing operator-managed files; neither file content belongs in the base Compose example.
services:
core:
environment:
GIT_CONFIG_COUNT: "2"
GIT_CONFIG_KEY_0: credential.helper
GIT_CONFIG_VALUE_0: store --file=/run/secrets/workspace-registry-git-credentials
GIT_CONFIG_KEY_1: http.sslCAInfo
GIT_CONFIG_VALUE_1: /run/secrets/workspace-registry-git-ca
volumes:
- ${THT_WORKSPACE_GIT_CREDENTIALS_FILE:?set THT_WORKSPACE_GIT_CREDENTIALS_FILE}:/run/secrets/workspace-registry-git-credentials:ro
- ${THT_WORKSPACE_GIT_CA_FILE:?set THT_WORKSPACE_GIT_CA_FILE}:/run/secrets/workspace-registry-git-ca:ro
@@ -0,0 +1,9 @@
# Optional override for an SSH Git remote. Source paths are required absolute operator-managed
# files. Host-key checking remains strict; do not add a fallback known-hosts or key mount.
services:
core:
environment:
GIT_SSH_COMMAND: ssh -i /run/secrets/workspace-registry-git-ssh-key -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/run/secrets/workspace-registry-git-known-hosts
volumes:
- ${THT_WORKSPACE_GIT_SSH_KEY_FILE:?set THT_WORKSPACE_GIT_SSH_KEY_FILE}:/run/secrets/workspace-registry-git-ssh-key:ro
- ${THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE:?set THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE}:/run/secrets/workspace-registry-git-known-hosts:ro
@@ -1,12 +1,12 @@
# Standalone local registry example. Copy beside the clone as compose.workspace-registry.yaml
# and put path-only bindings in .env; keep the referenced files outside Git.
# Standalone local registry example. Copy to an untracked operator directory and set the absolute
# THT_SOURCE_ROOT in .env. Add only the selected Git transport override from this directory.
name: thothii-workspace-registry-local
services:
core:
image: thothii-core:local
build:
context: ../../..
context: ${THT_SOURCE_ROOT:?set THT_SOURCE_ROOT to the absolute ThothII source checkout}
dockerfile: docker/core.Dockerfile
environment:
HOST: 0.0.0.0
@@ -24,21 +24,11 @@ services:
THT_WORKSPACE_GIT_AUTHOR_NAME: ${THT_WORKSPACE_GIT_AUTHOR_NAME:-Thoth Workspace Registry}
THT_WORKSPACE_GIT_AUTHOR_EMAIL: ${THT_WORKSPACE_GIT_AUTHOR_EMAIL:-thoth-workspace-registry@localhost}
THT_WORKSPACE_SECRET_ROOTS: /run/secrets
GIT_CONFIG_COUNT: "2"
GIT_CONFIG_KEY_0: credential.helper
GIT_CONFIG_VALUE_0: store --file=/run/secrets/workspace-registry-git-credentials
GIT_CONFIG_KEY_1: http.sslCAInfo
GIT_CONFIG_VALUE_1: /run/secrets/workspace-registry-git-ca
GIT_SSH_COMMAND: ssh -i /run/secrets/workspace-registry-git-ssh-key -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/run/secrets/workspace-registry-git-known-hosts
ports:
- "127.0.0.1:8787:8787"
volumes:
- thoth-local-data:/data
- workspace-registry:/data/workspace-registry
- ${THT_WORKSPACE_GIT_CREDENTIALS_FILE:-./installation-secrets/git-credentials}:/run/secrets/workspace-registry-git-credentials:ro
- ${THT_WORKSPACE_GIT_CA_FILE:-./installation-secrets/git-ca.pem}:/run/secrets/workspace-registry-git-ca:ro
- ${THT_WORKSPACE_GIT_SSH_KEY_FILE:-./installation-secrets/git-ssh-key}:/run/secrets/workspace-registry-git-ssh-key:ro
- ${THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE:-./installation-secrets/git-known-hosts}:/run/secrets/workspace-registry-git-known-hosts:ro
restart: "no"
volumes:
@@ -1,19 +1,27 @@
# Server registry example. Copy to a reviewed, untracked operator directory and set host paths
# and Git values in its .env. The core remains non-root (UID 10001) and never receives secrets
# through the Git checkout.
# Server registry example. Copy to a reviewed, untracked operator directory and set absolute host
# paths and Git values in .env. Add a selected Git transport override from this directory.
name: thothii-workspace-registry-server
services:
core:
image: thothii-core:local
build:
context: ../../..
context: ${THT_SOURCE_ROOT:?set THT_SOURCE_ROOT to the absolute ThothII source checkout}
dockerfile: docker/core.Dockerfile
environment:
HOST: 0.0.0.0
PORT: "8787"
AUTH_MODE: upstream
THOTH_PUBLIC_EXPOSURE: "true"
THT_SESSION_STORAGE: postgres
THT_CONFIG: /app/harness/workspaces/server-sessions.yaml
THT_SESSION_DB_HOST: ${THT_SESSION_DB_HOST:?set THT_SESSION_DB_HOST}
THT_SESSION_DB_PORT: ${THT_SESSION_DB_PORT:-5432}
THT_SESSION_DB_NAME: ${THT_SESSION_DB_NAME:?set THT_SESSION_DB_NAME}
THT_SESSION_RUNTIME_USER: ${THT_SESSION_RUNTIME_USER:?set THT_SESSION_RUNTIME_USER}
THT_SESSION_RUNTIME_PASSWORD_FILE: /run/secrets/session_runtime_password
THT_SESSION_DB_SSLMODE: ${THT_SESSION_DB_SSLMODE:-verify-full}
THT_SESSION_DB_SSLROOTCERT: /run/secrets/session_ca.pem
THT_HARNESS_DIR: /app/harness
THT_BIN: /opt/venv/bin/tht
SETTINGS_FILE: /data/settings/settings.json
@@ -24,19 +32,15 @@ services:
THT_WORKSPACE_GIT_AUTHOR_NAME: ${THT_WORKSPACE_GIT_AUTHOR_NAME:-Thoth Workspace Registry}
THT_WORKSPACE_GIT_AUTHOR_EMAIL: ${THT_WORKSPACE_GIT_AUTHOR_EMAIL:-thoth-workspace-registry@localhost}
THT_WORKSPACE_SECRET_ROOTS: /run/secrets
GIT_CONFIG_COUNT: "2"
GIT_CONFIG_KEY_0: credential.helper
GIT_CONFIG_VALUE_0: store --file=/run/secrets/workspace-registry-git-credentials
GIT_CONFIG_KEY_1: http.sslCAInfo
GIT_CONFIG_VALUE_1: /run/secrets/workspace-registry-git-ca
GIT_SSH_COMMAND: ssh -i /run/secrets/workspace-registry-git-ssh-key -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -o UserKnownHostsFile=/run/secrets/workspace-registry-git-known-hosts
volumes:
- ${THT_HOST_DATA_ROOT:-/srv/thothii/data}:/data
- ${THT_WORKSPACE_REGISTRY_HOST_PATH:-/srv/thothii/workspace-registry}:/data/workspace-registry
- ${THT_WORKSPACE_GIT_CREDENTIALS_FILE:-/srv/thothii/secrets/git-credentials}:/run/secrets/workspace-registry-git-credentials:ro
- ${THT_WORKSPACE_GIT_CA_FILE:-/srv/thothii/secrets/git-ca.pem}:/run/secrets/workspace-registry-git-ca:ro
- ${THT_WORKSPACE_GIT_SSH_KEY_FILE:-/srv/thothii/secrets/git-ssh-key}:/run/secrets/workspace-registry-git-ssh-key:ro
- ${THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE:-/srv/thothii/secrets/git-known-hosts}:/run/secrets/workspace-registry-git-known-hosts:ro
- ${THT_SERVER_WORKSPACE_CONFIG:?set THT_SERVER_WORKSPACE_CONFIG}:/app/harness/workspaces/server-sessions.yaml:ro
secrets:
- source: session_runtime_password
target: session_runtime_password
- source: session_ca
target: session_ca.pem
networks:
- portal
restart: unless-stopped
@@ -45,3 +49,9 @@ networks:
portal:
external: true
name: ${THT_PORTAL_NETWORK:-omics_portal_omics_network}
secrets:
session_runtime_password:
file: ${THT_SESSION_RUNTIME_PASSWORD_SOURCE:?set THT_SESSION_RUNTIME_PASSWORD_SOURCE}
session_ca:
file: ${THT_SESSION_CA_SOURCE:?set THT_SESSION_CA_SOURCE}
+18 -10
View File
@@ -33,12 +33,15 @@ workspaces/<workspace-id>.md
For SSH, use a scoped deploy key, a verified `known_hosts` file, and strict host-key checking. For
HTTPS, use Git Credential Manager or a secret-manager-created credentials file. Mount a private
HTTPS CA as its own file. Do not disable host or certificate verification.
HTTPS CA as its own file. Do not disable host or certificate verification. The base Compose file
does not mount a Git credential: add exactly one optional `git-ssh.workspace-registry.yaml` or
`git-https.workspace-registry.yaml` override, so unused credential paths are never bind-mounted.
```dotenv
THT_WORKSPACE_GIT_REMOTE=ssh://git@git.example.invalid/platform/thoth-workspaces.git
THT_WORKSPACE_GIT_BRANCH=main
THT_WORKSPACE_INSTALLATION_ID=local-laptop
THT_SOURCE_ROOT=/absolute/path/to/ThothII
THT_WORKSPACE_GIT_SSH_KEY_FILE=/absolute/path/installation-secrets/git-ssh-key
THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE=/absolute/path/installation-secrets/git-known-hosts
THT_WORKSPACE_GIT_CA_FILE=/absolute/path/installation-secrets/git-ca.pem
@@ -120,18 +123,21 @@ rather than weakening TLS; use runtime-trusted HTTPS or verified direct/SSH nati
## Bootstrap, first pull, and diagnostics
Copy [the local Compose example](examples/local-compose.workspace-registry.yaml) into an untracked
operator directory, create its local `.env` and mounted secret files, then render it before start.
Copy [the local Compose example](examples/local-compose.workspace-registry.yaml) and exactly one
selected [SSH Git override](examples/git-ssh.workspace-registry.yaml) or [HTTPS Git override](examples/git-https.workspace-registry.yaml)
into an untracked operator directory. Set `THT_SOURCE_ROOT` in its `.env` to the absolute source
checkout path; this keeps the copied Compose file buildable. Create only the secret files used by
the selected override, then render it before start.
<!-- verify:command -->
```sh
docker compose -f docs/install/examples/local-compose.workspace-registry.yaml config --quiet
THT_SOURCE_ROOT="$(pwd -P)" docker compose -f docs/install/examples/local-compose.workspace-registry.yaml config --quiet
```
From the operator directory:
```sh
docker compose -f compose.workspace-registry.yaml up --build -d
docker compose -f compose.workspace-registry.yaml -f git-ssh.workspace-registry.yaml up --build -d
curl --fail --silent http://127.0.0.1:8787/health
curl --fail --silent http://127.0.0.1:8787/workspace-registry/status
curl --fail --silent http://127.0.0.1:8787/workspaces
@@ -142,13 +148,15 @@ Use `POST /workspace-registry/pull` to fetch later revisions. Run workspace diag
required bindings are mounted. The optional writer probe uses a distinct writer file and removes
its uniquely named temporary record; ordinary diagnostics are read-only.
To migrate an existing PSD descriptor, create/clone an empty private remote, transform with
absolute paths, review the schema-v1 result, explicitly add vector database/schema and the complete
schema-v2 contract, then commit/push. The transformer never imports `${ENV}` values or secrets.
To migrate an existing PSD descriptor, create/clone an empty private remote, set the absolute
`THT_SOURCE_ROOT`, transform with absolute paths, review the schema-v1 result, explicitly add
vector database/schema and the complete schema-v2 contract, then commit/push. The transformer
never imports `${ENV}` values or secrets.
```sh
npm --prefix backend run build
node backend/dist/workspaces/migrate-legacy.js --input /absolute/path/psd.yaml --output /absolute/path/thoth-workspaces
THT_SOURCE_ROOT=/absolute/path/to/ThothII
npm --prefix "$THT_SOURCE_ROOT/backend" run build
node "$THT_SOURCE_ROOT/backend/dist/workspaces/migrate-legacy.js" --input /absolute/path/psd.yaml --output /absolute/path/thoth-workspaces
```
## Publish, update, backup, outage recovery, and rollback
+15 -7
View File
@@ -50,8 +50,10 @@ THT_WORKSPACE_GIT_SSH_KEY_FILE=/srv/thothii/secrets/git-ssh-key
THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE=/srv/thothii/secrets/git-known-hosts
```
Use the credential file for HTTPS, or key and known-hosts for SSH. Strict host-key checking stays
enabled and Git stderr is not exposed by the API. Rotate by atomically replacing the secret file,
Use the credential file for HTTPS, or key and known-hosts for SSH. The base server Compose file
mounts neither transport; add exactly one [HTTPS override](examples/git-https.workspace-registry.yaml)
or [SSH override](examples/git-ssh.workspace-registry.yaml). Strict host-key checking stays enabled
and Git stderr is not exposed by the API. Rotate by atomically replacing the secret file,
restarting `core`, and performing pull/status; never put the material in an environment variable or
`docker compose config` output.
@@ -126,13 +128,19 @@ reversible writer probe.
## Same-origin reverse proxy, bootstrap, and health
Copy [the server Compose example](examples/server-compose.workspace-registry.yaml) to the protected
operator directory, set host paths/remote/branch/installation ID/portal network in local `.env`,
then render it before deployment.
Copy [the server Compose example](examples/server-compose.workspace-registry.yaml) plus exactly one
selected Git override to the protected operator directory. Set `THT_SOURCE_ROOT` to the absolute
ThothII checkout; a copied file cannot use a relative build context. Copy
`deploy/workspaces/server-sessions.yaml.example` into that operator directory, review it, then set
the absolute `THT_SERVER_WORKSPACE_CONFIG` path. The same `.env` must set
`THT_SESSION_DB_HOST`, `THT_SESSION_DB_NAME`, `THT_SESSION_RUNTIME_USER`,
`THT_SESSION_RUNTIME_PASSWORD_SOURCE`, and `THT_SESSION_CA_SOURCE`; the base Compose file wires
`postgres`, `verify-full`, and the two Docker secret mount paths. This is the public server profile,
not a filesystem-session fallback.
<!-- verify:command -->
```sh
docker compose -f docs/install/examples/server-compose.workspace-registry.yaml config --quiet
./scripts/verify-workspace-install-docs.sh --fixtures-only
```
Configure the portal proxy so the frontend and `/api` share one origin. It authenticates first and
@@ -140,7 +148,7 @@ forwards the trusted identity expected by `AUTH_MODE=upstream`; it is the only p
From a trusted maintenance shell:
```sh
docker compose -f compose.workspace-registry.yaml up --build -d
docker compose -f compose.workspace-registry.yaml -f git-ssh.workspace-registry.yaml up --build -d
docker compose -f compose.workspace-registry.yaml exec -T core curl --fail --silent http://127.0.0.1:8787/health
docker compose -f compose.workspace-registry.yaml exec -T core curl --fail --silent http://127.0.0.1:8787/workspace-registry/status
```