#!/usr/bin/env bash set -euo pipefail repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "${repo_root}" project_name="${MINEROPS_LEGACY_RETIREMENT_PROJECT:-minerops-legacy-retirement-$$}" compose=(docker compose --project-name "${project_name}" --env-file .env.dev -f compose.dev.yaml) cleanup() { status=$? if (( status != 0 )); then "${compose[@]}" logs --no-color --tail 160 postgres || true fi "${compose[@]}" down --volumes --remove-orphans >/dev/null 2>&1 || true exit "${status}" } trap cleanup EXIT run_db_alembic() { local database="$1" shift "${compose[@]}" run --rm --no-deps -e POSTGRES_DB="${database}" backend alembic "$@" } psql_named() { local database="$1" shift "${compose[@]}" exec -T postgres sh -ec \ 'database="$1"; shift; exec psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$database" "$@"' \ sh "${database}" "$@" } create_database() { "${compose[@]}" exec -T postgres sh -ec \ 'exec createdb -U "$POSTGRES_USER" "$1"' sh "$1" } run_contract() { local database="$1" local case_name="$2" local agent_id="$3" "${compose[@]}" run --rm --no-deps \ --volume "${repo_root}/backend/tests:/app/tests:ro" \ --env POSTGRES_DB="${database}" \ --env MINEROPS_LEGACY_RETIREMENT_DISPOSABLE=1 \ --env MINEROPS_LEGACY_RETIREMENT_CASE="${case_name}" \ --env MINEROPS_AGENT_ID="${agent_id}" \ --env MINEROPS_AGENT_SHARED_SECRET=legacy-retirement-contract-secret \ backend python -m unittest -v \ tests.test_agent_legacy_auth_retirement_postgres } [[ -f .env.dev ]] || { echo "Missing .env.dev" >&2; exit 1; } "${compose[@]}" up --detach postgres for attempt in $(seq 1 60); do "${compose[@]}" exec -T postgres sh -ec \ 'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"' >/dev/null 2>&1 && break (( attempt < 60 )) || { echo "PostgreSQL did not become ready" >&2; exit 1; } sleep 1 done "${compose[@]}" build backend expected_head="$(run_db_alembic postgres heads 2>/dev/null | awk 'NR == 1 { print $1 }')" [[ "${expected_head}" == "0020_existing_agent_transition" ]] echo "Testing selective 0019 backfill from the 0018 schema..." create_database legacy_retirement_uncredentialed run_db_alembic legacy_retirement_uncredentialed upgrade 0018_legacy_agent_routing psql_named legacy_retirement_uncredentialed -c \ "INSERT INTO minerops_site_agents (agent_id, site_name) VALUES ('legacy-uncredentialed', 'Legacy')" run_db_alembic legacy_retirement_uncredentialed upgrade head [[ "$(psql_named legacy_retirement_uncredentialed -Atc "SELECT legacy_auth_disabled_at IS NULL FROM minerops_site_agents WHERE agent_id='legacy-uncredentialed'")" == "t" ]] [[ "$(psql_named legacy_retirement_uncredentialed -Atc "SELECT count(*) FROM agent_legacy_auth_retirements WHERE agent_id='legacy-uncredentialed'")" == "0" ]] create_database legacy_retirement_credentialed run_db_alembic legacy_retirement_credentialed upgrade 0018_legacy_agent_routing psql_named legacy_retirement_credentialed <<'SQL' INSERT INTO minerops_site_agents ( agent_id, site_name, agent_secret_hash, credential_created_at, credential_revoked_at ) VALUES ( 'legacy-credentialed', 'Legacy', repeat('a', 64), now() - interval '1 hour', now() ); SQL run_db_alembic legacy_retirement_credentialed upgrade head [[ "$(psql_named legacy_retirement_credentialed -Atc "SELECT legacy_auth_disabled_at = credential_created_at FROM minerops_site_agents WHERE agent_id='legacy-credentialed'")" == "t" ]] [[ "$(psql_named legacy_retirement_credentialed -Atc "SELECT retired_at = (SELECT credential_created_at FROM minerops_site_agents WHERE agent_id='legacy-credentialed') FROM agent_legacy_auth_retirements WHERE agent_id='legacy-credentialed'")" == "t" ]] echo "Testing backfill from used enrollment history after credential clearing..." create_database legacy_retirement_enrollment run_db_alembic legacy_retirement_enrollment upgrade 0018_legacy_agent_routing psql_named legacy_retirement_enrollment <<'SQL' INSERT INTO sites (id, name) VALUES ('00000000-0000-4000-8000-000000001901', 'Enrollment Evidence'); INSERT INTO agent_zones (id, site_id, name) VALUES ( '00000000-0000-4000-8000-000000001902', '00000000-0000-4000-8000-000000001901', 'Enrollment Evidence Zone' ); INSERT INTO minerops_site_agents ( agent_id, site_name, site_id, agent_zone_id ) VALUES ( 'enrollment-evidence-cleared', 'Enrollment Evidence', '00000000-0000-4000-8000-000000001901', '00000000-0000-4000-8000-000000001902' ); INSERT INTO agent_enrollments ( token_hash, site_id, agent_zone_id, display_name, created_at, expires_at, used_at, enrolled_agent_id ) VALUES ( repeat('c', 64), '00000000-0000-4000-8000-000000001901', '00000000-0000-4000-8000-000000001902', 'Enrollment Evidence Agent', now() - interval '2 hours', now() + interval '1 hour', now() - interval '1 hour', 'enrollment-evidence-cleared' ); SQL run_db_alembic legacy_retirement_enrollment upgrade head [[ "$(psql_named legacy_retirement_enrollment -Atc "SELECT count(*) FROM agent_legacy_auth_retirements WHERE agent_id='enrollment-evidence-cleared'")" == "1" ]] [[ "$(psql_named legacy_retirement_enrollment -Atc "SELECT legacy_auth_disabled_at IS NOT NULL AND agent_secret_hash IS NULL AND credential_created_at IS NULL AND credential_revoked_at IS NULL FROM minerops_site_agents WHERE agent_id='enrollment-evidence-cleared'")" == "t" ]] echo "Testing real PostgreSQL authentication before and after credential clearing..." run_contract legacy_retirement_uncredentialed legacy legacy-uncredentialed run_contract legacy_retirement_credentialed retired legacy-credentialed echo "Testing database-enforced atomic retirement and ledger immutability..." psql_named legacy_retirement_credentialed -c \ "INSERT INTO minerops_site_agents (agent_id, site_name, agent_secret_hash, credential_created_at) VALUES ('database-issued', 'Issued', repeat('b', 64), now())" [[ "$(psql_named legacy_retirement_credentialed -Atc "SELECT count(*) FROM agent_legacy_auth_retirements WHERE agent_id='database-issued'")" == "1" ]] [[ "$(psql_named legacy_retirement_credentialed -Atc "SELECT legacy_auth_disabled_at IS NOT NULL FROM minerops_site_agents WHERE agent_id='database-issued'")" == "t" ]] if psql_named legacy_retirement_credentialed -c \ "UPDATE minerops_site_agents SET legacy_auth_disabled_at = NULL WHERE agent_id='legacy-credentialed'"; then echo "Permanent retirement marker was unexpectedly cleared" >&2 exit 1 fi if psql_named legacy_retirement_credentialed -c \ "UPDATE agent_legacy_auth_retirements SET retired_at = now() WHERE agent_id='legacy-credentialed'"; then echo "Retirement history was unexpectedly updated" >&2 exit 1 fi if psql_named legacy_retirement_credentialed -c \ "DELETE FROM agent_legacy_auth_retirements WHERE agent_id='legacy-credentialed'"; then echo "Retirement history was unexpectedly deleted" >&2 exit 1 fi if psql_named legacy_retirement_credentialed -c \ "TRUNCATE agent_legacy_auth_retirements"; then echo "Retirement history was unexpectedly truncated" >&2 exit 1 fi echo "Testing downgrade decision points..." run_db_alembic legacy_retirement_uncredentialed downgrade 0018_legacy_agent_routing [[ "$(psql_named legacy_retirement_uncredentialed -Atc 'SELECT version_num FROM alembic_version')" == "0018_legacy_agent_routing" ]] if output="$(run_db_alembic legacy_retirement_credentialed downgrade 0018_legacy_agent_routing 2>&1)"; then echo "0019 downgrade unexpectedly discarded retirement history" >&2 exit 1 fi [[ "${output}" == *"durable identity-level legacy-auth retirement history exists"* ]] [[ "$(psql_named legacy_retirement_credentialed -Atc 'SELECT version_num FROM alembic_version')" == "${expected_head}" ]] echo "Durable legacy Agent authentication retirement checks passed."