diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 0949eb358..2e4f96730 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,6 +21,8 @@ updates: update-types: - minor - patch + exclude-patterns: + - github.com/compose-spec/compose-go/v2 - package-ecosystem: "npm" directory: "/" schedule: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 390b1ec66..3ddfd3ef5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: go tool gotestsum -- -race -v -count=1 ./... \ -coverpkg="./cmd/...,./internal/...,${pkgs}" -coverprofile=coverage.out - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6 with: name: code-coverage-report path: coverage.out @@ -39,7 +39,7 @@ jobs: - test runs-on: ubuntu-latest steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v7 with: name: code-coverage-report - uses: coverallsapp/github-action@v2 @@ -62,6 +62,7 @@ jobs: - uses: golangci/golangci-lint-action@v9 with: args: --timeout 3m --verbose + version: latest start: name: Start diff --git a/.github/workflows/install.yml b/.github/workflows/install.yml index 51b00645e..a28df0d17 100644 --- a/.github/workflows/install.yml +++ b/.github/workflows/install.yml @@ -30,7 +30,7 @@ jobs: mv tmp.$$.json package.json npm pack - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6 with: name: installer path: supabase-1.28.0.tgz @@ -43,7 +43,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v7 with: name: installer @@ -59,7 +59,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v7 with: name: installer @@ -75,7 +75,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v7 with: name: installer @@ -98,7 +98,7 @@ jobs: os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v7 with: name: installer @@ -117,7 +117,7 @@ jobs: os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - - uses: actions/download-artifact@v6 + - uses: actions/download-artifact@v7 with: name: installer diff --git a/cmd/bootstrap.go b/cmd/bootstrap.go index fd9f74912..a39e21448 100644 --- a/cmd/bootstrap.go +++ b/cmd/bootstrap.go @@ -3,8 +3,6 @@ package cmd import ( "context" "fmt" - "os" - "os/signal" "strings" "github.com/go-errors/errors" @@ -28,7 +26,7 @@ var ( Short: "Bootstrap a Supabase project from a starter template", Args: cobra.MaximumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) + ctx := cmd.Context() if !viper.IsSet("WORKDIR") { title := fmt.Sprintf("Enter a directory to bootstrap your project (or leave blank to use %s): ", utils.Bold(utils.CurrentDirAbs)) if workdir, err := utils.NewConsole().PromptText(ctx, title); err != nil { diff --git a/cmd/branches.go b/cmd/branches.go index 077d69cc3..1f12f8727 100644 --- a/cmd/branches.go +++ b/cmd/branches.go @@ -30,9 +30,6 @@ var ( Short: "Manage Supabase preview branches", } - branchRegion = utils.EnumFlag{ - Allowed: awsRegions(), - } persistent bool withData bool notifyURL string @@ -49,7 +46,7 @@ var ( } cmdFlags := cmd.Flags() if cmdFlags.Changed("region") { - body.Region = &branchRegion.Value + body.Region = ®ion.Value } if cmdFlags.Changed("size") { body.DesiredInstanceSize = (*api.CreateBranchBodyDesiredInstanceSize)(&size.Value) @@ -206,7 +203,7 @@ func init() { branchFlags := branchesCmd.PersistentFlags() branchFlags.StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.") createFlags := branchCreateCmd.Flags() - createFlags.Var(&branchRegion, "region", "Select a region to deploy the branch database.") + createFlags.Var(®ion, "region", "Select a region to deploy the branch database.") createFlags.Var(&size, "size", "Select a desired instance size for the branch database.") createFlags.BoolVar(&persistent, "persistent", false, "Whether to create a persistent branch.") createFlags.BoolVar(&withData, "with-data", false, "Whether to clone production data to the branch database.") diff --git a/cmd/db.go b/cmd/db.go index 5367436df..94af92908 100644 --- a/cmd/db.go +++ b/cmd/db.go @@ -3,7 +3,6 @@ package cmd import ( "fmt" "os" - "os/signal" "path/filepath" "github.com/spf13/afero" @@ -31,11 +30,6 @@ var ( GroupID: groupLocalDev, Use: "db", Short: "Manage Postgres databases", - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - cmd.SetContext(ctx) - return cmd.Root().PersistentPreRunE(cmd, args) - }, } dbBranchCmd = &cobra.Command{ @@ -87,6 +81,7 @@ var ( useMigra bool usePgAdmin bool usePgSchema bool + usePgDelta bool schema []string file string @@ -101,6 +96,8 @@ var ( if usePgSchema { differ = diff.DiffPgSchema fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "--use-pg-schema flag is experimental and may not include all entities, such as views and grants.") + } else if usePgDelta { + differ = diff.DiffPgDelta } return diff.Run(cmd.Context(), schema, file, flags.DbConfig, differ, afero.NewOsFs()) }, @@ -257,7 +254,8 @@ func init() { diffFlags.BoolVar(&useMigra, "use-migra", true, "Use migra to generate schema diff.") diffFlags.BoolVar(&usePgAdmin, "use-pgadmin", false, "Use pgAdmin to generate schema diff.") diffFlags.BoolVar(&usePgSchema, "use-pg-schema", false, "Use pg-schema-diff to generate schema diff.") - dbDiffCmd.MarkFlagsMutuallyExclusive("use-migra", "use-pgadmin") + diffFlags.BoolVar(&usePgDelta, "use-pg-delta", false, "Use pg-delta to generate schema diff.") + dbDiffCmd.MarkFlagsMutuallyExclusive("use-migra", "use-pgadmin", "use-pg-schema", "use-pg-delta") diffFlags.String("db-url", "", "Diffs against the database specified by the connection string (must be percent-encoded).") diffFlags.Bool("linked", false, "Diffs local migration files against the linked project.") diffFlags.Bool("local", true, "Diffs local migration files against the local database.") diff --git a/cmd/gen.go b/cmd/gen.go index f063f11a4..d15908a7b 100644 --- a/cmd/gen.go +++ b/cmd/gen.go @@ -3,7 +3,6 @@ package cmd import ( "encoding/json" "os" - "os/signal" "strings" "time" @@ -88,7 +87,7 @@ var ( return nil }, RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) + ctx := cmd.Context() if flags.DbConfig.Host == "" { // If no flag is specified, prompt for project id. if err := flags.ParseProjectRef(ctx, afero.NewMemMapFs()); errors.Is(err, utils.ErrNotLinked) { diff --git a/cmd/inspect.go b/cmd/inspect.go index 2405e8d78..160c73303 100644 --- a/cmd/inspect.go +++ b/cmd/inspect.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/inspect" @@ -33,11 +30,6 @@ var ( inspectDBCmd = &cobra.Command{ Use: "db", Short: "Tools to inspect your Supabase database", - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - cmd.SetContext(ctx) - return cmd.Root().PersistentPreRunE(cmd, args) - }, } inspectDBStatsCmd = &cobra.Command{ diff --git a/cmd/link.go b/cmd/link.go index 82b5f4ca3..026e7e244 100644 --- a/cmd/link.go +++ b/cmd/link.go @@ -3,7 +3,6 @@ package cmd import ( "fmt" "os" - "os/signal" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -28,7 +27,7 @@ var ( return nil }, RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) + ctx := cmd.Context() // Use an empty fs to skip loading from file if err := flags.ParseProjectRef(ctx, afero.NewMemMapFs()); err != nil { return err diff --git a/cmd/migration.go b/cmd/migration.go index fc92e40d2..697f3651d 100644 --- a/cmd/migration.go +++ b/cmd/migration.go @@ -3,7 +3,6 @@ package cmd import ( "fmt" "os" - "os/signal" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -25,11 +24,6 @@ var ( Use: "migration", Aliases: []string{"migrations"}, Short: "Manage database migration scripts", - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - cmd.SetContext(ctx) - return cmd.Root().PersistentPreRunE(cmd, args) - }, } migrationListCmd = &cobra.Command{ diff --git a/cmd/projects.go b/cmd/projects.go index 2ab5d7d2d..93a75fb20 100644 --- a/cmd/projects.go +++ b/cmd/projects.go @@ -2,7 +2,6 @@ package cmd import ( "os" - "sort" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -30,7 +29,7 @@ var ( orgId string dbPassword string region = utils.EnumFlag{ - Allowed: awsRegions(), + Allowed: utils.AwsRegions(), } size = utils.EnumFlag{ Allowed: []string{ @@ -153,12 +152,3 @@ func init() { projectsCmd.AddCommand(projectsApiKeysCmd) rootCmd.AddCommand(projectsCmd) } - -func awsRegions() []string { - result := make([]string, len(utils.CurrentProfile.ProjectRegions)) - for i, region := range utils.CurrentProfile.ProjectRegions { - result[i] = string(region) - } - sort.Strings(result) - return result -} diff --git a/cmd/root.go b/cmd/root.go index 5a1072284..00d7eb2fd 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -93,7 +93,7 @@ var ( } cmd.SilenceUsage = true // Load profile before changing workdir - ctx := cmd.Context() + ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) fsys := afero.NewOsFs() if err := utils.LoadProfile(ctx, fsys); err != nil { return err @@ -106,7 +106,6 @@ var ( if err := promptLogin(fsys); err != nil { return err } - ctx, _ = signal.NotifyContext(ctx, os.Interrupt) if cmd.Flags().Lookup("project-ref") != nil { if err := flags.ParseProjectRef(ctx, fsys); err != nil { return err diff --git a/cmd/seed.go b/cmd/seed.go index c36b70741..68b62cb25 100644 --- a/cmd/seed.go +++ b/cmd/seed.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/seed/buckets" @@ -16,11 +13,6 @@ var ( GroupID: groupLocalDev, Use: "seed", Short: "Seed a Supabase project from " + utils.ConfigPath, - PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - cmd.SetContext(ctx) - return cmd.Root().PersistentPreRunE(cmd, args) - }, } bucketsCmd = &cobra.Command{ diff --git a/cmd/status.go b/cmd/status.go index 11b774854..023c16e66 100644 --- a/cmd/status.go +++ b/cmd/status.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - env "github.com/Netflix/go-env" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -27,8 +24,7 @@ var ( return env.Unmarshal(es, &names) }, RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - return status.Run(ctx, names, utils.OutputFormat.Value, afero.NewOsFs()) + return status.Run(cmd.Context(), names, utils.OutputFormat.Value, afero.NewOsFs()) }, Example: ` supabase status -o env --override-name api.url=NEXT_PUBLIC_SUPABASE_URL supabase status -o json`, diff --git a/cmd/stop.go b/cmd/stop.go index 6a6f4aa55..1768ca683 100644 --- a/cmd/stop.go +++ b/cmd/stop.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/stop" @@ -19,8 +16,7 @@ var ( Use: "stop", Short: "Stop all local Supabase containers", RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - return stop.Run(ctx, !noBackup, projectId, all, afero.NewOsFs()) + return stop.Run(cmd.Context(), !noBackup, projectId, all, afero.NewOsFs()) }, } ) diff --git a/cmd/test.go b/cmd/test.go index 06fb77730..55e052066 100644 --- a/cmd/test.go +++ b/cmd/test.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/test/new" @@ -33,8 +30,7 @@ var ( Short: "Create a new test file", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - return new.Run(ctx, args[0], template.Value, afero.NewOsFs()) + return new.Run(cmd.Context(), args[0], template.Value, afero.NewOsFs()) }, } ) diff --git a/cmd/unlink.go b/cmd/unlink.go index e017e75ed..071bc02e3 100644 --- a/cmd/unlink.go +++ b/cmd/unlink.go @@ -1,9 +1,6 @@ package cmd import ( - "os" - "os/signal" - "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/supabase/cli/internal/unlink" @@ -15,8 +12,7 @@ var ( Use: "unlink", Short: "Unlink a Supabase project", RunE: func(cmd *cobra.Command, args []string) error { - ctx, _ := signal.NotifyContext(cmd.Context(), os.Interrupt) - return unlink.Run(ctx, afero.NewOsFs()) + return unlink.Run(cmd.Context(), afero.NewOsFs()) }, } ) diff --git a/go.mod b/go.mod index da5c8bd80..b05b45334 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,9 @@ module github.com/supabase/cli -go 1.24.10 +go 1.25.5 require ( - github.com/BurntSushi/toml v1.5.0 + github.com/BurntSushi/toml v1.6.0 github.com/Netflix/go-env v0.1.2 github.com/andybalholm/brotli v1.2.0 github.com/cenkalti/backoff/v4 v4.3.0 @@ -23,12 +23,12 @@ require ( github.com/getsentry/sentry-go v0.40.0 github.com/go-errors/errors v1.5.1 github.com/go-git/go-git/v5 v5.16.4 - github.com/go-playground/validator/v10 v10.28.0 + github.com/go-playground/validator/v10 v10.30.1 github.com/go-viper/mapstructure/v2 v2.4.0 github.com/go-xmlfmt/xmlfmt v1.1.3 github.com/golang-jwt/jwt/v5 v5.3.0 github.com/google/go-github/v62 v62.0.0 - github.com/google/go-querystring v1.1.0 + github.com/google/go-querystring v1.2.0 github.com/google/uuid v1.6.0 github.com/h2non/gock v1.2.0 github.com/jackc/pgconn v1.14.3 @@ -42,21 +42,21 @@ require ( github.com/olekukonko/tablewriter v1.1.2 github.com/slack-go/slack v0.17.3 github.com/spf13/afero v1.15.0 - github.com/spf13/cobra v1.10.1 + github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 - github.com/stripe/pg-schema-diff v1.0.2 + github.com/stripe/pg-schema-diff v1.0.5 github.com/supabase/cli/pkg v1.0.0 github.com/tidwall/jsonc v0.3.2 github.com/withfig/autocomplete-tools/packages/cobra v1.2.0 github.com/zalando/go-keyring v0.2.6 - go.opentelemetry.io/otel v1.38.0 - golang.org/x/mod v0.30.0 - golang.org/x/net v0.47.0 - golang.org/x/oauth2 v0.33.0 - golang.org/x/term v0.37.0 - google.golang.org/grpc v1.77.0 + go.opentelemetry.io/otel v1.39.0 + golang.org/x/mod v0.32.0 + golang.org/x/net v0.48.0 + golang.org/x/oauth2 v0.34.0 + golang.org/x/term v0.39.0 + google.golang.org/grpc v1.78.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -174,7 +174,7 @@ require ( github.com/fvbommel/sortorder v1.1.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.10 // indirect + github.com/gabriel-vasile/mimetype v1.4.12 // indirect github.com/getkin/kin-openapi v0.131.0 // indirect github.com/ghostiam/protogetter v0.3.15 // indirect github.com/go-critic/go-critic v0.13.0 // indirect @@ -415,10 +415,10 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect @@ -426,17 +426,17 @@ require ( go.uber.org/zap v1.24.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.45.0 // indirect + golang.org/x/crypto v0.46.0 // indirect golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.32.0 // indirect golang.org/x/time v0.11.0 // indirect - golang.org/x/tools v0.38.0 // indirect + golang.org/x/tools v0.40.0 // indirect golang.org/x/tools/go/expect v0.1.1-deprecated // indirect golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index e22db1772..d95920aab 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ github.com/Antonboom/testifylint v1.6.1/go.mod h1:k+nEkathI2NFjKO6HvwmSrbzUcQ6FA github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= -github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DefangLabs/secret-detector v0.0.0-20250403165618-22662109213e h1:rd4bOvKmDIx0WeTv9Qz+hghsgyjikFiPrseXHlKepO0= github.com/DefangLabs/secret-detector v0.0.0-20250403165618-22662109213e/go.mod h1:blbwPQh4DTlCZEfk1BLU4oMIhLda2U+A840Uag9DsZw= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 h1:sHglBQTwgx+rWPdisA5ynNEsoARbiCBOyGcJM4/OzsM= @@ -343,8 +343,8 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= -github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0= -github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= +github.com/gabriel-vasile/mimetype v1.4.12 h1:e9hWvmLYvtp846tLHam2o++qitpguFiYCKbn0w9jyqw= +github.com/gabriel-vasile/mimetype v1.4.12/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/getkin/kin-openapi v0.131.0 h1:NO2UeHnFKRYhZ8wg6Nyh5Cq7dHk4suQQr72a4pMrDxE= github.com/getkin/kin-openapi v0.131.0/go.mod h1:3OlG51PCYNsPByuiMB0t4fjnNlIDnaEDsjiKUV8nL58= github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= @@ -389,8 +389,8 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688= -github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU= +github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= +github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-sql-driver/mysql v1.3.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -489,12 +489,13 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4= github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4= -github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= -github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= +github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -1014,8 +1015,8 @@ github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IEx github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= -github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/jwalterweatherman v0.0.0-20141219030609-3d60171a6431/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= @@ -1048,8 +1049,8 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -github.com/stripe/pg-schema-diff v1.0.2 h1:1R4ZQb7mHvOc9BGw1xYrddqb2voL8ICyiUYSoAmTAFo= -github.com/stripe/pg-schema-diff v1.0.2/go.mod h1:LlN2VVP/njIq1Y7o6Nt35ItEyr6OWOCEz6+Jc/axbIY= +github.com/stripe/pg-schema-diff v1.0.5 h1:TNHkiRNMn7ttiBd+YBypAbx9v0SfVls+NQZFtamy1K4= +github.com/stripe/pg-schema-diff v1.0.5/go.mod h1:3IctPaAqm+0LtWw/GiwyRoRlU1/N/+00+eXVk0KZIHs= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tdakkota/asciicheck v0.4.1 h1:bm0tbcmi0jezRA2b5kg4ozmMuGAFotKI3RZfrhfovg8= @@ -1161,8 +1162,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0. go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.60.0/go.mod h1:CosX/aS4eHnG9D7nESYpV753l4j9q5j3SL/PUYd2lR8= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.35.0 h1:0NIXxOCFx+SKbhCVxwl3ETG8ClLPAa0KuKV6p3yhxP8= @@ -1173,14 +1174,14 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1229,8 +1230,8 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 h1:R84qjqJb5nVJMxqWYb3np9L5ZsaDtB+a39EqjV0JSUM= golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:S9Xr4PYopiDyqSyp5NjCrhFrqg6A5zA2E/iPHPhqnS8= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= @@ -1251,8 +1252,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -1278,10 +1279,10 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= -golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= +golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1294,8 +1295,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1340,8 +1341,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1352,8 +1353,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1366,8 +1367,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1398,8 +1399,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= +golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA= +golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc= golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= @@ -1412,13 +1413,13 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= -google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda h1:+2XxjfsAu6vqFxwGBRcHiMaDCuZiqXGDUDVWVtrFAnE= +google.golang.org/genproto/googleapis/api v0.0.0-20251029180050-ab9386a59fda/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda h1:i/Q+bfisr7gq6feoJnS/DlpdwEL4ihp41fvRiM3Ork0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251029180050-ab9386a59fda/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index d8279d135..8a07e2530 100644 --- a/internal/bootstrap/bootstrap.go +++ b/internal/bootstrap/bootstrap.go @@ -156,7 +156,7 @@ func suggestAppStart(cwd, command string) string { func checkProjectHealth(ctx context.Context) error { params := api.V1GetServicesHealthParams{ - Services: []api.V1GetServicesHealthParamsServices{api.Db}, + Services: []api.V1GetServicesHealthParamsServices{api.V1GetServicesHealthParamsServicesDb}, } resp, err := utils.GetSupabase().V1GetServicesHealthWithResponse(ctx, flags.ProjectRef, ¶ms) if err != nil { diff --git a/internal/db/diff/diff.go b/internal/db/diff/diff.go index af19faa5a..744ad381b 100644 --- a/internal/db/diff/diff.go +++ b/internal/db/diff/diff.go @@ -143,7 +143,7 @@ func DiffDatabase(ctx context.Context, schema []string, config pgconn.Config, w return "", err } defer utils.DockerRemove(shadow) - if err := start.WaitForHealthyService(ctx, start.HealthTimeout, shadow); err != nil { + if err := start.WaitForHealthyService(ctx, utils.Config.Db.HealthTimeout, shadow); err != nil { return "", err } if err := MigrateShadowDatabase(ctx, shadow, fsys, options...); err != nil { diff --git a/internal/db/diff/diff_test.go b/internal/db/diff/diff_test.go index 3c21a83cc..84e6c9acb 100644 --- a/internal/db/diff/diff_test.go +++ b/internal/db/diff/diff_test.go @@ -19,7 +19,6 @@ import ( "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/supabase/cli/internal/db/start" "github.com/supabase/cli/internal/testing/apitest" "github.com/supabase/cli/internal/testing/fstest" "github.com/supabase/cli/internal/testing/helper" @@ -212,7 +211,7 @@ func TestDiffDatabase(t *testing.T) { }) t.Run("throws error on health check failure", func(t *testing.T) { - start.HealthTimeout = time.Millisecond + utils.Config.Db.HealthTimeout = time.Millisecond // Setup in-memory fs fsys := afero.NewMemMapFs() // Setup mock docker diff --git a/internal/db/diff/migra.go b/internal/db/diff/migra.go index f79c4ae16..6ef830ff5 100644 --- a/internal/db/diff/migra.go +++ b/internal/db/diff/migra.go @@ -11,7 +11,6 @@ import ( "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" - "github.com/spf13/viper" "github.com/supabase/cli/internal/gen/types" "github.com/supabase/cli/internal/utils" "github.com/supabase/cli/pkg/config" @@ -119,33 +118,9 @@ func DiffSchemaMigra(ctx context.Context, source, target pgconn.Config, schema [ } else { env = append(env, "EXCLUDED_SCHEMAS="+strings.Join(managedSchemas, ",")) } - cmd := []string{"edge-runtime", "start", "--main-service=."} - if viper.GetBool("DEBUG") { - cmd = append(cmd, "--verbose") - } - cmdString := strings.Join(cmd, " ") - entrypoint := []string{"sh", "-c", `cat <<'EOF' > index.ts && ` + cmdString + ` -` + diffSchemaTypeScript + ` -EOF -`} - var out, stderr bytes.Buffer - if err := utils.DockerRunOnceWithConfig( - ctx, - container.Config{ - Image: utils.Config.EdgeRuntime.Image, - Env: env, - Entrypoint: entrypoint, - }, - container.HostConfig{ - Binds: []string{utils.EdgeRuntimeId + ":/root/.cache/deno:rw"}, - NetworkMode: network.NetworkHost, - }, - network.NetworkingConfig{}, - "", - &out, - &stderr, - ); err != nil && !strings.HasPrefix(stderr.String(), "main worker has been destroyed") { - return "", errors.Errorf("error diffing schema: %w:\n%s", err, stderr.String()) + var out bytes.Buffer + if err := diffWithStream(ctx, env, diffSchemaTypeScript, &out); err != nil { + return "", err } return out.String(), nil } diff --git a/internal/db/diff/pgadmin.go b/internal/db/diff/pgadmin.go index cb983ebe3..d53cd4660 100644 --- a/internal/db/diff/pgadmin.go +++ b/internal/db/diff/pgadmin.go @@ -58,7 +58,7 @@ func run(p utils.Program, ctx context.Context, schema []string, config pgconn.Co return err } defer utils.DockerRemove(shadow) - if err := start.WaitForHealthyService(ctx, start.HealthTimeout, shadow); err != nil { + if err := start.WaitForHealthyService(ctx, utils.Config.Db.HealthTimeout, shadow); err != nil { return err } if err := MigrateShadowDatabase(ctx, shadow, fsys); err != nil { diff --git a/internal/db/diff/pgdelta.go b/internal/db/diff/pgdelta.go new file mode 100644 index 000000000..12153068f --- /dev/null +++ b/internal/db/diff/pgdelta.go @@ -0,0 +1,73 @@ +package diff + +import ( + "bytes" + "context" + _ "embed" + "io" + "strings" + + "github.com/docker/docker/api/types/container" + "github.com/docker/docker/api/types/network" + "github.com/go-errors/errors" + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" + "github.com/spf13/viper" + "github.com/supabase/cli/internal/gen/types" + "github.com/supabase/cli/internal/utils" +) + +//go:embed templates/pgdelta.ts +var pgDeltaScript string + +func DiffPgDelta(ctx context.Context, source, target pgconn.Config, schema []string, options ...func(*pgx.ConnConfig)) (string, error) { + env := []string{ + "SOURCE=" + utils.ToPostgresURL(source), + "TARGET=" + utils.ToPostgresURL(target), + } + if ca, err := types.GetRootCA(ctx, utils.ToPostgresURL(target), options...); err != nil { + return "", err + } else if len(ca) > 0 { + env = append(env, "PGDELTA_TARGET_SSLROOTCERT="+ca) + } + if len(schema) > 0 { + env = append(env, "INCLUDED_SCHEMAS="+strings.Join(schema, ",")) + } + var out bytes.Buffer + if err := diffWithStream(ctx, env, pgDeltaScript, &out); err != nil { + return "", err + } + return out.String(), nil +} + +func diffWithStream(ctx context.Context, env []string, script string, stdout io.Writer) error { + cmd := []string{"edge-runtime", "start", "--main-service=."} + if viper.GetBool("DEBUG") { + cmd = append(cmd, "--verbose") + } + cmdString := strings.Join(cmd, " ") + entrypoint := []string{"sh", "-c", `cat <<'EOF' > index.ts && ` + cmdString + ` +` + script + ` +EOF +`} + var stderr bytes.Buffer + if err := utils.DockerRunOnceWithConfig( + ctx, + container.Config{ + Image: utils.Config.EdgeRuntime.Image, + Env: env, + Entrypoint: entrypoint, + }, + container.HostConfig{ + Binds: []string{utils.EdgeRuntimeId + ":/root/.cache/deno:rw"}, + NetworkMode: network.NetworkHost, + }, + network.NetworkingConfig{}, + "", + stdout, + &stderr, + ); err != nil && !strings.HasPrefix(stderr.String(), "main worker has been destroyed") { + return errors.Errorf("error diffing schema: %w:\n%s", err, stderr.String()) + } + return nil +} diff --git a/internal/db/diff/templates/pgdelta.ts b/internal/db/diff/templates/pgdelta.ts new file mode 100644 index 000000000..d809cb57a --- /dev/null +++ b/internal/db/diff/templates/pgdelta.ts @@ -0,0 +1,23 @@ +import { createPlan } from "npm:@supabase/pg-delta@1.0.0-alpha.1"; +import { supabase } from "npm:@supabase/pg-delta@1.0.0-alpha.1/integrations/supabase"; + +const source = Deno.env.get("SOURCE"); +const target = Deno.env.get("TARGET"); + +const includedSchemas = Deno.env.get("INCLUDED_SCHEMAS"); +if (includedSchemas) { + supabase.filter = { schema: includedSchemas.split(",") }; +} +supabase.role = "postgres"; + +try { + const result = await createPlan(source, target, supabase); + const statements = result?.plan.statements ?? []; + for (const sql of statements) { + console.log(`${sql};`); + } +} catch (e) { + console.error(e); + // Force close event loop + throw new Error(""); +} diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go index 40aee23f5..21df9f648 100644 --- a/internal/db/reset/reset.go +++ b/internal/db/reset/reset.go @@ -131,7 +131,7 @@ func resetDatabase15(ctx context.Context, version string, fsys afero.Fs, options if _, err := utils.DockerStart(ctx, config, hostConfig, networkingConfig, utils.DbId); err != nil { return err } - if err := start.WaitForHealthyService(ctx, start.HealthTimeout, utils.DbId); err != nil { + if err := start.WaitForHealthyService(ctx, utils.Config.Db.HealthTimeout, utils.DbId); err != nil { return err } if err := start.SetupLocalDatabase(ctx, version, fsys, os.Stderr, options...); err != nil { @@ -215,7 +215,7 @@ func RestartDatabase(ctx context.Context, w io.Writer) error { if err := utils.Docker.ContainerRestart(ctx, utils.DbId, container.StopOptions{}); err != nil { return errors.Errorf("failed to restart container: %w", err) } - if err := start.WaitForHealthyService(ctx, start.HealthTimeout, utils.DbId); err != nil { + if err := start.WaitForHealthyService(ctx, utils.Config.Db.HealthTimeout, utils.DbId); err != nil { return err } return restartServices(ctx) diff --git a/internal/db/reset/reset_test.go b/internal/db/reset/reset_test.go index 839ccdc8b..8bfad09b9 100644 --- a/internal/db/reset/reset_test.go +++ b/internal/db/reset/reset_test.go @@ -6,7 +6,6 @@ import ( "io" "net/http" "testing" - "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" @@ -16,7 +15,6 @@ import ( "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/supabase/cli/internal/db/start" "github.com/supabase/cli/internal/testing/apitest" "github.com/supabase/cli/internal/testing/fstest" "github.com/supabase/cli/internal/utils" @@ -376,7 +374,6 @@ func TestRestartDatabase(t *testing.T) { t.Run("throws error on health check timeout", func(t *testing.T) { utils.DbId = "test-reset" - start.HealthTimeout = 0 * time.Second // Setup mock docker require.NoError(t, apitest.MockDocker(utils.Docker)) defer gock.OffAll() diff --git a/internal/db/start/start.go b/internal/db/start/start.go index 92c8fe5eb..3edf86c59 100644 --- a/internal/db/start/start.go +++ b/internal/db/start/start.go @@ -30,7 +30,6 @@ import ( ) var ( - HealthTimeout = 120 * time.Second //go:embed templates/schema.sql initialSchema string //go:embed templates/webhook.sql @@ -177,7 +176,7 @@ EOF`} return err } // Ignore health check because restoring a large backup may take longer than 2 minutes - if err := WaitForHealthyService(ctx, HealthTimeout, utils.DbId); err != nil && len(fromBackup) == 0 { + if err := WaitForHealthyService(ctx, utils.Config.Db.HealthTimeout, utils.DbId); err != nil && len(fromBackup) == 0 { return err } // Initialize if we are on PG14 and there's no existing db volume diff --git a/internal/db/test/test.go b/internal/db/test/test.go index 428fc61a9..3f9aff8e6 100644 --- a/internal/db/test/test.go +++ b/internal/db/test/test.go @@ -26,24 +26,22 @@ const ( func Run(ctx context.Context, testFiles []string, config pgconn.Config, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error { // Build test command + if len(testFiles) == 0 { + testFiles = append(testFiles, utils.DbTestsDir) + } + binds := make([]string, len(testFiles)) cmd := []string{"pg_prove", "--ext", ".pg", "--ext", ".sql", "-r"} - for _, fp := range testFiles { - relPath, err := filepath.Rel(utils.DbTestsDir, fp) - if err != nil { - return errors.Errorf("failed to resolve relative path: %w", err) + for i, fp := range testFiles { + if !filepath.IsAbs(fp) { + fp = filepath.Join(utils.CurrentDirAbs, fp) } - cmd = append(cmd, relPath) + dockerPath := utils.ToDockerPath(fp) + cmd = append(cmd, dockerPath) + binds[i] = fmt.Sprintf("%s:%s:ro", fp, dockerPath) } if viper.GetBool("DEBUG") { cmd = append(cmd, "--verbose") } - // Mount tests directory into container as working directory - srcPath, err := filepath.Abs(utils.DbTestsDir) - if err != nil { - return errors.Errorf("failed to resolve absolute path: %w", err) - } - dstPath := "/tmp" - binds := []string{fmt.Sprintf("%s:%s:ro", srcPath, dstPath)} // Enable pgTAP if not already exists alreadyExists := false options = append(options, func(cc *pgx.ConnConfig) { @@ -87,8 +85,7 @@ func Run(ctx context.Context, testFiles []string, config pgconn.Config, fsys afe "PGPASSWORD=" + config.Password, "PGDATABASE=" + config.Database, }, - Cmd: cmd, - WorkingDir: dstPath, + Cmd: cmd, }, hostConfig, network.NetworkingConfig{}, diff --git a/internal/functions/serve/serve.go b/internal/functions/serve/serve.go index 9819a181d..b0db41ffd 100644 --- a/internal/functions/serve/serve.go +++ b/internal/functions/serve/serve.go @@ -153,7 +153,7 @@ func ServeFunctions(ctx context.Context, envFilePath string, noVerifyJWT *bool, return errors.Errorf("failed to resolve relative path: %w", err) } } - binds, functionsConfigString, err := populatePerFunctionConfigs(cwd, importMapPath, noVerifyJWT, fsys) + binds, functionsConfigString, err := PopulatePerFunctionConfigs(cwd, importMapPath, noVerifyJWT, fsys) if err != nil { return err } @@ -241,7 +241,7 @@ func parseEnvFile(envFilePath string, fsys afero.Fs) ([]string, error) { return env, err } -func populatePerFunctionConfigs(cwd, importMapPath string, noVerifyJWT *bool, fsys afero.Fs) ([]string, string, error) { +func PopulatePerFunctionConfigs(cwd, importMapPath string, noVerifyJWT *bool, fsys afero.Fs) ([]string, string, error) { slugs, err := deploy.GetFunctionSlugs(fsys) if err != nil { return nil, "", err diff --git a/internal/functions/serve/serve_test.go b/internal/functions/serve/serve_test.go index 7b0bb17fa..38b7f420c 100644 --- a/internal/functions/serve/serve_test.go +++ b/internal/functions/serve/serve_test.go @@ -161,7 +161,7 @@ func TestServeFunctions(t *testing.T) { // Setup in-memory fs fsys := afero.FromIOFS{FS: testdata} // Run test - binds, configString, err := populatePerFunctionConfigs("/", "", nil, fsys) + binds, configString, err := PopulatePerFunctionConfigs("/", "", nil, fsys) // Check error assert.NoError(t, err) assert.ElementsMatch(t, []string{ diff --git a/internal/gen/bearerjwt/bearerjwt.go b/internal/gen/bearerjwt/bearerjwt.go index e81f79e6a..a813dbf85 100644 --- a/internal/gen/bearerjwt/bearerjwt.go +++ b/internal/gen/bearerjwt/bearerjwt.go @@ -35,11 +35,14 @@ func Run(ctx context.Context, claims jwt.Claims, w io.Writer, fsys afero.Fs) err func getSigningKey(ctx context.Context) (*config.JWK, error) { console := utils.NewConsole() if len(utils.Config.Auth.SigningKeysPath) == 0 { - title := "Enter your signing key in JWK format: " + title := "Enter your signing key in JWK format (or leave blank to use local default): " kid, err := console.PromptText(ctx, title) if err != nil { return nil, err } + if len(kid) == 0 && len(utils.Config.Auth.SigningKeys) > 0 { + return &utils.Config.Auth.SigningKeys[0], nil + } key := config.JWK{} if err := json.Unmarshal([]byte(kid), &key); err != nil { return nil, errors.Errorf("failed to parse JWK: %w", err) diff --git a/internal/inspect/calls/calls.sql b/internal/inspect/calls/calls.sql index be29b15d0..8fa9eb8a9 100644 --- a/internal/inspect/calls/calls.sql +++ b/internal/inspect/calls/calls.sql @@ -2,7 +2,7 @@ SELECT query, (interval '1 millisecond' * total_exec_time)::text AS total_exec_time, to_char((total_exec_time/sum(total_exec_time) OVER()) * 100, 'FM90D0') || '%' AS prop_exec_time, - to_char(calls, 'FM999G999G990') AS ncalls, + to_char(calls, 'FM999G999G999G999G990') AS ncalls, /* Handle column names for 15 and 17 */ diff --git a/internal/migration/squash/squash.go b/internal/migration/squash/squash.go index b2c1650af..afc52c687 100644 --- a/internal/migration/squash/squash.go +++ b/internal/migration/squash/squash.go @@ -85,7 +85,7 @@ func squashMigrations(ctx context.Context, migrations []string, fsys afero.Fs, o return err } defer utils.DockerRemove(shadow) - if err := start.WaitForHealthyService(ctx, start.HealthTimeout, shadow); err != nil { + if err := start.WaitForHealthyService(ctx, utils.Config.Db.HealthTimeout, shadow); err != nil { return err } conn, err := diff.ConnectShadowDatabase(ctx, 10*time.Second, options...) diff --git a/internal/migration/squash/squash_test.go b/internal/migration/squash/squash_test.go index 15eb52c9f..9bb51dab6 100644 --- a/internal/migration/squash/squash_test.go +++ b/internal/migration/squash/squash_test.go @@ -22,7 +22,6 @@ import ( "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/supabase/cli/internal/db/start" "github.com/supabase/cli/internal/migration/repair" "github.com/supabase/cli/internal/testing/apitest" "github.com/supabase/cli/internal/testing/fstest" @@ -214,7 +213,7 @@ func TestSquashMigrations(t *testing.T) { }) t.Run("throws error on health check failure", func(t *testing.T) { - start.HealthTimeout = time.Millisecond + utils.Config.Db.HealthTimeout = time.Millisecond // Setup in-memory fs fsys := afero.NewMemMapFs() // Setup mock docker diff --git a/internal/start/start.go b/internal/start/start.go index cf4bc68fd..1184b6590 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -4,6 +4,7 @@ import ( "bytes" "context" _ "embed" + "encoding/json" "fmt" "io" "net" @@ -250,6 +251,11 @@ func run(ctx context.Context, fsys afero.Fs, excludedContainers []string, dbConf isS3ProtocolEnabled := utils.Config.Storage.S3Protocol != nil && utils.Config.Storage.S3Protocol.Enabled fmt.Fprintln(os.Stderr, "Starting containers...") + workdir, err := os.Getwd() + if err != nil { + return errors.Errorf("failed to get working directory: %w", err) + } + // Start Logflare if utils.Config.Analytics.Enabled && !isContainerExcluded(utils.Config.Analytics.Image, excluded) { env := []string{ @@ -272,10 +278,6 @@ func run(ctx context.Context, fsys afero.Fs, excludedContainers []string, dbConf switch utils.Config.Analytics.Backend { case config.LogflareBigQuery: - workdir, err := os.Getwd() - if err != nil { - return errors.Errorf("failed to get working directory: %w", err) - } hostJwtPath := filepath.Join(workdir, utils.Config.Analytics.GcpJwtPath) bind = append(bind, hostJwtPath+":/opt/app/rel/logflare/bin/gcloud.json") // This is hardcoded in studio frontend @@ -305,7 +307,8 @@ func run(ctx context.Context, fsys afero.Fs, excludedContainers []string, dbConf EOF `}, Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", + Test: []string{ + "CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", "http://127.0.0.1:4000/health", }, Interval: 10 * time.Second, @@ -316,8 +319,10 @@ EOF ExposedPorts: nat.PortSet{"4000/tcp": {}}, }, container.HostConfig{ - Binds: bind, - PortBindings: nat.PortMap{"4000/tcp": []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Analytics.Port), 10)}}}, + Binds: bind, + PortBindings: nat.PortMap{"4000/tcp": []nat.PortBinding{{ + HostPort: strconv.FormatUint(uint64(utils.Config.Analytics.Port), 10), + }}}, RestartPolicy: container.RestartPolicy{Name: container.RestartPolicyUnlessStopped}, }, network.NetworkingConfig{ @@ -391,7 +396,8 @@ EOF EOF `}, Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "wget", "--no-verbose", "--tries=1", "--spider", + Test: []string{ + "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9001/health", }, Interval: 10 * time.Second, @@ -524,8 +530,8 @@ EOF container.HostConfig{ Binds: binds, PortBindings: nat.PortMap{nat.Port(fmt.Sprintf("%d/tcp", dockerPort)): []nat.PortBinding{{ - HostPort: strconv.FormatUint(uint64(utils.Config.Api.Port), 10)}, - }}, + HostPort: strconv.FormatUint(uint64(utils.Config.Api.Port), 10), + }}}, RestartPolicy: container.RestartPolicy{Name: container.RestartPolicyUnlessStopped}, }, network.NetworkingConfig{ @@ -616,8 +622,8 @@ EOF fmt.Sprintf("GOTRUE_RATE_LIMIT_WEB3=%v", utils.Config.Auth.RateLimit.Web3), } - // Since signing key is validated by ResolveJWKS, simply read the key file. - if keys, err := afero.ReadFile(fsys, utils.Config.Auth.SigningKeysPath); err == nil && len(keys) > 0 { + // Serialise default or custom signing keys + if keys, err := json.Marshal(utils.Config.Auth.SigningKeys); err == nil { env = append(env, "GOTRUE_JWT_KEYS="+string(keys)) // TODO: deprecate HS256 when it's no longer supported env = append(env, "GOTRUE_JWT_VALID_METHODS=HS256,RS256,ES256") @@ -815,7 +821,8 @@ EOF Env: env, ExposedPorts: nat.PortSet{"9999/tcp": {}}, Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "wget", "--no-verbose", "--tries=1", "--spider", + Test: []string{ + "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:9999/health", }, Interval: 10 * time.Second, @@ -842,12 +849,18 @@ EOF // Start Mailpit if utils.Config.Inbucket.Enabled && !isContainerExcluded(utils.Config.Inbucket.Image, excluded) { - inbucketPortBindings := nat.PortMap{"8025/tcp": []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.Port), 10)}}} + inbucketPortBindings := nat.PortMap{"8025/tcp": []nat.PortBinding{{ + HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.Port), 10), + }}} if utils.Config.Inbucket.SmtpPort != 0 { - inbucketPortBindings["1025/tcp"] = []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.SmtpPort), 10)}} + inbucketPortBindings["1025/tcp"] = []nat.PortBinding{{ + HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.SmtpPort), 10), + }} } if utils.Config.Inbucket.Pop3Port != 0 { - inbucketPortBindings["1110/tcp"] = []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.Pop3Port), 10)}} + inbucketPortBindings["1110/tcp"] = []nat.PortBinding{{ + HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.Pop3Port), 10), + }} } if _, err := utils.DockerStart( ctx, @@ -914,7 +927,8 @@ EOF ExposedPorts: nat.PortSet{"4000/tcp": {}}, Healthcheck: &container.HealthConfig{ // Podman splits command by spaces unless it's quoted, but curl header can't be quoted. - Test: []string{"CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", + Test: []string{ + "CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", "-H", "Host:" + utils.Config.Realtime.TenantId, "http://127.0.0.1:4000/api/ping", }, @@ -1008,7 +1022,8 @@ EOF }, Healthcheck: &container.HealthConfig{ // For some reason, localhost resolves to IPv6 address on GitPod which breaks healthcheck. - Test: []string{"CMD", "wget", "--no-verbose", "--tries=1", "--spider", + Test: []string{ + "CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:5000/status", }, Interval: 10 * time.Second, @@ -1125,6 +1140,16 @@ EOF // Start Studio. if utils.Config.Studio.Enabled && !isContainerExcluded(utils.Config.Studio.Image, excluded) { + binds, _, err := serve.PopulatePerFunctionConfigs(workdir, "", nil, fsys) + if err != nil { + return err + } + + // Mount snippets directory for Studio to access + hostSnippetsPath := filepath.Join(workdir, utils.SnippetsDir) + containerSnippetsPath := utils.ToDockerPath(hostSnippetsPath) + binds = append(binds, fmt.Sprintf("%s:%s:rw", hostSnippetsPath, containerSnippetsPath)) + binds = utils.RemoveDuplicates(binds) if _, err := utils.DockerStart( ctx, container.Config{ @@ -1143,6 +1168,8 @@ EOF fmt.Sprintf("LOGFLARE_URL=http://%v:4000", utils.LogflareId), fmt.Sprintf("NEXT_PUBLIC_ENABLE_LOGS=%v", utils.Config.Analytics.Enabled), fmt.Sprintf("NEXT_ANALYTICS_BACKEND_PROVIDER=%v", utils.Config.Analytics.Backend), + "EDGE_FUNCTIONS_MANAGEMENT_FOLDER=" + utils.ToDockerPath(filepath.Join(workdir, utils.FunctionsDir)), + "SNIPPETS_MANAGEMENT_FOLDER=" + containerSnippetsPath, // Ref: https://github.com/vercel/next.js/issues/51684#issuecomment-1612834913 "HOSTNAME=0.0.0.0", }, @@ -1154,7 +1181,10 @@ EOF }, }, container.HostConfig{ - PortBindings: nat.PortMap{"3000/tcp": []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Studio.Port), 10)}}}, + Binds: binds, + PortBindings: nat.PortMap{"3000/tcp": []nat.PortBinding{{ + HostPort: strconv.FormatUint(uint64(utils.Config.Studio.Port), 10), + }}}, RestartPolicy: container.RestartPolicy{Name: container.RestartPolicyUnlessStopped}, }, network.NetworkingConfig{ @@ -1230,8 +1260,8 @@ EOF }, container.HostConfig{ PortBindings: nat.PortMap{nat.Port(fmt.Sprintf("%d/tcp", dockerPort)): []nat.PortBinding{{ - HostPort: strconv.FormatUint(uint64(utils.Config.Db.Pooler.Port), 10)}, - }}, + HostPort: strconv.FormatUint(uint64(utils.Config.Db.Pooler.Port), 10), + }}}, RestartPolicy: container.RestartPolicy{Name: container.RestartPolicyUnlessStopped}, }, network.NetworkingConfig{ diff --git a/internal/start/start_test.go b/internal/start/start_test.go index a90d7a719..bec6da5cf 100644 --- a/internal/start/start_test.go +++ b/internal/start/start_test.go @@ -257,27 +257,48 @@ func TestDatabaseStart(t *testing.T) { func TestFormatMapForEnvConfig(t *testing.T) { t.Run("It produces the correct format and removes the trailing comma", func(t *testing.T) { + testcases := []struct { + key string + value string + expected string + }{ + { + key: "123456", + value: "123456", + expected: `^\w{6}:\w{6}$`, + }, + { + key: "234567", + value: "234567", + expected: `^\w{6}:\w{6},\w{6}:\w{6}$`, + }, + { + key: "345678", + value: "345678", + expected: `^\w{6}:\w{6},\w{6}:\w{6},\w{6}:\w{6}$`, + }, + { + key: "456789", + value: "456789", + expected: `^\w{6}:\w{6},\w{6}:\w{6},\w{6}:\w{6},\w{6}:\w{6}$`, + }, + } + output := bytes.Buffer{} input := map[string]string{} - - keys := [4]string{"123456", "234567", "345678", "456789"} - values := [4]string{"123456", "234567", "345678", "456789"} - expected := [4]string{ - `^\w{6}:\w{6}$`, - `^\w{6}:\w{6},\w{6}:\w{6}$`, - `^\w{6}:\w{6},\w{6}:\w{6},\w{6}:\w{6}$`, - `^\w{6}:\w{6},\w{6}:\w{6},\w{6}:\w{6},\w{6}:\w{6}$`, - } formatMapForEnvConfig(input, &output) if len(output.Bytes()) > 0 { t.Error("No values should be expected when empty map is provided") } - for i := range 4 { + + for _, c := range testcases { output.Reset() - input[keys[i]] = values[i] + input[c.key] = c.value formatMapForEnvConfig(input, &output) result := output.String() - assert.Regexp(t, regexp.MustCompile(expected[i]), result) + r, err := regexp.Compile(c.expected) + require.NoError(t, err) + assert.Regexp(t, r, result) } }) } diff --git a/internal/utils/connect.go b/internal/utils/connect.go index 5fc4e3b9b..3b52d29da 100644 --- a/internal/utils/connect.go +++ b/internal/utils/connect.go @@ -164,7 +164,22 @@ func ConnectByUrl(ctx context.Context, url string, options ...func(*pgx.ConnConf } cc.Fallbacks = fallbacks }) - return pgxv5.Connect(ctx, url, options...) + conn, err := pgxv5.Connect(ctx, url, options...) + var pgErr *pgconn.PgError + if errors.As(err, &pgErr) { + if strings.Contains(pgErr.Message, "connect: connection refused") { + CmdSuggestion = fmt.Sprintf("Make sure your local IP is allowed in Network Restrictions and Network Bans.\n%s/project/_/database/settings", CurrentProfile.DashboardURL) + } else if strings.Contains(pgErr.Message, "SSL connection is required") && viper.GetBool("DEBUG") { + CmdSuggestion = "SSL connection is not supported with --debug flag" + } else if strings.Contains(pgErr.Message, "SCRAM exchange: Wrong password") || strings.Contains(pgErr.Message, "failed SASL auth") { + // password authentication failed for user / invalid SCRAM server-final-message received from server + CmdSuggestion = "Try setting the SUPABASE_DB_PASSWORD environment variable" + } else if strings.Contains(pgErr.Message, "connect: no route to host") || strings.Contains(pgErr.Message, "Tenant or user not found") { + // Assumes IPv6 check has been performed before this + CmdSuggestion = "Make sure your project exists on profile: " + CurrentProfile.Name + } + } + return conn, err } const ( diff --git a/internal/utils/misc.go b/internal/utils/misc.go index f81b792f5..b47a8a3eb 100644 --- a/internal/utils/misc.go +++ b/internal/utils/misc.go @@ -80,6 +80,7 @@ var ( SchemasDir = filepath.Join(SupabaseDirPath, "schemas") MigrationsDir = filepath.Join(SupabaseDirPath, "migrations") FunctionsDir = filepath.Join(SupabaseDirPath, "functions") + SnippetsDir = filepath.Join(SupabaseDirPath, "snippets") FallbackImportMapPath = filepath.Join(FunctionsDir, "import_map.json") FallbackEnvFilePath = filepath.Join(FunctionsDir, ".env") DbTestsDir = filepath.Join(SupabaseDirPath, "tests") diff --git a/internal/utils/profile.go b/internal/utils/profile.go index 1910f30b7..723b52fa8 100644 --- a/internal/utils/profile.go +++ b/internal/utils/profile.go @@ -3,6 +3,7 @@ package utils import ( "context" "fmt" + "sort" "strings" "github.com/go-errors/errors" @@ -128,3 +129,12 @@ func getProfileName(fsys afero.Fs) string { return prof } } + +func AwsRegions() []string { + result := make([]string, len(allProfiles[0].ProjectRegions)) + for i, region := range allProfiles[0].ProjectRegions { + result[i] = string(region) + } + sort.Strings(result) + return result +} diff --git a/pkg/api/types.gen.go b/pkg/api/types.gen.go index dc89e1c57..65079455c 100644 --- a/pkg/api/types.gen.go +++ b/pkg/api/types.gen.go @@ -818,6 +818,52 @@ const ( ProjectUpgradeEligibilityResponseTargetUpgradeVersionsReleaseChannelWithdrawn ProjectUpgradeEligibilityResponseTargetUpgradeVersionsReleaseChannel = "withdrawn" ) +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors0Type. +const ( + ObjectsDependingOnPgCron ProjectUpgradeEligibilityResponseValidationErrors0Type = "objects_depending_on_pg_cron" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors1Type. +const ( + IndexesReferencingLlToEarth ProjectUpgradeEligibilityResponseValidationErrors1Type = "indexes_referencing_ll_to_earth" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors2Type. +const ( + FunctionUsingObsoleteLang ProjectUpgradeEligibilityResponseValidationErrors2Type = "function_using_obsolete_lang" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors3Type. +const ( + UnsupportedExtension ProjectUpgradeEligibilityResponseValidationErrors3Type = "unsupported_extension" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors4Type. +const ( + UnsupportedFdwHandler ProjectUpgradeEligibilityResponseValidationErrors4Type = "unsupported_fdw_handler" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors5Type. +const ( + UnloggedTableWithPersistentSequence ProjectUpgradeEligibilityResponseValidationErrors5Type = "unlogged_table_with_persistent_sequence" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors6ObjType. +const ( + ProjectUpgradeEligibilityResponseValidationErrors6ObjTypeFunction ProjectUpgradeEligibilityResponseValidationErrors6ObjType = "function" + ProjectUpgradeEligibilityResponseValidationErrors6ObjTypeTable ProjectUpgradeEligibilityResponseValidationErrors6ObjType = "table" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors6Type. +const ( + UserDefinedObjectsInInternalSchemas ProjectUpgradeEligibilityResponseValidationErrors6Type = "user_defined_objects_in_internal_schemas" +) + +// Defines values for ProjectUpgradeEligibilityResponseValidationErrors7Type. +const ( + ActiveReplicationSlot ProjectUpgradeEligibilityResponseValidationErrors7Type = "active_replication_slot" +) + // Defines values for RegionsInfoAllSmartGroupCode. const ( RegionsInfoAllSmartGroupCodeAmericas RegionsInfoAllSmartGroupCode = "americas" @@ -1578,14 +1624,14 @@ const ( // Defines values for V1GetServicesHealthParamsServices. const ( - Auth V1GetServicesHealthParamsServices = "auth" - Db V1GetServicesHealthParamsServices = "db" - DbPostgresUser V1GetServicesHealthParamsServices = "db_postgres_user" - PgBouncer V1GetServicesHealthParamsServices = "pg_bouncer" - Pooler V1GetServicesHealthParamsServices = "pooler" - Realtime V1GetServicesHealthParamsServices = "realtime" - Rest V1GetServicesHealthParamsServices = "rest" - Storage V1GetServicesHealthParamsServices = "storage" + V1GetServicesHealthParamsServicesAuth V1GetServicesHealthParamsServices = "auth" + V1GetServicesHealthParamsServicesDb V1GetServicesHealthParamsServices = "db" + V1GetServicesHealthParamsServicesDbPostgresUser V1GetServicesHealthParamsServices = "db_postgres_user" + V1GetServicesHealthParamsServicesPgBouncer V1GetServicesHealthParamsServices = "pg_bouncer" + V1GetServicesHealthParamsServicesPooler V1GetServicesHealthParamsServices = "pooler" + V1GetServicesHealthParamsServicesRealtime V1GetServicesHealthParamsServices = "realtime" + V1GetServicesHealthParamsServicesRest V1GetServicesHealthParamsServices = "rest" + V1GetServicesHealthParamsServicesStorage V1GetServicesHealthParamsServices = "storage" ) // Defines values for V1ListAllSnippetsParamsSortBy. @@ -1873,6 +1919,9 @@ type AuthConfigResponse struct { NimbusOauthClientId nullable.Nullable[string] `json:"nimbus_oauth_client_id"` NimbusOauthClientSecret nullable.Nullable[string] `json:"nimbus_oauth_client_secret"` NimbusOauthEmailOptional nullable.Nullable[bool] `json:"nimbus_oauth_email_optional"` + OauthServerAllowDynamicRegistration bool `json:"oauth_server_allow_dynamic_registration"` + OauthServerAuthorizationPath nullable.Nullable[string] `json:"oauth_server_authorization_path"` + OauthServerEnabled bool `json:"oauth_server_enabled"` PasswordHibpEnabled nullable.Nullable[bool] `json:"password_hibp_enabled"` PasswordMinLength nullable.Nullable[int] `json:"password_min_length"` PasswordRequiredCharacters nullable.Nullable[AuthConfigResponsePasswordRequiredCharacters] `json:"password_required_characters"` @@ -3044,14 +3093,24 @@ type ProjectUpgradeEligibilityResponse struct { Eligible bool `json:"eligible"` LatestAppVersion string `json:"latest_app_version"` LegacyAuthCustomRoles []string `json:"legacy_auth_custom_roles"` - ObjectsToBeDropped []string `json:"objects_to_be_dropped"` - TargetUpgradeVersions []struct { + + // ObjectsToBeDropped Use validation_errors instead. + // Deprecated: + ObjectsToBeDropped []string `json:"objects_to_be_dropped"` + TargetUpgradeVersions []struct { AppVersion string `json:"app_version"` PostgresVersion ProjectUpgradeEligibilityResponseTargetUpgradeVersionsPostgresVersion `json:"postgres_version"` ReleaseChannel ProjectUpgradeEligibilityResponseTargetUpgradeVersionsReleaseChannel `json:"release_channel"` } `json:"target_upgrade_versions"` - UnsupportedExtensions []string `json:"unsupported_extensions"` - UserDefinedObjectsInInternalSchemas []string `json:"user_defined_objects_in_internal_schemas"` + + // UnsupportedExtensions Use validation_errors instead. + // Deprecated: + UnsupportedExtensions []string `json:"unsupported_extensions"` + + // UserDefinedObjectsInInternalSchemas Use validation_errors instead. + // Deprecated: + UserDefinedObjectsInInternalSchemas []string `json:"user_defined_objects_in_internal_schemas"` + ValidationErrors []ProjectUpgradeEligibilityResponse_ValidationErrors_Item `json:"validation_errors"` } // ProjectUpgradeEligibilityResponseCurrentAppVersionReleaseChannel defines model for ProjectUpgradeEligibilityResponse.CurrentAppVersionReleaseChannel. @@ -3063,6 +3122,95 @@ type ProjectUpgradeEligibilityResponseTargetUpgradeVersionsPostgresVersion strin // ProjectUpgradeEligibilityResponseTargetUpgradeVersionsReleaseChannel defines model for ProjectUpgradeEligibilityResponse.TargetUpgradeVersions.ReleaseChannel. type ProjectUpgradeEligibilityResponseTargetUpgradeVersionsReleaseChannel string +// ProjectUpgradeEligibilityResponseValidationErrors0 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors0 struct { + Dependents []string `json:"dependents"` + Type ProjectUpgradeEligibilityResponseValidationErrors0Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors0Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.0.Type. +type ProjectUpgradeEligibilityResponseValidationErrors0Type string + +// ProjectUpgradeEligibilityResponseValidationErrors1 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors1 struct { + IndexName string `json:"index_name"` + SchemaName string `json:"schema_name"` + TableName string `json:"table_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors1Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors1Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.1.Type. +type ProjectUpgradeEligibilityResponseValidationErrors1Type string + +// ProjectUpgradeEligibilityResponseValidationErrors2 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors2 struct { + FunctionName string `json:"function_name"` + LangName string `json:"lang_name"` + SchemaName string `json:"schema_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors2Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors2Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.2.Type. +type ProjectUpgradeEligibilityResponseValidationErrors2Type string + +// ProjectUpgradeEligibilityResponseValidationErrors3 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors3 struct { + ExtensionName string `json:"extension_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors3Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors3Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.3.Type. +type ProjectUpgradeEligibilityResponseValidationErrors3Type string + +// ProjectUpgradeEligibilityResponseValidationErrors4 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors4 struct { + FdwHandlerName string `json:"fdw_handler_name"` + FdwName string `json:"fdw_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors4Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors4Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.4.Type. +type ProjectUpgradeEligibilityResponseValidationErrors4Type string + +// ProjectUpgradeEligibilityResponseValidationErrors5 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors5 struct { + SchemaName string `json:"schema_name"` + SequenceName string `json:"sequence_name"` + TableName string `json:"table_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors5Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors5Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.5.Type. +type ProjectUpgradeEligibilityResponseValidationErrors5Type string + +// ProjectUpgradeEligibilityResponseValidationErrors6 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors6 struct { + ObjName string `json:"obj_name"` + ObjType ProjectUpgradeEligibilityResponseValidationErrors6ObjType `json:"obj_type"` + SchemaName string `json:"schema_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors6Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors6ObjType defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.6.ObjType. +type ProjectUpgradeEligibilityResponseValidationErrors6ObjType string + +// ProjectUpgradeEligibilityResponseValidationErrors6Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.6.Type. +type ProjectUpgradeEligibilityResponseValidationErrors6Type string + +// ProjectUpgradeEligibilityResponseValidationErrors7 defines model for . +type ProjectUpgradeEligibilityResponseValidationErrors7 struct { + SlotName string `json:"slot_name"` + Type ProjectUpgradeEligibilityResponseValidationErrors7Type `json:"type"` +} + +// ProjectUpgradeEligibilityResponseValidationErrors7Type defines model for ProjectUpgradeEligibilityResponse.ValidationErrors.7.Type. +type ProjectUpgradeEligibilityResponseValidationErrors7Type string + +// ProjectUpgradeEligibilityResponse_ValidationErrors_Item defines model for ProjectUpgradeEligibilityResponse.validation_errors.Item. +type ProjectUpgradeEligibilityResponse_ValidationErrors_Item struct { + union json.RawMessage +} + // ProjectUpgradeInitiateResponse defines model for ProjectUpgradeInitiateResponse. type ProjectUpgradeInitiateResponse struct { TrackingId string `json:"tracking_id"` @@ -3584,6 +3732,9 @@ type UpdateAuthConfigBody struct { MfaWebAuthnVerifyEnabled nullable.Nullable[bool] `json:"mfa_web_authn_verify_enabled,omitempty"` NimbusOauthClientId nullable.Nullable[string] `json:"nimbus_oauth_client_id,omitempty"` NimbusOauthClientSecret nullable.Nullable[string] `json:"nimbus_oauth_client_secret,omitempty"` + OauthServerAllowDynamicRegistration nullable.Nullable[bool] `json:"oauth_server_allow_dynamic_registration,omitempty"` + OauthServerAuthorizationPath nullable.Nullable[string] `json:"oauth_server_authorization_path,omitempty"` + OauthServerEnabled nullable.Nullable[bool] `json:"oauth_server_enabled,omitempty"` PasswordHibpEnabled nullable.Nullable[bool] `json:"password_hibp_enabled,omitempty"` PasswordMinLength nullable.Nullable[int] `json:"password_min_length,omitempty"` PasswordRequiredCharacters nullable.Nullable[UpdateAuthConfigBodyPasswordRequiredCharacters] `json:"password_required_characters,omitempty"` @@ -4370,7 +4521,10 @@ type V1RunQueryBody struct { // V1ServiceHealthResponse defines model for V1ServiceHealthResponse. type V1ServiceHealthResponse struct { - Error *string `json:"error,omitempty"` + Error *string `json:"error,omitempty"` + + // Healthy Deprecated. Use `status` instead. + // Deprecated: Healthy bool `json:"healthy"` Info *V1ServiceHealthResponse_Info `json:"info,omitempty"` Name V1ServiceHealthResponseName `json:"name"` @@ -4391,7 +4545,10 @@ type V1ServiceHealthResponseInfo0Name string type V1ServiceHealthResponseInfo1 struct { ConnectedCluster int `json:"connected_cluster"` DbConnected bool `json:"db_connected"` - Healthy bool `json:"healthy"` + + // Healthy Deprecated. Use `status` instead. + // Deprecated: + Healthy bool `json:"healthy"` } // V1ServiceHealthResponseInfo2 defines model for . @@ -5739,6 +5896,224 @@ func (t *ListProjectAddonsResponse_SelectedAddons_Variant_Id) UnmarshalJSON(b [] return err } +// AsProjectUpgradeEligibilityResponseValidationErrors0 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors0 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors0() (ProjectUpgradeEligibilityResponseValidationErrors0, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors0 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors0 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors0 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors0(v ProjectUpgradeEligibilityResponseValidationErrors0) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors0 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors0 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors0(v ProjectUpgradeEligibilityResponseValidationErrors0) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors1 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors1 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors1() (ProjectUpgradeEligibilityResponseValidationErrors1, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors1 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors1 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors1 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors1(v ProjectUpgradeEligibilityResponseValidationErrors1) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors1 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors1 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors1(v ProjectUpgradeEligibilityResponseValidationErrors1) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors2 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors2 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors2() (ProjectUpgradeEligibilityResponseValidationErrors2, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors2 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors2 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors2 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors2(v ProjectUpgradeEligibilityResponseValidationErrors2) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors2 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors2 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors2(v ProjectUpgradeEligibilityResponseValidationErrors2) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors3 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors3 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors3() (ProjectUpgradeEligibilityResponseValidationErrors3, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors3 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors3 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors3 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors3(v ProjectUpgradeEligibilityResponseValidationErrors3) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors3 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors3 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors3(v ProjectUpgradeEligibilityResponseValidationErrors3) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors4 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors4 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors4() (ProjectUpgradeEligibilityResponseValidationErrors4, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors4 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors4 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors4 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors4(v ProjectUpgradeEligibilityResponseValidationErrors4) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors4 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors4 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors4(v ProjectUpgradeEligibilityResponseValidationErrors4) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors5 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors5 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors5() (ProjectUpgradeEligibilityResponseValidationErrors5, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors5 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors5 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors5 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors5(v ProjectUpgradeEligibilityResponseValidationErrors5) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors5 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors5 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors5(v ProjectUpgradeEligibilityResponseValidationErrors5) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors6 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors6 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors6() (ProjectUpgradeEligibilityResponseValidationErrors6, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors6 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors6 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors6 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors6(v ProjectUpgradeEligibilityResponseValidationErrors6) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors6 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors6 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors6(v ProjectUpgradeEligibilityResponseValidationErrors6) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +// AsProjectUpgradeEligibilityResponseValidationErrors7 returns the union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as a ProjectUpgradeEligibilityResponseValidationErrors7 +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) AsProjectUpgradeEligibilityResponseValidationErrors7() (ProjectUpgradeEligibilityResponseValidationErrors7, error) { + var body ProjectUpgradeEligibilityResponseValidationErrors7 + err := json.Unmarshal(t.union, &body) + return body, err +} + +// FromProjectUpgradeEligibilityResponseValidationErrors7 overwrites any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item as the provided ProjectUpgradeEligibilityResponseValidationErrors7 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) FromProjectUpgradeEligibilityResponseValidationErrors7(v ProjectUpgradeEligibilityResponseValidationErrors7) error { + b, err := json.Marshal(v) + t.union = b + return err +} + +// MergeProjectUpgradeEligibilityResponseValidationErrors7 performs a merge with any union data inside the ProjectUpgradeEligibilityResponse_ValidationErrors_Item, using the provided ProjectUpgradeEligibilityResponseValidationErrors7 +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MergeProjectUpgradeEligibilityResponseValidationErrors7(v ProjectUpgradeEligibilityResponseValidationErrors7) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + + merged, err := runtime.JSONMerge(t.union, b) + t.union = merged + return err +} + +func (t ProjectUpgradeEligibilityResponse_ValidationErrors_Item) MarshalJSON() ([]byte, error) { + b, err := t.union.MarshalJSON() + return b, err +} + +func (t *ProjectUpgradeEligibilityResponse_ValidationErrors_Item) UnmarshalJSON(b []byte) error { + err := t.union.UnmarshalJSON(b) + return err +} + // AsV1CreateProjectBodyRegionSelection0 returns the union data inside the V1CreateProjectBody_RegionSelection as a V1CreateProjectBodyRegionSelection0 func (t V1CreateProjectBody_RegionSelection) AsV1CreateProjectBodyRegionSelection0() (V1CreateProjectBodyRegionSelection0, error) { var body V1CreateProjectBodyRegionSelection0 diff --git a/pkg/config/auth.go b/pkg/config/auth.go index 56288b882..3c6ee2fd4 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -1319,6 +1319,15 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { body.ExternalTwitterEmailOptional = nullable.NewNullableWithValue(p.EmailOptional) } } + if p, ok := e["x"]; ok { + if body.ExternalXEnabled = nullable.NewNullableWithValue(p.Enabled); p.Enabled { + body.ExternalXClientId = nullable.NewNullableWithValue(p.ClientId) + if len(p.Secret.SHA256) > 0 { + body.ExternalXSecret = nullable.NewNullableWithValue(p.Secret.Value) + } + body.ExternalXEmailOptional = nullable.NewNullableWithValue(p.EmailOptional) + } + } if p, ok := e["workos"]; ok { if body.ExternalWorkosEnabled = nullable.NewNullableWithValue(p.Enabled); p.Enabled { body.ExternalWorkosClientId = nullable.NewNullableWithValue(p.ClientId) @@ -1558,6 +1567,18 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { e["twitter"] = p } + if p, ok := e["x"]; ok { + if p.Enabled { + p.ClientId = ValOrDefault(remoteConfig.ExternalXClientId, "") + if len(p.Secret.SHA256) > 0 { + p.Secret.SHA256 = ValOrDefault(remoteConfig.ExternalXSecret, "") + } + p.EmailOptional = ValOrDefault(remoteConfig.ExternalXEmailOptional, false) + } + p.Enabled = ValOrDefault(remoteConfig.ExternalXEnabled, false) + e["x"] = p + } + if p, ok := e["workos"]; ok { if p.Enabled { p.ClientId = ValOrDefault(remoteConfig.ExternalWorkosClientId, "") diff --git a/pkg/config/auth_test.go b/pkg/config/auth_test.go index 0d04c7609..fc0b2c6f4 100644 --- a/pkg/config/auth_test.go +++ b/pkg/config/auth_test.go @@ -1115,6 +1115,7 @@ func TestExternalDiff(t *testing.T) { "spotify": {Enabled: true}, "twitch": {Enabled: true}, "twitter": {Enabled: true}, + "x": {Enabled: true}, "workos": {Enabled: true}, "zoom": {Enabled: true}, } @@ -1177,6 +1178,9 @@ func TestExternalDiff(t *testing.T) { ExternalTwitterClientId: nullable.NewNullableWithValue(""), ExternalTwitterEnabled: nullable.NewNullableWithValue(true), ExternalTwitterSecret: nullable.NewNullableWithValue(""), + ExternalXClientId: nullable.NewNullableWithValue(""), + ExternalXEnabled: nullable.NewNullableWithValue(true), + ExternalXSecret: nullable.NewNullableWithValue(""), ExternalWorkosClientId: nullable.NewNullableWithValue(""), ExternalWorkosEnabled: nullable.NewNullableWithValue(true), ExternalWorkosSecret: nullable.NewNullableWithValue(""), @@ -1233,6 +1237,7 @@ func TestExternalDiff(t *testing.T) { "spotify": {}, "twitch": {}, "twitter": {}, + "x": {}, "workos": {}, "zoom": {}, } @@ -1276,6 +1281,7 @@ func TestExternalDiff(t *testing.T) { "spotify": {}, "twitch": {}, "twitter": {}, + "x": {}, "workos": {}, "zoom": {}, } @@ -1299,6 +1305,7 @@ func TestExternalDiff(t *testing.T) { ExternalSpotifyEnabled: nullable.NewNullableWithValue(false), ExternalTwitchEnabled: nullable.NewNullableWithValue(false), ExternalTwitterEnabled: nullable.NewNullableWithValue(false), + ExternalXEnabled: nullable.NewNullableWithValue(false), ExternalWorkosEnabled: nullable.NewNullableWithValue(false), ExternalZoomEnabled: nullable.NewNullableWithValue(false), // Deprecated fields should be ignored diff --git a/pkg/config/config.go b/pkg/config/config.go index 6e9ef96bb..8cf2e4a27 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -386,6 +386,18 @@ func NewConfig(editors ...ConfigEditor) config { TestOTP: map[string]string{}, }, External: map[string]provider{}, + SigningKeys: []JWK{{ + KeyType: "EC", + KeyID: "b81269f1-21d8-4f2e-b719-c2240a840d90", + Use: "sig", + KeyOps: []string{"sign", "verify"}, + Algorithm: "ES256", + Extractable: cast.Ptr(true), + Curve: "P-256", + X: "M5Sjqn5zwC9Kl1zVfUUGvv9boQjCGd45G8sdopBExB4", + Y: "P6IXMvA2WYXSHSOMTBH2jsw_9rrzGy89FjPf6oOsIxQ", + PrivateExponent: "dIhR8wywJlqlua4y_yMq2SLhlFXDZJBCvFrY1DCHyVU", + }}, }, Inbucket: inbucket{ Image: Images.Inbucket, @@ -1538,7 +1550,7 @@ func (a *auth) ResolveJWKS(ctx context.Context) (string, error) { jwks.Keys = append(jwks.Keys, json.RawMessage(publicKeyEncoded)) } // Fallback to JWT_SECRET for backward compatibility - if len(a.SigningKeys) == 0 { + if len(a.SigningKeysPath) == 0 { jwtSecret := secretJWK{ KeyType: "oct", KeyBase64URL: base64.RawURLEncoding.EncodeToString([]byte(a.JwtSecret.Value)), diff --git a/pkg/config/db.go b/pkg/config/db.go index b2b947667..122f5364b 100644 --- a/pkg/config/db.go +++ b/pkg/config/db.go @@ -3,6 +3,7 @@ package config import ( "bytes" "slices" + "time" "github.com/go-errors/errors" v1API "github.com/supabase/cli/pkg/api" @@ -78,6 +79,7 @@ type ( Image string `toml:"-"` Port uint16 `toml:"port"` ShadowPort uint16 `toml:"shadow_port"` + HealthTimeout time.Duration `toml:"health_timeout"` MajorVersion uint `toml:"major_version"` Password string `toml:"-"` RootKey Secret `toml:"root_key"` diff --git a/pkg/config/templates/Dockerfile b/pkg/config/templates/Dockerfile index 4509e3f2a..c19389098 100644 --- a/pkg/config/templates/Dockerfile +++ b/pkg/config/templates/Dockerfile @@ -1,19 +1,19 @@ # Exposed for updates by .github/dependabot.yml -FROM supabase/postgres:17.6.1.066 AS pg +FROM supabase/postgres:17.6.1.071 AS pg # Append to ServiceImages when adding new dependencies below FROM library/kong:2.8.1 AS kong FROM axllent/mailpit:v1.22.3 AS mailpit -FROM postgrest/postgrest:v14.1 AS postgrest -FROM supabase/postgres-meta:v0.95.1 AS pgmeta -FROM supabase/studio:2025.12.15-sha-e98ba37 AS studio +FROM postgrest/postgrest:v14.3 AS postgrest +FROM supabase/postgres-meta:v0.95.2 AS pgmeta +FROM supabase/studio:2026.01.07-sha-037e5f9 AS studio FROM darthsim/imgproxy:v3.8.0 AS imgproxy -FROM supabase/edge-runtime:v1.69.28 AS edgeruntime +FROM supabase/edge-runtime:v1.70.0 AS edgeruntime FROM timberio/vector:0.28.1-alpine AS vector FROM supabase/supavisor:2.7.4 AS supavisor FROM supabase/gotrue:v2.184.0 AS gotrue -FROM supabase/realtime:v2.68.6 AS realtime -FROM supabase/storage-api:v1.33.0 AS storage -FROM supabase/logflare:1.27.2 AS logflare +FROM supabase/realtime:v2.69.2 AS realtime +FROM supabase/storage-api:v1.33.5 AS storage +FROM supabase/logflare:1.27.3 AS logflare # Append to JobImages when adding new dependencies below FROM supabase/pgadmin-schema-diff:cli-0.0.5 AS differ FROM supabase/migra:3.0.1663481299 AS migra diff --git a/pkg/config/templates/config.toml b/pkg/config/templates/config.toml index eede7d83d..87af2c389 100644 --- a/pkg/config/templates/config.toml +++ b/pkg/config/templates/config.toml @@ -29,6 +29,8 @@ enabled = false port = 54322 # Port used by db diff command to initialize the shadow database. shadow_port = 54320 +# Maximum amount of time to wait for health check when starting the local database. +health_timeout = "2m" # The database major version to use. This has to be the same as your remote database's. Run `SHOW # server_version;` on the remote database to check. major_version = 17 @@ -295,7 +297,7 @@ max_frequency = "5s" # Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, # `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, -# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +# `twitter`, `x`, `slack`, `spotify`, `workos`, `zoom`. [auth.external.apple] enabled = false client_id = "" diff --git a/pkg/config/testdata/config.toml b/pkg/config/testdata/config.toml index 6b92371b7..ad2a0dd3e 100644 --- a/pkg/config/testdata/config.toml +++ b/pkg/config/testdata/config.toml @@ -29,6 +29,8 @@ key_path = "../certs/my-key.pem" port = 54322 # Port used by db diff command to initialize the shadow database. shadow_port = 54320 +# Maximum amount of time to wait for health check when starting the local database. +health_timeout = "2m" # The database major version to use. This has to be the same as your remote database's. Run `SHOW # server_version;` on the remote database to check. major_version = 17 @@ -304,7 +306,7 @@ verify_enabled = true # Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, # `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, -# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +# `twitter`, `x`, `slack`, `spotify`, `workos`, `zoom`. [auth.external.azure] enabled = true client_id = "env(AZURE_CLIENT_ID)" diff --git a/pkg/go.mod b/pkg/go.mod index 2dfb67c77..e54e34203 100644 --- a/pkg/go.mod +++ b/pkg/go.mod @@ -3,7 +3,7 @@ module github.com/supabase/cli/pkg go 1.24.10 require ( - github.com/BurntSushi/toml v1.5.0 + github.com/BurntSushi/toml v1.6.0 github.com/andybalholm/brotli v1.2.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/docker/go-units v0.5.0 @@ -25,8 +25,8 @@ require ( github.com/spf13/viper v1.21.0 github.com/stretchr/testify v1.11.1 github.com/tidwall/jsonc v0.3.2 - golang.org/x/mod v0.30.0 - google.golang.org/grpc v1.77.0 + golang.org/x/mod v0.32.0 + google.golang.org/grpc v1.78.0 ) require ( diff --git a/pkg/go.sum b/pkg/go.sum index 3a1669dfd..a5f5d59c8 100644 --- a/pkg/go.sum +++ b/pkg/go.sum @@ -1,6 +1,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= -github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk= +github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= @@ -224,8 +224,8 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= +golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c= +golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -290,8 +290,8 @@ golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= -google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff --git a/pkg/migration/scripts/dump_schema.sh b/pkg/migration/scripts/dump_schema.sh index 0b7c8fb90..c136cc086 100755 --- a/pkg/migration/scripts/dump_schema.sh +++ b/pkg/migration/scripts/dump_schema.sh @@ -44,6 +44,7 @@ pg_dump \ | sed -E 's/^ALTER PUBLICATION "supabase_realtime_/-- &/' \ | sed -E 's/^ALTER FOREIGN DATA WRAPPER (.+) OWNER TO /-- &/' \ | sed -E 's/^ALTER DEFAULT PRIVILEGES FOR ROLE "supabase_admin"/-- &/' \ +| sed -E 's/^GRANT ALL ON FOREIGN DATA WRAPPER (.+) TO "postgres" WITH GRANT OPTION/-- &/' \ | sed -E "s/^GRANT (.+) ON (.+) \"(${EXCLUDED_SCHEMAS:-})\"/-- &/" \ | sed -E "s/^REVOKE (.+) ON (.+) \"(${EXCLUDED_SCHEMAS:-})\"/-- &/" \ | sed -E 's/^(CREATE EXTENSION IF NOT EXISTS "pg_tle").+/\1;/' \