feat: unify installation model catalog
This commit is contained in:
@@ -1,121 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# Fresh Compose flow: mounted Pi policy/auth must produce a selectable, credential-ready provider.
|
||||
# Base Compose is deliberately model-free; `tht start` appends the generated catalog projection.
|
||||
set -euo pipefail
|
||||
|
||||
root="$(cd "$(dirname "$0")/.." && pwd -P)"
|
||||
tmp_parent="${TMPDIR:-/tmp}"
|
||||
tmp="$(mktemp -d "${tmp_parent%/}/thoth-provider-readiness.XXXXXX")"
|
||||
project="thothii-provider-readiness-$$"
|
||||
compose=(
|
||||
docker compose --project-name "$project" --env-file "$tmp/local.env"
|
||||
-f "$root/compose.yaml" -f "$root/deploy/compose.local.yaml"
|
||||
)
|
||||
cleanup() {
|
||||
"${compose[@]}" down --volumes --remove-orphans >/dev/null 2>&1 || true
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
trap cleanup EXIT HUP INT TERM
|
||||
trap 'rm -rf "$tmp"' EXIT HUP INT TERM
|
||||
|
||||
printf '%s\n' '{"zai":{"type":"api_key","key":"fixture-native-auth-key"}}' >"$tmp/pi-auth.json"
|
||||
printf '%s\n' '{}' >"$tmp/pi-auth.json"
|
||||
printf '%s\n' 'THT_MODEL_API_KEY=fixture-model-api-key' >"$tmp/thothii.secrets"
|
||||
chmod 0600 "$tmp/pi-auth.json" "$tmp/thothii.secrets"
|
||||
auth_config="$tmp/auth"
|
||||
mkdir "$auth_config"
|
||||
chmod 0700 "$auth_config"
|
||||
printf '%s\n' \
|
||||
'version: 1' \
|
||||
'mode: local' \
|
||||
'publicUrl: http://127.0.0.1:8080' \
|
||||
'local:' \
|
||||
' usersFile: users.yaml' \
|
||||
>"$auth_config/auth.yaml"
|
||||
node - "$auth_config/users.yaml" <<'NODE'
|
||||
const { argon2 } = require("node:crypto");
|
||||
const { writeFileSync } = require("node:fs");
|
||||
printf '%s\n' 'schemaVersion: 2' >"$tmp/thothii-installation.yaml"
|
||||
printf '%s' 'fixture-catalog-runtime-password' >"$tmp/catalog-runtime-password"
|
||||
printf '%s' 'fixture-catalog-migrator-password' >"$tmp/catalog-migrator-password"
|
||||
mkdir "$tmp/auth"
|
||||
printf '%s\n' 'mode: local' >"$tmp/auth/auth.yaml"
|
||||
chmod 0600 "$tmp/pi-auth.json" "$tmp/thothii.secrets" "$tmp/thothii-installation.yaml" \
|
||||
"$tmp/catalog-runtime-password" "$tmp/catalog-migrator-password" "$tmp/auth/auth.yaml"
|
||||
chmod 0700 "$tmp/auth"
|
||||
|
||||
const message = Buffer.from("fixture-local-password", "utf8");
|
||||
const nonce = Buffer.from([...Array(16).keys()]);
|
||||
argon2("argon2id", {
|
||||
message,
|
||||
nonce,
|
||||
memory: 65_536,
|
||||
parallelism: 1,
|
||||
tagLength: 32,
|
||||
passes: 3,
|
||||
}, (error, digest) => {
|
||||
message.fill(0);
|
||||
nonce.fill(0);
|
||||
if (error || !digest) throw error ?? new Error("fixture password hash failed");
|
||||
const salt = Buffer.from([...Array(16).keys()]).toString("base64").replaceAll("=", "");
|
||||
const hash = digest.toString("base64").replaceAll("=", "");
|
||||
writeFileSync(process.argv[2], [
|
||||
"version: 1",
|
||||
"users:",
|
||||
" - id: 00000000-0000-4000-8000-000000000001",
|
||||
" username: fixture-user",
|
||||
" displayName: Fixture user",
|
||||
` passwordHash: $argon2id$v=19$m=65536,t=3,p=1$${salt}$${hash}`,
|
||||
" roles:",
|
||||
" - user",
|
||||
" enabled: true",
|
||||
" authRevision: 1",
|
||||
"",
|
||||
].join("\\n"), { mode: 0o600 });
|
||||
});
|
||||
NODE
|
||||
chmod 0600 "$auth_config/auth.yaml" "$auth_config/users.yaml"
|
||||
printf '%s\n' \
|
||||
'THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git' \
|
||||
"PI_AUTH_FILE=$tmp/pi-auth.json" \
|
||||
"THT_SECRETS_FILE=$tmp/thothii.secrets" \
|
||||
"THT_AUTH_CONFIG_ROOT=$auth_config" \
|
||||
'THOTH_CORE_HTTP_PORT=0' \
|
||||
'THOTH_HTTP_PORT=0' \
|
||||
>"$tmp/local.env"
|
||||
rendered="$tmp/rendered.json"
|
||||
THT_WORKSPACE_GIT_REMOTE=https://git.example.invalid/platform/thoth-workspaces.git \
|
||||
PI_AUTH_FILE="$tmp/pi-auth.json" \
|
||||
THT_SECRETS_FILE="$tmp/thothii.secrets" \
|
||||
THT_INSTALLATION_CONFIG_SOURCE="$tmp/thothii-installation.yaml" \
|
||||
THT_CATALOG_RUNTIME_PASSWORD_SOURCE="$tmp/catalog-runtime-password" \
|
||||
THT_CATALOG_MIGRATOR_PASSWORD_SOURCE="$tmp/catalog-migrator-password" \
|
||||
THT_AUTH_CONFIG_ROOT="$tmp/auth" \
|
||||
docker compose --project-directory "$root" \
|
||||
-f "$root/compose.yaml" -f "$root/deploy/compose.local.yaml" \
|
||||
config --format json >"$rendered"
|
||||
|
||||
"${compose[@]}" up --detach --wait --wait-timeout 90 --build core
|
||||
core_id="$("${compose[@]}" ps -q core)"
|
||||
core_address="$("${compose[@]}" port core 8787 | head -n 1)"
|
||||
|
||||
"${compose[@]}" exec -T core sh -ceu '
|
||||
test -r /home/thoth/.pi/agent/auth.json
|
||||
test -r /home/thoth/.pi/agent/models.json
|
||||
test -r /home/thoth/.pi/agent/settings.json
|
||||
test -r /run/secrets/thothii.secrets
|
||||
'
|
||||
|
||||
curl --fail --silent --show-error "http://$core_address/models" >"$tmp/models.json"
|
||||
node - "$tmp/models.json" <<'NODE'
|
||||
const fs = require("fs");
|
||||
const body = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||
if (!body.models?.some((model) => model.provider === "zai" && model.id === "glm-5.2")) {
|
||||
throw new Error("fresh Compose did not expose the mounted Pi-enabled model");
|
||||
node - "$rendered" <<'NODE'
|
||||
const { readFileSync } = require("node:fs");
|
||||
const config = JSON.parse(readFileSync(process.argv[2], "utf8"));
|
||||
const core = config.services?.core;
|
||||
if (!core) throw new Error("base Compose lacks core");
|
||||
for (const name of [
|
||||
"THT_MODEL_CATALOG_FILE",
|
||||
"THT_MODEL_CATALOG_REVISION",
|
||||
"THT_DEFAULT_SESSION_MODEL",
|
||||
"THT_INTERNAL_EMBEDDING_ID",
|
||||
"THT_INTERNAL_EMBEDDING_MODEL",
|
||||
"THT_INTERNAL_EMBEDDING_DIMENSIONS",
|
||||
]) {
|
||||
if (Object.hasOwn(core.environment || {}, name)) {
|
||||
throw new Error(`base Compose invented installation-owned model input ${name}`);
|
||||
}
|
||||
}
|
||||
for (const target of (core.volumes || []).map((mount) => mount.target)) {
|
||||
if (target === "/run/thothii-model-catalog/catalog.json"
|
||||
|| target === "/home/thoth/.pi/agent/models.json"
|
||||
|| target === "/home/thoth/.pi/agent/settings.json") {
|
||||
throw new Error(`base Compose mounted a generated model adapter: ${target}`);
|
||||
}
|
||||
}
|
||||
const installation = (core.configs || []).filter(
|
||||
(entry) => entry.target === "/run/thothii-installation/thothii-installation.yaml",
|
||||
);
|
||||
if (installation.length !== 1 || installation[0].source !== "thothii_installation_config") {
|
||||
throw new Error("base Compose lacks the protected installation descriptor mount");
|
||||
}
|
||||
NODE
|
||||
|
||||
curl --fail --silent --show-error -X PUT \
|
||||
-H 'content-type: application/json' \
|
||||
--data '{"provider":"zai","model":"glm-5.2","reasoning":"low"}' \
|
||||
"http://$core_address/pi-management/config" >"$tmp/configured.json"
|
||||
curl --fail --silent --show-error \
|
||||
"http://$core_address/pi-management/status" >"$tmp/status.json"
|
||||
node - "$tmp/status.json" <<'NODE'
|
||||
const fs = require("fs");
|
||||
const body = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||
if (!body.ready || body.credentials !== "present") {
|
||||
throw new Error("mounted Pi provider is not credential-ready");
|
||||
}
|
||||
if (body.config?.provider !== "zai" || body.config?.model !== "glm-5.2") {
|
||||
throw new Error("Pi provider configuration was not persisted");
|
||||
}
|
||||
NODE
|
||||
if grep -Fq 'fixture-model-api-key' "$rendered"; then
|
||||
echo "rendered base Compose leaked the model key" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ -e "$root/deploy/pi/models.json" || -e "$root/deploy/pi/settings.json" ]]; then
|
||||
echo "legacy authored Pi model sources still exist" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
inspect="$(docker inspect "$core_id")"
|
||||
for secret in fixture-native-auth-key fixture-model-api-key; do
|
||||
if grep -Fq "$secret" <<<"$inspect"; then
|
||||
echo "container inspection leaked $secret" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Compose provider-readiness contract passed."
|
||||
echo "Base Compose model fail-closed contract passed."
|
||||
|
||||
Reference in New Issue
Block a user