Skip to content

Commit 3612d71

Browse files
authored
fix: use pgkit migra with experimental flag (#4062)
2 parents 343ecfe + e863ffd commit 3612d71

File tree

12 files changed

+121
-13
lines changed

12 files changed

+121
-13
lines changed

cmd/db.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ var (
101101
if usePgSchema {
102102
differ = diff.DiffPgSchema
103103
fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "--use-pg-schema flag is experimental and may not include all entities, such as views and grants.")
104+
} else if !viper.GetBool("EXPERIMENTAL") {
105+
differ = diff.DiffSchemaMigraBash
104106
}
105107
return diff.Run(cmd.Context(), schema, file, flags.DbConfig, differ, afero.NewOsFs())
106108
},

internal/db/diff/diff.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import (
2828
"github.com/supabase/cli/pkg/parser"
2929
)
3030

31-
type DiffFunc func(context.Context, string, string, []string) (string, error)
31+
type DiffFunc func(context.Context, string, string, []string, ...func(*pgx.ConnConfig)) (string, error)
3232

3333
func Run(ctx context.Context, schema []string, file string, config pgconn.Config, differ DiffFunc, fsys afero.Fs, options ...func(*pgx.ConnConfig)) (err error) {
3434
out, err := DiffDatabase(ctx, schema, config, os.Stderr, fsys, differ, options...)
@@ -136,7 +136,7 @@ func MigrateShadowDatabase(ctx context.Context, container string, fsys afero.Fs,
136136
return migration.ApplyMigrations(ctx, migrations, conn, afero.NewIOFS(fsys))
137137
}
138138

139-
func DiffDatabase(ctx context.Context, schema []string, config pgconn.Config, w io.Writer, fsys afero.Fs, differ func(context.Context, string, string, []string) (string, error), options ...func(*pgx.ConnConfig)) (string, error) {
139+
func DiffDatabase(ctx context.Context, schema []string, config pgconn.Config, w io.Writer, fsys afero.Fs, differ DiffFunc, options ...func(*pgx.ConnConfig)) (string, error) {
140140
fmt.Fprintln(w, "Creating shadow database...")
141141
shadow, err := CreateShadowDatabase(ctx, utils.Config.Db.ShadowPort)
142142
if err != nil {
@@ -175,7 +175,7 @@ func DiffDatabase(ctx context.Context, schema []string, config pgconn.Config, w
175175
}
176176
source := utils.ToPostgresURL(shadowConfig)
177177
target := utils.ToPostgresURL(config)
178-
return differ(ctx, source, target, schema)
178+
return differ(ctx, source, target, schema, options...)
179179
}
180180

181181
func migrateBaseDatabase(ctx context.Context, config pgconn.Config, migrations []string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {

internal/db/diff/diff_test.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/h2non/gock"
1616
"github.com/jackc/pgconn"
1717
"github.com/jackc/pgerrcode"
18+
"github.com/jackc/pgx/v4"
1819
"github.com/spf13/afero"
1920
"github.com/stretchr/testify/assert"
2021
"github.com/stretchr/testify/require"
@@ -72,7 +73,17 @@ func TestRun(t *testing.T) {
7273
Reply("CREATE DATABASE")
7374
defer conn.Close(t)
7475
// Run test
75-
err := Run(context.Background(), []string{"public"}, "file", dbConfig, DiffSchemaMigra, fsys, conn.Intercept)
76+
err := Run(context.Background(), []string{"public"}, "file", dbConfig, DiffSchemaMigra, fsys, func(cc *pgx.ConnConfig) {
77+
if cc.Host == dbConfig.Host {
78+
// Fake a SSL error when connecting to target database
79+
cc.LookupFunc = func(ctx context.Context, host string) (addrs []string, err error) {
80+
return nil, errors.New("server refused TLS connection")
81+
}
82+
} else {
83+
// Hijack connection to shadow database
84+
conn.Intercept(cc)
85+
}
86+
})
7687
// Check error
7788
assert.NoError(t, err)
7889
assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -306,7 +317,17 @@ create schema public`)
306317
Query(migration.INSERT_MIGRATION_VERSION, "0", "test", []string{sql}).
307318
Reply("INSERT 0 1")
308319
// Run test
309-
diff, err := DiffDatabase(context.Background(), []string{"public"}, dbConfig, io.Discard, fsys, DiffSchemaMigra, conn.Intercept)
320+
diff, err := DiffDatabase(context.Background(), []string{"public"}, dbConfig, io.Discard, fsys, DiffSchemaMigra, func(cc *pgx.ConnConfig) {
321+
if cc.Host == dbConfig.Host {
322+
// Fake a SSL error when connecting to target database
323+
cc.LookupFunc = func(ctx context.Context, host string) (addrs []string, err error) {
324+
return nil, errors.New("server refused TLS connection")
325+
}
326+
} else {
327+
// Hijack connection to shadow database
328+
conn.Intercept(cc)
329+
}
330+
})
310331
// Check error
311332
assert.Empty(t, diff)
312333
assert.ErrorContains(t, err, "error diffing schema")

internal/db/diff/migra.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ import (
99
"github.com/docker/docker/api/types/container"
1010
"github.com/docker/docker/api/types/network"
1111
"github.com/go-errors/errors"
12+
"github.com/jackc/pgx/v4"
1213
"github.com/spf13/viper"
14+
"github.com/supabase/cli/internal/gen/types"
1315
"github.com/supabase/cli/internal/utils"
1416
"github.com/supabase/cli/pkg/config"
17+
"github.com/supabase/cli/pkg/migration"
1518
)
1619

1720
var (
@@ -20,6 +23,11 @@ var (
2023
//go:embed templates/migra.ts
2124
diffSchemaTypeScript string
2225

26+
//go:embed templates/staging-ca-2021.crt
27+
caStaging string
28+
//go:embed templates/prod-ca-2021.crt
29+
caProd string
30+
2331
managedSchemas = []string{
2432
// Local development
2533
"_analytics",
@@ -54,7 +62,14 @@ var (
5462
)
5563

5664
// Diffs local database schema against shadow, dumps output to stdout.
57-
func DiffSchemaMigraBash(ctx context.Context, source, target string, schema []string) (string, error) {
65+
func DiffSchemaMigraBash(ctx context.Context, source, target string, schema []string, options ...func(*pgx.ConnConfig)) (string, error) {
66+
// Load all user defined schemas
67+
if len(schema) == 0 {
68+
var err error
69+
if schema, err = loadSchema(ctx, target, options...); err != nil {
70+
return "", err
71+
}
72+
}
5873
env := []string{"SOURCE=" + source, "TARGET=" + target}
5974
// Passing in script string means command line args must be set manually, ie. "$@"
6075
args := "set -- " + strings.Join(schema, " ") + ";"
@@ -80,8 +95,25 @@ func DiffSchemaMigraBash(ctx context.Context, source, target string, schema []st
8095
return out.String(), nil
8196
}
8297

83-
func DiffSchemaMigra(ctx context.Context, source, target string, schema []string) (string, error) {
98+
func loadSchema(ctx context.Context, dbURL string, options ...func(*pgx.ConnConfig)) ([]string, error) {
99+
conn, err := utils.ConnectByUrl(ctx, dbURL, options...)
100+
if err != nil {
101+
return nil, err
102+
}
103+
defer conn.Close(context.Background())
104+
// RLS policies in auth and storage schemas can be included with -s flag
105+
return migration.ListUserSchemas(ctx, conn)
106+
}
107+
108+
func DiffSchemaMigra(ctx context.Context, source, target string, schema []string, options ...func(*pgx.ConnConfig)) (string, error) {
84109
env := []string{"SOURCE=" + source, "TARGET=" + target}
110+
// node-postgres does not support sslmode=prefer
111+
if require, err := types.IsRequireSSL(ctx, target, options...); err != nil {
112+
return "", err
113+
} else if require {
114+
rootCA := caStaging + caProd
115+
env = append(env, "SSL_CA="+rootCA)
116+
}
85117
if len(schema) > 0 {
86118
env = append(env, "INCLUDED_SCHEMAS="+strings.Join(schema, ","))
87119
} else {

internal/db/diff/pgschema.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import (
77
"strings"
88

99
"github.com/go-errors/errors"
10+
"github.com/jackc/pgx/v4"
1011
pgschema "github.com/stripe/pg-schema-diff/pkg/diff"
1112
)
1213

13-
func DiffPgSchema(ctx context.Context, source, target string, schema []string) (string, error) {
14+
func DiffPgSchema(ctx context.Context, source, target string, schema []string, _ ...func(*pgx.ConnConfig)) (string, error) {
1415
dbSrc, err := sql.Open("pgx", source)
1516
if err != nil {
1617
return "", errors.Errorf("failed to open source database: %w", err)

internal/db/diff/templates/migra.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { createClient } from "npm:@pgkit/client";
22
import { Migration } from "npm:@pgkit/migra";
33

4+
// Avoids error on self-signed certificate
5+
const ca = Deno.env.get("SSL_CA");
46
const clientBase = createClient(Deno.env.get("SOURCE"));
5-
const clientHead = createClient(Deno.env.get("TARGET"));
7+
const clientHead = createClient(Deno.env.get("TARGET"), {
8+
pgpOptions: { connect: { ssl: ca && { ca } } },
9+
});
610
const includedSchemas = Deno.env.get("INCLUDED_SCHEMAS")?.split(",") ?? [];
711
const excludedSchemas = Deno.env.get("EXCLUDED_SCHEMAS")?.split(",") ?? [];
812

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIIDxDCCAqygAwIBAgIUbLxMod62P2ktCiAkxnKJwtE9VPYwDQYJKoZIhvcNAQEL
3+
BQAwazELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5l
4+
dyBDYXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEeMBwGA1UEAwwVU3VwYWJh
5+
c2UgUm9vdCAyMDIxIENBMB4XDTIxMDQyODEwNTY1M1oXDTMxMDQyNjEwNTY1M1ow
6+
azELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5ldyBD
7+
YXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEeMBwGA1UEAwwVU3VwYWJhc2Ug
8+
Um9vdCAyMDIxIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqQXW
9+
QyHOB+qR2GJobCq/CBmQ40G0oDmCC3mzVnn8sv4XNeWtE5XcEL0uVih7Jo4Dkx1Q
10+
DmGHBH1zDfgs2qXiLb6xpw/CKQPypZW1JssOTMIfQppNQ87K75Ya0p25Y3ePS2t2
11+
GtvHxNjUV6kjOZjEn2yWEcBdpOVCUYBVFBNMB4YBHkNRDa/+S4uywAoaTWnCJLUi
12+
cvTlHmMw6xSQQn1UfRQHk50DMCEJ7Cy1RxrZJrkXXRP3LqQL2ijJ6F4yMfh+Gyb4
13+
O4XajoVj/+R4GwywKYrrS8PrSNtwxr5StlQO8zIQUSMiq26wM8mgELFlS/32Uclt
14+
NaQ1xBRizkzpZct9DwIDAQABo2AwXjALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFKjX
15+
uXY32CztkhImng4yJNUtaUYsMB8GA1UdIwQYMBaAFKjXuXY32CztkhImng4yJNUt
16+
aUYsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAB8spzNn+4VU
17+
tVxbdMaX+39Z50sc7uATmus16jmmHjhIHz+l/9GlJ5KqAMOx26mPZgfzG7oneL2b
18+
VW+WgYUkTT3XEPFWnTp2RJwQao8/tYPXWEJDc0WVQHrpmnWOFKU/d3MqBgBm5y+6
19+
jB81TU/RG2rVerPDWP+1MMcNNy0491CTL5XQZ7JfDJJ9CCmXSdtTl4uUQnSuv/Qx
20+
Cea13BX2ZgJc7Au30vihLhub52De4P/4gonKsNHYdbWjg7OWKwNv/zitGDVDB9Y2
21+
CMTyZKG3XEu5Ghl1LEnI3QmEKsqaCLv12BnVjbkSeZsMnevJPs1Ye6TjjJwdik5P
22+
o/bKiIz+Fq8=
23+
-----END CERTIFICATE-----
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
-----BEGIN CERTIFICATE-----
2+
MIID1DCCArygAwIBAgIUbYRdq/8/uNq8G9stMCdOFSBgA2MwDQYJKoZIhvcNAQEL
3+
BQAwczELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0RlbHdhcmUxEzARBgNVBAcMCk5l
4+
dyBDYXN0bGUxFTATBgNVBAoMDFN1cGFiYXNlIEluYzEmMCQGA1UEAwwdU3VwYWJh
5+
c2UgU3RhZ2luZyBSb290IDIwMjEgQ0EwHhcNMjEwNDI4MTAzNjEzWhcNMzEwNDI2
6+
MTAzNjEzWjBzMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHRGVsd2FyZTETMBEGA1UE
7+
BwwKTmV3IENhc3RsZTEVMBMGA1UECgwMU3VwYWJhc2UgSW5jMSYwJAYDVQQDDB1T
8+
dXBhYmFzZSBTdGFnaW5nIFJvb3QgMjAyMSBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
9+
ggEPADCCAQoCggEBAN0AKRE8a56O8LaZxiOAcHFUFnwiKUvPoXPq26Ifw+Nv+7zg
10+
N2V5WnMZbbw24q61Os60ZUn0XmbVtuIeJ+stPHsO7qxxuL+bmPR+qU5tkDrIOyEe
11+
YD/2u8/q6ssVv42k4XcXbhM6RVz7CkCDY0TiBm1bMtRZso3xB6E9wAjxDf43XfV5
12+
PAGs3JI+Zo/vyqCDlN0hHOrB/aBl01JXqQWI84Gia5ooucq4SjA1CyawBcQ2IAvG
13+
rXuy1BouY+xM3zRuNvtfFP6rb5Mta+jCYEMh1AZ8yP8sYUWAyhxX6k9EbOb009wQ
14+
aZljbUCh/UglGWuBxdzePavx+zPjzWXB1NyVkpkCAwEAAaNgMF4wCwYDVR0PBAQD
15+
AgEGMB0GA1UdDgQWBBQFx+PHLf27iIo/PMfIfGqXF7Zb+DAfBgNVHSMEGDAWgBQF
16+
x+PHLf27iIo/PMfIfGqXF7Zb+DAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB
17+
CwUAA4IBAQB/xIiz5dDqzGXjqYqXZYx4iSfSxsVayeOPDMfmaiCfSMJEUG4cUiwG
18+
OvMPGztaUEYeip5SCvSKuAAjVkXyP7ahKR7t7lZ9mErVXyxSZoVLbOd578CuYiZk
19+
OgT17UjPv66WMzEKEr8wGpomTYWWfEkuqt8ENdiM1Z4LNFahdKj36+jm6/a+9R8K
20+
25VIL68DTaQpBxFWG6ixC1HRMHJ12lDhKsshIi099BVpkGibESlxPrQOdKKqBB/J
21+
vIX+/Hb+mS4H5zYMeK2wX0onp+GBcD6X9L1UJuXMVd+BRan8RFidXL5s3++xXjQq
22+
Nzbc6lnA69urKffvcT07YwMsY/OmHzVa
23+
-----END CERTIFICATE-----

internal/gen/types/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func Run(ctx context.Context, projectId string, dbConfig pgconn.Config, lang str
7878

7979
fmt.Fprintln(os.Stderr, "Connecting to", dbConfig.Host, dbConfig.Port)
8080
escaped := utils.ToPostgresURL(dbConfig)
81-
if require, err := isRequireSSL(ctx, originalURL, options...); err != nil {
81+
if require, err := IsRequireSSL(ctx, originalURL, options...); err != nil {
8282
return err
8383
} else if require {
8484
// node-postgres does not support sslmode=prefer
@@ -106,7 +106,7 @@ func Run(ctx context.Context, projectId string, dbConfig pgconn.Config, lang str
106106
)
107107
}
108108

109-
func isRequireSSL(ctx context.Context, dbUrl string, options ...func(*pgx.ConnConfig)) (bool, error) {
109+
func IsRequireSSL(ctx context.Context, dbUrl string, options ...func(*pgx.ConnConfig)) (bool, error) {
110110
conn, err := utils.ConnectByUrl(ctx, dbUrl+"&sslmode=require", options...)
111111
if err != nil {
112112
if strings.HasSuffix(err.Error(), "(server refused TLS connection)") {

internal/utils/flags/db_url.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ func NewDbConfigWithPassword(ctx context.Context, projectRef string) pgconn.Conf
138138
}
139139
config.User = newRole.User
140140
return config
141+
} else {
142+
fmt.Fprintln(utils.GetDebugLogger(), err)
141143
}
142144
}
143145
if config.Password, err = credentials.StoreProvider.Get(projectRef); err == nil {

0 commit comments

Comments
 (0)