Fix: allow safe update for postgres user #591
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CLI Release | |
| on: | |
| push: | |
| tags: | |
| - "v*-cli" | |
| pull_request: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version tag (e.g., v1.0.0-cli)" | |
| required: true | |
| type: string | |
| jobs: | |
| build-native: | |
| name: Build ${{ matrix.arch }} | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - system: aarch64-darwin | |
| runner: macos-14 | |
| arch: darwin-arm64 | |
| - system: x86_64-linux | |
| runner: ubuntu-latest | |
| arch: linux-x64 | |
| - system: aarch64-linux | |
| runner: ubuntu-24.04-arm | |
| arch: linux-arm64 | |
| steps: | |
| - name: Checkout repository | |
| uses: supabase/postgres/.github/actions/shared-checkout@HEAD | |
| - name: Install Nix | |
| uses: ./.github/actions/nix-install-ephemeral | |
| - name: Run portability check | |
| run: | | |
| nix build .#checks.${{ matrix.system }}.psql_17_cli_portable --system ${{ matrix.system }} -L --accept-flake-config | |
| - name: Build portable CLI bundle | |
| run: | | |
| nix build .#psql_17_cli_portable --system ${{ matrix.system }} -L --accept-flake-config | |
| - name: Determine version | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| else | |
| VERSION="${{ github.ref_name }}" | |
| fi | |
| # Sanitize version by replacing slashes with dashes | |
| VERSION="${VERSION//\//-}" | |
| echo "version=${VERSION}" >> "$GITHUB_OUTPUT" | |
| - name: Prepare build directory | |
| run: | | |
| VERSION="${{ steps.version.outputs.version }}" | |
| ARCH="${{ matrix.arch }}" | |
| BUILD_DIR="supabase-postgres-${VERSION}-${ARCH}" | |
| mkdir -p "${BUILD_DIR}" | |
| shopt -s dotglob | |
| cp -rL result/* "${BUILD_DIR}/" | |
| shopt -u dotglob | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: supabase-postgres-${{ matrix.arch }} | |
| path: supabase-postgres-${{ steps.version.outputs.version }}-${{ matrix.arch }} | |
| retention-days: 90 | |
| include-hidden-files: true | |
| test-portability: | |
| name: ${{ matrix.arch }} without Nix | |
| needs: [build-native] | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runner: macos-14 | |
| arch: darwin-arm64 | |
| - runner: ubuntu-latest | |
| arch: linux-x64 | |
| - runner: ubuntu-24.04-arm | |
| arch: linux-arm64 | |
| steps: | |
| - name: Download artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: supabase-postgres-${{ matrix.arch }} | |
| path: . | |
| - name: Test binaries work without Nix | |
| run: | | |
| cd bin | |
| find . -maxdepth 1 -type f -exec chmod +x {} + | |
| ls -la | |
| echo "Testing postgres --version..." | |
| ./postgres --version | |
| echo "Testing pg_config --version..." | |
| ./pg_config --version | |
| echo "Testing psql --version..." | |
| ./psql --version | |
| echo "Testing initdb --version..." | |
| ./initdb --version | |
| - name: Test initialization script | |
| run: | | |
| set -e | |
| echo "==========================================" | |
| echo "Testing supabase-postgres-init.sh" | |
| echo "==========================================" | |
| # Make init script executable | |
| chmod +x ./share/supabase-cli/bin/supabase-postgres-init.sh | |
| # Test 1: Initialize database with init script | |
| export PGDATA="$(pwd)/pgdata-init-test" | |
| export POSTGRES_USER="test_user" | |
| export POSTGRES_PASSWORD="test_password" | |
| export POSTGRES_DB="test_db" | |
| echo "Starting PostgreSQL with init script..." | |
| ./share/supabase-cli/bin/supabase-postgres-init.sh -p 54321 > init.log 2>&1 & | |
| INIT_PID=$! | |
| # Wait for PostgreSQL to be ready | |
| for i in {1..30}; do | |
| if ./bin/pg_isready -p 54321 -h 127.0.0.1 -U test_user > /dev/null 2>&1; then | |
| echo "PostgreSQL is ready" | |
| break | |
| fi | |
| if [ $i -eq 30 ]; then | |
| echo "PostgreSQL failed to start" | |
| cat init.log | |
| exit 1 | |
| fi | |
| sleep 1 | |
| done | |
| echo "" | |
| echo "==========================================" | |
| echo "Testing password authentication" | |
| echo "==========================================" | |
| # Test password authentication (should work with scram-sha-256) | |
| PGPASSWORD="test_password" ./bin/psql -p 54321 -h 127.0.0.1 -U test_user -d test_db -c "SELECT version();" > /dev/null | |
| if [ $? -eq 0 ]; then | |
| echo "✓ Password authentication successful" | |
| else | |
| echo "✗ Password authentication failed" | |
| exit 1 | |
| fi | |
| # Test wrong password (should fail) - temporarily disable set -e | |
| set +e | |
| PGPASSWORD="wrong_password" ./bin/psql -p 54321 -h 127.0.0.1 -U test_user -d test_db -c "SELECT 1;" > /dev/null 2>&1 | |
| WRONG_PW_STATUS=$? | |
| set -e | |
| if [ $WRONG_PW_STATUS -ne 0 ]; then | |
| echo "✓ Wrong password correctly rejected" | |
| else | |
| echo "✗ Wrong password was accepted (security issue!)" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "==========================================" | |
| echo "Testing database initialization" | |
| echo "==========================================" | |
| # Verify database exists | |
| PGPASSWORD="test_password" ./bin/psql -p 54321 -h 127.0.0.1 -U test_user -d test_db -v ON_ERROR_STOP=1 -c "SELECT current_database();" | grep "test_db" | |
| if [ $? -eq 0 ]; then | |
| echo "✓ Custom database created" | |
| else | |
| echo "✗ Custom database not found" | |
| exit 1 | |
| fi | |
| # Verify configuration files were set up | |
| if [ -f "$PGDATA/postgresql.conf" ] && [ -f "$PGDATA/pg_hba.conf" ]; then | |
| echo "✓ Configuration files created" | |
| else | |
| echo "✗ Configuration files missing" | |
| exit 1 | |
| fi | |
| # Verify pgsodium/vault getkey scripts are configured | |
| if grep -q "pgsodium.getkey_script" "$PGDATA/postgresql.conf" && grep -q "vault.getkey_script" "$PGDATA/postgresql.conf"; then | |
| echo "✓ Getkey scripts configured" | |
| else | |
| echo "✗ Getkey scripts not configured" | |
| exit 1 | |
| fi | |
| echo "" | |
| echo "==========================================" | |
| echo "Testing idempotency" | |
| echo "==========================================" | |
| # Stop PostgreSQL | |
| ./bin/pg_ctl -D "$PGDATA" stop -m fast | |
| wait $INIT_PID 2>/dev/null || true | |
| # Run init script again (should skip initialization) | |
| ./share/supabase-cli/bin/supabase-postgres-init.sh -p 54321 > init2.log 2>&1 & | |
| INIT_PID2=$! | |
| # Wait for PostgreSQL to be ready | |
| for i in {1..30}; do | |
| if ./bin/pg_isready -p 54321 -h 127.0.0.1 -U test_user > /dev/null 2>&1; then | |
| echo "PostgreSQL is ready after re-init" | |
| break | |
| fi | |
| if [ $i -eq 30 ]; then | |
| echo "PostgreSQL failed to start on second run" | |
| cat init2.log | |
| exit 1 | |
| fi | |
| sleep 1 | |
| done | |
| # Verify we can still connect with same password | |
| PGPASSWORD="test_password" ./bin/psql -p 54321 -h 127.0.0.1 -U test_user -d test_db -c "SELECT 1;" > /dev/null | |
| if [ $? -eq 0 ]; then | |
| echo "✓ Idempotency verified - database not re-initialized" | |
| else | |
| echo "✗ Failed to connect after re-running init script" | |
| exit 1 | |
| fi | |
| # Check log to verify it skipped initialization | |
| if grep -q "already initialized" init2.log; then | |
| echo "✓ Init script correctly detected existing database" | |
| else | |
| echo "⚠ Warning: Init script may have re-initialized (check init2.log)" | |
| fi | |
| # Stop PostgreSQL | |
| ./bin/pg_ctl -D "$PGDATA" stop -m fast | |
| wait $INIT_PID2 2>/dev/null || true | |
| echo "" | |
| echo "==========================================" | |
| echo "Init script tests completed successfully" | |
| echo "==========================================" | |
| echo "" | |
| - name: Test migrations with CLI variant | |
| run: | | |
| set -e | |
| # Use bundled pgsodium getkey script | |
| GETKEY_SCRIPT="$(pwd)/share/supabase-cli/config/pgsodium_getkey.sh" | |
| chmod +x "$GETKEY_SCRIPT" | |
| # Initialize test database | |
| PGDATA="$(pwd)/pgdata-test" | |
| ./bin/initdb -D "$PGDATA" -U supabase_admin --no-instructions | |
| # Copy CLI config and add pgsodium/vault getkey scripts | |
| cp share/supabase-cli/config/postgresql.conf.template "$PGDATA/postgresql.conf" | |
| cat >> "$PGDATA/postgresql.conf" << EOF | |
| # pgsodium and vault configuration for testing | |
| pgsodium.getkey_script = '$GETKEY_SCRIPT' | |
| vault.getkey_script = '$GETKEY_SCRIPT' | |
| EOF | |
| # Start PostgreSQL | |
| ./bin/postgres -D "$PGDATA" -p 54322 > postgres.log 2>&1 & | |
| PG_PID=$! | |
| # Wait for PostgreSQL to be ready | |
| for i in {1..30}; do | |
| if ./bin/pg_isready -p 54322 -h 127.0.0.1 -U supabase_admin > /dev/null 2>&1; then | |
| echo "PostgreSQL is ready" | |
| break | |
| fi | |
| if [ $i -eq 30 ]; then | |
| echo "PostgreSQL failed to start" | |
| cat postgres.log | |
| exit 1 | |
| fi | |
| sleep 1 | |
| done | |
| # Run migrations | |
| cd share/supabase-cli/migrations | |
| chmod +x migrate.sh | |
| echo "==========================================" | |
| echo "Running migrations..." | |
| echo "==========================================" | |
| PATH="$(pwd)/../../../bin:$PATH" \ | |
| POSTGRES_PASSWORD=postgres \ | |
| POSTGRES_PORT=54322 \ | |
| POSTGRES_DB=postgres \ | |
| POSTGRES_USER=supabase_admin \ | |
| ./migrate.sh 2>&1 | tee migration.log | |
| MIGRATION_STATUS=${PIPESTATUS[0]} | |
| echo "" | |
| echo "==========================================" | |
| echo "Migration output complete" | |
| echo "==========================================" | |
| # Check migration results - all migrations must succeed | |
| if [ $MIGRATION_STATUS -ne 0 ]; then | |
| echo "Migrations failed" | |
| cat migration.log | |
| exit 1 | |
| fi | |
| echo "All migrations applied successfully" | |
| # Verify extensions are installed | |
| cd ../../.. | |
| ./bin/psql -p 54322 -h 127.0.0.1 -U supabase_admin -d postgres -v ON_ERROR_STOP=1 -c "\dx" | tee extensions.log | |
| # Check for required extensions | |
| for ext in pg_graphql pgcrypto uuid-ossp supabase_vault; do | |
| if ! grep -q "$ext" extensions.log; then | |
| echo "Required extension $ext not found" | |
| exit 1 | |
| fi | |
| done | |
| echo "" | |
| echo "==========================================" | |
| echo "Testing timezone functionality with bundled timezone data" | |
| echo "==========================================" | |
| cat > timezone_test.sql << 'EOF' | |
| -- Test basic timezone conversion | |
| SELECT now() AT TIME ZONE 'America/New_York' AS ny_time; | |
| SELECT now() AT TIME ZONE 'Europe/London' AS london_time; | |
| SELECT now() AT TIME ZONE 'Asia/Tokyo' AS tokyo_time; | |
| -- Verify timezone database is accessible | |
| SELECT COUNT(*) AS timezone_count FROM pg_timezone_names; | |
| -- Test that we have reasonable number of timezones (should be 500+) | |
| DO $$ | |
| DECLARE | |
| tz_count INTEGER; | |
| BEGIN | |
| SELECT COUNT(*) INTO tz_count FROM pg_timezone_names; | |
| IF tz_count < 500 THEN | |
| RAISE EXCEPTION 'Insufficient timezones: found %, expected 500+', tz_count; | |
| END IF; | |
| RAISE NOTICE 'Timezone test passed: found % timezones', tz_count; | |
| END $$; | |
| -- Show current timezone setting | |
| SHOW timezone; | |
| EOF | |
| # Run timezone tests from file | |
| ./bin/psql -p 54322 -h 127.0.0.1 -U supabase_admin -d postgres -v ON_ERROR_STOP=1 -f timezone_test.sql | tee timezone.log | |
| TIMEZONE_STATUS=${PIPESTATUS[0]} | |
| if [ $TIMEZONE_STATUS -ne 0 ]; then | |
| echo "Timezone tests failed" | |
| cat timezone.log | |
| exit 1 | |
| fi | |
| echo "Timezone tests passed successfully" | |
| echo "" | |
| # Stop PostgreSQL | |
| ./bin/pg_ctl -D "$PGDATA" stop -m fast | |
| echo "Migration test completed successfully" | |
| release: | |
| name: Create GitHub Release | |
| needs: [build-native, test-portability] | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p release temp | |
| # Determine version | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ github.event.inputs.version }}" | |
| else | |
| VERSION="${{ github.ref_name }}" | |
| fi | |
| VERSION="${VERSION//\//-}" | |
| # Create tarballs from each artifact directory | |
| for dir in artifacts/*; do | |
| if [ -d "$dir" ]; then | |
| ARTIFACT_NAME=$(basename "$dir") | |
| # Extract arch from artifact name (e.g., "supabase-postgres-darwin-arm64" -> "darwin-arm64") | |
| ARCH="${ARTIFACT_NAME#supabase-postgres-}" | |
| BUILD_DIR="supabase-postgres-${VERSION}-${ARCH}" | |
| echo "Creating tarball for ${BUILD_DIR}..." | |
| # Create temp directory with proper structure | |
| mkdir -p "temp/${BUILD_DIR}" | |
| cp -r "$dir"/* "temp/${BUILD_DIR}/" | |
| # Create tarball with directory structure | |
| tar -czhf "release/${BUILD_DIR}.tar.gz" -C temp "${BUILD_DIR}" | |
| # Generate checksum | |
| sha256sum "release/${BUILD_DIR}.tar.gz" > "release/${BUILD_DIR}.tar.gz.sha256" | |
| # Cleanup temp directory for this artifact | |
| rm -rf "temp/${BUILD_DIR}" | |
| echo "✓ Created release/${BUILD_DIR}.tar.gz" | |
| fi | |
| done | |
| ls -lh release/ | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: release/* | |
| generate_release_notes: true |