328 lines
7.4 KiB
Bash
Executable File
328 lines
7.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "${repo_root}"
|
|
|
|
project="minerops-agent-enrollment-migration-$$"
|
|
compose=(
|
|
docker compose
|
|
--project-name "${project}"
|
|
--env-file .env.dev
|
|
-f compose.dev.yaml
|
|
)
|
|
|
|
cleanup() {
|
|
"${compose[@]}" down -v --remove-orphans >/dev/null 2>&1 || true
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
set -a
|
|
# shellcheck disable=SC1091
|
|
source .env.dev
|
|
set +a
|
|
|
|
echo "Starting disposable PostgreSQL..."
|
|
"${compose[@]}" up -d postgres
|
|
|
|
echo "Waiting for PostgreSQL..."
|
|
for attempt in $(seq 1 60); do
|
|
if "${compose[@]}" exec -T postgres \
|
|
pg_isready -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" >/dev/null 2>&1; then
|
|
break
|
|
fi
|
|
if [[ "${attempt}" -eq 60 ]]; then
|
|
echo "PostgreSQL did not become ready" >&2
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
echo "Building backend with migration 0017..."
|
|
"${compose[@]}" build backend >/dev/null
|
|
|
|
run_backend() {
|
|
"${compose[@]}" run --rm --no-deps backend "$@"
|
|
}
|
|
|
|
psql_exec() {
|
|
"${compose[@]}" exec -T postgres \
|
|
psql -v ON_ERROR_STOP=1 \
|
|
-U "${POSTGRES_USER}" \
|
|
-d "${POSTGRES_DB}" "$@"
|
|
}
|
|
|
|
echo "Testing upgrade through 0016..."
|
|
run_backend alembic upgrade 0016_agent_zones
|
|
|
|
revision="$(
|
|
psql_exec -Atc "SELECT version_num FROM alembic_version"
|
|
)"
|
|
[[ "${revision}" == "0016_agent_zones" ]]
|
|
|
|
echo "Testing 0016 -> 0017..."
|
|
run_backend alembic upgrade 0017_agent_enrollment
|
|
|
|
revision="$(
|
|
psql_exec -Atc "SELECT version_num FROM alembic_version"
|
|
)"
|
|
[[ "${revision}" == "0017_agent_enrollment" ]]
|
|
|
|
echo "Checking new Agent credential columns..."
|
|
for column in \
|
|
display_name \
|
|
agent_secret_hash \
|
|
credential_created_at \
|
|
credential_revoked_at
|
|
do
|
|
count="$(
|
|
psql_exec -Atc "
|
|
SELECT COUNT(*)
|
|
FROM information_schema.columns
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'minerops_site_agents'
|
|
AND column_name = '${column}'
|
|
"
|
|
)"
|
|
[[ "${count}" == "1" ]]
|
|
done
|
|
|
|
echo "Checking enrollment table..."
|
|
count="$(
|
|
psql_exec -Atc "
|
|
SELECT COUNT(*)
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'agent_enrollments'
|
|
"
|
|
)"
|
|
[[ "${count}" == "1" ]]
|
|
|
|
echo "Checking expected indexes..."
|
|
for index in \
|
|
uq_minerops_site_agents_agent_secret_hash \
|
|
uq_agent_enrollments_token_hash \
|
|
uq_agent_enrollments_open_zone \
|
|
uq_agent_enrollments_enrolled_agent \
|
|
idx_agent_enrollments_site_id \
|
|
idx_agent_enrollments_created_at
|
|
do
|
|
count="$(
|
|
psql_exec -Atc "
|
|
SELECT COUNT(*)
|
|
FROM pg_indexes
|
|
WHERE schemaname = 'public'
|
|
AND indexname = '${index}'
|
|
"
|
|
)"
|
|
[[ "${count}" == "1" ]]
|
|
done
|
|
|
|
echo "Testing immediate legal downgrade..."
|
|
run_backend alembic downgrade 0016_agent_zones
|
|
|
|
revision="$(
|
|
psql_exec -Atc "SELECT version_num FROM alembic_version"
|
|
)"
|
|
[[ "${revision}" == "0016_agent_zones" ]]
|
|
|
|
count="$(
|
|
psql_exec -Atc "
|
|
SELECT COUNT(*)
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'agent_enrollments'
|
|
"
|
|
)"
|
|
[[ "${count}" == "0" ]]
|
|
|
|
echo "Re-upgrading to 0017..."
|
|
run_backend alembic upgrade 0017_agent_enrollment
|
|
|
|
echo "Creating isolated Site and Agent Zone fixtures..."
|
|
psql_exec <<'SQL'
|
|
INSERT INTO sites (id, name)
|
|
VALUES (
|
|
'00000000-0000-4000-8000-000000001700',
|
|
'Enrollment Migration Test Site'
|
|
);
|
|
|
|
INSERT INTO agent_zones (
|
|
id,
|
|
site_id,
|
|
name,
|
|
description,
|
|
is_enabled
|
|
)
|
|
VALUES (
|
|
'00000000-0000-4000-8000-000000001701',
|
|
'00000000-0000-4000-8000-000000001700',
|
|
'Enrollment Test Zone',
|
|
'Disposable migration test',
|
|
true
|
|
);
|
|
SQL
|
|
|
|
echo "Testing database constraints..."
|
|
|
|
psql_exec <<'SQL'
|
|
DO $$
|
|
BEGIN
|
|
BEGIN
|
|
INSERT INTO agent_enrollments (
|
|
token_hash,
|
|
site_id,
|
|
agent_zone_id,
|
|
display_name,
|
|
expires_at
|
|
)
|
|
VALUES (
|
|
'not-a-sha256-hash',
|
|
'00000000-0000-4000-8000-000000001700',
|
|
'00000000-0000-4000-8000-000000001701',
|
|
'Invalid Hash',
|
|
now() + interval '30 minutes'
|
|
);
|
|
RAISE EXCEPTION 'invalid token hash was accepted';
|
|
EXCEPTION
|
|
WHEN check_violation THEN NULL;
|
|
END;
|
|
END $$;
|
|
SQL
|
|
|
|
psql_exec <<'SQL'
|
|
INSERT INTO agent_enrollments (
|
|
id,
|
|
token_hash,
|
|
site_id,
|
|
agent_zone_id,
|
|
display_name,
|
|
expires_at
|
|
)
|
|
VALUES (
|
|
'00000000-0000-4000-8000-000000001710',
|
|
repeat('a', 64),
|
|
'00000000-0000-4000-8000-000000001700',
|
|
'00000000-0000-4000-8000-000000001701',
|
|
'Enrollment Test Agent',
|
|
now() + interval '30 minutes'
|
|
);
|
|
|
|
DO $$
|
|
BEGIN
|
|
BEGIN
|
|
INSERT INTO agent_enrollments (
|
|
token_hash,
|
|
site_id,
|
|
agent_zone_id,
|
|
display_name,
|
|
expires_at
|
|
)
|
|
VALUES (
|
|
repeat('b', 64),
|
|
'00000000-0000-4000-8000-000000001700',
|
|
'00000000-0000-4000-8000-000000001701',
|
|
'Second Open Enrollment',
|
|
now() + interval '30 minutes'
|
|
);
|
|
RAISE EXCEPTION 'second open enrollment was accepted';
|
|
EXCEPTION
|
|
WHEN unique_violation THEN NULL;
|
|
END;
|
|
END $$;
|
|
SQL
|
|
|
|
echo "Testing credential hash integrity and uniqueness..."
|
|
|
|
psql_exec <<'SQL'
|
|
INSERT INTO minerops_site_agents (
|
|
agent_id,
|
|
site_id,
|
|
agent_zone_id,
|
|
site_name,
|
|
display_name,
|
|
agent_secret_hash,
|
|
credential_created_at
|
|
)
|
|
VALUES (
|
|
'agent-enrollment-test',
|
|
'00000000-0000-4000-8000-000000001700',
|
|
'00000000-0000-4000-8000-000000001701',
|
|
'Enrollment Migration Test Site',
|
|
'Enrollment Test Agent',
|
|
repeat('c', 64),
|
|
now()
|
|
);
|
|
|
|
DO $$
|
|
BEGIN
|
|
BEGIN
|
|
INSERT INTO minerops_site_agents (
|
|
agent_id,
|
|
site_name,
|
|
display_name,
|
|
agent_secret_hash,
|
|
credential_created_at
|
|
)
|
|
VALUES (
|
|
'agent-enrollment-duplicate-secret',
|
|
'Enrollment Migration Test Site',
|
|
'Duplicate Secret',
|
|
repeat('c', 64),
|
|
now()
|
|
);
|
|
RAISE EXCEPTION 'duplicate Agent secret hash was accepted';
|
|
EXCEPTION
|
|
WHEN unique_violation THEN NULL;
|
|
END;
|
|
END $$;
|
|
SQL
|
|
|
|
echo "Testing downgrade refusal after feature use..."
|
|
|
|
set +e
|
|
downgrade_output="$(
|
|
run_backend alembic downgrade 0016_agent_zones 2>&1
|
|
)"
|
|
downgrade_status=$?
|
|
set -e
|
|
|
|
if [[ "${downgrade_status}" -eq 0 ]]; then
|
|
echo "Downgrade unexpectedly succeeded after enrollment/credential use" >&2
|
|
exit 1
|
|
fi
|
|
|
|
grep -Eq \
|
|
'Cannot downgrade 0017: Agent enrollment history exists|Cannot downgrade 0017: per-Agent credentials exist' \
|
|
<<<"${downgrade_output}"
|
|
|
|
revision="$(
|
|
psql_exec -Atc "SELECT version_num FROM alembic_version"
|
|
)"
|
|
[[ "${revision}" == "0017_agent_enrollment" ]]
|
|
|
|
echo "Confirming refusal happened before destructive schema changes..."
|
|
|
|
count="$(
|
|
psql_exec -Atc "
|
|
SELECT COUNT(*)
|
|
FROM information_schema.tables
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'agent_enrollments'
|
|
"
|
|
)"
|
|
[[ "${count}" == "1" ]]
|
|
|
|
count="$(
|
|
psql_exec -Atc "
|
|
SELECT COUNT(*)
|
|
FROM information_schema.columns
|
|
WHERE table_schema = 'public'
|
|
AND table_name = 'minerops_site_agents'
|
|
AND column_name = 'agent_secret_hash'
|
|
"
|
|
)"
|
|
[[ "${count}" == "1" ]]
|
|
|
|
echo "Agent enrollment migration lifecycle checks passed."
|