|
| 1 | +{ |
| 2 | + writeShellApplication, |
| 3 | + coreutils, |
| 4 | + gnused, |
| 5 | + supabase-cli, |
| 6 | + yq, |
| 7 | + postgresql_15, |
| 8 | +}: |
| 9 | +writeShellApplication { |
| 10 | + name = "cli-smoke-test"; |
| 11 | + runtimeInputs = [ |
| 12 | + coreutils |
| 13 | + gnused |
| 14 | + supabase-cli |
| 15 | + yq |
| 16 | + postgresql_15 |
| 17 | + ]; |
| 18 | + text = '' |
| 19 | + # CLI Smoke Test - Tests Supabase CLI with locally built Docker images |
| 20 | + # |
| 21 | + # Usage: |
| 22 | + # nix run .#cli-smoke-test -- 17 |
| 23 | + # nix run .#cli-smoke-test -- --no-build 15 |
| 24 | + # nix run .#cli-smoke-test -- --debug 17 # Full debug output (local only) |
| 25 | +
|
| 26 | + set -euo pipefail |
| 27 | +
|
| 28 | + REPO_ROOT="$(pwd)" |
| 29 | + PG_VERSION="" |
| 30 | + SKIP_BUILD=false |
| 31 | + DEBUG_MODE=false |
| 32 | + WORK_DIR="" |
| 33 | +
|
| 34 | + RED='\033[0;31m' |
| 35 | + GREEN='\033[0;32m' |
| 36 | + YELLOW='\033[1;33m' |
| 37 | + NC='\033[0m' |
| 38 | +
|
| 39 | + log_info() { echo -e "''${GREEN}[INFO]''${NC} $1"; } |
| 40 | + log_warn() { echo -e "''${YELLOW}[WARN]''${NC} $1"; } |
| 41 | + log_error() { echo -e "''${RED}[ERROR]''${NC} $1"; } |
| 42 | +
|
| 43 | + print_help() { |
| 44 | + cat << 'EOF' |
| 45 | + Usage: nix run .#cli-smoke-test -- [OPTIONS] PG_VERSION |
| 46 | +
|
| 47 | + Run Supabase CLI smoke tests with a locally built PostgreSQL Docker image. |
| 48 | +
|
| 49 | + Arguments: |
| 50 | + PG_VERSION PostgreSQL version to test (15 or 17) |
| 51 | +
|
| 52 | + Options: |
| 53 | + -h, --help Show this help message |
| 54 | + --no-build Skip building the image (use existing supabase/postgres:<version>) |
| 55 | + --debug Enable debug output (includes credentials - local use only!) |
| 56 | +
|
| 57 | + Examples: |
| 58 | + nix run .#cli-smoke-test -- 17 |
| 59 | + nix run .#cli-smoke-test -- 15 |
| 60 | + nix run .#cli-smoke-test -- --no-build 17 |
| 61 | + nix run .#cli-smoke-test -- --debug 17 |
| 62 | + EOF |
| 63 | + } |
| 64 | +
|
| 65 | + cleanup() { |
| 66 | + local exit_code=$? |
| 67 | + log_info "Cleaning up..." |
| 68 | + supabase stop --no-backup 2>/dev/null || true |
| 69 | + if [[ -n "$WORK_DIR" ]] && [[ -d "$WORK_DIR" ]]; then |
| 70 | + rm -rf "$WORK_DIR" |
| 71 | + fi |
| 72 | + exit $exit_code |
| 73 | + } |
| 74 | +
|
| 75 | + trap cleanup EXIT |
| 76 | +
|
| 77 | + main() { |
| 78 | + while [[ $# -gt 0 ]]; do |
| 79 | + case "$1" in |
| 80 | + -h|--help) print_help; exit 0 ;; |
| 81 | + --no-build) SKIP_BUILD=true; shift ;; |
| 82 | + --debug) DEBUG_MODE=true; shift ;; |
| 83 | + -*) log_error "Unknown option: $1"; print_help; exit 1 ;; |
| 84 | + *) PG_VERSION="$1"; shift ;; |
| 85 | + esac |
| 86 | + done |
| 87 | +
|
| 88 | + if [[ -z "$PG_VERSION" ]]; then |
| 89 | + log_error "PostgreSQL version required (15 or 17)" |
| 90 | + print_help |
| 91 | + exit 1 |
| 92 | + fi |
| 93 | +
|
| 94 | + if [[ "$PG_VERSION" != "15" && "$PG_VERSION" != "17" ]]; then |
| 95 | + log_error "Invalid PostgreSQL version: $PG_VERSION (must be 15 or 17)" |
| 96 | + exit 1 |
| 97 | + fi |
| 98 | +
|
| 99 | + DOCKERFILE="Dockerfile-$PG_VERSION" |
| 100 | + # CLI uses public.ecr.aws/supabase/postgres as base image |
| 101 | + IMAGE_NAME="public.ecr.aws/supabase/postgres:$PG_VERSION" |
| 102 | +
|
| 103 | + if [[ ! -f "$REPO_ROOT/$DOCKERFILE" ]]; then |
| 104 | + log_error "Dockerfile not found: $REPO_ROOT/$DOCKERFILE" |
| 105 | + log_error "Make sure you're running from the postgres repository root" |
| 106 | + exit 1 |
| 107 | + fi |
| 108 | +
|
| 109 | + if [[ ! -f "$REPO_ROOT/ansible/vars.yml" ]]; then |
| 110 | + log_error "ansible/vars.yml not found" |
| 111 | + log_error "Make sure you're running from the postgres repository root" |
| 112 | + exit 1 |
| 113 | + fi |
| 114 | +
|
| 115 | + log_info "CLI Smoke Test for PostgreSQL $PG_VERSION" |
| 116 | +
|
| 117 | + # Build Docker image |
| 118 | + if [[ "$SKIP_BUILD" != "true" ]]; then |
| 119 | + log_info "Building Docker image from $DOCKERFILE..." |
| 120 | + if ! docker build -f "$REPO_ROOT/$DOCKERFILE" -t "$IMAGE_NAME" "$REPO_ROOT"; then |
| 121 | + log_error "Failed to build Docker image" |
| 122 | + exit 1 |
| 123 | + fi |
| 124 | + else |
| 125 | + log_info "Skipping build (--no-build)" |
| 126 | + if ! docker image inspect "$IMAGE_NAME" &>/dev/null; then |
| 127 | + log_error "Image $IMAGE_NAME not found. Run without --no-build first." |
| 128 | + exit 1 |
| 129 | + fi |
| 130 | + fi |
| 131 | +
|
| 132 | + # Get component versions from ansible/vars.yml |
| 133 | + log_info "Reading component versions from ansible/vars.yml..." |
| 134 | + REST_VERSION=$(yq -r '.postgrest_release' "$REPO_ROOT/ansible/vars.yml") |
| 135 | + AUTH_VERSION=$(yq -r '.gotrue_release' "$REPO_ROOT/ansible/vars.yml") |
| 136 | + PG_RELEASE=$(yq -r ".postgres_release[\"postgres$PG_VERSION\"]" "$REPO_ROOT/ansible/vars.yml") |
| 137 | +
|
| 138 | + log_info " PostgREST: $REST_VERSION" |
| 139 | + log_info " GoTrue: $AUTH_VERSION" |
| 140 | + log_info " Postgres: $PG_RELEASE" |
| 141 | +
|
| 142 | + # Create working directory |
| 143 | + WORK_DIR=$(mktemp -d) |
| 144 | + log_info "Working directory: $WORK_DIR" |
| 145 | + cd "$WORK_DIR" |
| 146 | +
|
| 147 | + # Prepare Supabase CLI config |
| 148 | + mkdir -p supabase/.temp |
| 149 | +
|
| 150 | + # Set component versions - CLI reads these to determine which images to use |
| 151 | + echo "v$REST_VERSION" > supabase/.temp/rest-version |
| 152 | + echo "v$AUTH_VERSION" > supabase/.temp/gotrue-version |
| 153 | + # Use major version so CLI constructs supabase/postgres:$PG_VERSION (our local build) |
| 154 | + echo "$PG_VERSION" > supabase/.temp/postgres-version |
| 155 | +
|
| 156 | + cat > supabase/config.toml << EOF |
| 157 | + [db] |
| 158 | + major_version = $PG_VERSION |
| 159 | + EOF |
| 160 | +
|
| 161 | + log_info "Starting Supabase..." |
| 162 | + if [[ "$DEBUG_MODE" == "true" ]]; then |
| 163 | + # Debug mode: full output including credentials (local use only) |
| 164 | + if ! supabase start --debug; then |
| 165 | + log_error "Failed to start Supabase" |
| 166 | + exit 1 |
| 167 | + fi |
| 168 | + else |
| 169 | + # CI mode: redact credentials from output |
| 170 | + SUPABASE_OUTPUT=$(mktemp) |
| 171 | + SUPABASE_EXIT=0 |
| 172 | + supabase start > "$SUPABASE_OUTPUT" 2>&1 || SUPABASE_EXIT=$? |
| 173 | +
|
| 174 | + # Redact sensitive information before displaying |
| 175 | + sed -E \ |
| 176 | + -e 's/(Secret[[:space:]]*\│[[:space:]]*)[^│]*/\1[REDACTED]/g' \ |
| 177 | + -e 's/(Publishable[[:space:]]*\│[[:space:]]*)[^│]*/\1[REDACTED]/g' \ |
| 178 | + -e 's/(Access Key[[:space:]]*\│[[:space:]]*)[^│]*/\1[REDACTED]/g' \ |
| 179 | + -e 's/(Secret Key[[:space:]]*\│[[:space:]]*)[^│]*/\1[REDACTED]/g' \ |
| 180 | + -e 's/postgres:postgres@/postgres:[REDACTED]@/g' \ |
| 181 | + -e 's/sb_secret_[A-Za-z0-9_-]*/sb_secret_[REDACTED]/g' \ |
| 182 | + -e 's/sb_publishable_[A-Za-z0-9_-]*/sb_publishable_[REDACTED]/g' \ |
| 183 | + -e 's/"Data":"[^"]*"/"Data":"[REDACTED]"/g' \ |
| 184 | + -e 's/"SecretKey":[0-9]*/"SecretKey":[REDACTED]/g' \ |
| 185 | + -e 's/[a-f0-9]{32,64}/[REDACTED]/g' \ |
| 186 | + "$SUPABASE_OUTPUT" |
| 187 | +
|
| 188 | + rm -f "$SUPABASE_OUTPUT" |
| 189 | +
|
| 190 | + if [[ $SUPABASE_EXIT -ne 0 ]]; then |
| 191 | + log_error "Failed to start Supabase" |
| 192 | + exit 1 |
| 193 | + fi |
| 194 | + fi |
| 195 | +
|
| 196 | + log_info "Verifying database connection..." |
| 197 | + if ! PGPASSWORD=postgres psql -h localhost -p 54322 -U postgres -d postgres -c "SELECT version();" ; then |
| 198 | + log_error "Failed to connect to database" |
| 199 | + exit 1 |
| 200 | + fi |
| 201 | +
|
| 202 | + log_info "Running health checks..." |
| 203 | + PGPASSWORD=postgres psql -h localhost -p 54322 -U postgres -d postgres << 'EOSQL' |
| 204 | + -- Check extensions schema exists |
| 205 | + SELECT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'extensions'); |
| 206 | +
|
| 207 | + -- Check some key extensions |
| 208 | + SELECT extname, extversion FROM pg_extension WHERE extname IN ('uuid-ossp', 'pgcrypto', 'pgjwt') ORDER BY extname; |
| 209 | +
|
| 210 | + -- Basic table creation test |
| 211 | + CREATE TABLE IF NOT EXISTS smoke_test (id serial primary key, created_at timestamptz default now()); |
| 212 | + INSERT INTO smoke_test DEFAULT VALUES; |
| 213 | + SELECT * FROM smoke_test; |
| 214 | + DROP TABLE smoke_test; |
| 215 | + EOSQL |
| 216 | +
|
| 217 | + log_info "''${GREEN}CLI Smoke Test PASSED for PostgreSQL $PG_VERSION''${NC}" |
| 218 | + } |
| 219 | +
|
| 220 | + main "$@" |
| 221 | + ''; |
| 222 | +} |
0 commit comments