fix(ci): restore deployment release gates

This commit is contained in:
2026-08-25 16:45:56 +02:00
parent 8ba87b68dc
commit 3e106d5262
11 changed files with 30 additions and 14 deletions
+11
View File
@@ -36,6 +36,10 @@ jobs:
with: with:
node-version: "24.16.0" node-version: "24.16.0"
package-manager-cache: false package-manager-cache: false
- name: Install release gate prerequisites
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends ripgrep
- name: Verify shell syntax and LF policy - name: Verify shell syntax and LF policy
run: | run: |
git ls-files -z '*.sh' | xargs -0 -n1 bash -n git ls-files -z '*.sh' | xargs -0 -n1 bash -n
@@ -60,6 +64,9 @@ jobs:
run: | run: |
bash scripts/test-server-pi-state-topology.sh bash scripts/test-server-pi-state-topology.sh
bash scripts/unified-deployment-smoke.sh --self-test bash scripts/unified-deployment-smoke.sh --self-test
- name: Install backend dependencies
working-directory: backend
run: npm ci
- name: Test and type-check backend - name: Test and type-check backend
working-directory: backend working-directory: backend
run: | run: |
@@ -140,6 +147,10 @@ jobs:
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with: with:
persist-credentials: false persist-credentials: false
- name: Install release gate prerequisites
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends ripgrep
- name: Run unified deployment smoke - name: Run unified deployment smoke
run: timeout --signal=TERM --kill-after=45s 32m bash scripts/unified-deployment-smoke.sh run: timeout --signal=TERM --kill-after=45s 32m bash scripts/unified-deployment-smoke.sh
- name: Run tht update smoke - name: Run tht update smoke
+1 -1
View File
@@ -247,7 +247,7 @@
- **Engine:** `evidencePolicy` no longer stops filesystem sources (`evidence_materialization_required` - **Engine:** `evidencePolicy` no longer stops filesystem sources (`evidence_materialization_required`
retired); `preprocess evidence`/`preprocess run` operate on the materialized root. Evidence Qdrant retired); `preprocess evidence`/`preprocess run` operate on the materialized root. Evidence Qdrant
records remain revision-scoped; corpus ACTIVE is revision-qualified. HTTP/S3 Evidence is unchanged. records remain revision-scoped; corpus ACTIVE is revision-qualified. HTTP/S3 Evidence is unchanged.
- **Curated-only runtime contract (Evidence schema v2):** the new authoring layout preserves the - **Curated-only runtime contract (Evidence contract version 2):** the new authoring layout preserves the
complete commit-addressed `evidence/` tree (`source/`, `curated/`, manifest and evaluation files), complete commit-addressed `evidence/` tree (`source/`, `curated/`, manifest and evaluation files),
while the rendered filesystem acquisition pattern is exactly `curated/**/*.md`. Version 2 rejects while the rendered filesystem acquisition pattern is exactly `curated/**/*.md`. Version 2 rejects
every other pattern, including source, mixed source/curated, broad curated, and non-Markdown every other pattern, including source, mixed source/curated, broad curated, and non-Markdown
+1 -1
View File
@@ -21,7 +21,7 @@ test ! -e /var/run/docker.sock
touch /data/.core-smoke-writable touch /data/.core-smoke-writable
rm /data/.core-smoke-writable rm /data/.core-smoke-writable
/app/docker/core-entrypoint.sh server & AUTH_MODE=upstream /app/docker/core-entrypoint.sh server &
server_pid=$! server_pid=$!
trap 'kill "$server_pid" 2>/dev/null || true; wait "$server_pid" 2>/dev/null || true' EXIT INT TERM trap 'kill "$server_pid" 2>/dev/null || true; wait "$server_pid" 2>/dev/null || true' EXIT INT TERM
+2 -1
View File
@@ -3,7 +3,8 @@
set -euo pipefail set -euo pipefail
root="$(cd "$(dirname "$0")/.." && pwd -P)" root="$(cd "$(dirname "$0")/.." && pwd -P)"
tmp="$(mktemp -d "${TMPDIR%/}/thoth-canonical-install.XXXXXX")" tmp_parent="${TMPDIR:-/tmp}"
tmp="$(mktemp -d "${tmp_parent%/}/thoth-canonical-install.XXXXXX")"
trap 'rm -rf "$tmp"' EXIT HUP INT TERM trap 'rm -rf "$tmp"' EXIT HUP INT TERM
for retired_example in \ for retired_example in \
+2 -1
View File
@@ -3,7 +3,8 @@
set -euo pipefail set -euo pipefail
root="$(cd "$(dirname "$0")/.." && pwd -P)" root="$(cd "$(dirname "$0")/.." && pwd -P)"
tmp="$(mktemp -d "${TMPDIR%/}/thoth-provider-readiness.XXXXXX")" tmp_parent="${TMPDIR:-/tmp}"
tmp="$(mktemp -d "${tmp_parent%/}/thoth-provider-readiness.XXXXXX")"
project="thothii-provider-readiness-$$" project="thothii-provider-readiness-$$"
compose=( compose=(
docker compose --project-name "$project" --env-file "$tmp/local.env" docker compose --project-name "$project" --env-file "$tmp/local.env"
+2 -1
View File
@@ -3,7 +3,8 @@
set -euo pipefail set -euo pipefail
root="$(cd "$(dirname "$0")/.." && pwd -P)" root="$(cd "$(dirname "$0")/.." && pwd -P)"
fixture_root="$(mktemp -d "${TMPDIR%/}/thoth-compose-secret-policy.XXXXXX")" tmp_parent="${TMPDIR:-/tmp}"
fixture_root="$(mktemp -d "${tmp_parent%/}/thoth-compose-secret-policy.XXXXXX")"
trap 'rm -rf "$fixture_root"' EXIT HUP INT TERM trap 'rm -rf "$fixture_root"' EXIT HUP INT TERM
write_secret() { write_secret() {
+2 -1
View File
@@ -3,7 +3,8 @@
set -euo pipefail set -euo pipefail
root="$(cd "$(dirname "$0")/.." && pwd -P)" root="$(cd "$(dirname "$0")/.." && pwd -P)"
tmp="$(mktemp -d "${TMPDIR%/}/thoth-external-llm.XXXXXX")" tmp_parent="${TMPDIR:-/tmp}"
tmp="$(mktemp -d "${tmp_parent%/}/thoth-external-llm.XXXXXX")"
trap 'rm -rf "$tmp"' EXIT HUP INT TERM trap 'rm -rf "$tmp"' EXIT HUP INT TERM
printf '%s\n' '{}' >"$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" printf '%s\n' 'THT_MODEL_API_KEY=fixture-model-api-key' >"$tmp/thothii.secrets"
+3 -2
View File
@@ -3,7 +3,8 @@
set -euo pipefail set -euo pipefail
root="$(cd "$(dirname "$0")/.." && pwd -P)" root="$(cd "$(dirname "$0")/.." && pwd -P)"
fixture="$(mktemp -d "${TMPDIR%/}/thoth-coupling-scope.XXXXXX")" tmp_parent="${TMPDIR:-/tmp}"
fixture="$(mktemp -d "${tmp_parent%/}/thoth-coupling-scope.XXXXXX")"
trap 'rm -rf "$fixture"' EXIT HUP INT TERM trap 'rm -rf "$fixture"' EXIT HUP INT TERM
new_fixture() { new_fixture() {
@@ -65,7 +66,7 @@ assert_clean
assert_detected compose.yaml 'services: # Chirone runtime coupling' assert_detected compose.yaml 'services: # Chirone runtime coupling'
assert_detected docker/smoke/core-smoke.sh 'test -d /home/chirone' assert_detected docker/smoke/core-smoke.sh 'test -d /home/chirone'
assert_detected docs/install/local.md 'Install the PSD deployment profile.' assert_detected docs/install/local.md 'Install the Chirone deployment profile.'
assert_detected deploy/env/local.env.example 'NETWORK=omics_portal' assert_detected deploy/env/local.env.example 'NETWORK=omics_portal'
assert_detected scripts/run-stack.sh 'exec datamart-builder' assert_detected scripts/run-stack.sh 'exec datamart-builder'
assert_detected frontend/vite.config.ts 'const base = "/omics_portal";' assert_detected frontend/vite.config.ts 'const base = "/omics_portal";'
+1 -1
View File
@@ -112,7 +112,7 @@ for forbidden_file in \
|| offenders+=("active filename: $forbidden_file (superseded deployment contract)") || offenders+=("active filename: $forbidden_file (superseded deployment contract)")
done done
forbidden='omics_portal|chirone|localllm_default|datamart-builder|compose\.production\.yaml|compose\.psd-local\.yaml|\bpsd\b' forbidden='omics_portal|chirone|localllm_default|datamart-builder|compose\.production\.yaml|compose\.psd-local\.yaml'
retired_semantic='local-vector|pgvector(_direct)?|pg_(dump|restore)|THT_VECTOR_([A-Z0-9_]+)|THT_OLLAMA_URL|THT_WS_[A-Z0-9_]*_(VECTOR|EMBEDDING)_[A-Z0-9_]+|VECTOR_API_KEY_(FILE|SOURCE)|EMBEDDING_API_KEY_(FILE|SOURCE)|vector-api-key|(^|[^A-Za-z0-9_])THT_VEC_(REST_URL|WRITE_REST_URL)|thoth_vector_http' retired_semantic='local-vector|pgvector(_direct)?|pg_(dump|restore)|THT_VECTOR_([A-Z0-9_]+)|THT_OLLAMA_URL|THT_WS_[A-Z0-9_]*_(VECTOR|EMBEDDING)_[A-Z0-9_]+|VECTOR_API_KEY_(FILE|SOURCE)|EMBEDDING_API_KEY_(FILE|SOURCE)|vector-api-key|(^|[^A-Za-z0-9_])THT_VEC_(REST_URL|WRITE_REST_URL)|thoth_vector_http'
scan_category runtime "$forbidden" "${runtime_files[@]}" scan_category runtime "$forbidden" "${runtime_files[@]}"
scan_category install "$forbidden" "${install_files[@]}" scan_category install "$forbidden" "${install_files[@]}"
+1 -1
View File
@@ -205,7 +205,7 @@ services:
labels: labels:
io.thothii.task13.run: "$runLabel" io.thothii.task13.run: "$runLabel"
volumes: volumes:
- "$remoteYaml:/fixtures/remote.git:ro" - "${remoteYaml}:/fixtures/remote.git:ro"
frontend: frontend:
image: $frontendImage image: $frontendImage
build: build:
+4 -4
View File
@@ -323,9 +323,10 @@ def named_example(name):
examples = { examples = {
"filesystem": { "filesystem": {
"evidence": { "evidence": {
"schema_version": 2,
"source": { "source": {
"type": "filesystem", "uri": "example/evidence", "type": "filesystem", "uri": "example/evidence",
"patterns": ["**/*.md"], "max_bytes": 10485760, "patterns": ["curated/**/*.md"], "max_bytes": 10485760,
}, },
"policy": {"max_chunk_chars": 4000, "retain_published_generations": 3}, "policy": {"max_chunk_chars": 4000, "retain_published_generations": 3},
}, },
@@ -375,7 +376,7 @@ required_contract_phrases = [
"It is authoritative for workspace ID,\nname, description, and display order.", "It is authoritative for workspace ID,\nname, description, and display order.",
"The descriptor at `<id>/workspace.yaml` must match the\ncatalog metadata exactly.", "The descriptor at `<id>/workspace.yaml` must match the\ncatalog metadata exactly.",
"catalog-only entries are invalid and reject the complete candidate revision.", "catalog-only entries are invalid and reject the complete candidate revision.",
"The API never writes `thoth-workspaces.yaml`,\n`<id>/workspace.yaml`, `<id>/schema/**`, or `<id>/evidence/**`.", "The API and runtime never write\n`thoth-workspaces.yaml`, `<id>/workspace.yaml`, `<id>/schema/**`, or `<id>/evidence/**` in the\nauthoring repository.",
] ]
normalized_contract = normalize_space(contract) normalized_contract = normalize_space(contract)
for phrase in required_contract_phrases: for phrase in required_contract_phrases:
@@ -1862,10 +1863,9 @@ for required in (
ui = (root / "frontend/src/shell/WorkspaceManager.tsx").read_text() ui = (root / "frontend/src/shell/WorkspaceManager.tsx").read_text()
for required in ( for required in (
"Create a workspace repository",
"Update workspace repository", "Update workspace repository",
"No workspace selection is required", "No workspace selection is required",
"Temporary files are deleted after the test", "deletes temporary files when the check finishes",
): ):
if required not in ui: if required not in ui:
raise SystemExit(f"Workspace management lacks required explanation: {required}") raise SystemExit(f"Workspace management lacks required explanation: {required}")