540 lines
22 KiB
Bash
Executable File
540 lines
22 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Exercises the registry through an isolated Compose project. An optional WORKSPACE_GIT_REMOTE
|
|
# is contacted read-only as a connectivity preflight; all pull/fallback mutations target a fresh
|
|
# temporary bare repository so this smoke test can never alter an operator's shared registry.
|
|
set -euo pipefail
|
|
|
|
root="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
tmp="$(mktemp -d "${TMPDIR:-/tmp}/thoth-workspace-registry-smoke.XXXXXX")"
|
|
tmp="$(cd "$tmp" && pwd -P)"
|
|
tmp_slug="$(basename "$tmp" | tr '[:upper:]._' '[:lower:]--' | tr -cd 'a-z0-9-')"
|
|
project="thoth-workspace-registry-smoke-${tmp_slug}-$$"
|
|
image="thothii-workspace-registry-smoke:${project}"
|
|
remote="$tmp/remote.git"
|
|
seed="$tmp/seed"
|
|
branch="workspace-registry-smoke"
|
|
core_remote="/fixtures/remote.git"
|
|
|
|
cleanup_smoke_image() {
|
|
local inspect_status listed list_status
|
|
docker image inspect --format '{{.Id}}' "$image" >/dev/null 2>&1
|
|
inspect_status=$?
|
|
if [[ "$inspect_status" -eq 0 ]]; then
|
|
docker image rm -f "$image" >/dev/null 2>&1
|
|
return $?
|
|
fi
|
|
|
|
listed="$(docker image ls --quiet --no-trunc "$image" 2>/dev/null)"
|
|
list_status=$?
|
|
[[ "$list_status" -eq 0 && -z "$listed" ]]
|
|
}
|
|
|
|
workspace_registry_smoke_leftovers() {
|
|
local output status=0
|
|
if output="$(docker ps -a --filter "label=com.docker.compose.project=$project" -q)"; then
|
|
printf '%s\n' "$output"
|
|
else
|
|
status=1
|
|
fi
|
|
if output="$(docker volume ls --filter "label=com.docker.compose.project=$project" -q)"; then
|
|
printf '%s\n' "$output"
|
|
else
|
|
status=1
|
|
fi
|
|
if output="$(docker network ls --filter "label=com.docker.compose.project=$project" -q)"; then
|
|
printf '%s\n' "$output"
|
|
else
|
|
status=1
|
|
fi
|
|
if output="$(docker image inspect --format '{{.Id}}' "$image" 2>/dev/null)"; then
|
|
printf '%s\n' "$output"
|
|
elif output="$(docker image ls --quiet --no-trunc "$image" 2>/dev/null)"; then
|
|
printf '%s\n' "$output"
|
|
else
|
|
status=1
|
|
fi
|
|
return "$status"
|
|
}
|
|
|
|
cleanup() {
|
|
local body_status=$?
|
|
local down_status image_status enumeration_status rm_status=0 cleanup_incomplete=0 final_status
|
|
local leftovers
|
|
trap - EXIT HUP INT TERM
|
|
set +e
|
|
|
|
compose down --volumes --remove-orphans >/dev/null 2>&1
|
|
down_status=$?
|
|
cleanup_smoke_image
|
|
image_status=$?
|
|
leftovers="$(workspace_registry_smoke_leftovers)"
|
|
enumeration_status=$?
|
|
leftovers="$(printf '%s\n' "$leftovers" | sed '/^$/d')"
|
|
|
|
if [[ "$down_status" -ne 0 || "$image_status" -ne 0 || "$enumeration_status" -ne 0 || -n "$leftovers" ]]; then
|
|
cleanup_incomplete=1
|
|
else
|
|
rm -rf "$tmp"
|
|
rm_status=$?
|
|
[[ "$rm_status" -eq 0 ]] || cleanup_incomplete=1
|
|
fi
|
|
|
|
if [[ "$cleanup_incomplete" -ne 0 ]]; then
|
|
echo "workspace registry cleanup incomplete: compose down status=$down_status, image cleanup status=$image_status, enumeration status=$enumeration_status, temp cleanup status=$rm_status." >&2
|
|
if [[ -n "$leftovers" ]]; then
|
|
echo "workspace registry cleanup left owned Docker resources:" >&2
|
|
printf '%s\n' "$leftovers" >&2
|
|
fi
|
|
echo "workspace registry smoke recovery path retained: $tmp" >&2
|
|
if [[ "$body_status" -ne 0 ]]; then
|
|
final_status=$body_status
|
|
else
|
|
final_status=1
|
|
fi
|
|
else
|
|
echo "workspace registry cleanup proof: no compose containers, volumes, networks, image, or temporary path remain for $project."
|
|
final_status=$body_status
|
|
fi
|
|
exit "$final_status"
|
|
}
|
|
|
|
compose() {
|
|
SMOKE_ROOT="$root" \
|
|
SMOKE_IMAGE="$image" \
|
|
SMOKE_REMOTE="$remote" \
|
|
SMOKE_BRANCH="$branch" \
|
|
SMOKE_CORE_REMOTE="$core_remote" \
|
|
docker compose --project-name "$project" -f - "$@" <<'COMPOSE_YAML'
|
|
services:
|
|
core:
|
|
build:
|
|
context: "${SMOKE_ROOT:?}"
|
|
dockerfile: docker/core.Dockerfile
|
|
image: "${SMOKE_IMAGE:?}"
|
|
environment:
|
|
HOST: 0.0.0.0
|
|
PORT: "8787"
|
|
AUTH_MODE: none
|
|
THT_HARNESS_DIR: /app/harness
|
|
THT_BIN: /opt/venv/bin/tht
|
|
SETTINGS_FILE: /tmp/settings.json
|
|
THT_WORKSPACE_REGISTRY_ROOT: /data/workspace-registry
|
|
THT_WORKSPACE_SECRET_STORE_ROOT: /tmp/workspace-secrets
|
|
THT_WORKSPACE_SECRET_RUNTIME_ROOT: /tmp/workspace-secret-runtime
|
|
THT_WORKSPACE_GIT_REMOTE: "${SMOKE_CORE_REMOTE:?}"
|
|
THT_WORKSPACE_GIT_BRANCH: "${SMOKE_BRANCH:?}"
|
|
THT_WORKSPACE_INSTALLATION_ID: smoke
|
|
THT_WORKSPACE_SECRET_ROOTS: /run/secrets
|
|
volumes:
|
|
- type: volume
|
|
source: workspace-registry
|
|
target: /data/workspace-registry
|
|
- type: bind
|
|
source: "${SMOKE_REMOTE:?}"
|
|
target: /fixtures/remote.git
|
|
read_only: true
|
|
volumes:
|
|
workspace-registry: {}
|
|
COMPOSE_YAML
|
|
}
|
|
|
|
workspace_registry_smoke_self_test_image_cleanup_identity() {
|
|
local calls exact_image foreign_project foreign_tag leftovers removed=0
|
|
calls="$(mktemp "${TMPDIR:-/tmp}/thoth-workspace-registry-smoke-image-contract.XXXXXX")"
|
|
project="thoth-workspace-registry-smoke-selftest-123"
|
|
exact_image="thothii-workspace-registry-smoke:${project}"
|
|
foreign_project="thothii-workspace-registry-smoke:thoth-workspace-registry-smoke-foreign-456"
|
|
foreign_tag="thothii-workspace-registry-smoke:local"
|
|
image="$exact_image"
|
|
|
|
docker() {
|
|
printf '%s\n' "docker $*" >>"$calls"
|
|
case "$1 $2" in
|
|
"image inspect")
|
|
[[ "$3" == "--format" && "$5" == "$exact_image" ]] || return 43
|
|
[[ "$removed" -eq 0 ]]
|
|
;;
|
|
"image rm")
|
|
[[ "$3" == "-f" && "$4" == "$exact_image" ]] || return 42
|
|
removed=1
|
|
;;
|
|
"image ls")
|
|
[[ "$3" == "--quiet" && "$4" == "--no-trunc" && "$5" == "$exact_image" ]] || return 47
|
|
;;
|
|
"ps -a"|"volume ls"|"network ls")
|
|
[[ "$*" == *"label=com.docker.compose.project=$project"* ]] || return 45
|
|
;;
|
|
*)
|
|
return 46
|
|
;;
|
|
esac
|
|
}
|
|
|
|
cleanup_smoke_image
|
|
leftovers="$(workspace_registry_smoke_leftovers)"
|
|
[[ -z "$(printf '%s\n' "$leftovers" | sed '/^$/d')" ]] || {
|
|
echo "self-test observed leftovers for the per-run image" >&2
|
|
printf '%s\n' "$leftovers" >&2
|
|
return 1
|
|
}
|
|
grep -Fq "docker image rm -f $exact_image" "$calls" \
|
|
|| { echo "self-test did not remove the exact per-run image reference" >&2; return 1; }
|
|
if grep -Fq "$foreign_project" "$calls" || grep -Fq "$foreign_tag" "$calls"; then
|
|
echo "self-test cleanup touched a foreign workspace-registry smoke image reference" >&2
|
|
return 1
|
|
fi
|
|
rm -f "$calls"
|
|
echo "workspace registry smoke image cleanup identity self-test passed"
|
|
}
|
|
|
|
workspace_registry_smoke_self_test_compose_config() {
|
|
local special_root rendered
|
|
special_root="$tmp/compose config path # colon: fixture"
|
|
root="$special_root/root context"
|
|
remote="$special_root/remote repo # fixture.git"
|
|
branch="workspace registry # branch"
|
|
core_remote="/fixtures/remote repo # fixture.git"
|
|
image="thothii-workspace-registry-smoke:compose-config-selftest"
|
|
project="thoth-workspace-registry-smoke-compose-config-selftest-$$"
|
|
rendered="$special_root/rendered.yaml"
|
|
mkdir -p "$root" "$remote"
|
|
|
|
compose config --quiet
|
|
compose config --format json >"$rendered"
|
|
grep -Fq "$root" "$rendered"
|
|
grep -Fq "$remote" "$rendered"
|
|
grep -Fq "$branch" "$rendered"
|
|
grep -Fq "$core_remote" "$rendered"
|
|
grep -Fq '"read_only": true' "$rendered"
|
|
rm -rf "$tmp"
|
|
echo "workspace registry smoke Compose config special-path self-test passed"
|
|
}
|
|
|
|
workspace_registry_smoke_self_test_cleanup_failure_path() {
|
|
local fixture_root retained calls output status
|
|
fixture_root="$tmp/cleanup failure # fixture"
|
|
retained="$fixture_root/retained smoke path"
|
|
calls="$fixture_root/calls.log"
|
|
mkdir -p "$retained"
|
|
|
|
set +e
|
|
output="$(
|
|
(
|
|
tmp="$retained"
|
|
project="thoth-workspace-registry-smoke-cleanup-failure-selftest"
|
|
image="thothii-workspace-registry-smoke:cleanup-failure-selftest"
|
|
compose() { printf '%s\n' "compose $*" >>"$calls"; return 71; }
|
|
cleanup_smoke_image() { printf '%s\n' 'image cleanup' >>"$calls"; return 72; }
|
|
workspace_registry_smoke_leftovers() { printf '%s\n' 'owned-resource-selftest'; printf '%s\n' 'enumerate leftovers' >>"$calls"; return 73; }
|
|
trap cleanup EXIT
|
|
exit 37
|
|
) 2>&1
|
|
)"
|
|
status=$?
|
|
set -e
|
|
|
|
[[ "$status" -eq 37 ]] || { echo "cleanup self-test did not preserve body status 37 (got $status)" >&2; return 1; }
|
|
grep -Fq 'compose down --volumes --remove-orphans' "$calls"
|
|
grep -Fq 'image cleanup' "$calls"
|
|
grep -Fq 'enumerate leftovers' "$calls"
|
|
grep -Fq 'cleanup incomplete: compose down status=71, image cleanup status=72, enumeration status=73' <<<"$output"
|
|
grep -Fq 'owned-resource-selftest' <<<"$output"
|
|
grep -Fq "recovery path retained: $retained" <<<"$output"
|
|
[[ -d "$retained" ]] || { echo "cleanup self-test did not retain its recovery path" >&2; return 1; }
|
|
rm -rf "$tmp"
|
|
echo "workspace registry smoke cleanup failure-path self-test passed"
|
|
}
|
|
|
|
workspace_registry_smoke_metadata() {
|
|
local fixture="$1"
|
|
awk '
|
|
/^workspace:[[:space:]]*$/ { in_workspace = 1; next }
|
|
in_workspace && /^[^[:space:]]/ { in_workspace = 0 }
|
|
in_workspace && /^ id:[[:space:]]*/ {
|
|
sub(/^ id:[[:space:]]*/, "")
|
|
id = $0
|
|
next
|
|
}
|
|
in_workspace && /^ name:[[:space:]]*/ {
|
|
sub(/^ name:[[:space:]]*/, "")
|
|
name = $0
|
|
next
|
|
}
|
|
in_workspace && /^ description:[[:space:]]*/ {
|
|
sub(/^ description:[[:space:]]*/, "")
|
|
description = $0
|
|
next
|
|
}
|
|
END {
|
|
if (id == "" || name == "") exit 1
|
|
print id
|
|
print name
|
|
if (description != "") print description
|
|
}
|
|
' "$fixture"
|
|
}
|
|
|
|
workspace_registry_smoke_write_catalog() {
|
|
local catalog_path="$1" id="$2" name="$3" description="${4:-}"
|
|
{
|
|
printf 'schema_version: 1
|
|
'
|
|
printf 'workspaces:
|
|
'
|
|
printf ' - id: %s
|
|
' "$id"
|
|
printf ' name: %s
|
|
' "$name"
|
|
if [[ -n "$description" ]]; then
|
|
printf ' description: %s
|
|
' "$description"
|
|
fi
|
|
} >"$catalog_path"
|
|
}
|
|
|
|
workspace_registry_smoke_replace_once() {
|
|
local target="$1" old="$2" new="$3"
|
|
python3 - "$target" "$old" "$new" <<'PY'
|
|
from pathlib import Path
|
|
import sys
|
|
path = Path(sys.argv[1])
|
|
old = sys.argv[2]
|
|
new = sys.argv[3]
|
|
text = path.read_text()
|
|
count = text.count(old)
|
|
if count != 1:
|
|
raise SystemExit(f"expected exactly one occurrence of {old!r} in {path}, found {count}")
|
|
path.write_text(text.replace(old, new, 1))
|
|
PY
|
|
}
|
|
|
|
workspace_registry_smoke_seed_fixture() {
|
|
local fixture="$1" metadata
|
|
mapfile -t metadata < <(workspace_registry_smoke_metadata "$fixture")
|
|
workspace_registry_smoke_id="${metadata[0]}"
|
|
workspace_registry_smoke_name="${metadata[1]}"
|
|
workspace_registry_smoke_description="${metadata[2]-}"
|
|
|
|
mkdir -p "$seed/$workspace_registry_smoke_id"
|
|
cp "$fixture" "$seed/$workspace_registry_smoke_id/workspace.yaml"
|
|
workspace_registry_smoke_write_catalog "$seed/thoth-workspaces.yaml" "$workspace_registry_smoke_id" "$workspace_registry_smoke_name" "$workspace_registry_smoke_description"
|
|
if grep -Fq 'type: filesystem' "$fixture"; then
|
|
mkdir -p "$seed/$workspace_registry_smoke_id/evidence"
|
|
printf 'guide v1\n' >"$seed/$workspace_registry_smoke_id/evidence/guide.md"
|
|
fi
|
|
}
|
|
|
|
workspace_registry_smoke_commit() {
|
|
local message="$1"
|
|
git -C "$seed" add -A >/dev/null
|
|
git -C "$seed" -c user.name='Workspace Registry Smoke' -c user.email='workspace-registry-smoke@example.invalid' commit -m "$message" >/dev/null
|
|
git -C "$seed" push ${2:-origin} "HEAD:$branch" >/dev/null
|
|
}
|
|
|
|
workspace_registry_smoke_prepare_fixture() {
|
|
git init --bare --initial-branch=main "$remote" >/dev/null
|
|
git clone "$remote" "$seed" >/dev/null
|
|
git -C "$seed" checkout -b "$branch" >/dev/null
|
|
workspace_registry_smoke_seed_fixture "$root/scripts/fixtures/workspace-registry-smoke.yaml"
|
|
workspace_registry_smoke_commit 'Seed workspace registry smoke'
|
|
}
|
|
|
|
workspace_registry_smoke_registry_head() {
|
|
printf '%s' "$1" | sed -n 's/.*"head":"\([0-9a-f]*\)".*/\1/p'
|
|
}
|
|
|
|
workspace_registry_smoke_reset_seed() {
|
|
local commit="$1"
|
|
git -C "$seed" reset --hard "$commit" >/dev/null
|
|
git -C "$seed" push --force origin "HEAD:$branch" >/dev/null
|
|
}
|
|
|
|
workspace_registry_smoke_fixtures_only() {
|
|
local descriptor_path catalog_path initial_head updated_head
|
|
workspace_registry_smoke_prepare_fixture
|
|
descriptor_path="$seed/$workspace_registry_smoke_id/workspace.yaml"
|
|
catalog_path="$seed/thoth-workspaces.yaml"
|
|
|
|
[[ -f "$catalog_path" ]] || { echo 'missing root workspace catalog' >&2; return 1; }
|
|
[[ -f "$descriptor_path" ]] || { echo 'missing nested workspace descriptor' >&2; return 1; }
|
|
[[ -f "$seed/$workspace_registry_smoke_id/evidence/guide.md" ]] || { echo 'missing nested workspace evidence' >&2; return 1; }
|
|
[[ ! -e "$seed/workspaces/$workspace_registry_smoke_id.yaml" ]] || { echo 'legacy flat descriptor path was created' >&2; return 1; }
|
|
[[ ! -e "$seed/workspace-content/$workspace_registry_smoke_id" ]] || { echo 'legacy flat evidence path was created' >&2; return 1; }
|
|
grep -Fq 'schema_version: 1' "$catalog_path"
|
|
grep -Fq 'name: Local' "$catalog_path"
|
|
grep -Fq 'description: Isolated workspace registry smoke fixture.' "$catalog_path"
|
|
|
|
initial_head="$(git -C "$seed" rev-parse HEAD)"
|
|
workspace_registry_smoke_replace_once "$descriptor_path" 'name: Local' 'name: Local Updated'
|
|
workspace_registry_smoke_replace_once "$catalog_path" 'name: Local' 'name: Local Updated'
|
|
workspace_registry_smoke_commit 'Update workspace registry smoke metadata'
|
|
updated_head="$(git -C "$seed" rev-parse HEAD)"
|
|
[[ "$updated_head" != "$initial_head" ]] || { echo 'metadata co-commit did not advance Git head' >&2; return 1; }
|
|
grep -Fq 'name: Local Updated' "$descriptor_path"
|
|
grep -Fq 'name: Local Updated' "$catalog_path"
|
|
|
|
printf 'guide v2\n' >"$seed/$workspace_registry_smoke_id/evidence/guide.md"
|
|
workspace_registry_smoke_commit 'Update workspace registry smoke evidence only'
|
|
[[ "$(git -C "$seed" rev-parse HEAD)" != "$updated_head" ]] || { echo 'evidence-only commit did not advance Git head' >&2; return 1; }
|
|
|
|
mkdir -p "$seed/orphan"
|
|
cp "$descriptor_path" "$seed/orphan/workspace.yaml"
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'id: local' 'id: orphan'
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'name: Local Updated' 'name: Orphan Workspace'
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'collection: local' 'collection: orphan'
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'uri: local/evidence' 'uri: orphan/evidence'
|
|
mkdir -p "$seed/orphan/evidence"
|
|
printf 'orphan guide\n' >"$seed/orphan/evidence/guide.md"
|
|
[[ -f "$seed/orphan/workspace.yaml" ]] || { echo 'orphan descriptor was not created' >&2; return 1; }
|
|
|
|
mkdir -p "$seed/workspaces" "$seed/workspace-content/$workspace_registry_smoke_id/evidence"
|
|
cp "$root/scripts/fixtures/workspace-registry-smoke.yaml" "$seed/workspaces/$workspace_registry_smoke_id.yaml"
|
|
printf 'legacy guide\n' >"$seed/workspace-content/$workspace_registry_smoke_id/evidence/guide.md"
|
|
[[ -f "$seed/workspaces/$workspace_registry_smoke_id.yaml" ]] || { echo 'legacy flat descriptor fixture missing' >&2; return 1; }
|
|
[[ -f "$seed/workspace-content/$workspace_registry_smoke_id/evidence/guide.md" ]] || { echo 'legacy flat evidence fixture missing' >&2; return 1; }
|
|
|
|
echo 'workspace registry smoke fixture contract passed'
|
|
}
|
|
|
|
case "${WORKSPACE_REGISTRY_SMOKE_SELF_TEST:-}" in
|
|
"") ;;
|
|
image-cleanup-identity)
|
|
workspace_registry_smoke_self_test_image_cleanup_identity
|
|
rm -rf "$tmp"
|
|
exit 0
|
|
;;
|
|
compose-config-contract)
|
|
workspace_registry_smoke_self_test_compose_config
|
|
exit 0
|
|
;;
|
|
cleanup-failure-path)
|
|
workspace_registry_smoke_self_test_cleanup_failure_path
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "unknown workspace registry smoke self-test: ${WORKSPACE_REGISTRY_SMOKE_SELF_TEST}" >&2
|
|
rm -rf "$tmp"
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
if [[ "${1:-}" == "--fixtures-only" ]]; then
|
|
workspace_registry_smoke_fixtures_only
|
|
rm -rf "$tmp"
|
|
exit 0
|
|
fi
|
|
|
|
trap cleanup EXIT
|
|
trap 'exit 129' HUP
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
|
|
wait_for_core() {
|
|
local attempt
|
|
for attempt in $(seq 1 30); do
|
|
if compose exec -T core curl -fsS http://127.0.0.1:8787/health >/dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
compose logs core >&2 || true
|
|
return 1
|
|
}
|
|
|
|
if [[ -n "${WORKSPACE_GIT_REMOTE:-}" ]]; then
|
|
echo "== Read-only Git remote preflight =="
|
|
git ls-remote --heads "$WORKSPACE_GIT_REMOTE" >/dev/null
|
|
fi
|
|
|
|
echo "== Seed isolated workspace registry =="
|
|
workspace_registry_smoke_prepare_fixture
|
|
|
|
echo "== Build and start isolated Compose core =="
|
|
compose up -d --build
|
|
wait_for_core
|
|
initial_status="$(compose exec -T core curl -fsS http://127.0.0.1:8787/workspace-registry/status)"
|
|
printf '%s' "$initial_status" | grep -Eq '"head":"[0-9a-f]{40}"'
|
|
compose exec -T core test -f /data/workspace-registry/state/active.json
|
|
|
|
echo "== Recreate offline and prove registry-volume fallback =="
|
|
core_remote="/fixtures/offline.git"
|
|
compose up -d --force-recreate
|
|
wait_for_core
|
|
recreated_status="$(compose exec -T core curl -fsS http://127.0.0.1:8787/workspace-registry/status)"
|
|
initial_head="$(workspace_registry_smoke_registry_head "$initial_status")"
|
|
recreated_head="$(workspace_registry_smoke_registry_head "$recreated_status")"
|
|
test -n "$initial_head" && test "$initial_head" = "$recreated_head"
|
|
printf '%s' "$recreated_status" | grep -Fq '"degraded":true'
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local'
|
|
|
|
echo "== Pull a valid catalog+descriptor metadata update =="
|
|
workspace_registry_smoke_replace_once "$seed/$workspace_registry_smoke_id/workspace.yaml" 'name: Local' 'name: Local Updated'
|
|
workspace_registry_smoke_replace_once "$seed/thoth-workspaces.yaml" 'name: Local' 'name: Local Updated'
|
|
workspace_registry_smoke_commit 'Update workspace registry smoke metadata'
|
|
core_remote="/fixtures/remote.git"
|
|
compose up -d --force-recreate
|
|
wait_for_core
|
|
valid_status="$(compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull)"
|
|
valid_head="$(workspace_registry_smoke_registry_head "$valid_status")"
|
|
[[ "$valid_head" =~ ^[0-9a-f]{40}$ && "$valid_head" != "$initial_head" ]]
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
good_seed_commit="$(git -C "$seed" rev-parse HEAD)"
|
|
|
|
echo "== Pull a content-only Evidence update =="
|
|
printf 'guide v2\n' >"$seed/$workspace_registry_smoke_id/evidence/guide.md"
|
|
workspace_registry_smoke_commit 'Update workspace registry smoke evidence only'
|
|
evidence_status="$(compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull)"
|
|
evidence_head="$(workspace_registry_smoke_registry_head "$evidence_status")"
|
|
[[ "$evidence_head" =~ ^[0-9a-f]{40}$ && "$evidence_head" != "$valid_head" ]]
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
good_seed_commit="$(git -C "$seed" rev-parse HEAD)"
|
|
|
|
echo "== Reject catalog/descriptor metadata mismatch and retain the last valid snapshot =="
|
|
workspace_registry_smoke_replace_once "$seed/thoth-workspaces.yaml" 'name: Local Updated' 'name: Local Drift'
|
|
workspace_registry_smoke_commit 'Break workspace registry metadata parity'
|
|
if compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull >/dev/null; then
|
|
echo 'registry accepted catalog/descriptor metadata mismatch' >&2
|
|
exit 1
|
|
fi
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
compose exec -T core test -f /data/workspace-registry/state/active.json
|
|
workspace_registry_smoke_replace_once "$seed/thoth-workspaces.yaml" 'name: Local Drift' 'name: Local Updated'
|
|
workspace_registry_smoke_commit 'Restore workspace registry metadata parity'
|
|
restore_status="$(compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull)"
|
|
evidence_head="$(workspace_registry_smoke_registry_head "$restore_status")"
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
|
|
echo "== Reject orphan descriptor directories not listed in the catalog =="
|
|
mkdir -p "$seed/orphan"
|
|
cp "$seed/$workspace_registry_smoke_id/workspace.yaml" "$seed/orphan/workspace.yaml"
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'id: local' 'id: orphan'
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'name: Local Updated' 'name: Orphan Workspace'
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'collection: local' 'collection: orphan'
|
|
workspace_registry_smoke_replace_once "$seed/orphan/workspace.yaml" 'uri: local/evidence' 'uri: orphan/evidence'
|
|
mkdir -p "$seed/orphan/evidence"
|
|
printf 'orphan guide\n' >"$seed/orphan/evidence/guide.md"
|
|
workspace_registry_smoke_commit 'Add orphan workspace directory'
|
|
if compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull >/dev/null; then
|
|
echo 'registry accepted orphan descriptor directory' >&2
|
|
exit 1
|
|
fi
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
rm -rf "$seed/orphan"
|
|
workspace_registry_smoke_commit 'Remove orphan workspace directory'
|
|
restore_status="$(compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull)"
|
|
evidence_head="$(workspace_registry_smoke_registry_head "$restore_status")"
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
|
|
echo "== Reject the retired flat workspace layout and retain the last valid snapshot =="
|
|
mkdir -p "$seed/workspaces" "$seed/workspace-content/$workspace_registry_smoke_id/evidence"
|
|
cp "$root/scripts/fixtures/workspace-registry-smoke.yaml" "$seed/workspaces/$workspace_registry_smoke_id.yaml"
|
|
printf 'legacy guide\n' >"$seed/workspace-content/$workspace_registry_smoke_id/evidence/guide.md"
|
|
workspace_registry_smoke_commit 'Reintroduce retired flat workspace layout'
|
|
if compose exec -T core curl -fsS -X POST http://127.0.0.1:8787/workspace-registry/pull >/dev/null; then
|
|
echo 'registry accepted the retired flat workspace layout' >&2
|
|
exit 1
|
|
fi
|
|
compose exec -T core curl -fsS http://127.0.0.1:8787/workspaces | grep -Fq 'Local Updated'
|
|
|
|
echo "workspace registry smoke passed"
|