From e5219deab1b487db20e7b5ce63889eae0950cca4 Mon Sep 17 00:00:00 2001 From: mptyl Date: Tue, 4 Aug 2026 08:11:28 +0200 Subject: [PATCH] fix: harden workspace registry installation docs --- .../git-https.workspace-registry.yaml | 13 ++ .../examples/git-ssh.workspace-registry.yaml | 9 ++ .../local-compose.workspace-registry.yaml | 16 +-- .../server-compose.workspace-registry.yaml | 38 +++--- docs/install/local-workspace-registry.md | 28 +++-- docs/install/server-workspace-registry.md | 22 ++-- scripts/test-verify-workspace-install-docs.sh | 22 ++++ scripts/verify-workspace-install-docs.sh | 118 ++++++++++++++++++ 8 files changed, 222 insertions(+), 44 deletions(-) create mode 100644 docs/install/examples/git-https.workspace-registry.yaml create mode 100644 docs/install/examples/git-ssh.workspace-registry.yaml create mode 100755 scripts/test-verify-workspace-install-docs.sh diff --git a/docs/install/examples/git-https.workspace-registry.yaml b/docs/install/examples/git-https.workspace-registry.yaml new file mode 100644 index 00000000..562116df --- /dev/null +++ b/docs/install/examples/git-https.workspace-registry.yaml @@ -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 diff --git a/docs/install/examples/git-ssh.workspace-registry.yaml b/docs/install/examples/git-ssh.workspace-registry.yaml new file mode 100644 index 00000000..2c46be3f --- /dev/null +++ b/docs/install/examples/git-ssh.workspace-registry.yaml @@ -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 diff --git a/docs/install/examples/local-compose.workspace-registry.yaml b/docs/install/examples/local-compose.workspace-registry.yaml index a54c008f..db1e2107 100644 --- a/docs/install/examples/local-compose.workspace-registry.yaml +++ b/docs/install/examples/local-compose.workspace-registry.yaml @@ -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: diff --git a/docs/install/examples/server-compose.workspace-registry.yaml b/docs/install/examples/server-compose.workspace-registry.yaml index 8ff23178..0dff8069 100644 --- a/docs/install/examples/server-compose.workspace-registry.yaml +++ b/docs/install/examples/server-compose.workspace-registry.yaml @@ -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} diff --git a/docs/install/local-workspace-registry.md b/docs/install/local-workspace-registry.md index 31b2f04c..02ec06b4 100644 --- a/docs/install/local-workspace-registry.md +++ b/docs/install/local-workspace-registry.md @@ -33,12 +33,15 @@ workspaces/.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. ```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 diff --git a/docs/install/server-workspace-registry.md b/docs/install/server-workspace-registry.md index d89cb99d..f13717ae 100644 --- a/docs/install/server-workspace-registry.md +++ b/docs/install/server-workspace-registry.md @@ -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. ```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 ``` diff --git a/scripts/test-verify-workspace-install-docs.sh b/scripts/test-verify-workspace-install-docs.sh new file mode 100755 index 00000000..863e4bfd --- /dev/null +++ b/scripts/test-verify-workspace-install-docs.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Regression test for copyable installation examples and secret-file validation. +set -euo pipefail + +root="$(cd "$(dirname "$0")/.." && pwd -P)" +output="$(mktemp "${TMPDIR:-/tmp}/thoth-install-docs-test.XXXXXX")" +trap 'rm -f "$output"' EXIT HUP INT TERM + +"$root/scripts/verify-workspace-install-docs.sh" --fixtures-only >"$output" + +for fixture in \ + "copied local base fixture" \ + "copied server PostgreSQL/TLS fixture" \ + "copied HTTPS Git override fixture" \ + "copied SSH Git override fixture" \ + "non-path secret-file fixture rejected"; do + grep -Fqx "$fixture passed" "$output" >/dev/null || { + echo "missing fixture verification: $fixture" >&2 + cat "$output" >&2 + exit 1 + } +done diff --git a/scripts/verify-workspace-install-docs.sh b/scripts/verify-workspace-install-docs.sh index 49c87c9f..beee4bb2 100755 --- a/scripts/verify-workspace-install-docs.sh +++ b/scripts/verify-workspace-install-docs.sh @@ -5,7 +5,117 @@ set -euo pipefail root="$(cd "$(dirname "$0")/.." && pwd -P)" profile="${1:-}" +trim() { + local value="$1" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + printf '%s' "$value" +} + +verify_secret_file_values() { + local source="$1" line trimmed name value + while IFS= read -r line || [[ -n "$line" ]]; do + trimmed="$(trim "$line")" + if [[ "$trimmed" == *=* || "$trimmed" == *:* ]]; then + name="$(trim "${trimmed%%[=:]*}")" + value="$(trim "${trimmed#"$name"}")" + value="$(trim "${value#[:=]}")" + if [[ "$name" =~ ^[A-Za-z_][A-Za-z0-9_]*_FILE$ ]]; then + value="$(trim "${value%%#*}")" + value="${value#\"}"; value="${value%\"}" + value="${value#\'}"; value="${value%\'}" + if [[ -n "$value" && "$value" != /* ]]; then + echo "non-path secret-file value for $name in $source" >&2 + return 1 + fi + fi + fi + done <"$source" + return 0 +} + +verify_server_public_contract() { + local server_example="$root/docs/install/examples/server-compose.workspace-registry.yaml" + for expected in \ + 'THT_SESSION_STORAGE: postgres' \ + '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' \ + 'session_runtime_password:' \ + 'session_ca:'; do + grep -Fq "$expected" "$server_example" || { + echo "server Compose example lacks required public PostgreSQL/TLS contract: $expected" >&2 + return 1 + } + done +} + +compose_fixture() { + local name="$1" directory="$2"; shift 2 + ( + cd "$directory" + docker compose --env-file .env "$@" config --quiet + ) + echo "$name passed" +} + +verify_copied_operator_fixtures() { + local fixture_root local_dir server_dir https_dir ssh_dir + fixture_root="$(mktemp -d "${TMPDIR:-/tmp}/thoth-install-fixtures.XXXXXX")" + trap 'rm -rf "$fixture_root"' RETURN + local_dir="$fixture_root/local"; server_dir="$fixture_root/server" + https_dir="$fixture_root/https"; ssh_dir="$fixture_root/ssh" + mkdir -p "$local_dir" "$server_dir" "$https_dir" "$ssh_dir" + + cp "$root/docs/install/examples/local-compose.workspace-registry.yaml" "$local_dir/compose.workspace-registry.yaml" + printf 'THT_SOURCE_ROOT=%s\n' "$root" >"$local_dir/.env" + compose_fixture "copied local base fixture" "$local_dir" -f compose.workspace-registry.yaml + + cp "$root/docs/install/examples/server-compose.workspace-registry.yaml" "$server_dir/compose.workspace-registry.yaml" + cp "$root/deploy/workspaces/server-sessions.yaml.example" "$server_dir/server-sessions.yaml" + : >"$server_dir/session-runtime-password"; : >"$server_dir/session-ca.pem" + printf '%s\n' \ + "THT_SOURCE_ROOT=$root" \ + "THT_SERVER_WORKSPACE_CONFIG=$server_dir/server-sessions.yaml" \ + 'THT_SESSION_DB_HOST=sessions.example.invalid' \ + 'THT_SESSION_DB_NAME=thoth_sessions' \ + 'THT_SESSION_RUNTIME_USER=thoth_sessions_app' \ + "THT_SESSION_RUNTIME_PASSWORD_SOURCE=$server_dir/session-runtime-password" \ + "THT_SESSION_CA_SOURCE=$server_dir/session-ca.pem" >"$server_dir/.env" + compose_fixture "copied server PostgreSQL/TLS fixture" "$server_dir" -f compose.workspace-registry.yaml + + cp "$root/docs/install/examples/local-compose.workspace-registry.yaml" "$https_dir/compose.workspace-registry.yaml" + cp "$root/docs/install/examples/git-https.workspace-registry.yaml" "$https_dir/git-https.yaml" + : >"$https_dir/git-credentials"; : >"$https_dir/git-ca.pem" + printf '%s\n' \ + "THT_SOURCE_ROOT=$root" \ + "THT_WORKSPACE_GIT_CREDENTIALS_FILE=$https_dir/git-credentials" \ + "THT_WORKSPACE_GIT_CA_FILE=$https_dir/git-ca.pem" >"$https_dir/.env" + compose_fixture "copied HTTPS Git override fixture" "$https_dir" -f compose.workspace-registry.yaml -f git-https.yaml + + cp "$root/docs/install/examples/local-compose.workspace-registry.yaml" "$ssh_dir/compose.workspace-registry.yaml" + cp "$root/docs/install/examples/git-ssh.workspace-registry.yaml" "$ssh_dir/git-ssh.yaml" + : >"$ssh_dir/git-ssh-key"; : >"$ssh_dir/git-known-hosts" + printf '%s\n' \ + "THT_SOURCE_ROOT=$root" \ + "THT_WORKSPACE_GIT_SSH_KEY_FILE=$ssh_dir/git-ssh-key" \ + "THT_WORKSPACE_GIT_KNOWN_HOSTS_FILE=$ssh_dir/git-known-hosts" >"$ssh_dir/.env" + compose_fixture "copied SSH Git override fixture" "$ssh_dir" -f compose.workspace-registry.yaml -f git-ssh.yaml + + printf 'THT_WS_EXAMPLE_DWH_PASSWORD_FILE=not-a-path\n' >"$fixture_root/non-path-secret.env" + if verify_secret_file_values "$fixture_root/non-path-secret.env" >/dev/null 2>&1; then + echo "non-path secret-file fixture was accepted" >&2 + return 1 + fi + echo "non-path secret-file fixture rejected passed" +} + case "$profile" in + --fixtures-only) + [[ $# -eq 1 ]] || { echo "usage: $0 --fixtures-only" >&2; exit 2; } + verify_copied_operator_fixtures + exit 0 + ;; --profile) profile="${2:-}" [[ $# -eq 2 ]] || { echo "usage: $0 --profile {local|server}" >&2; exit 2; } @@ -72,6 +182,11 @@ if grep -Ein '(^|[[:space:]])(password|api[_-]?key|token|secret)[[:space:]]*[:=] echo "installation documentation contains a secret literal" >&2 exit 1 fi +verify_secret_file_values "$manual" +verify_secret_file_values "$example" +verify_secret_file_values "$root/docs/install/examples/git-https.workspace-registry.yaml" +verify_secret_file_values "$root/docs/install/examples/git-ssh.workspace-registry.yaml" +verify_server_public_contract commands="$(mktemp "${TMPDIR:-/tmp}/thoth-install-docs.XXXXXX")" trap 'rm -f "$commands"' EXIT HUP INT TERM @@ -99,4 +214,7 @@ echo "== Run isolated workspace-registry bootstrap and recovery smoke ==" env -u WORKSPACE_GIT_REMOTE ./scripts/workspace-registry-smoke.sh ) +echo "== Validate copied operator fixtures and optional Git transports ==" +verify_copied_operator_fixtures + echo "$profile installation documentation verification passed"