Repository: supabase/cli
Pull request #1961 (2024-02-19 08:16:56)

fix: always treat db-url flag as remote database
## What kind of change does this PR introduce?

Bug fix https://github.com/supabase/cli/issues/1956

## What is the new behavior?

If user specifies `--db-url` flag, always treat it as a remote database.

## Additional context

Add any other context or screenshots.



Patch:
diff --git a/internal/db/push/push.go b/internal/db/push/push.go
index a640e907..90680985 100644
--- a/internal/db/push/push.go
+++ b/internal/db/push/push.go
@@ -35,7 +35,7 @@ func Run(ctx context.Context, dryRun, ignoreVersionMismatch bool, includeRoles,
 		return err
 	}
 	if len(pending) == 0 {
-		fmt.Println("Linked project is up to date.")
+		fmt.Println("Remote database is up to date.")
 		return nil
 	}
 	// Push pending migrations
diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go
index 8d217089..8c60dd1e 100644
--- a/internal/db/reset/reset.go
+++ b/internal/db/reset/reset.go
@@ -50,21 +50,16 @@ func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.F
 			return err
 		}
 	}
-	if !utils.IsLoopback(config.Host) {
+	if !utils.IsLocalDatabase(config) {
 		if shouldReset := utils.PromptYesNo("Confirm resetting the remote database?", true, os.Stdin); !shouldReset {
 			return errors.New(context.Canceled)
 		}
 		return resetRemote(ctx, version, config, fsys, options...)
 	}
 
-	// Sanity checks.
-	{
-		if err := utils.LoadConfigFS(fsys); err != nil {
-			return err
-		}
-		if err := utils.AssertSupabaseDbIsRunning(); err != nil {
-			return err
-		}
+	// Config file is loaded before parsing --linked or --local flags
+	if err := utils.AssertSupabaseDbIsRunning(); err != nil {
+		return err
 	}
 
 	// Reset postgres database because extensions (pg_cron, pg_net) require postgres
diff --git a/internal/migration/list/list.go b/internal/migration/list/list.go
index d9de5327..d14c0ec3 100644
--- a/internal/migration/list/list.go
+++ b/internal/migration/list/list.go
@@ -140,11 +140,8 @@ func LoadLocalMigrations(fsys afero.Fs) ([]string, error) {
 }
 
 func LoadPartialMigrations(version string, fsys afero.Fs) ([]string, error) {
-	if err := utils.MkdirIfNotExistFS(fsys, utils.MigrationsDir); err != nil {
-		return nil, err
-	}
 	localMigrations, err := afero.ReadDir(fsys, utils.MigrationsDir)
-	if err != nil {
+	if err != nil && !errors.Is(err, os.ErrNotExist) {
 		return nil, errors.Errorf("failed to read directory: %w", err)
 	}
 	var names []string
diff --git a/internal/migration/squash/squash.go b/internal/migration/squash/squash.go
index fa9259b9..86eb5089 100644
--- a/internal/migration/squash/squash.go
+++ b/internal/migration/squash/squash.go
@@ -38,7 +38,7 @@ func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.F
 		return err
 	}
 	// 2. Update migration history
-	if utils.IsLoopback(config.Host) || !utils.PromptYesNo("Update remote migration history table?", true, os.Stdin) {
+	if utils.IsLocalDatabase(config) || !utils.PromptYesNo("Update remote migration history table?", true, os.Stdin) {
 		return nil
 	}
 	return baselineMigrations(ctx, config, version, fsys, options...)
diff --git a/internal/migration/up/up.go b/internal/migration/up/up.go
index 2f1619d9..53c08dfb 100644
--- a/internal/migration/up/up.go
+++ b/internal/migration/up/up.go
@@ -20,9 +20,6 @@ var (
 )
 
 func Run(ctx context.Context, includeAll bool, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
-	if err := utils.LoadConfigFS(fsys); err != nil {
-		return err
-	}
 	conn, err := utils.ConnectByConfig(ctx, config, options...)
 	if err != nil {
 		return err
diff --git a/internal/utils/connect.go b/internal/utils/connect.go
index 2117011d..5f738928 100644
--- a/internal/utils/connect.go
+++ b/internal/utils/connect.go
@@ -158,7 +158,7 @@ func ConnectByUrl(ctx context.Context, url string, options ...func(*pgx.ConnConf
 }
 
 func ConnectByConfig(ctx context.Context, config pgconn.Config, options ...func(*pgx.ConnConfig)) (*pgx.Conn, error) {
-	if IsLoopback(config.Host) {
+	if IsLocalDatabase(config) {
 		fmt.Fprintln(os.Stderr, "Connecting to local database...")
 		return ConnectLocalPostgres(ctx, config, options...)
 	}
@@ -166,12 +166,6 @@ func ConnectByConfig(ctx context.Context, config pgconn.Config, options ...func(
 	return ConnectRemotePostgres(ctx, config, options...)
 }
 
-func IsLoopback(host string) bool {
-	if strings.ToLower(host) == "localhost" {
-		return true
-	}
-	if ip := net.ParseIP(host); ip != nil {
-		return ip.IsLoopback()
-	}
-	return false
+func IsLocalDatabase(config pgconn.Config) bool {
+	return config.Host == Config.Hostname && config.Port == uint16(Config.Db.Port)
 }


Test patch:
diff --git a/internal/db/diff/diff_test.go b/internal/db/diff/diff_test.go
index 5ffb39f3..5c283e28 100644
--- a/internal/db/diff/diff_test.go
+++ b/internal/db/diff/diff_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/supabase/cli/internal/db/start"
 	"github.com/supabase/cli/internal/migration/history"
 	"github.com/supabase/cli/internal/testing/apitest"
+	"github.com/supabase/cli/internal/testing/fstest"
 	"github.com/supabase/cli/internal/testing/pgtest"
 	"github.com/supabase/cli/internal/utils"
 	"gopkg.in/h2non/gock.v1"
@@ -174,7 +175,7 @@ func TestMigrateShadow(t *testing.T) {
 
 	t.Run("throws error on permission denied", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Run test
 		err := MigrateShadowDatabase(context.Background(), "", fsys)
 		// Check error
diff --git a/internal/db/lint/lint_test.go b/internal/db/lint/lint_test.go
index cc00c307..3bb9f876 100644
--- a/internal/db/lint/lint_test.go
+++ b/internal/db/lint/lint_test.go
@@ -28,9 +28,10 @@ var dbConfig = pgconn.Config{
 }
 
 func TestLintCommand(t *testing.T) {
+	utils.Config.Hostname = "127.0.0.1"
+	utils.Config.Db.Port = 5432
 	// Setup in-memory fs
 	fsys := afero.NewMemMapFs()
-	require.NoError(t, utils.WriteConfig(fsys, false))
 	// Setup mock docker
 	require.NoError(t, apitest.MockDocker(utils.Docker))
 	defer gock.OffAll()
@@ -64,8 +65,9 @@ func TestLintCommand(t *testing.T) {
 		Reply("SELECT 1", []interface{}{"f1", string(data)}).
 		Query("rollback").Reply("ROLLBACK")
 	// Run test
-	assert.NoError(t, Run(context.Background(), []string{"public"}, "warning", dbConfig, fsys, conn.Intercept))
-	// Validate api
+	err = Run(context.Background(), []string{"public"}, "warning", dbConfig, fsys, conn.Intercept)
+	// Check error
+	assert.NoError(t, err)
 	assert.Empty(t, apitest.ListUnmatchedRequests())
 }
 
diff --git a/internal/db/pull/pull_test.go b/internal/db/pull/pull_test.go
index cfd06891..bc9ca39d 100644
--- a/internal/db/pull/pull_test.go
+++ b/internal/db/pull/pull_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/supabase/cli/internal/db/reset"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/testing/apitest"
+	"github.com/supabase/cli/internal/testing/fstest"
 	"github.com/supabase/cli/internal/testing/pgtest"
 	"github.com/supabase/cli/internal/utils"
 	"gopkg.in/h2non/gock.v1"
@@ -217,7 +218,7 @@ func TestPullSchema(t *testing.T) {
 func TestSyncRemote(t *testing.T) {
 	t.Run("throws error on permission denied", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
diff --git a/internal/db/reset/reset_test.go b/internal/db/reset/reset_test.go
index da0fd4d5..b66dee13 100644
--- a/internal/db/reset/reset_test.go
+++ b/internal/db/reset/reset_test.go
@@ -6,7 +6,6 @@ import (
 	"fmt"
 	"io"
 	"net/http"
-	"os"
 	"strings"
 	"testing"
 	"time"
@@ -25,9 +24,12 @@ import (
 )
 
 func TestResetCommand(t *testing.T) {
+	utils.Config.Hostname = "127.0.0.1"
+	utils.Config.Db.Port = 5432
+
 	var dbConfig = pgconn.Config{
-		Host:     "127.0.0.1",
-		Port:     5432,
+		Host:     utils.Config.Hostname,
+		Port:     uint16(utils.Config.Db.Port),
 		User:     "admin",
 		Password: "password",
 		Database: "postgres",
@@ -42,15 +44,9 @@ func TestResetCommand(t *testing.T) {
 		assert.ErrorContains(t, err, "invalid port (outside range)")
 	})
 
-	t.Run("throws error on missing config", func(t *testing.T) {
-		err := Run(context.Background(), "", dbConfig, afero.NewMemMapFs())
-		assert.ErrorIs(t, err, os.ErrNotExist)
-	})
-
 	t.Run("throws error on db is not started", func(t *testing.T) {
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
-		require.NoError(t, utils.WriteConfig(fsys, false))
 		// Setup mock docker
 		require.NoError(t, apitest.MockDocker(utils.Docker))
 		defer gock.OffAll()
@@ -65,18 +61,19 @@ func TestResetCommand(t *testing.T) {
 	})
 
 	t.Run("throws error on failure to recreate", func(t *testing.T) {
+		utils.DbId = "test-reset"
+		utils.Config.Db.MajorVersion = 15
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
-		require.NoError(t, utils.WriteConfig(fsys, false))
 		// Setup mock docker
 		require.NoError(t, apitest.MockDocker(utils.Docker))
 		defer gock.OffAll()
 		gock.New(utils.Docker.DaemonHost()).
-			Get("/v" + utils.Docker.ClientVersion() + "/containers").
+			Get("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId).
 			Reply(http.StatusOK).
 			JSON(types.ContainerJSON{})
 		gock.New(utils.Docker.DaemonHost()).
-			Delete("/v" + utils.Docker.ClientVersion() + "/containers").
+			Delete("/v" + utils.Docker.ClientVersion() + "/containers/" + utils.DbId).
 			ReplyError(errors.New("network error"))
 		// Run test
 		err := Run(context.Background(), "", dbConfig, fsys)
@@ -264,7 +261,7 @@ func TestRestartDatabase(t *testing.T) {
 	})
 
 	t.Run("throws error on db restart failure", func(t *testing.T) {
-		utils.DbId = "test-db"
+		utils.DbId = "test-reset"
 		// Setup mock docker
 		require.NoError(t, apitest.MockDocker(utils.Docker))
 		defer gock.OffAll()
diff --git a/internal/db/test/test.go b/internal/db/test/test.go
index 88b1b48e..2fb4e753 100644
--- a/internal/db/test/test.go
+++ b/internal/db/test/test.go
@@ -23,16 +23,7 @@ const (
 	DISABLE_PGTAP = "drop extension if exists pgtap"
 )
 
-func Run(ctx context.Context, testFiles []string, dbConfig pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
-	// Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
-		return err
-	}
-
-	return pgProve(ctx, testFiles, dbConfig, options...)
-}
-
-func pgProve(ctx context.Context, testFiles []string, config pgconn.Config, options ...func(*pgx.ConnConfig)) error {
+func Run(ctx context.Context, testFiles []string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
 	// Build test command
 	cmd := []string{"pg_prove", "--ext", ".pg", "--ext", ".sql", "-r"}
 	for _, fp := range testFiles {
@@ -76,7 +67,7 @@ func pgProve(ctx context.Context, testFiles []string, config pgconn.Config, opti
 	}
 	// Use custom network when connecting to local database
 	networkID := "host"
-	if utils.IsLoopback(config.Host) && config.Port == uint16(utils.Config.Db.Port) {
+	if utils.IsLocalDatabase(config) {
 		config.Host = utils.DbAliases[0]
 		config.Port = 5432
 		networkID = utils.NetId
diff --git a/internal/db/test/test_test.go b/internal/db/test/test_test.go
index be509911..a392d5a8 100644
--- a/internal/db/test/test_test.go
+++ b/internal/db/test/test_test.go
@@ -3,7 +3,6 @@ package test
 import (
 	"context"
 	"errors"
-	"os"
 	"testing"
 
 	"github.com/jackc/pgconn"
@@ -25,28 +24,60 @@ var dbConfig = pgconn.Config{
 	Database: "postgres",
 }
 
-func TestPgProve(t *testing.T) {
+func TestRunCommand(t *testing.T) {
+	t.Run("runs tests with pg_prove", func(t *testing.T) {
+		// Setup in-memory fs
+		fsys := afero.NewMemMapFs()
+		require.NoError(t, utils.WriteConfig(fsys, false))
+		// Setup mock postgres
+		conn := pgtest.NewConn()
+		defer conn.Close(t)
+		conn.Query(ENABLE_PGTAP).
+			Reply("CREATE EXTENSION").
+			Query(DISABLE_PGTAP).
+			Reply("DROP EXTENSION")
+		// Setup mock docker
+		require.NoError(t, apitest.MockDocker(utils.Docker))
+		defer gock.OffAll()
+		containerId := "test-pg-prove"
+		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.PgProveImage), containerId)
+		require.NoError(t, apitest.MockDockerLogs(utils.Docker, containerId, "Result: SUCCESS"))
+		// Run test
+		err := Run(context.Background(), []string{"nested"}, dbConfig, fsys, conn.Intercept)
+		// Check error
+		assert.NoError(t, err)
+	})
+
 	t.Run("throws error on connect failure", func(t *testing.T) {
+		// Setup in-memory fs
+		fsys := afero.NewMemMapFs()
+		require.NoError(t, utils.WriteConfig(fsys, false))
 		// Run test
-		err := pgProve(context.Background(), nil, dbConfig)
+		err := Run(context.Background(), nil, dbConfig, fsys)
 		// Check error
 		assert.ErrorContains(t, err, "failed to connect to postgres")
 	})
 
 	t.Run("throws error on pgtap failure", func(t *testing.T) {
+		// Setup in-memory fs
+		fsys := afero.NewMemMapFs()
+		require.NoError(t, utils.WriteConfig(fsys, false))
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
 		conn.Query(ENABLE_PGTAP).
 			ReplyError(pgerrcode.DuplicateObject, `extension "pgtap" already exists, skipping`)
 		// Run test
-		err := pgProve(context.Background(), nil, dbConfig, conn.Intercept)
+		err := Run(context.Background(), nil, dbConfig, fsys, conn.Intercept)
 		// Check error
 		assert.ErrorContains(t, err, "failed to enable pgTAP")
 	})
 
 	t.Run("throws error on network failure", func(t *testing.T) {
 		errNetwork := errors.New("network error")
+		// Setup in-memory fs
+		fsys := afero.NewMemMapFs()
+		require.NoError(t, utils.WriteConfig(fsys, false))
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
@@ -61,43 +92,9 @@ func TestPgProve(t *testing.T) {
 			Get("/v" + utils.Docker.ClientVersion() + "/images/" + utils.GetRegistryImageUrl(utils.PgProveImage) + "/json").
 			ReplyError(errNetwork)
 		// Run test
-		err := pgProve(context.Background(), nil, dbConfig, conn.Intercept)
+		err := Run(context.Background(), nil, dbConfig, fsys, conn.Intercept)
 		// Check error
 		assert.ErrorIs(t, err, errNetwork)
 		assert.Empty(t, apitest.ListUnmatchedRequests())
 	})
 }
-
-func TestRunCommand(t *testing.T) {
-	t.Run("runs tests with pg_prove", func(t *testing.T) {
-		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
-		require.NoError(t, utils.WriteConfig(fsys, false))
-		// Setup mock postgres
-		conn := pgtest.NewConn()
-		defer conn.Close(t)
-		conn.Query(ENABLE_PGTAP).
-			Reply("CREATE EXTENSION").
-			Query(DISABLE_PGTAP).
-			Reply("DROP EXTENSION")
-		// Setup mock docker
-		require.NoError(t, apitest.MockDocker(utils.Docker))
-		defer gock.OffAll()
-		containerId := "test-pg-prove"
-		apitest.MockDockerStart(utils.Docker, utils.GetRegistryImageUrl(utils.PgProveImage), containerId)
-		require.NoError(t, apitest.MockDockerLogs(utils.Docker, containerId, "Result: SUCCESS"))
-		// Run test
-		err := Run(context.Background(), []string{"nested"}, dbConfig, fsys, conn.Intercept)
-		// Check error
-		assert.NoError(t, err)
-	})
-
-	t.Run("throws error on missing config", func(t *testing.T) {
-		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
-		// Run test
-		err := Run(context.Background(), nil, dbConfig, fsys)
-		// Check error
-		assert.ErrorIs(t, err, os.ErrNotExist)
-	})
-}
diff --git a/internal/migration/apply/apply_test.go b/internal/migration/apply/apply_test.go
index d8043e64..af67d9cb 100644
--- a/internal/migration/apply/apply_test.go
+++ b/internal/migration/apply/apply_test.go
@@ -48,11 +48,11 @@ func TestMigrateDatabase(t *testing.T) {
 		assert.NoError(t, MigrateAndSeed(context.Background(), "", nil, afero.NewMemMapFs()))
 	})
 
-	t.Run("throws error on write failure", func(t *testing.T) {
+	t.Run("throws error on open failure", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Run test
-		err := MigrateAndSeed(context.Background(), "", nil, afero.NewReadOnlyFs(fsys))
+		err := MigrateAndSeed(context.Background(), "", nil, fsys)
 		// Check error
 		assert.ErrorIs(t, err, os.ErrPermission)
 	})
diff --git a/internal/migration/list/list_test.go b/internal/migration/list/list_test.go
index a98b6975..f4a1c625 100644
--- a/internal/migration/list/list_test.go
+++ b/internal/migration/list/list_test.go
@@ -2,7 +2,7 @@ package list
 
 import (
 	"context"
-	"io/fs"
+	"os"
 	"path/filepath"
 	"strings"
 	"testing"
@@ -12,6 +12,7 @@ import (
 	"github.com/spf13/afero"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
+	"github.com/supabase/cli/internal/testing/fstest"
 	"github.com/supabase/cli/internal/testing/pgtest"
 	"github.com/supabase/cli/internal/utils"
 )
@@ -48,18 +49,18 @@ func TestMigrationList(t *testing.T) {
 		assert.ErrorContains(t, err, "invalid port (outside range)")
 	})
 
-	t.Run("throws error on local failure", func(t *testing.T) {
+	t.Run("throws error on open failure", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
 		conn.Query(LIST_MIGRATION_VERSION).
 			Reply("SELECT 0")
 		// Run test
-		err := Run(context.Background(), dbConfig, afero.NewReadOnlyFs(fsys), conn.Intercept)
+		err := Run(context.Background(), dbConfig, fsys, conn.Intercept)
 		// Check error
-		assert.ErrorContains(t, err, "operation not permitted")
+		assert.ErrorIs(t, err, os.ErrPermission)
 	})
 }
 
@@ -93,7 +94,7 @@ func TestRemoteMigrations(t *testing.T) {
 		// Run test
 		versions, err := loadRemoteVersions(context.Background(), dbConfig, conn.Intercept)
 		// Check error
-		assert.ErrorContains(t, err, "failed to parse rows")
+		assert.NoError(t, err)
 		assert.Empty(t, versions)
 	})
 
@@ -110,18 +111,6 @@ func TestRemoteMigrations(t *testing.T) {
 	})
 }
 
-type MockFs struct {
-	afero.MemMapFs
-	DenyPath string
-}
-
-func (m *MockFs) Open(name string) (afero.File, error) {
-	if strings.HasPrefix(name, m.DenyPath) {
-		return nil, fs.ErrPermission
-	}
-	return m.MemMapFs.Open(name)
-}
-
 func TestLocalMigrations(t *testing.T) {
 	t.Run("loads migration versions", func(t *testing.T) {
 		// Setup in-memory fs
@@ -151,22 +140,13 @@ func TestLocalMigrations(t *testing.T) {
 		assert.Empty(t, versions)
 	})
 
-	t.Run("throws error on permission denied", func(t *testing.T) {
-		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
-		// Run test
-		_, err := LoadLocalVersions(afero.NewReadOnlyFs(fsys))
-		// Check error
-		assert.ErrorContains(t, err, "operation not permitted")
-	})
-
 	t.Run("throws error on open failure", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := MockFs{DenyPath: utils.MigrationsDir}
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Run test
-		_, err := LoadLocalVersions(&fsys)
+		_, err := LoadLocalVersions(fsys)
 		// Check error
-		assert.ErrorContains(t, err, "permission denied")
+		assert.ErrorIs(t, err, os.ErrPermission)
 	})
 }
 
diff --git a/internal/migration/squash/squash_test.go b/internal/migration/squash/squash_test.go
index a1e1a6db..b919a6e3 100644
--- a/internal/migration/squash/squash_test.go
+++ b/internal/migration/squash/squash_test.go
@@ -17,6 +17,7 @@ import (
 	"github.com/supabase/cli/internal/migration/history"
 	"github.com/supabase/cli/internal/migration/repair"
 	"github.com/supabase/cli/internal/testing/apitest"
+	"github.com/supabase/cli/internal/testing/fstest"
 	"github.com/supabase/cli/internal/testing/pgtest"
 	"github.com/supabase/cli/internal/utils"
 	"gopkg.in/h2non/gock.v1"
@@ -67,7 +68,10 @@ func TestSquashCommand(t *testing.T) {
 		conn.Query(history.INSERT_MIGRATION_VERSION, "1", "target", "{}").
 			Reply("INSERT 0 1")
 		// Run test
-		err := Run(context.Background(), "", pgconn.Config{Host: "127.0.0.1"}, fsys, conn.Intercept)
+		err := Run(context.Background(), "", pgconn.Config{
+			Host: "127.0.0.1",
+			Port: 54322,
+		}, fsys, conn.Intercept)
 		// Check error
 		assert.NoError(t, err)
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -122,9 +126,9 @@ func TestSquashCommand(t *testing.T) {
 func TestSquashVersion(t *testing.T) {
 	t.Run("throws error on permission denied", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewMemMapFs()
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Run test
-		err := squashToVersion(context.Background(), "0", afero.NewReadOnlyFs(fsys))
+		err := squashToVersion(context.Background(), "0", fsys)
 		// Check error
 		assert.ErrorIs(t, err, os.ErrPermission)
 	})
diff --git a/internal/migration/up/up_test.go b/internal/migration/up/up_test.go
index 37cd429b..04171fd2 100644
--- a/internal/migration/up/up_test.go
+++ b/internal/migration/up/up_test.go
@@ -2,6 +2,7 @@ package up
 
 import (
 	"context"
+	"os"
 	"path/filepath"
 	"testing"
 
@@ -10,6 +11,7 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"github.com/supabase/cli/internal/migration/list"
+	"github.com/supabase/cli/internal/testing/fstest"
 	"github.com/supabase/cli/internal/testing/pgtest"
 	"github.com/supabase/cli/internal/utils"
 )
@@ -47,7 +49,7 @@ func TestPendingMigrations(t *testing.T) {
 
 	t.Run("throws error on local load failure", func(t *testing.T) {
 		// Setup in-memory fs
-		fsys := afero.NewReadOnlyFs(afero.NewMemMapFs())
+		fsys := &fstest.OpenErrorFs{DenyPath: utils.MigrationsDir}
 		// Setup mock postgres
 		conn := pgtest.NewConn()
 		defer conn.Close(t)
@@ -61,7 +63,7 @@ func TestPendingMigrations(t *testing.T) {
 		// Run test
 		_, err = GetPendingMigrations(ctx, false, mock, fsys)
 		// Check error
-		assert.ErrorContains(t, err, "operation not permitted")
+		assert.ErrorIs(t, err, os.ErrPermission)
 	})
 
 	t.Run("throws error on missing local migration", func(t *testing.T) {