Repository: supabase/cli
Pull request #3021 (2025-01-07 02:27:04)

Prod deploy
- **fix: resolve file paths in remote config (#3002)**
- **chore(deps): bump github.com/golangci/golangci-lint from 1.62.2 to 1.63.1 (#3004)**
- **fix: assume platform defaults when local sms keys are unset**
- **chore: use double quote consistently**
- **fix: bump gotrue to 2.166.0**
- **bump to the latest version v2.167.0**
- **chore(deps): bump github.com/go-git/go-git/v5 from 5.13.0 to 5.13.1 (#3008)**
- **chore(deps): bump github.com/golangci/golangci-lint from 1.63.1 to 1.63.3 (#3009)**
- **fix: bump edge-runtime to 1.66.2**
- **fix: ignore hash if local secret is unset (#3012)**
- **chore(deps): bump github.com/getsentry/sentry-go from 0.30.0 to 0.31.1 (#3010)**
- **fix: obtain Postgres URL from branches get command (#2996)**
- **chore(deps): bump github.com/golangci/golangci-lint from 1.63.3 to 1.63.4 (#3018)**
- **chore(deps): bump golang.org/x/term from 0.27.0 to 0.28.0 (#3017)**
- **chore(deps): bump golang.org/x/oauth2 from 0.24.0 to 0.25.0 (#3016)**



Patch:
diff --git a/.golangci.yml b/.golangci.yml
index 9d518983..b91c1afd 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -20,4 +20,4 @@ linters-settings:
   stylecheck:
     checks: ["all", "-ST1003"]
   dupl:
-    threshold: 200
+    threshold: 250
diff --git a/cmd/branches.go b/cmd/branches.go
index 0248e7f3..b541704b 100644
--- a/cmd/branches.go
+++ b/cmd/branches.go
@@ -82,7 +82,7 @@ var (
 			} else {
 				branchId = args[0]
 			}
-			return get.Run(ctx, branchId)
+			return get.Run(ctx, branchId, afero.NewOsFs())
 		},
 	}
 
@@ -165,6 +165,8 @@ func init() {
 	createFlags.Var(&branchRegion, "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.")
+	getFlags := branchGetCmd.Flags()
+	getFlags.VarP(&utils.OutputFormat, "output", "o", "Output format of branch details.")
 	branchesCmd.AddCommand(branchCreateCmd)
 	branchesCmd.AddCommand(branchListCmd)
 	branchesCmd.AddCommand(branchGetCmd)
diff --git a/cmd/db.go b/cmd/db.go
index 13f29401..bcc7ac5e 100644
--- a/cmd/db.go
+++ b/cmd/db.go
@@ -219,11 +219,13 @@ var (
 		},
 	}
 
+	fromBackup string
+
 	dbStartCmd = &cobra.Command{
 		Use:   "start",
 		Short: "Starts local Postgres database",
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return start.Run(cmd.Context(), afero.NewOsFs())
+			return start.Run(cmd.Context(), fromBackup, afero.NewOsFs())
 		},
 	}
 
@@ -329,6 +331,8 @@ func init() {
 	lintFlags.Var(&lintFailOn, "fail-on", "Error level to exit with non-zero status.")
 	dbCmd.AddCommand(dbLintCmd)
 	// Build start command
+	startFlags := dbStartCmd.Flags()
+	startFlags.StringVar(&fromBackup, "from-backup", "", "Path to a logical backup file.")
 	dbCmd.AddCommand(dbStartCmd)
 	// Build test command
 	dbCmd.AddCommand(dbTestCmd)
diff --git a/cmd/link.go b/cmd/link.go
index b1aec1d7..65b8b5f0 100644
--- a/cmd/link.go
+++ b/cmd/link.go
@@ -8,7 +8,6 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"github.com/supabase/cli/internal/link"
-	"github.com/supabase/cli/internal/utils"
 	"github.com/supabase/cli/internal/utils/flags"
 	"golang.org/x/term"
 )
@@ -31,7 +30,7 @@ var (
 				return err
 			}
 			fsys := afero.NewOsFs()
-			if err := utils.LoadConfigFS(fsys); err != nil {
+			if err := flags.LoadConfig(fsys); err != nil {
 				return err
 			}
 			return link.Run(ctx, flags.ProjectRef, fsys)
diff --git a/go.mod b/go.mod
index 77f62b25..efa4c92b 100644
--- a/go.mod
+++ b/go.mod
@@ -13,16 +13,17 @@ require (
 	github.com/charmbracelet/lipgloss v0.12.1
 	github.com/containers/common v0.61.0
 	github.com/deepmap/oapi-codegen/v2 v2.2.0
-	github.com/docker/cli v27.4.1+incompatible
-	github.com/docker/docker v27.4.1+incompatible
+	github.com/docker/cli v27.5.0+incompatible
+	github.com/docker/docker v27.5.0+incompatible
 	github.com/docker/go-connections v0.5.0
 	github.com/docker/go-units v0.5.0
-	github.com/getsentry/sentry-go v0.30.0
+	github.com/ecies/go/v2 v2.0.10
+	github.com/getsentry/sentry-go v0.31.1
 	github.com/go-errors/errors v1.5.1
-	github.com/go-git/go-git/v5 v5.13.0
+	github.com/go-git/go-git/v5 v5.13.1
 	github.com/go-xmlfmt/xmlfmt v1.1.3
 	github.com/golang-jwt/jwt/v5 v5.2.1
-	github.com/golangci/golangci-lint v1.62.2
+	github.com/golangci/golangci-lint v1.63.4
 	github.com/google/go-github/v62 v62.0.0
 	github.com/google/go-querystring v1.1.0
 	github.com/google/uuid v1.6.0
@@ -38,19 +39,20 @@ require (
 	github.com/muesli/reflow v0.3.0
 	github.com/oapi-codegen/runtime v1.1.1
 	github.com/slack-go/slack v0.15.0
-	github.com/spf13/afero v1.11.0
+	github.com/spf13/afero v1.12.0
 	github.com/spf13/cobra v1.8.1
 	github.com/spf13/pflag v1.0.5
 	github.com/spf13/viper v1.19.0
 	github.com/stretchr/testify v1.10.0
 	github.com/stripe/pg-schema-diff v0.8.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.33.0
 	golang.org/x/mod v0.22.0
-	golang.org/x/oauth2 v0.24.0
-	golang.org/x/term v0.27.0
-	google.golang.org/grpc v1.69.2
+	golang.org/x/oauth2 v0.25.0
+	golang.org/x/term v0.28.0
+	google.golang.org/grpc v1.69.4
 	gopkg.in/yaml.v3 v3.0.1
 	gotest.tools/gotestsum v1.12.0
 )
@@ -60,10 +62,10 @@ require (
 	4d63.com/gochecknoglobals v0.2.1 // indirect
 	al.essio.dev/pkg/shellescape v1.5.1 // indirect
 	dario.cat/mergo v1.0.1 // indirect
-	github.com/4meepo/tagalign v1.3.4 // indirect
+	github.com/4meepo/tagalign v1.4.1 // indirect
 	github.com/Abirdcfly/dupword v0.1.3 // indirect
 	github.com/Antonboom/errname v1.0.0 // indirect
-	github.com/Antonboom/nilnil v1.0.0 // indirect
+	github.com/Antonboom/nilnil v1.0.1 // indirect
 	github.com/Antonboom/testifylint v1.5.2 // indirect
 	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
 	github.com/Crocmagnon/fatcontext v0.5.3 // indirect
@@ -74,13 +76,14 @@ require (
 	github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
 	github.com/ProtonMail/go-crypto v1.1.3 // indirect
 	github.com/alecthomas/chroma/v2 v2.8.0 // indirect
-	github.com/alecthomas/go-check-sumtype v0.2.0 // indirect
+	github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
 	github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
 	github.com/alexkohler/prealloc v1.0.0 // indirect
 	github.com/alingse/asasalint v0.0.11 // indirect
+	github.com/alingse/nilnesserr v0.1.1 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
 	github.com/ashanbrown/forbidigo v1.6.0 // indirect
-	github.com/ashanbrown/makezero v1.1.1 // indirect
+	github.com/ashanbrown/makezero v1.2.0 // indirect
 	github.com/atotto/clipboard v0.1.4 // indirect
 	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
 	github.com/aymerick/douceur v0.2.0 // indirect
@@ -88,11 +91,11 @@ require (
 	github.com/bitfield/gotestdox v0.2.2 // indirect
 	github.com/bkielbasa/cyclop v1.2.3 // indirect
 	github.com/blizzy78/varnamelen v0.8.0 // indirect
-	github.com/bombsimon/wsl/v4 v4.4.1 // indirect
+	github.com/bombsimon/wsl/v4 v4.5.0 // indirect
 	github.com/breml/bidichk v0.3.2 // indirect
 	github.com/breml/errchkjson v0.4.0 // indirect
-	github.com/butuzov/ireturn v0.3.0 // indirect
-	github.com/butuzov/mirror v1.2.0 // indirect
+	github.com/butuzov/ireturn v0.3.1 // indirect
+	github.com/butuzov/mirror v1.3.0 // indirect
 	github.com/catenacyber/perfsprint v0.7.1 // indirect
 	github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
 	github.com/cespare/xxhash/v2 v2.3.0 // indirect
@@ -100,25 +103,27 @@ require (
 	github.com/charmbracelet/harmonica v0.2.0 // indirect
 	github.com/charmbracelet/x/ansi v0.1.4 // indirect
 	github.com/chavacava/garif v0.1.0 // indirect
-	github.com/ckaznocha/intrange v0.2.1 // indirect
+	github.com/ckaznocha/intrange v0.3.0 // indirect
 	github.com/cloudflare/circl v1.3.7 // indirect
 	github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
 	github.com/containerd/log v0.1.0 // indirect
 	github.com/containers/storage v1.56.0 // indirect
-	github.com/curioswitch/go-reassign v0.2.0 // indirect
-	github.com/cyphar/filepath-securejoin v0.3.4 // indirect
+	github.com/curioswitch/go-reassign v0.3.0 // indirect
+	github.com/cyphar/filepath-securejoin v0.3.6 // indirect
 	github.com/daixiang0/gci v0.13.5 // indirect
 	github.com/danieljoos/wincred v1.2.2 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
 	github.com/denis-tingaikin/go-header v0.5.0 // indirect
 	github.com/distribution/reference v0.6.0 // indirect
-	github.com/dlclark/regexp2 v1.4.0 // indirect
+	github.com/dlclark/regexp2 v1.11.0 // indirect
 	github.com/dnephin/pflag v1.0.7 // indirect
 	github.com/docker/distribution v2.8.3+incompatible // indirect
 	github.com/docker/docker-credential-helpers v0.8.2 // indirect
 	github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c // indirect
 	github.com/docker/go-metrics v0.0.1 // indirect
 	github.com/emirpasic/gods v1.18.1 // indirect
+	github.com/ethereum/go-ethereum v1.14.12 // indirect
 	github.com/ettle/strcase v0.2.0 // indirect
 	github.com/fatih/color v1.18.0 // indirect
 	github.com/fatih/structtag v1.2.0 // indirect
@@ -131,7 +136,7 @@ require (
 	github.com/ghostiam/protogetter v0.3.8 // indirect
 	github.com/go-critic/go-critic v0.11.5 // indirect
 	github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
-	github.com/go-git/go-billy/v5 v5.6.0 // indirect
+	github.com/go-git/go-billy/v5 v5.6.1 // indirect
 	github.com/go-logr/logr v1.4.2 // indirect
 	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-openapi/jsonpointer v0.21.0 // indirect
@@ -152,9 +157,8 @@ require (
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
 	github.com/golangci/go-printf-func-name v0.1.0 // indirect
-	github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 // indirect
+	github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9 // indirect
 	github.com/golangci/misspell v0.6.0 // indirect
-	github.com/golangci/modinfo v0.3.4 // indirect
 	github.com/golangci/plugin-module-register v0.1.1 // indirect
 	github.com/golangci/revgrep v0.5.3 // indirect
 	github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
@@ -170,7 +174,9 @@ require (
 	github.com/gostaticanalysis/nilerr v0.1.1 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
 	github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
+	github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
 	github.com/hashicorp/go-version v1.7.0 // indirect
+	github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/hexops/gotextdiff v1.0.3 // indirect
 	github.com/inconshreveable/mousetrap v1.1.0 // indirect
@@ -182,9 +188,9 @@ require (
 	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
 	github.com/jgautheron/goconst v1.7.1 // indirect
 	github.com/jingyugao/rowserrcheck v1.1.1 // indirect
-	github.com/jjti/go-spancheck v0.6.2 // indirect
+	github.com/jjti/go-spancheck v0.6.4 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
-	github.com/julz/importas v0.1.0 // indirect
+	github.com/julz/importas v0.2.0 // indirect
 	github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
 	github.com/kevinburke/ssh_config v1.2.0 // indirect
 	github.com/kisielk/errcheck v1.8.0 // indirect
@@ -195,8 +201,11 @@ require (
 	github.com/kunwardeep/paralleltest v1.0.10 // indirect
 	github.com/kyoh86/exportloopref v0.1.11 // indirect
 	github.com/lasiar/canonicalheader v1.1.2 // indirect
-	github.com/ldez/gomoddirectives v0.2.4 // indirect
-	github.com/ldez/tagliatelle v0.5.0 // indirect
+	github.com/ldez/exptostd v0.3.1 // indirect
+	github.com/ldez/gomoddirectives v0.6.0 // indirect
+	github.com/ldez/grignotin v0.7.0 // indirect
+	github.com/ldez/tagliatelle v0.7.1 // indirect
+	github.com/ldez/usetesting v0.4.2 // indirect
 	github.com/leonklingele/grouper v1.1.2 // indirect
 	github.com/lib/pq v1.10.9 // indirect
 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
@@ -210,7 +219,7 @@ require (
 	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-localereader v0.0.1 // indirect
 	github.com/mattn/go-runewidth v0.0.16 // indirect
-	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
+	github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
 	github.com/mgechev/revive v1.5.1 // indirect
 	github.com/microcosm-cc/bluemonday v1.0.25 // indirect
 	github.com/miekg/pkcs11 v1.1.1 // indirect
@@ -228,7 +237,7 @@ require (
 	github.com/nakabonne/nestif v0.3.1 // indirect
 	github.com/nishanths/exhaustive v0.12.0 // indirect
 	github.com/nishanths/predeclared v0.2.2 // indirect
-	github.com/nunnatsa/ginkgolinter v0.18.3 // indirect
+	github.com/nunnatsa/ginkgolinter v0.18.4 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.0 // indirect
@@ -239,7 +248,7 @@ require (
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/polyfloyd/go-errorlint v1.7.0 // indirect
 	github.com/prometheus/client_golang v1.12.1 // indirect
-	github.com/prometheus/client_model v0.2.0 // indirect
+	github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a // indirect
 	github.com/prometheus/common v0.32.1 // indirect
 	github.com/prometheus/procfs v0.7.3 // indirect
 	github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect
@@ -247,7 +256,7 @@ require (
 	github.com/quasilyte/gogrep v0.5.0 // indirect
 	github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
 	github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
-	github.com/raeperd/recvcheck v0.1.2 // indirect
+	github.com/raeperd/recvcheck v0.2.0 // indirect
 	github.com/rivo/uniseg v0.4.7 // indirect
 	github.com/rogpeppe/go-internal v1.13.1 // indirect
 	github.com/ryancurrah/gomodguard v1.3.5 // indirect
@@ -255,10 +264,10 @@ require (
 	github.com/sagikazarmark/locafero v0.4.0 // indirect
 	github.com/sagikazarmark/slog-shim v0.1.0 // indirect
 	github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect
-	github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect
-	github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 // indirect
+	github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
+	github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
 	github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
-	github.com/sashamelentyev/usestdlibvars v1.27.0 // indirect
+	github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect
 	github.com/securego/gosec/v2 v2.21.4 // indirect
 	github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
 	github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
@@ -271,21 +280,21 @@ require (
 	github.com/sourcegraph/go-diff v0.7.0 // indirect
 	github.com/spf13/cast v1.6.0 // indirect
 	github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
-	github.com/stbenjam/no-sprintf-host-port v0.1.1 // indirect
+	github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
 	github.com/stretchr/objx v0.5.2 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
-	github.com/tdakkota/asciicheck v0.2.0 // indirect
-	github.com/tetafro/godot v1.4.18 // indirect
+	github.com/tdakkota/asciicheck v0.3.0 // indirect
+	github.com/tetafro/godot v1.4.20 // indirect
 	github.com/theupdateframework/notary v0.7.0 // indirect
-	github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 // indirect
+	github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect
 	github.com/timonwong/loggercheck v0.10.1 // indirect
-	github.com/tomarrell/wrapcheck/v2 v2.9.0 // indirect
+	github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect
 	github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
-	github.com/ultraware/funlen v0.1.0 // indirect
-	github.com/ultraware/whitespace v0.1.1 // indirect
-	github.com/uudashr/gocognit v1.1.3 // indirect
-	github.com/uudashr/iface v1.2.1 // indirect
+	github.com/ultraware/funlen v0.2.0 // indirect
+	github.com/ultraware/whitespace v0.2.0 // indirect
+	github.com/uudashr/gocognit v1.2.0 // indirect
+	github.com/uudashr/iface v1.3.0 // indirect
 	github.com/xanzy/ssh-agent v0.3.3 // indirect
 	github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
 	github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
@@ -314,17 +323,17 @@ require (
 	go.uber.org/automaxprocs v1.6.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
 	go.uber.org/zap v1.24.0 // indirect
-	golang.org/x/crypto v0.31.0 // indirect
+	golang.org/x/crypto v0.32.0 // indirect
 	golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
 	golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect
 	golang.org/x/net v0.33.0 // indirect
 	golang.org/x/sync v0.10.0 // indirect
-	golang.org/x/sys v0.28.0 // indirect
+	golang.org/x/sys v0.29.0 // indirect
 	golang.org/x/text v0.21.0 // indirect
-	golang.org/x/tools v0.27.0 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 // indirect
-	google.golang.org/protobuf v1.35.1 // indirect
+	golang.org/x/tools v0.28.0 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
+	google.golang.org/protobuf v1.36.1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
diff --git a/go.sum b/go.sum
index 6195b3ea..aa602cf6 100644
--- a/go.sum
+++ b/go.sum
@@ -39,14 +39,14 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9
 dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
 dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/4meepo/tagalign v1.3.4 h1:P51VcvBnf04YkHzjfclN6BbsopfJR5rxs1n+5zHt+w8=
-github.com/4meepo/tagalign v1.3.4/go.mod h1:M+pnkHH2vG8+qhE5bVc/zeP7HS/j910Fwa9TUSyZVI0=
+github.com/4meepo/tagalign v1.4.1 h1:GYTu2FaPGOGb/xJalcqHeD4il5BiCywyEYZOA55P6J4=
+github.com/4meepo/tagalign v1.4.1/go.mod h1:2H9Yu6sZ67hmuraFgfZkNcg5Py9Ch/Om9l2K/2W1qS4=
 github.com/Abirdcfly/dupword v0.1.3 h1:9Pa1NuAsZvpFPi9Pqkd93I7LIYRURj+A//dFd5tgBeE=
 github.com/Abirdcfly/dupword v0.1.3/go.mod h1:8VbB2t7e10KRNdwTVoxdBaxla6avbhGzb8sCTygUMhw=
 github.com/Antonboom/errname v1.0.0 h1:oJOOWR07vS1kRusl6YRSlat7HFnb3mSfMl6sDMRoTBA=
 github.com/Antonboom/errname v1.0.0/go.mod h1:gMOBFzK/vrTiXN9Oh+HFs+e6Ndl0eTFbtsRTSRdXyGI=
-github.com/Antonboom/nilnil v1.0.0 h1:n+v+B12dsE5tbAqRODXmEKfZv9j2KcTBrp+LkoM4HZk=
-github.com/Antonboom/nilnil v1.0.0/go.mod h1:fDJ1FSFoLN6yoG65ANb1WihItf6qt9PJVTn/s2IrcII=
+github.com/Antonboom/nilnil v1.0.1 h1:C3Tkm0KUxgfO4Duk3PM+ztPncTFlOf0b2qadmS0s4xs=
+github.com/Antonboom/nilnil v1.0.1/go.mod h1:CH7pW2JsRNFgEh8B2UaPZTEPhCMuFowP/e8Udp9Nnb0=
 github.com/Antonboom/testifylint v1.5.2 h1:4s3Xhuv5AvdIgbd8wOOEeo0uZG7PbDKQyKY5lGoQazk=
 github.com/Antonboom/testifylint v1.5.2/go.mod h1:vxy8VJ0bc6NavlYqjZfmp6EfqXMtBgQ4+mhCojwC1P8=
 github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
@@ -76,14 +76,14 @@ github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQA
 github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
 github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d h1:hi6J4K6DKrR4/ljxn6SF6nURyu785wKMuQcjt7H3VCQ=
 github.com/Shopify/logrus-bugsnag v0.0.0-20170309145241-6dbc35f2c30d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
-github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
-github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
+github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
+github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
 github.com/alecthomas/chroma/v2 v2.8.0 h1:w9WJUjFFmHHB2e8mRpL9jjy3alYDlU0QLDezj1xE264=
 github.com/alecthomas/chroma/v2 v2.8.0/go.mod h1:yrkMI9807G1ROx13fhe1v6PN2DDeaR73L3d+1nmYQtw=
-github.com/alecthomas/go-check-sumtype v0.2.0 h1:Bo+e4DFf3rs7ME9w/0SU/g6nmzJaphduP8Cjiz0gbwY=
-github.com/alecthomas/go-check-sumtype v0.2.0/go.mod h1:WyYPfhfkdhyrdaligV6svFopZV8Lqdzn5pyVBaV6jhQ=
-github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
-github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
+github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU=
+github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E=
+github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
+github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -95,6 +95,8 @@ github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pO
 github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
 github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
 github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
+github.com/alingse/nilnesserr v0.1.1 h1:7cYuJewpy9jFNMEA72Q1+3Nm3zKHzg+Q28D5f2bBFUA=
+github.com/alingse/nilnesserr v0.1.1/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg=
 github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
 github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
@@ -105,8 +107,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd
 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
 github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8gerOIVIY=
 github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU=
-github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
-github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
+github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU=
+github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4=
 github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
 github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
@@ -130,8 +132,8 @@ github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ
 github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
 github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
 github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
-github.com/bombsimon/wsl/v4 v4.4.1 h1:jfUaCkN+aUpobrMO24zwyAMwMAV5eSziCkOKEauOLdw=
-github.com/bombsimon/wsl/v4 v4.4.1/go.mod h1:Xu/kDxGZTofQcDGCtQe9KCzhHphIe0fDuyWTxER9Feo=
+github.com/bombsimon/wsl/v4 v4.5.0 h1:iZRsEvDdyhd2La0FVi5k6tYehpOR/R7qIUjmKk7N74A=
+github.com/bombsimon/wsl/v4 v4.5.0/go.mod h1:NOQ3aLF4nD7N5YPXMruR6ZXDOAqLoM0GEpLwTdvmOSc=
 github.com/breml/bidichk v0.3.2 h1:xV4flJ9V5xWTqxL+/PMFF6dtJPvZLPsyixAoPe8BGJs=
 github.com/breml/bidichk v0.3.2/go.mod h1:VzFLBxuYtT23z5+iVkamXO386OB+/sVwZOpIj6zXGos=
 github.com/breml/errchkjson v0.4.0 h1:gftf6uWZMtIa/Is3XJgibewBm2ksAQSY/kABDNFTAdk=
@@ -142,10 +144,10 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj
 github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
 github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
 github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
-github.com/butuzov/ireturn v0.3.0 h1:hTjMqWw3y5JC3kpnC5vXmFJAWI/m31jaCYQqzkS6PL0=
-github.com/butuzov/ireturn v0.3.0/go.mod h1:A09nIiwiqzN/IoVo9ogpa0Hzi9fex1kd9PSD6edP5ZA=
-github.com/butuzov/mirror v1.2.0 h1:9YVK1qIjNspaqWutSv8gsge2e/Xpq1eqEkslEUHy5cs=
-github.com/butuzov/mirror v1.2.0/go.mod h1:DqZZDtzm42wIAIyHXeN8W/qb1EPlb9Qn/if9icBOpdQ=
+github.com/butuzov/ireturn v0.3.1 h1:mFgbEI6m+9W8oP/oDdfA34dLisRFCj2G6o/yiI1yZrY=
+github.com/butuzov/ireturn v0.3.1/go.mod h1:ZfRp+E7eJLC0NQmk1Nrm1LOrn/gQlOykv+cVPdiXH5M=
+github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc=
+github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI=
 github.com/catenacyber/perfsprint v0.7.1 h1:PGW5G/Kxn+YrN04cRAZKC+ZuvlVwolYMrIyyTJ/rMmc=
 github.com/catenacyber/perfsprint v0.7.1/go.mod h1:/wclWYompEyjUD2FuIIDVKNkqz7IgBIWXIH3V0Zol50=
 github.com/ccojocar/zxcvbn-go v1.0.2 h1:na/czXU8RrhXO4EZme6eQJLR4PzcGsahsBOAwU6I3Vg=
@@ -176,8 +178,8 @@ github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+U
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
-github.com/ckaznocha/intrange v0.2.1 h1:M07spnNEQoALOJhwrImSrJLaxwuiQK+hA2DeajBlwYk=
-github.com/ckaznocha/intrange v0.2.1/go.mod h1:7NEhVyf8fzZO5Ds7CRaqPEm52Ut83hsTiL5zbER/HYk=
+github.com/ckaznocha/intrange v0.3.0 h1:VqnxtK32pxgkhJgYQEeOArVidIPg+ahLP7WBOXZd5ZY=
+github.com/ckaznocha/intrange v0.3.0/go.mod h1:+I/o2d2A1FBHgGELbGxzIcyd3/9l9DuwjM8FsbSS3Lo=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004 h1:lkAMpLVBDaj17e85keuznYcH5rqI438v41pKcBl4ZxQ=
 github.com/cloudflare/cfssl v0.0.0-20180223231731-4e2dcbde5004/go.mod h1:yMWuSON2oQp+43nFtAV/uvKQIFpSPerB57DCt9t8sSA=
@@ -201,10 +203,10 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
 github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
-github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
-github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
-github.com/cyphar/filepath-securejoin v0.3.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8=
-github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM=
+github.com/curioswitch/go-reassign v0.3.0 h1:dh3kpQHuADL3cobV/sSGETA8DOv457dwl+fbBAhrQPs=
+github.com/curioswitch/go-reassign v0.3.0/go.mod h1:nApPCCTtqLJN/s8HfItCcKV0jIPwluBOvZP+dsJGA88=
+github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
+github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
 github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c=
 github.com/daixiang0/gci v0.13.5/go.mod h1:12etP2OniiIdP4q+kjUGrC/rUagga7ODbqsom5Eo5Yk=
 github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
@@ -213,6 +215,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
 github.com/deepmap/oapi-codegen/v2 v2.2.0 h1:FW4f7C0Xb6EaezBSB3GYw2QGwHD5ChDflG+3xSZBdvY=
 github.com/deepmap/oapi-codegen/v2 v2.2.0/go.mod h1:L4zUv7ULYDtYSb/aYk/xO3OYcQU6BoU/0viULkbi2DE=
 github.com/denis-tingaikin/go-header v0.5.0 h1:SRdnP5ZKvcO9KKRP1KJrhFR3RrlGuD+42t4429eC9k8=
@@ -220,17 +224,17 @@ github.com/denis-tingaikin/go-header v0.5.0/go.mod h1:mMenU5bWrok6Wl2UsZjy+1okeg
 github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
 github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
-github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E=
-github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
 github.com/dnephin/pflag v1.0.7 h1:oxONGlWxhmUct0YzKTgrpQv9AUA1wtPBn7zuSjJqptk=
 github.com/dnephin/pflag v1.0.7/go.mod h1:uxE91IoWURlOiTUIA8Mq5ZZkAv3dPUfZNaT80Zm7OQE=
-github.com/docker/cli v27.4.1+incompatible h1:VzPiUlRJ/xh+otB75gva3r05isHMo5wXDfPRi5/b4hI=
-github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v27.5.0+incompatible h1:aMphQkcGtpHixwwhAXJT1rrK/detk2JIvDaFkLctbGM=
+github.com/docker/cli v27.5.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
 github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
 github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
-github.com/docker/docker v27.4.1+incompatible h1:ZJvcY7gfwHn1JF48PfbyXg7Jyt9ZCWDW+GGXOIxEwp4=
-github.com/docker/docker v27.4.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v27.5.0+incompatible h1:um++2NcQtGRTz5eEgO6aJimo6/JxrTXC941hd05JO6U=
+github.com/docker/docker v27.5.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo=
 github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M=
 github.com/docker/go v1.5.1-1.0.20160303222718-d30aec9fd63c h1:lzqkGL9b3znc+ZUgi7FlLnqjQhcXxkNM/quxIjBVMD0=
@@ -246,8 +250,10 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
 github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
 github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
 github.com/dvsekhvalnov/jose2go v0.0.0-20170216131308-f21a8cedbbae/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
-github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug=
-github.com/elazarl/goproxy v1.2.1/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
+github.com/ecies/go/v2 v2.0.10 h1:AaLxGio0MLLbvWur4rKnLzw+K9zI+wMScIDAtqCqOtU=
+github.com/ecies/go/v2 v2.0.10/go.mod h1:N73OyuR6tuKznit2LhXjrZ0XAQ234uKbzYz8pEPYzlI=
+github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
+github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
@@ -255,6 +261,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
 github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
+github.com/ethereum/go-ethereum v1.14.12 h1:8hl57x77HSUo+cXExrURjU/w1VhL+ShCTJrTwcCQSe4=
+github.com/ethereum/go-ethereum v1.14.12/go.mod h1:RAC2gVMWJ6FkxSPESfbshrcKpIokgQKsVKmAuqdekDY=
 github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q=
 github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A=
 github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
@@ -279,8 +287,8 @@ github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
 github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
 github.com/getkin/kin-openapi v0.124.0 h1:VSFNMB9C9rTKBnQ/fpyDU8ytMTr4dWI9QovSKj9kz/M=
 github.com/getkin/kin-openapi v0.124.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
-github.com/getsentry/sentry-go v0.30.0 h1:lWUwDnY7sKHaVIoZ9wYqRHJ5iEmoc0pqcRqFkosKzBo=
-github.com/getsentry/sentry-go v0.30.0/go.mod h1:WU9B9/1/sHDqeV8T+3VwwbjeR5MSXs/6aqG3mqZrezA=
+github.com/getsentry/sentry-go v0.31.1 h1:ELVc0h7gwyhnXHDouXkhqTFSO5oslsRDk0++eyE0KJ4=
+github.com/getsentry/sentry-go v0.31.1/go.mod h1:CYNcMMz73YigoHljQRG+qPF+eMq8gG72XcGN/p71BAY=
 github.com/ghostiam/protogetter v0.3.8 h1:LYcXbYvybUyTIxN2Mj9h6rHrDZBDwZloPoKctWrFyJY=
 github.com/ghostiam/protogetter v0.3.8/go.mod h1:WZ0nw9pfzsgxuRsPOFQomgDVSWtDLJRfQJEhsGbmQMA=
 github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
@@ -291,12 +299,12 @@ github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8b
 github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
-github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
+github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
+github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
-github.com/go-git/go-git/v5 v5.13.0 h1:vLn5wlGIh/X78El6r3Jr+30W16Blk0CTcxTYcYPWi5E=
-github.com/go-git/go-git/v5 v5.13.0/go.mod h1:Wjo7/JyVKtQgUNdXYXIepzWfJQkUEIGvkvVkiXRR/zw=
+github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
+github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -399,14 +407,12 @@ github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9
 github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
 github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUPPyAKJuzv8pEJU=
 github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s=
-github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9 h1:/1322Qns6BtQxUZDTAT4SdcoxknUki7IAoK4SAXr8ME=
-github.com/golangci/gofmt v0.0.0-20240816233607-d8596aa466a9/go.mod h1:Oesb/0uFAyWoaw1U1qS5zyjCg5NP9C9iwjnI4tIsXEE=
-github.com/golangci/golangci-lint v1.62.2 h1:b8K5K9PN+rZN1+mKLtsZHz2XXS9aYKzQ9i25x3Qnxxw=
-github.com/golangci/golangci-lint v1.62.2/go.mod h1:ILWWyeFUrctpHVGMa1dg2xZPKoMUTc5OIMgW7HZr34g=
+github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9 h1:t5wybL6RtO83VwoMOb7U/Peqe3gGKQlPIC66wXmnkvM=
+github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9/go.mod h1:Ag3L7sh7E28qAp/5xnpMMTuGYqxLZoSaEHZDkZB1RgU=
+github.com/golangci/golangci-lint v1.63.4 h1:bJQFQ3hSfUto597dkL7ipDzOxsGEpiWdLiZ359OWOBI=
+github.com/golangci/golangci-lint v1.63.4/go.mod h1:Hx0B7Lg5/NXbaOHem8+KU+ZUIzMI6zNj/7tFwdnn10I=
 github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
 github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
-github.com/golangci/modinfo v0.3.4 h1:oU5huX3fbxqQXdfspamej74DFX0kyGLkw1ppvXoJ8GA=
-github.com/golangci/modinfo v0.3.4/go.mod h1:wytF1M5xl9u0ij8YSvhkEVPP3M5Mc7XLl1pxH3B2aUM=
 github.com/golangci/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c=
 github.com/golangci/plugin-module-register v0.1.1/go.mod h1:TTpqoB6KkwOJMV8u7+NyXMrkwwESJLOkfl9TxR1DGFc=
 github.com/golangci/revgrep v0.5.3 h1:3tL7c1XBMtWHHqVpS5ChmiAAoe4PF/d5+ULzV9sLAzs=
@@ -476,8 +482,8 @@ github.com/gostaticanalysis/forcetypeassert v0.1.0/go.mod h1:qZEedyP/sY1lTGV1uJ3
 github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3Uqrmrcpk=
 github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A=
 github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M=
-github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY=
-github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU=
+github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8=
+github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
 github.com/h2non/gock v1.2.0 h1:K6ol8rfrRkUOefooBC8elXoaNGYkpp7y2qcxGG6BzUE=
@@ -486,11 +492,17 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslC
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8=
 github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4=
+github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo=
+github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw=
+github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
+github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
 github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
 github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
+github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
 github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
@@ -565,8 +577,8 @@ github.com/jinzhu/gorm v0.0.0-20170222002820-5409931a1bb8/go.mod h1:Vla75njaFJ8c
 github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d h1:jRQLvyVGL+iVtDElaEIDdKwpPqUIZJfzkNLV34htpEc=
 github.com/jinzhu/inflection v0.0.0-20170102125226-1c35d901db3d/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/jjti/go-spancheck v0.6.2 h1:iYtoxqPMzHUPp7St+5yA8+cONdyXD3ug6KK15n7Pklk=
-github.com/jjti/go-spancheck v0.6.2/go.mod h1:+X7lvIrR5ZdUTkxFYqzJ0abr8Sb5LOo80uOhWNqIrYA=
+github.com/jjti/go-spancheck v0.6.4 h1:Tl7gQpYf4/TMU7AT84MN83/6PutY21Nb9fuQjFTpRRc=
+github.com/jjti/go-spancheck v0.6.4/go.mod h1:yAEYdKJ2lRkDA8g7X+oKUHXOWVAXSBJRv04OhF+QUjk=
 github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
 github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
 github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -583,8 +595,8 @@ github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPci
 github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
-github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
+github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ=
+github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY=
 github.com/karamaru-alpha/copyloopvar v1.1.0 h1:x7gNyKcC2vRBO1H2Mks5u1VxQtYvFiym7fCjIP8RPos=
 github.com/karamaru-alpha/copyloopvar v1.1.0/go.mod h1:u7CIfztblY0jZLOQZgH3oYsJzpC2A7S6u/lfgSXHy0k=
 github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
@@ -617,10 +629,16 @@ github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/
 github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA=
 github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4=
 github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI=
-github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg=
-github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g=
-github.com/ldez/tagliatelle v0.5.0 h1:epgfuYt9v0CG3fms0pEgIMNPuFf/LpPIfjk4kyqSioo=
-github.com/ldez/tagliatelle v0.5.0/go.mod h1:rj1HmWiL1MiKQuOONhd09iySTEkUuE/8+5jtPYz9xa4=
+github.com/ldez/exptostd v0.3.1 h1:90yWWoAKMFHeovTK8uzBms9Ppp8Du/xQ20DRO26Ymrw=
+github.com/ldez/exptostd v0.3.1/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ=
+github.com/ldez/gomoddirectives v0.6.0 h1:Jyf1ZdTeiIB4dd+2n4qw+g4aI9IJ6JyfOZ8BityWvnA=
+github.com/ldez/gomoddirectives v0.6.0/go.mod h1:TuwOGYoPAoENDWQpe8DMqEm5nIfjrxZXmxX/CExWyZ4=
+github.com/ldez/grignotin v0.7.0 h1:vh0dI32WhHaq6LLPZ38g7WxXuZ1+RzyrJ7iPG9JMa8c=
+github.com/ldez/grignotin v0.7.0/go.mod h1:uaVTr0SoZ1KBii33c47O1M8Jp3OP3YDwhZCmzT9GHEk=
+github.com/ldez/tagliatelle v0.7.1 h1:bTgKjjc2sQcsgPiT902+aadvMjCeMHrY7ly2XKFORIk=
+github.com/ldez/tagliatelle v0.7.1/go.mod h1:3zjxUpsNB2aEZScWiZTHrAXOl1x25t3cRmzfK1mlo2I=
+github.com/ldez/usetesting v0.4.2 h1:J2WwbrFGk3wx4cZwSMiCQQ00kjGR0+tuuyW0Lqm4lwA=
+github.com/ldez/usetesting v0.4.2/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ=
 github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY=
 github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA=
 github.com/lib/pq v0.0.0-20150723085316-0dad96c0b94f/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
@@ -666,8 +684,9 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC
 github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
 github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
 github.com/mattn/go-sqlite3 v1.6.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
+github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/mgechev/revive v1.5.1 h1:hE+QPeq0/wIzJwOphdVyUJ82njdd8Khp4fUIHGZHW3M=
 github.com/mgechev/revive v1.5.1/go.mod h1:lC9AhkJIBs5zwx8wkudyHrU+IJkrEKmpCmGMnIJPk4o=
 github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
@@ -718,8 +737,8 @@ github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhK
 github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs=
 github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
 github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
-github.com/nunnatsa/ginkgolinter v0.18.3 h1:WgS7X3zzmni3vwHSBhvSgqrRgUecN6PQUcfB0j1noDw=
-github.com/nunnatsa/ginkgolinter v0.18.3/go.mod h1:BE1xyB/PNtXXG1azrvrqJW5eFH0hSRylNzFy8QHPwzs=
+github.com/nunnatsa/ginkgolinter v0.18.4 h1:zmX4KUR+6fk/vhUFt8DOP6KwznekhkmVSzzVJve2vyM=
+github.com/nunnatsa/ginkgolinter v0.18.4/go.mod h1:AMEane4QQ6JwFz5GgjI5xLUM9S/CylO+UyM97fN2iBI=
 github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
 github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
@@ -780,8 +799,9 @@ github.com/prometheus/client_model v0.0.0-20171117100541-99fa1f4be8e5/go.mod h1:
 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
 github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
 github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a h1:CmF68hwI0XsOQ5UwlBopMi2Ow4Pbg32akc4KIVCOm+Y=
+github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
 github.com/prometheus/common v0.0.0-20180110214958-89604d197083/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc=
@@ -807,8 +827,8 @@ github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl
 github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
-github.com/raeperd/recvcheck v0.1.2 h1:SjdquRsRXJc26eSonWIo8b7IMtKD3OAT2Lb5G3ZX1+4=
-github.com/raeperd/recvcheck v0.1.2/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=
+github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI=
+github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU=
 github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
@@ -832,14 +852,14 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g
 github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
 github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y=
 github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
-github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
-github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
-github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4=
-github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY=
+github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0=
+github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
 github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
 github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
-github.com/sashamelentyev/usestdlibvars v1.27.0 h1:t/3jZpSXtRPRf2xr0m63i32ZrusyurIGT9E5wAvXQnI=
-github.com/sashamelentyev/usestdlibvars v1.27.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
+github.com/sashamelentyev/usestdlibvars v1.28.0 h1:jZnudE2zKCtYlGzLVreNp5pmCdOxXUzwsMDBkR21cyQ=
+github.com/sashamelentyev/usestdlibvars v1.28.0/go.mod h1:9nl0jgOfHKWNFS43Ojw0i7aRoS4j6EBye3YBhmAIRF8=
 github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
 github.com/securego/gosec/v2 v2.21.4 h1:Le8MSj0PDmOnHJgUATjD96PaXRvCpKC+DGJvwyy0Mlk=
 github.com/securego/gosec/v2 v2.21.4/go.mod h1:Jtb/MwRQfRxCXyCm1rfM1BEiiiTfUOdyzzAhlr6lUTA=
@@ -874,8 +894,8 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
 github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
 github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
 github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
-github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
-github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
+github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
+github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
 github.com/spf13/cast v0.0.0-20150508191742-4d07383ffe94/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
 github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
 github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
@@ -892,8 +912,8 @@ github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+
 github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
 github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0=
 github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
-github.com/stbenjam/no-sprintf-host-port v0.1.1 h1:tYugd/yrm1O0dV+ThCbaKZh195Dfm07ysF0U6JQXczc=
-github.com/stbenjam/no-sprintf-host-port v0.1.1/go.mod h1:TLhvtIvONRzdmkFiio4O8LHsN9N74I+PhRquPsxpL0I=
+github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4=
+github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@@ -916,34 +936,36 @@ github.com/stripe/pg-schema-diff v0.8.0 h1:Ggm4yDbPtaflYQLV3auEMTLxQPaentV/wmDEo
 github.com/stripe/pg-schema-diff v0.8.0/go.mod h1:HuTBuWLuvnY9g9nptbSD58xugN19zSJNkF4w/sYRtdU=
 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.2.0 h1:o8jvnUANo0qXtnslk2d3nMKTFNlOnJjRrNcj0j9qkHM=
-github.com/tdakkota/asciicheck v0.2.0/go.mod h1:Qb7Y9EgjCLJGup51gDHFzbI08/gbGhL/UVhYIPWG2rg=
+github.com/tdakkota/asciicheck v0.3.0 h1:LqDGgZdholxZMaJgpM6b0U9CFIjDCbFdUF00bDnBKOQ=
+github.com/tdakkota/asciicheck v0.3.0/go.mod h1:KoJKXuX/Z/lt6XzLo8WMBfQGzak0SrAKZlvRr4tg8Ac=
 github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
 github.com/tenntenn/modver v1.0.1/go.mod h1:bePIyQPb7UeioSRkw3Q0XeMhYZSMx9B8ePqg6SAMGH0=
 github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpRQGxTSkNYKJ51yaw6ChIqO+Je8UqsTKN/cDag=
 github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
-github.com/tetafro/godot v1.4.18 h1:ouX3XGiziKDypbpXqShBfnNLTSjR8r3/HVzrtJ+bHlI=
-github.com/tetafro/godot v1.4.18/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
+github.com/tetafro/godot v1.4.20 h1:z/p8Ek55UdNvzt4TFn2zx2KscpW4rWqcnUrdmvWJj7E=
+github.com/tetafro/godot v1.4.20/go.mod h1:2oVxTBSftRTh4+MVfUaUXR6bn2GDXCaMcOG4Dk3rfio=
 github.com/theupdateframework/notary v0.7.0 h1:QyagRZ7wlSpjT5N2qQAh/pN+DVqgekv4DzbAiAiEL3c=
 github.com/theupdateframework/notary v0.7.0/go.mod h1:c9DRxcmhHmVLDay4/2fUYdISnHqbFDGRSlXPO0AhYWw=
-github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966 h1:quvGphlmUVU+nhpFa4gg4yJyTRJ13reZMDHrKwYw53M=
-github.com/timakin/bodyclose v0.0.0-20230421092635-574207250966/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
+github.com/tidwall/jsonc v0.3.2 h1:ZTKrmejRlAJYdn0kcaFqRAKlxxFIC21pYq8vLa4p2Wc=
+github.com/tidwall/jsonc v0.3.2/go.mod h1:dw+3CIxqHi+t8eFSpzzMlcVYxKp08UP5CD8/uSFCyJE=
+github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 h1:y4mJRFlM6fUyPhoXuFg/Yu02fg/nIPFMOY8tOqppoFg=
+github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3/go.mod h1:mkjARE7Yr8qU23YcGMSALbIxTQ9r9QBVahQOBRfU460=
 github.com/timonwong/loggercheck v0.10.1 h1:uVZYClxQFpw55eh+PIoqM7uAOHMrhVcDoWDery9R8Lg=
 github.com/timonwong/loggercheck v0.10.1/go.mod h1:HEAWU8djynujaAVX7QI65Myb8qgfcZ1uKbdpg3ZzKl8=
-github.com/tomarrell/wrapcheck/v2 v2.9.0 h1:801U2YCAjLhdN8zhZ/7tdjB3EnAoRlJHt/s+9hijLQ4=
-github.com/tomarrell/wrapcheck/v2 v2.9.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
+github.com/tomarrell/wrapcheck/v2 v2.10.0 h1:SzRCryzy4IrAH7bVGG4cK40tNUhmVmMDuJujy4XwYDg=
+github.com/tomarrell/wrapcheck/v2 v2.10.0/go.mod h1:g9vNIyhb5/9TQgumxQyOEqDHsmGYcGsVMOx/xGkqdMo=
 github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
 github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/ultraware/funlen v0.1.0 h1:BuqclbkY6pO+cvxoq7OsktIXZpgBSkYTQtmwhAK81vI=
-github.com/ultraware/funlen v0.1.0/go.mod h1:XJqmOQja6DpxarLj6Jj1U7JuoS8PvL4nEqDaQhy22p4=
-github.com/ultraware/whitespace v0.1.1 h1:bTPOGejYFulW3PkcrqkeQwOd6NKOOXvmGD9bo/Gk8VQ=
-github.com/ultraware/whitespace v0.1.1/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
-github.com/uudashr/gocognit v1.1.3 h1:l+a111VcDbKfynh+airAy/DJQKaXh2m9vkoysMPSZyM=
-github.com/uudashr/gocognit v1.1.3/go.mod h1:aKH8/e8xbTRBwjbCkwZ8qt4l2EpKXl31KMHgSS+lZ2U=
-github.com/uudashr/iface v1.2.1 h1:vHHyzAUmWZ64Olq6NZT3vg/z1Ws56kyPdBOd5kTXDF8=
-github.com/uudashr/iface v1.2.1/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
+github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI=
+github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA=
+github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g=
+github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8=
+github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA=
+github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU=
+github.com/uudashr/iface v1.3.0 h1:zwPch0fs9tdh9BmL5kcgSpvnObV+yHjO4JjVBl8IA10=
+github.com/uudashr/iface v1.3.0/go.mod h1:4QvspiRd3JLPAEXBQ9AiZpLbJlrWWgRChOKDJEuQTdg=
 github.com/withfig/autocomplete-tools/packages/cobra v1.2.0 h1:MzD3XeOOSO3mAjOPpF07jFteSKZxsRHvlIcAR9RQzKM=
 github.com/withfig/autocomplete-tools/packages/cobra v1.2.0/go.mod h1:RoXh7+7qknOXL65uTzdzE1mPxqcPwS7FLCE9K5GfmKo=
 github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
@@ -1056,11 +1078,12 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
 golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio=
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
+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.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
-golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
+golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1099,7 +1122,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
@@ -1107,6 +1129,7 @@ golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 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.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
 golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
@@ -1152,9 +1175,11 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
 golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
 golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
 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.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
@@ -1165,8 +1190,8 @@ golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4Iltr
 golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
-golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
-golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
+golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
+golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 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=
@@ -1181,6 +1206,7 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 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.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
 golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
@@ -1225,7 +1251,6 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1248,11 +1273,12 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.10.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.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
-golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
+golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 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=
@@ -1261,13 +1287,15 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
 golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
 golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
 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.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
-golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
+golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1279,6 +1307,7 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+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.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
@@ -1288,8 +1317,8 @@ golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
-golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
-golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
+golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -1344,23 +1373,23 @@ golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc
 golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
 golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
 golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
 golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
 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.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
 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.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
-golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
-golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
+golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
+golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1418,10 +1447,10 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
 google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
-google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 h1:fVoAXEKA4+yufmbdVYv+SE73+cPZbbbe8paLsHfkK+U=
-google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53/go.mod h1:riSXTwQ4+nqmPGtobMFyW5FqVAmIs0St6VPp4Ug7CE4=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53 h1:X58yt85/IXCx0Y3ZwN6sEIKZzQtDEYaBWrDvErdXrRE=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20241015192408-796eee8c2d53/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
+google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q=
+google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 h1:TqExAhdPaB60Ux47Cn0oLV07rGnxZzIsaRhQaqS666A=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8/go.mod h1:lcTa1sDdWEIHMWlITnIczmw5w60CF9ffkb8Z+DVmmjA=
 google.golang.org/grpc v1.0.5/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1435,8 +1464,8 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
 google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
 google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
 google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
-google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
-google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
+google.golang.org/grpc v1.69.4 h1:MF5TftSMkd8GLw/m0KM6V8CMOCY6NZ1NQDPGFgbTt4A=
+google.golang.org/grpc v1.69.4/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
 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=
@@ -1449,8 +1478,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
-google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
+google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/cenkalti/backoff.v2 v2.2.1 h1:eJ9UAg01/HIHG987TwxvnzK2MgxXq97YY6rYDpY9aII=
diff --git a/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go
index 677ef153..8310a82f 100644
--- a/internal/bootstrap/bootstrap.go
+++ b/internal/bootstrap/bootstrap.go
@@ -95,7 +95,7 @@ func Run(ctx context.Context, starter StarterTemplate, fsys afero.Fs, options ..
 		return err
 	}
 	// 4. Link project
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	link.LinkServices(ctx, flags.ProjectRef, tenant.NewApiKey(keys).Anon, fsys)
diff --git a/internal/branches/get/get.go b/internal/branches/get/get.go
index ee5bc332..22f3274e 100644
--- a/internal/branches/get/get.go
+++ b/internal/branches/get/get.go
@@ -3,13 +3,17 @@ package get
 import (
 	"context"
 	"fmt"
+	"os"
 
 	"github.com/go-errors/errors"
+	"github.com/jackc/pgconn"
+	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/pkg/cast"
 )
 
-func Run(ctx context.Context, branchId string) error {
+func Run(ctx context.Context, branchId string, fsys afero.Fs) error {
 	resp, err := utils.GetSupabase().V1GetABranchConfigWithResponse(ctx, branchId)
 	if err != nil {
 		return errors.Errorf("failed to retrieve preview branch: %w", err)
@@ -29,10 +33,25 @@ func Run(ctx context.Context, branchId string) error {
 		resp.JSON200.JwtSecret = &masked
 	}
 
-	table := `|HOST|PORT|USER|PASSWORD|JWT SECRET|POSTGRES VERSION|STATUS|
-|-|-|-|-|-|-|-|
+	config := pgconn.Config{
+		Host:     utils.GetSupabaseDbHost(resp.JSON200.DbHost),
+		Port:     cast.UIntToUInt16(cast.IntToUint(resp.JSON200.DbPort)),
+		User:     *resp.JSON200.DbUser,
+		Password: *resp.JSON200.DbPass,
+	}
+
+	postgresConnectionString := utils.ToPostgresURL(config)
+	if utils.OutputFormat.Value != utils.OutputPretty {
+		envs := map[string]string{
+			"POSTGRES_URL": postgresConnectionString,
+		}
+		return utils.EncodeOutput(utils.OutputFormat.Value, os.Stdout, envs)
+	}
+
+	table := `|HOST|PORT|USER|PASSWORD|JWT SECRET|POSTGRES VERSION|STATUS|POSTGRES URL|
+|-|-|-|-|-|-|-|-|
 ` + fmt.Sprintf(
-		"|`%s`|`%d`|`%s`|`%s`|`%s`|`%s`|`%s`|\n",
+		"|`%s`|`%d`|`%s`|`%s`|`%s`|`%s`|`%s`|`%s`|\n",
 		resp.JSON200.DbHost,
 		resp.JSON200.DbPort,
 		*resp.JSON200.DbUser,
@@ -40,6 +59,8 @@ func Run(ctx context.Context, branchId string) error {
 		*resp.JSON200.JwtSecret,
 		resp.JSON200.PostgresVersion,
 		resp.JSON200.Status,
+		postgresConnectionString,
 	)
+
 	return list.RenderTable(table)
 }
diff --git a/internal/config/push/push.go b/internal/config/push/push.go
index a4c90147..d2dadddc 100644
--- a/internal/config/push/push.go
+++ b/internal/config/push/push.go
@@ -7,11 +7,12 @@ import (
 
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/config"
 )
 
 func Run(ctx context.Context, ref string, fsys afero.Fs) error {
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	client := config.NewConfigUpdater(*utils.GetSupabase())
diff --git a/internal/db/branch/create/create.go b/internal/db/branch/create/create.go
index 085e10f9..55012837 100644
--- a/internal/db/branch/create/create.go
+++ b/internal/db/branch/create/create.go
@@ -14,6 +14,7 @@ import (
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 )
 
 var (
@@ -22,7 +23,7 @@ var (
 )
 
 func Run(branch string, fsys afero.Fs) error {
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	if err := utils.AssertSupabaseDbIsRunning(); err != nil {
diff --git a/internal/db/branch/delete/delete.go b/internal/db/branch/delete/delete.go
index f59f5e51..ea14cd34 100644
--- a/internal/db/branch/delete/delete.go
+++ b/internal/db/branch/delete/delete.go
@@ -12,10 +12,11 @@ import (
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 )
 
 func Run(branch string, fsys afero.Fs) error {
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	if err := utils.AssertSupabaseDbIsRunning(); err != nil {
diff --git a/internal/db/branch/switch_/switch_.go b/internal/db/branch/switch_/switch_.go
index 462b26c6..d11803e8 100644
--- a/internal/db/branch/switch_/switch_.go
+++ b/internal/db/branch/switch_/switch_.go
@@ -12,12 +12,13 @@ import (
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/db/reset"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 )
 
 func Run(ctx context.Context, target string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
 	// 1. Sanity checks
 	{
-		if err := utils.LoadConfigFS(fsys); err != nil {
+		if err := flags.LoadConfig(fsys); err != nil {
 			return err
 		}
 		if err := utils.AssertSupabaseDbIsRunning(); err != nil {
diff --git a/internal/db/diff/diff.go b/internal/db/diff/diff.go
index 6c5faa89..d54f5e53 100644
--- a/internal/db/diff/diff.go
+++ b/internal/db/diff/diff.go
@@ -24,6 +24,7 @@ import (
 	"github.com/supabase/cli/internal/db/start"
 	"github.com/supabase/cli/internal/gen/keys"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 	"github.com/supabase/cli/pkg/parser"
 )
@@ -32,7 +33,7 @@ type DiffFunc func(context.Context, string, string, []string) (string, error)
 
 func Run(ctx context.Context, schema []string, file string, config pgconn.Config, differ DiffFunc, fsys afero.Fs, options ...func(*pgx.ConnConfig)) (err error) {
 	// Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	if utils.IsLocalDatabase(config) {
diff --git a/internal/db/diff/pgadmin.go b/internal/db/diff/pgadmin.go
index 29802358..55046bf2 100644
--- a/internal/db/diff/pgadmin.go
+++ b/internal/db/diff/pgadmin.go
@@ -11,6 +11,7 @@ import (
 	"github.com/supabase/cli/internal/db/start"
 	"github.com/supabase/cli/internal/migration/new"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/config"
 )
 
@@ -35,7 +36,7 @@ func SaveDiff(out, file string, fsys afero.Fs) error {
 func RunPgAdmin(ctx context.Context, schema []string, file string, config pgconn.Config, fsys afero.Fs) error {
 	// Sanity checks.
 	{
-		if err := utils.LoadConfigFS(fsys); err != nil {
+		if err := flags.LoadConfig(fsys); err != nil {
 			return err
 		}
 		if err := utils.AssertSupabaseDbIsRunning(); err != nil {
diff --git a/internal/db/pull/pull.go b/internal/db/pull/pull.go
index f6a235e1..6cc8dcca 100644
--- a/internal/db/pull/pull.go
+++ b/internal/db/pull/pull.go
@@ -18,6 +18,7 @@ import (
 	"github.com/supabase/cli/internal/migration/new"
 	"github.com/supabase/cli/internal/migration/repair"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 )
 
@@ -35,7 +36,7 @@ var (
 
 func Run(ctx context.Context, schema []string, config pgconn.Config, name string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
 	// 1. Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	// 2. Check postgres connection
diff --git a/internal/db/push/push.go b/internal/db/push/push.go
index 2141255a..7e524155 100644
--- a/internal/db/push/push.go
+++ b/internal/db/push/push.go
@@ -31,9 +31,10 @@ func Run(ctx context.Context, dryRun, ignoreVersionMismatch bool, includeRoles,
 	}
 	var seeds []migration.SeedFile
 	if includeSeed {
-		if remote, _ := utils.Config.GetRemoteByProjectRef(flags.ProjectRef); !remote.Db.Seed.Enabled {
-			fmt.Fprintln(os.Stderr, "Skipping seed because it is disabled in config.toml for project:", remote.ProjectId)
-		} else if seeds, err = migration.GetPendingSeeds(ctx, remote.Db.Seed.SqlPaths, conn, afero.NewIOFS(fsys)); err != nil {
+		// TODO: flag should override config but we don't resolve glob paths when seed is disabled.
+		if !utils.Config.Db.Seed.Enabled {
+			fmt.Fprintln(os.Stderr, "Skipping seed because it is disabled in config.toml for project:", flags.ProjectRef)
+		} else if seeds, err = migration.GetPendingSeeds(ctx, utils.Config.Db.Seed.SqlPaths, conn, afero.NewIOFS(fsys)); err != nil {
 			return err
 		}
 	}
diff --git a/internal/db/remote/changes/changes.go b/internal/db/remote/changes/changes.go
index c735b598..9aa4a47b 100644
--- a/internal/db/remote/changes/changes.go
+++ b/internal/db/remote/changes/changes.go
@@ -8,6 +8,7 @@ import (
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/db/diff"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 )
 
@@ -15,7 +16,7 @@ var output string
 
 func Run(ctx context.Context, schema []string, config pgconn.Config, fsys afero.Fs) error {
 	// Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 
diff --git a/internal/db/remote/commit/commit.go b/internal/db/remote/commit/commit.go
index f9062d49..6e00a029 100644
--- a/internal/db/remote/commit/commit.go
+++ b/internal/db/remote/commit/commit.go
@@ -15,12 +15,13 @@ import (
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/migration/repair"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 )
 
 func Run(ctx context.Context, schema []string, config pgconn.Config, fsys afero.Fs) error {
 	// Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 
diff --git a/internal/db/reset/reset.go b/internal/db/reset/reset.go
index 3830a019..307f14f5 100644
--- a/internal/db/reset/reset.go
+++ b/internal/db/reset/reset.go
@@ -27,7 +27,6 @@ import (
 	"github.com/supabase/cli/internal/migration/repair"
 	"github.com/supabase/cli/internal/seed/buckets"
 	"github.com/supabase/cli/internal/utils"
-	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 )
 
@@ -250,15 +249,11 @@ func resetRemote(ctx context.Context, version string, config pgconn.Config, fsys
 	if err := migration.ApplyMigrations(ctx, migrations, conn, afero.NewIOFS(fsys)); err != nil {
 		return err
 	}
-	remote, _ := utils.Config.GetRemoteByProjectRef(flags.ProjectRef)
-	if !remote.Db.Seed.Enabled {
-		fmt.Fprintln(os.Stderr, "Skipping seed because it is disabled in config.toml for project:", remote.ProjectId)
-		return nil
-	} else if !utils.Config.Db.Seed.Enabled {
+	if !utils.Config.Db.Seed.Enabled {
 		// Skip because --no-seed flag is set
 		return nil
 	}
-	seeds, err := migration.GetPendingSeeds(ctx, remote.Db.Seed.SqlPaths, conn, afero.NewIOFS(fsys))
+	seeds, err := migration.GetPendingSeeds(ctx, utils.Config.Db.Seed.SqlPaths, conn, afero.NewIOFS(fsys))
 	if err != nil {
 		return err
 	}
diff --git a/internal/db/start/start.go b/internal/db/start/start.go
index c4722f22..4180fe05 100644
--- a/internal/db/start/start.go
+++ b/internal/db/start/start.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"path/filepath"
 	"strconv"
 	"strings"
 	"time"
@@ -22,6 +23,7 @@ import (
 	"github.com/supabase/cli/internal/migration/apply"
 	"github.com/supabase/cli/internal/status"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 )
 
@@ -29,12 +31,16 @@ var (
 	HealthTimeout = 120 * time.Second
 	//go:embed templates/schema.sql
 	initialSchema string
+	//go:embed templates/webhook.sql
+	webhookSchema string
 	//go:embed templates/_supabase.sql
 	_supabaseSchema string
+	//go:embed templates/restore.sh
+	restoreScript string
 )
 
-func Run(ctx context.Context, fsys afero.Fs) error {
-	if err := utils.LoadConfigFS(fsys); err != nil {
+func Run(ctx context.Context, fromBackup string, fsys afero.Fs) error {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	if err := utils.AssertSupabaseDbIsRunning(); err == nil {
@@ -43,7 +49,7 @@ func Run(ctx context.Context, fsys afero.Fs) error {
 	} else if !errors.Is(err, utils.ErrNotRunning) {
 		return err
 	}
-	err := StartDatabase(ctx, fsys, os.Stderr)
+	err := StartDatabase(ctx, fromBackup, fsys, os.Stderr)
 	if err != nil {
 		if err := utils.DockerRemoveAll(context.Background(), os.Stderr, utils.Config.ProjectId); err != nil {
 			fmt.Fprintln(os.Stderr, err)
@@ -86,6 +92,7 @@ cat <<'EOF' > /etc/postgresql-custom/pgsodium_root.key && \
 cat <<'EOF' >> /etc/postgresql/postgresql.conf && \
 docker-entrypoint.sh postgres -D /etc/postgresql
 ` + initialSchema + `
+` + webhookSchema + `
 ` + _supabaseSchema + `
 EOF
 ` + utils.Config.Db.RootKey + `
@@ -116,7 +123,7 @@ func NewHostConfig() container.HostConfig {
 	return hostConfig
 }
 
-func StartDatabase(ctx context.Context, fsys afero.Fs, w io.Writer, options ...func(*pgx.ConnConfig)) error {
+func StartDatabase(ctx context.Context, fromBackup string, fsys afero.Fs, w io.Writer, options ...func(*pgx.ConnConfig)) error {
 	config := NewContainerConfig()
 	hostConfig := NewHostConfig()
 	networkingConfig := network.NetworkingConfig{
@@ -137,11 +144,35 @@ EOF
 EOF`}
 		hostConfig.Tmpfs = map[string]string{"/docker-entrypoint-initdb.d": ""}
 	}
+	if len(fromBackup) > 0 {
+		config.Entrypoint = []string{"sh", "-c", `
+cat <<'EOF' > /etc/postgresql.schema.sql && \
+cat <<'EOF' > /docker-entrypoint-initdb.d/migrate.sh && \
+cat <<'EOF' > /etc/postgresql-custom/pgsodium_root.key && \
+cat <<'EOF' >> /etc/postgresql/postgresql.conf && \
+docker-entrypoint.sh postgres -D /etc/postgresql
+` + initialSchema + `
+` + _supabaseSchema + `
+EOF
+` + restoreScript + `
+EOF
+` + utils.Config.Db.RootKey + `
+EOF
+` + utils.Config.Db.Settings.ToPostgresConfig() + `
+EOF`}
+		if !filepath.IsAbs(fromBackup) {
+			fromBackup = filepath.Join(utils.CurrentDirAbs, fromBackup)
+		}
+		hostConfig.Binds = append(hostConfig.Binds, utils.ToDockerPath(fromBackup)+":/etc/backup.sql:ro")
+	}
 	// Creating volume will not override existing volume, so we must inspect explicitly
 	_, err := utils.Docker.VolumeInspect(ctx, utils.DbId)
 	utils.NoBackupVolume = client.IsErrNotFound(err)
 	if utils.NoBackupVolume {
 		fmt.Fprintln(w, "Starting database...")
+	} else if len(fromBackup) > 0 {
+		utils.CmdSuggestion = fmt.Sprintf("Run %s to remove existing docker volumes.", utils.Aqua("supabase stop --no-backup"))
+		return errors.Errorf("backup volume already exists")
 	} else {
 		fmt.Fprintln(w, "Starting database from backup...")
 	}
@@ -152,7 +183,11 @@ EOF`}
 		return err
 	}
 	// Initialize if we are on PG14 and there's no existing db volume
-	if utils.NoBackupVolume {
+	if len(fromBackup) > 0 {
+		if err := initSchema15(ctx, utils.DbId); err != nil {
+			return err
+		}
+	} else if utils.NoBackupVolume {
 		if err := SetupLocalDatabase(ctx, "", fsys, w, options...); err != nil {
 			return err
 		}
diff --git a/internal/db/start/templates/restore.sh b/internal/db/start/templates/restore.sh
new file mode 100755
index 00000000..26f6418e
--- /dev/null
+++ b/internal/db/start/templates/restore.sh
@@ -0,0 +1,41 @@
+#!/bin/sh
+set -eu
+
+#######################################
+# Used by both ami and docker builds to initialise database schema.
+# Env vars:
+#   POSTGRES_DB        defaults to postgres
+#   POSTGRES_HOST      defaults to localhost
+#   POSTGRES_PORT      defaults to 5432
+#   POSTGRES_PASSWORD  defaults to ""
+#   USE_DBMATE         defaults to ""
+# Exit code:
+#   0 if migration succeeds, non-zero on error.
+#######################################
+
+export PGDATABASE="${POSTGRES_DB:-postgres}"
+export PGHOST="${POSTGRES_HOST:-localhost}"
+export PGPORT="${POSTGRES_PORT:-5432}"
+export PGPASSWORD="${POSTGRES_PASSWORD:-}"
+
+echo "$0: restoring roles"
+cat "/etc/backup.sql" \
+| grep 'CREATE ROLE' \
+| grep -v 'supabase_admin' \
+| psql -v ON_ERROR_STOP=1 --no-password --no-psqlrc -U supabase_admin
+
+echo "$0: restoring schema"
+cat "/etc/backup.sql" \
+| sed -E 's/^CREATE VIEW /CREATE OR REPLACE VIEW /' \
+| sed -E 's/^CREATE FUNCTION /CREATE OR REPLACE FUNCTION /' \
+| sed -E 's/^CREATE TRIGGER /CREATE OR REPLACE TRIGGER /' \
+| sed -E 's/^GRANT ALL ON FUNCTION graphql_public\./-- &/' \
+| sed -E 's/^CREATE ROLE /-- &/' \
+| psql -v ON_ERROR_STOP=1 --no-password --no-psqlrc -U supabase_admin
+
+# run any post migration script to update role passwords
+postinit="/etc/postgresql.schema.sql"
+if [ -e "$postinit" ]; then
+    echo "$0: running $postinit"
+    psql -v ON_ERROR_STOP=1 --no-password --no-psqlrc -U supabase_admin -f "$postinit"
+fi
diff --git a/internal/db/start/templates/schema.sql b/internal/db/start/templates/schema.sql
index 534dd120..810d9506 100644
--- a/internal/db/start/templates/schema.sql
+++ b/internal/db/start/templates/schema.sql
@@ -14,236 +14,3 @@ ALTER USER supabase_read_only_user WITH PASSWORD :'pgpass';
 
 create schema if not exists _realtime;
 alter schema _realtime owner to postgres;
-
-BEGIN;
-
--- Create pg_net extension
-CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions;
-
--- Create supabase_functions schema
-CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin;
-
-GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role;
-ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role;
-ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role;
-ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role;
-
--- supabase_functions.migrations definition
-CREATE TABLE supabase_functions.migrations (
-  version text PRIMARY KEY,
-  inserted_at timestamptz NOT NULL DEFAULT NOW()
-);
-
--- Initial supabase_functions migration
-INSERT INTO supabase_functions.migrations (version) VALUES ('initial');
-
--- supabase_functions.hooks definition
-CREATE TABLE supabase_functions.hooks (
-  id bigserial PRIMARY KEY,
-  hook_table_id integer NOT NULL,
-  hook_name text NOT NULL,
-  created_at timestamptz NOT NULL DEFAULT NOW(),
-  request_id bigint
-);
-CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id);
-CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name);
-COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.';
-
-CREATE FUNCTION supabase_functions.http_request()
-  RETURNS trigger
-  LANGUAGE plpgsql
-  AS $function$
-  DECLARE
-    request_id bigint;
-    payload jsonb;
-    url text := TG_ARGV[0]::text;
-    method text := TG_ARGV[1]::text;
-    headers jsonb DEFAULT '{}'::jsonb;
-    params jsonb DEFAULT '{}'::jsonb;
-    timeout_ms integer DEFAULT 1000;
-  BEGIN
-    IF url IS NULL OR url = 'null' THEN
-      RAISE EXCEPTION 'url argument is missing';
-    END IF;
-
-    IF method IS NULL OR method = 'null' THEN
-      RAISE EXCEPTION 'method argument is missing';
-    END IF;
-
-    IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN
-      headers = '{"Content-Type": "application/json"}'::jsonb;
-    ELSE
-      headers = TG_ARGV[2]::jsonb;
-    END IF;
-
-    IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN
-      params = '{}'::jsonb;
-    ELSE
-      params = TG_ARGV[3]::jsonb;
-    END IF;
-
-    IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN
-      timeout_ms = 1000;
-    ELSE
-      timeout_ms = TG_ARGV[4]::integer;
-    END IF;
-
-    CASE
-      WHEN method = 'GET' THEN
-        SELECT http_get INTO request_id FROM net.http_get(
-          url,
-          params,
-          headers,
-          timeout_ms
-        );
-      WHEN method = 'POST' THEN
-        payload = jsonb_build_object(
-          'old_record', OLD,
-          'record', NEW,
-          'type', TG_OP,
-          'table', TG_TABLE_NAME,
-          'schema', TG_TABLE_SCHEMA
-        );
-
-        SELECT http_post INTO request_id FROM net.http_post(
-          url,
-          payload,
-          params,
-          headers,
-          timeout_ms
-        );
-      ELSE
-        RAISE EXCEPTION 'method argument % is invalid', method;
-    END CASE;
-
-    INSERT INTO supabase_functions.hooks
-      (hook_table_id, hook_name, request_id)
-    VALUES
-      (TG_RELID, TG_NAME, request_id);
-
-    RETURN NEW;
-  END
-$function$;
-
--- Supabase super admin
-DO
-$$
-BEGIN
-  IF NOT EXISTS (
-    SELECT 1
-    FROM pg_roles
-    WHERE rolname = 'supabase_functions_admin'
-  )
-  THEN
-    CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;
-  END IF;
-END
-$$;
-
-GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin;
-GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin;
-GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin;
-ALTER USER supabase_functions_admin SET search_path = "supabase_functions";
-ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin;
-ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin;
-ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin;
-GRANT supabase_functions_admin TO postgres;
-
--- Remove unused supabase_pg_net_admin role
-DO
-$$
-BEGIN
-  IF EXISTS (
-    SELECT 1
-    FROM pg_roles
-    WHERE rolname = 'supabase_pg_net_admin'
-  )
-  THEN
-    REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin;
-    DROP OWNED BY supabase_pg_net_admin;
-    DROP ROLE supabase_pg_net_admin;
-  END IF;
-END
-$$;
-
--- pg_net grants when extension is already enabled
-DO
-$$
-BEGIN
-  IF EXISTS (
-    SELECT 1
-    FROM pg_extension
-    WHERE extname = 'pg_net'
-  )
-  THEN
-    GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
-
-    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
-    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
-
-    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
-    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
-
-    REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
-    REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
-
-    GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
-    GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
-  END IF;
-END
-$$;
-
--- Event trigger for pg_net
-CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access()
-RETURNS event_trigger
-LANGUAGE plpgsql
-AS $$
-BEGIN
-  IF EXISTS (
-    SELECT 1
-    FROM pg_event_trigger_ddl_commands() AS ev
-    JOIN pg_extension AS ext
-    ON ev.objid = ext.oid
-    WHERE ext.extname = 'pg_net'
-  )
-  THEN
-    GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
-
-    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
-    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
-
-    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
-    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
-
-    REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
-    REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
-
-    GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
-    GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
-  END IF;
-END;
-$$;
-COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net';
-
-DO
-$$
-BEGIN
-  IF NOT EXISTS (
-    SELECT 1
-    FROM pg_event_trigger
-    WHERE evtname = 'issue_pg_net_access'
-  ) THEN
-    CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION')
-    EXECUTE PROCEDURE extensions.grant_pg_net_access();
-  END IF;
-END
-$$;
-
-INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants');
-
-ALTER function supabase_functions.http_request() SECURITY DEFINER;
-ALTER function supabase_functions.http_request() SET search_path = supabase_functions;
-REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC;
-GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role;
-
-COMMIT;
diff --git a/internal/db/start/templates/webhook.sql b/internal/db/start/templates/webhook.sql
new file mode 100644
index 00000000..52cd0974
--- /dev/null
+++ b/internal/db/start/templates/webhook.sql
@@ -0,0 +1,232 @@
+BEGIN;
+
+-- Create pg_net extension
+CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions;
+
+-- Create supabase_functions schema
+CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin;
+
+GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role;
+ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role;
+ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role;
+ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role;
+
+-- supabase_functions.migrations definition
+CREATE TABLE supabase_functions.migrations (
+  version text PRIMARY KEY,
+  inserted_at timestamptz NOT NULL DEFAULT NOW()
+);
+
+-- Initial supabase_functions migration
+INSERT INTO supabase_functions.migrations (version) VALUES ('initial');
+
+-- supabase_functions.hooks definition
+CREATE TABLE supabase_functions.hooks (
+  id bigserial PRIMARY KEY,
+  hook_table_id integer NOT NULL,
+  hook_name text NOT NULL,
+  created_at timestamptz NOT NULL DEFAULT NOW(),
+  request_id bigint
+);
+CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id);
+CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name);
+COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.';
+
+CREATE FUNCTION supabase_functions.http_request()
+  RETURNS trigger
+  LANGUAGE plpgsql
+  AS $function$
+  DECLARE
+    request_id bigint;
+    payload jsonb;
+    url text := TG_ARGV[0]::text;
+    method text := TG_ARGV[1]::text;
+    headers jsonb DEFAULT '{}'::jsonb;
+    params jsonb DEFAULT '{}'::jsonb;
+    timeout_ms integer DEFAULT 1000;
+  BEGIN
+    IF url IS NULL OR url = 'null' THEN
+      RAISE EXCEPTION 'url argument is missing';
+    END IF;
+
+    IF method IS NULL OR method = 'null' THEN
+      RAISE EXCEPTION 'method argument is missing';
+    END IF;
+
+    IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN
+      headers = '{"Content-Type": "application/json"}'::jsonb;
+    ELSE
+      headers = TG_ARGV[2]::jsonb;
+    END IF;
+
+    IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN
+      params = '{}'::jsonb;
+    ELSE
+      params = TG_ARGV[3]::jsonb;
+    END IF;
+
+    IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN
+      timeout_ms = 1000;
+    ELSE
+      timeout_ms = TG_ARGV[4]::integer;
+    END IF;
+
+    CASE
+      WHEN method = 'GET' THEN
+        SELECT http_get INTO request_id FROM net.http_get(
+          url,
+          params,
+          headers,
+          timeout_ms
+        );
+      WHEN method = 'POST' THEN
+        payload = jsonb_build_object(
+          'old_record', OLD,
+          'record', NEW,
+          'type', TG_OP,
+          'table', TG_TABLE_NAME,
+          'schema', TG_TABLE_SCHEMA
+        );
+
+        SELECT http_post INTO request_id FROM net.http_post(
+          url,
+          payload,
+          params,
+          headers,
+          timeout_ms
+        );
+      ELSE
+        RAISE EXCEPTION 'method argument % is invalid', method;
+    END CASE;
+
+    INSERT INTO supabase_functions.hooks
+      (hook_table_id, hook_name, request_id)
+    VALUES
+      (TG_RELID, TG_NAME, request_id);
+
+    RETURN NEW;
+  END
+$function$;
+
+-- Supabase super admin
+DO
+$$
+BEGIN
+  IF NOT EXISTS (
+    SELECT 1
+    FROM pg_roles
+    WHERE rolname = 'supabase_functions_admin'
+  )
+  THEN
+    CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION;
+  END IF;
+END
+$$;
+
+GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin;
+GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin;
+GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin;
+ALTER USER supabase_functions_admin SET search_path = "supabase_functions";
+ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin;
+ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin;
+ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin;
+GRANT supabase_functions_admin TO postgres;
+
+-- Remove unused supabase_pg_net_admin role
+DO
+$$
+BEGIN
+  IF EXISTS (
+    SELECT 1
+    FROM pg_roles
+    WHERE rolname = 'supabase_pg_net_admin'
+  )
+  THEN
+    REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin;
+    DROP OWNED BY supabase_pg_net_admin;
+    DROP ROLE supabase_pg_net_admin;
+  END IF;
+END
+$$;
+
+-- pg_net grants when extension is already enabled
+DO
+$$
+BEGIN
+  IF EXISTS (
+    SELECT 1
+    FROM pg_extension
+    WHERE extname = 'pg_net'
+  )
+  THEN
+    GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+
+    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
+    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
+
+    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
+    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
+
+    REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
+    REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
+
+    GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+    GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+  END IF;
+END
+$$;
+
+-- Event trigger for pg_net
+CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access()
+RETURNS event_trigger
+LANGUAGE plpgsql
+AS $$
+BEGIN
+  IF EXISTS (
+    SELECT 1
+    FROM pg_event_trigger_ddl_commands() AS ev
+    JOIN pg_extension AS ext
+    ON ev.objid = ext.oid
+    WHERE ext.extname = 'pg_net'
+  )
+  THEN
+    GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+
+    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
+    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER;
+
+    ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
+    ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net;
+
+    REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
+    REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC;
+
+    GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+    GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role;
+  END IF;
+END;
+$$;
+COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net';
+
+DO
+$$
+BEGIN
+  IF NOT EXISTS (
+    SELECT 1
+    FROM pg_event_trigger
+    WHERE evtname = 'issue_pg_net_access'
+  ) THEN
+    CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION')
+    EXECUTE PROCEDURE extensions.grant_pg_net_access();
+  END IF;
+END
+$$;
+
+INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants');
+
+ALTER function supabase_functions.http_request() SECURITY DEFINER;
+ALTER function supabase_functions.http_request() SET search_path = supabase_functions;
+REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role;
+
+COMMIT;
diff --git a/internal/functions/deploy/bundle.go b/internal/functions/deploy/bundle.go
index 0119a559..02f31863 100644
--- a/internal/functions/deploy/bundle.go
+++ b/internal/functions/deploy/bundle.go
@@ -57,12 +57,16 @@ func (b *dockerBundler) Bundle(ctx context.Context, entrypoint string, importMap
 	if viper.GetBool("DEBUG") {
 		cmd = append(cmd, "--verbose")
 	}
+	env := []string{}
+	if custom_registry := os.Getenv("NPM_CONFIG_REGISTRY"); custom_registry != "" {
+		env = append(env, "NPM_CONFIG_REGISTRY="+custom_registry)
+	}
 	// Run bundle
 	if err := utils.DockerRunOnceWithConfig(
 		ctx,
 		container.Config{
 			Image:      utils.Config.EdgeRuntime.Image,
-			Env:        []string{},
+			Env:        env,
 			Cmd:        cmd,
 			WorkingDir: utils.ToDockerPath(cwd),
 		},
diff --git a/internal/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go
index 529b7897..196d2e8a 100644
--- a/internal/functions/deploy/deploy.go
+++ b/internal/functions/deploy/deploy.go
@@ -18,7 +18,7 @@ import (
 
 func Run(ctx context.Context, slugs []string, projectRef string, noVerifyJWT *bool, importMapPath string, fsys afero.Fs) error {
 	// Load function config and project id
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	} else if len(slugs) > 0 {
 		for _, s := range slugs {
@@ -60,8 +60,7 @@ func GetFunctionSlugs(fsys afero.Fs) (slugs []string, err error) {
 		}
 	}
 	// Add all function slugs declared in config file
-	remote, _ := utils.Config.GetRemoteByProjectRef(flags.ProjectRef)
-	for slug := range remote.Functions {
+	for slug := range utils.Config.Functions {
 		slugs = append(slugs, slug)
 	}
 	return slugs, nil
@@ -71,6 +70,8 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool,
 	// Although some functions do not require import map, it's more convenient to setup
 	// vscode deno extension with a single import map for all functions.
 	fallbackExists := true
+	functionsUsingDeprecatedGlobalFallback := []string{}
+	functionsUsingDeprecatedImportMap := []string{}
 	if _, err := fsys.Stat(utils.FallbackImportMapPath); errors.Is(err, os.ErrNotExist) {
 		fallbackExists = false
 	} else if err != nil {
@@ -80,10 +81,9 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool,
 	if len(importMapPath) > 0 && !filepath.IsAbs(importMapPath) {
 		importMapPath = filepath.Join(utils.CurrentDirAbs, importMapPath)
 	}
-	remote, _ := utils.Config.GetRemoteByProjectRef(flags.ProjectRef)
 	functionConfig := make(config.FunctionConfig, len(slugs))
 	for _, name := range slugs {
-		function := remote.Functions[name]
+		function := utils.Config.Functions[name]
 		// Precedence order: flag > config > fallback
 		functionDir := filepath.Join(utils.FunctionsDir, name)
 		if len(function.Entrypoint) == 0 {
@@ -94,12 +94,17 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool,
 		} else if len(function.ImportMap) == 0 {
 			denoJsonPath := filepath.Join(functionDir, "deno.json")
 			denoJsoncPath := filepath.Join(functionDir, "deno.jsonc")
+			importMapPath := filepath.Join(functionDir, "import_map.json")
 			if _, err := fsys.Stat(denoJsonPath); err == nil {
 				function.ImportMap = denoJsonPath
 			} else if _, err := fsys.Stat(denoJsoncPath); err == nil {
 				function.ImportMap = denoJsoncPath
+			} else if _, err := fsys.Stat(importMapPath); err == nil {
+				function.ImportMap = importMapPath
+				functionsUsingDeprecatedImportMap = append(functionsUsingDeprecatedImportMap, name)
 			} else if fallbackExists {
 				function.ImportMap = utils.FallbackImportMapPath
+				functionsUsingDeprecatedGlobalFallback = append(functionsUsingDeprecatedGlobalFallback, name)
 			}
 		}
 		if noVerifyJWT != nil {
@@ -107,5 +112,23 @@ func GetFunctionConfig(slugs []string, importMapPath string, noVerifyJWT *bool,
 		}
 		functionConfig[name] = function
 	}
+	if len(functionsUsingDeprecatedImportMap) > 0 {
+		fmt.Fprintln(os.Stderr,
+			utils.Yellow("WARNING:"),
+			"Functions using deprecated import_map.json (please migrate to deno.json):",
+			utils.Aqua(strings.Join(functionsUsingDeprecatedImportMap, ", ")),
+		)
+	}
+	if len(functionsUsingDeprecatedGlobalFallback) > 0 {
+		fmt.Fprintln(os.Stderr,
+			utils.Yellow("WARNING:"),
+			"Functions using fallback import map:",
+			utils.Aqua(strings.Join(functionsUsingDeprecatedGlobalFallback, ", ")),
+		)
+		fmt.Fprintln(os.Stderr,
+			"Please use recommended per function dependency declaration ",
+			utils.Aqua("https://supabase.com/docs/guides/functions/import-maps"),
+		)
+	}
 	return functionConfig, nil
 }
diff --git a/internal/functions/download/download.go b/internal/functions/download/download.go
index e3b68cae..ca99c1bc 100644
--- a/internal/functions/download/download.go
+++ b/internal/functions/download/download.go
@@ -16,6 +16,7 @@ import (
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/api"
 )
 
@@ -112,7 +113,7 @@ func Run(ctx context.Context, slug string, projectRef string, useLegacyBundle bo
 		return RunLegacy(ctx, slug, projectRef, fsys)
 	}
 	// 1. Sanity check
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	// 2. Download eszip to temp file
diff --git a/internal/functions/new/new.go b/internal/functions/new/new.go
index 3656e9b5..67a9893e 100644
--- a/internal/functions/new/new.go
+++ b/internal/functions/new/new.go
@@ -11,12 +11,18 @@ import (
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 )
 
 var (
 	//go:embed templates/index.ts
-	indexEmbed    string
-	indexTemplate = template.Must(template.New("indexl").Parse(indexEmbed))
+	indexEmbed string
+	//go:embed templates/deno.json
+	denoEmbed string
+	//go:embed templates/.npmrc
+	npmrcEmbed string
+
+	indexTemplate = template.Must(template.New("index").Parse(indexEmbed))
 )
 
 type indexConfig struct {
@@ -38,25 +44,37 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error {
 		if err := utils.MkdirIfNotExistFS(fsys, funcDir); err != nil {
 			return err
 		}
-		path := filepath.Join(funcDir, "index.ts")
-		f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
-		if err != nil {
-			return errors.Errorf("failed to create function entrypoint: %w", err)
-		}
-		defer f.Close()
-		// Templatize index.ts by config.toml if available
-		if err := utils.LoadConfigFS(fsys); err != nil {
+
+		// Load config if available
+		if err := flags.LoadConfig(fsys); err != nil {
 			utils.CmdSuggestion = ""
 		}
-		config := indexConfig{
+
+		if err := createTemplateFile(fsys, filepath.Join(funcDir, "index.ts"), indexTemplate, indexConfig{
 			URL:   utils.GetApiUrl("/functions/v1/" + slug),
 			Token: utils.Config.Auth.AnonKey,
+		}); err != nil {
+			return errors.Errorf("failed to create function entrypoint: %w", err)
 		}
-		if err := indexTemplate.Option("missingkey=error").Execute(f, config); err != nil {
-			return errors.Errorf("failed to initialise function entrypoint: %w", err)
+
+		if err := afero.WriteFile(fsys, filepath.Join(funcDir, "deno.json"), []byte(denoEmbed), 0644); err != nil {
+			return errors.Errorf("failed to create deno.json config: %w", err)
+		}
+
+		if err := afero.WriteFile(fsys, filepath.Join(funcDir, ".npmrc"), []byte(npmrcEmbed), 0644); err != nil {
+			return errors.Errorf("failed to create .npmrc config: %w", err)
 		}
 	}
 
 	fmt.Println("Created new Function at " + utils.Bold(funcDir))
 	return nil
 }
+
+func createTemplateFile(fsys afero.Fs, path string, tmpl *template.Template, data interface{}) error {
+	f, err := fsys.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0644)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return tmpl.Option("missingkey=error").Execute(f, data)
+}
diff --git a/internal/functions/new/templates/.npmrc b/internal/functions/new/templates/.npmrc
new file mode 100644
index 00000000..48c63886
--- /dev/null
+++ b/internal/functions/new/templates/.npmrc
@@ -0,0 +1,3 @@
+# Configuration for private npm package dependencies
+# For more information on using private registries with Edge Functions, see:
+# https://supabase.com/docs/guides/functions/import-maps#importing-from-private-registries
diff --git a/internal/functions/new/templates/deno.json b/internal/functions/new/templates/deno.json
new file mode 100644
index 00000000..f6ca8454
--- /dev/null
+++ b/internal/functions/new/templates/deno.json
@@ -0,0 +1,3 @@
+{
+  "imports": {}
+}
diff --git a/internal/functions/serve/serve.go b/internal/functions/serve/serve.go
index 62811d76..485d8c7c 100644
--- a/internal/functions/serve/serve.go
+++ b/internal/functions/serve/serve.go
@@ -19,6 +19,7 @@ import (
 	"github.com/supabase/cli/internal/functions/deploy"
 	"github.com/supabase/cli/internal/secrets/set"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 )
 
 type InspectMode string
@@ -70,7 +71,7 @@ var (
 
 func Run(ctx context.Context, envFilePath string, noVerifyJWT *bool, importMapPath string, runtimeOption RuntimeOption, fsys afero.Fs) error {
 	// 1. Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	if err := utils.AssertSupabaseDbIsRunning(); err != nil {
diff --git a/internal/gen/types/types.go b/internal/gen/types/types.go
index b399cfb5..9ffc7dc7 100644
--- a/internal/gen/types/types.go
+++ b/internal/gen/types/types.go
@@ -31,8 +31,7 @@ func Run(ctx context.Context, projectId string, dbConfig pgconn.Config, lang str
 	originalURL := utils.ToPostgresURL(dbConfig)
 	// Add default schemas if --schema flag is not specified
 	if len(schemas) == 0 {
-		remote, _ := utils.Config.GetRemoteByProjectRef(projectId)
-		schemas = utils.RemoveDuplicates(append([]string{"public"}, remote.Api.Schemas...))
+		schemas = utils.RemoveDuplicates(append([]string{"public"}, utils.Config.Api.Schemas...))
 	}
 	included := strings.Join(schemas, ",")
 
diff --git a/internal/init/init.go b/internal/init/init.go
index f4e470b0..72241a0e 100644
--- a/internal/init/init.go
+++ b/internal/init/init.go
@@ -1,6 +1,7 @@
 package init
 
 import (
+	"bytes"
 	"context"
 	_ "embed"
 	"encoding/json"
@@ -12,6 +13,7 @@ import (
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/tidwall/jsonc"
 )
 
 var (
@@ -100,15 +102,14 @@ func updateGitIgnore(ignorePath string, fsys afero.Fs) error {
 type VSCodeSettings map[string]interface{}
 
 func loadUserSettings(path string, fsys afero.Fs) (VSCodeSettings, error) {
-	// Open our jsonFile
-	jsonFile, err := fsys.Open(path)
+	data, err := afero.ReadFile(fsys, path)
 	if err != nil {
 		return nil, errors.Errorf("failed to load settings file: %w", err)
 	}
-	defer jsonFile.Close()
+	data = jsonc.ToJSONInPlace(data)
 	// Parse and unmarshal JSON file.
 	var userSettings VSCodeSettings
-	dec := json.NewDecoder(jsonFile)
+	dec := json.NewDecoder(bytes.NewReader(data))
 	if err := dec.Decode(&userSettings); err != nil {
 		return nil, errors.Errorf("failed to parse settings: %w", err)
 	}
diff --git a/internal/link/link.go b/internal/link/link.go
index e791271b..d35321e2 100644
--- a/internal/link/link.go
+++ b/internal/link/link.go
@@ -26,7 +26,6 @@ import (
 
 func Run(ctx context.Context, projectRef string, fsys afero.Fs, options ...func(*pgx.ConnConfig)) error {
 	copy := utils.Config.Clone()
-	copy.Auth.HashSecrets(projectRef)
 	original, err := cliConfig.ToTomlBytes(copy)
 	if err != nil {
 		fmt.Fprintln(utils.GetDebugLogger(), err)
diff --git a/internal/migration/squash/squash.go b/internal/migration/squash/squash.go
index 2ed9e625..4aad8b83 100644
--- a/internal/migration/squash/squash.go
+++ b/internal/migration/squash/squash.go
@@ -20,6 +20,7 @@ import (
 	"github.com/supabase/cli/internal/migration/list"
 	"github.com/supabase/cli/internal/migration/repair"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/migration"
 )
 
@@ -34,7 +35,7 @@ func Run(ctx context.Context, version string, config pgconn.Config, fsys afero.F
 			return err
 		}
 	}
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	// 1. Squash local migrations
diff --git a/internal/seed/buckets/buckets.go b/internal/seed/buckets/buckets.go
index b460fdc7..365c3a39 100644
--- a/internal/seed/buckets/buckets.go
+++ b/internal/seed/buckets/buckets.go
@@ -26,9 +26,8 @@ func Run(ctx context.Context, projectRef string, interactive bool, fsys afero.Fs
 		}
 		return shouldOverwrite
 	}
-	remote, _ := utils.Config.GetRemoteByProjectRef(projectRef)
-	if err := api.UpsertBuckets(ctx, remote.Storage.Buckets, filter); err != nil {
+	if err := api.UpsertBuckets(ctx, utils.Config.Storage.Buckets, filter); err != nil {
 		return err
 	}
-	return api.UpsertObjects(ctx, remote.Storage.Buckets, utils.NewRootFS(fsys))
+	return api.UpsertObjects(ctx, utils.Config.Storage.Buckets, utils.NewRootFS(fsys))
 }
diff --git a/internal/start/start.go b/internal/start/start.go
index f5a24d8c..2501d5b8 100644
--- a/internal/start/start.go
+++ b/internal/start/start.go
@@ -37,7 +37,7 @@ import (
 func Run(ctx context.Context, fsys afero.Fs, excludedContainers []string, ignoreHealthCheck bool) error {
 	// Sanity checks.
 	{
-		if err := utils.LoadConfigFS(fsys); err != nil {
+		if err := flags.LoadConfig(fsys); err != nil {
 			return err
 		}
 		if err := utils.AssertSupabaseDbIsRunning(); err == nil {
@@ -162,7 +162,7 @@ func run(p utils.Program, ctx context.Context, fsys afero.Fs, excludedContainers
 	// Start Postgres.
 	w := utils.StatusWriter{Program: p}
 	if dbConfig.Host == utils.DbId {
-		if err := start.StartDatabase(ctx, fsys, w, options...); err != nil {
+		if err := start.StartDatabase(ctx, "", fsys, w, options...); err != nil {
 			return err
 		}
 	}
@@ -507,7 +507,7 @@ EOF
 				fmt.Sprintf("GOTRUE_SMTP_HOST=%s", utils.Config.Auth.Email.Smtp.Host),
 				fmt.Sprintf("GOTRUE_SMTP_PORT=%d", utils.Config.Auth.Email.Smtp.Port),
 				fmt.Sprintf("GOTRUE_SMTP_USER=%s", utils.Config.Auth.Email.Smtp.User),
-				fmt.Sprintf("GOTRUE_SMTP_PASS=%s", utils.Config.Auth.Email.Smtp.Pass),
+				fmt.Sprintf("GOTRUE_SMTP_PASS=%s", utils.Config.Auth.Email.Smtp.Pass.Value),
 				fmt.Sprintf("GOTRUE_SMTP_ADMIN_EMAIL=%s", utils.Config.Auth.Email.Smtp.AdminEmail),
 				fmt.Sprintf("GOTRUE_SMTP_SENDER_NAME=%s", utils.Config.Auth.Email.Smtp.SenderName),
 			)
@@ -550,7 +550,7 @@ EOF
 				env,
 				"GOTRUE_SMS_PROVIDER=twilio",
 				"GOTRUE_SMS_TWILIO_ACCOUNT_SID="+utils.Config.Auth.Sms.Twilio.AccountSid,
-				"GOTRUE_SMS_TWILIO_AUTH_TOKEN="+utils.Config.Auth.Sms.Twilio.AuthToken,
+				"GOTRUE_SMS_TWILIO_AUTH_TOKEN="+utils.Config.Auth.Sms.Twilio.AuthToken.Value,
 				"GOTRUE_SMS_TWILIO_MESSAGE_SERVICE_SID="+utils.Config.Auth.Sms.Twilio.MessageServiceSid,
 			)
 		case utils.Config.Auth.Sms.TwilioVerify.Enabled:
@@ -558,21 +558,21 @@ EOF
 				env,
 				"GOTRUE_SMS_PROVIDER=twilio_verify",
 				"GOTRUE_SMS_TWILIO_VERIFY_ACCOUNT_SID="+utils.Config.Auth.Sms.TwilioVerify.AccountSid,
-				"GOTRUE_SMS_TWILIO_VERIFY_AUTH_TOKEN="+utils.Config.Auth.Sms.TwilioVerify.AuthToken,
+				"GOTRUE_SMS_TWILIO_VERIFY_AUTH_TOKEN="+utils.Config.Auth.Sms.TwilioVerify.AuthToken.Value,
 				"GOTRUE_SMS_TWILIO_VERIFY_MESSAGE_SERVICE_SID="+utils.Config.Auth.Sms.TwilioVerify.MessageServiceSid,
 			)
 		case utils.Config.Auth.Sms.Messagebird.Enabled:
 			env = append(
 				env,
 				"GOTRUE_SMS_PROVIDER=messagebird",
-				"GOTRUE_SMS_MESSAGEBIRD_ACCESS_KEY="+utils.Config.Auth.Sms.Messagebird.AccessKey,
+				"GOTRUE_SMS_MESSAGEBIRD_ACCESS_KEY="+utils.Config.Auth.Sms.Messagebird.AccessKey.Value,
 				"GOTRUE_SMS_MESSAGEBIRD_ORIGINATOR="+utils.Config.Auth.Sms.Messagebird.Originator,
 			)
 		case utils.Config.Auth.Sms.Textlocal.Enabled:
 			env = append(
 				env,
 				"GOTRUE_SMS_PROVIDER=textlocal",
-				"GOTRUE_SMS_TEXTLOCAL_API_KEY="+utils.Config.Auth.Sms.Textlocal.ApiKey,
+				"GOTRUE_SMS_TEXTLOCAL_API_KEY="+utils.Config.Auth.Sms.Textlocal.ApiKey.Value,
 				"GOTRUE_SMS_TEXTLOCAL_SENDER="+utils.Config.Auth.Sms.Textlocal.Sender,
 			)
 		case utils.Config.Auth.Sms.Vonage.Enabled:
@@ -580,7 +580,7 @@ EOF
 				env,
 				"GOTRUE_SMS_PROVIDER=vonage",
 				"GOTRUE_SMS_VONAGE_API_KEY="+utils.Config.Auth.Sms.Vonage.ApiKey,
-				"GOTRUE_SMS_VONAGE_API_SECRET="+utils.Config.Auth.Sms.Vonage.ApiSecret,
+				"GOTRUE_SMS_VONAGE_API_SECRET="+utils.Config.Auth.Sms.Vonage.ApiSecret.Value,
 				"GOTRUE_SMS_VONAGE_FROM="+utils.Config.Auth.Sms.Vonage.From,
 			)
 		}
@@ -590,7 +590,7 @@ EOF
 				env,
 				"GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED=true",
 				"GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI="+hook.URI,
-				"GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_SECRETS="+hook.Secrets,
+				"GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_SECRETS="+hook.Secrets.Value,
 			)
 		}
 		if hook := utils.Config.Auth.Hook.PasswordVerificationAttempt; hook != nil && hook.Enabled {
@@ -598,7 +598,7 @@ EOF
 				env,
 				"GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED=true",
 				"GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="+hook.URI,
-				"GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_SECRETS="+hook.Secrets,
+				"GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_SECRETS="+hook.Secrets.Value,
 			)
 		}
 		if hook := utils.Config.Auth.Hook.CustomAccessToken; hook != nil && hook.Enabled {
@@ -606,7 +606,7 @@ EOF
 				env,
 				"GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED=true",
 				"GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI="+hook.URI,
-				"GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS="+hook.Secrets,
+				"GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS="+hook.Secrets.Value,
 			)
 		}
 		if hook := utils.Config.Auth.Hook.SendSMS; hook != nil && hook.Enabled {
@@ -614,7 +614,7 @@ EOF
 				env,
 				"GOTRUE_HOOK_SEND_SMS_ENABLED=true",
 				"GOTRUE_HOOK_SEND_SMS_URI="+hook.URI,
-				"GOTRUE_HOOK_SEND_SMS_SECRETS="+hook.Secrets,
+				"GOTRUE_HOOK_SEND_SMS_SECRETS="+hook.Secrets.Value,
 			)
 		}
 		if hook := utils.Config.Auth.Hook.SendEmail; hook != nil && hook.Enabled {
@@ -622,7 +622,7 @@ EOF
 				env,
 				"GOTRUE_HOOK_SEND_EMAIL_ENABLED=true",
 				"GOTRUE_HOOK_SEND_EMAIL_URI="+hook.URI,
-				"GOTRUE_HOOK_SEND_EMAIL_SECRETS="+hook.Secrets,
+				"GOTRUE_HOOK_SEND_EMAIL_SECRETS="+hook.Secrets.Value,
 			)
 		}
 
@@ -640,7 +640,7 @@ EOF
 				env,
 				fmt.Sprintf("GOTRUE_EXTERNAL_%s_ENABLED=%v", strings.ToUpper(name), config.Enabled),
 				fmt.Sprintf("GOTRUE_EXTERNAL_%s_CLIENT_ID=%s", strings.ToUpper(name), config.ClientId),
-				fmt.Sprintf("GOTRUE_EXTERNAL_%s_SECRET=%s", strings.ToUpper(name), config.Secret),
+				fmt.Sprintf("GOTRUE_EXTERNAL_%s_SECRET=%s", strings.ToUpper(name), config.Secret.Value),
 				fmt.Sprintf("GOTRUE_EXTERNAL_%s_SKIP_NONCE_CHECK=%t", strings.ToUpper(name), config.SkipNonceCheck),
 			)
 
diff --git a/internal/status/status.go b/internal/status/status.go
index 1b9d02f9..68eae2fe 100644
--- a/internal/status/status.go
+++ b/internal/status/status.go
@@ -19,6 +19,7 @@ import (
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 	"github.com/supabase/cli/pkg/fetcher"
 )
 
@@ -67,7 +68,7 @@ func (c *CustomName) toValues(exclude ...string) map[string]string {
 
 func Run(ctx context.Context, names CustomName, format string, fsys afero.Fs) error {
 	// Sanity checks.
-	if err := utils.LoadConfigFS(fsys); err != nil {
+	if err := flags.LoadConfig(fsys); err != nil {
 		return err
 	}
 	if err := assertContainerHealthy(ctx, utils.DbId); err != nil {
diff --git a/internal/stop/stop.go b/internal/stop/stop.go
index 39c5e00e..da98f160 100644
--- a/internal/stop/stop.go
+++ b/internal/stop/stop.go
@@ -9,6 +9,7 @@ import (
 	"github.com/docker/docker/api/types/volume"
 	"github.com/spf13/afero"
 	"github.com/supabase/cli/internal/utils"
+	"github.com/supabase/cli/internal/utils/flags"
 )
 
 func Run(ctx context.Context, backup bool, projectId string, all bool, fsys afero.Fs) error {
@@ -17,7 +18,7 @@ func Run(ctx context.Context, backup bool, projectId string, all bool, fsys afer
 		// Sanity checks.
 		if len(projectId) > 0 {
 			utils.Config.ProjectId = projectId
-		} else if err := utils.LoadConfigFS(fsys); err != nil {
+		} else if err := flags.LoadConfig(fsys); err != nil {
 			return err
 		}
 		searchProjectIdFilter = utils.Config.ProjectId
diff --git a/internal/storage/cp/cp.go b/internal/storage/cp/cp.go
index e55120a1..4ead4463 100644
--- a/internal/storage/cp/cp.go
+++ b/internal/storage/cp/cp.go
@@ -52,7 +52,7 @@ func Run(ctx context.Context, src, dst string, recursive bool, maxJobs uint, fsy
 		if recursive {
 			return UploadStorageObjectAll(ctx, api, dstParsed.Path, localPath, maxJobs, fsys, opts...)
 		}
-		return api.UploadObject(ctx, dstParsed.Path, src, fsys, opts...)
+		return api.UploadObject(ctx, dstParsed.Path, src, utils.NewRootFS(fsys), opts...)
 	} else if strings.EqualFold(srcParsed.Scheme, client.STORAGE_SCHEME) && strings.EqualFold(dstParsed.Scheme, client.STORAGE_SCHEME) {
 		return errors.New("Copying between buckets is not supported")
 	}
@@ -115,7 +115,6 @@ func UploadStorageObjectAll(ctx context.Context, api storage.StorageAPI, remoteP
 			return err
 		}
 	}
-	remote, _ := utils.Config.GetRemoteByProjectRef(flags.ProjectRef)
 	// Overwrites existing object when using --recursive flag
 	opts = append(opts, func(fo *storage.FileOptions) {
 		fo.Overwrite = true
@@ -149,12 +148,12 @@ func UploadStorageObjectAll(ctx context.Context, api storage.StorageAPI, remoteP
 		}
 		fmt.Fprintln(os.Stderr, "Uploading:", filePath, "=>", dstPath)
 		job := func() error {
-			err := api.UploadObject(ctx, dstPath, filePath, fsys, opts...)
+			err := api.UploadObject(ctx, dstPath, filePath, utils.NewRootFS(fsys), opts...)
 			if err != nil && strings.Contains(err.Error(), `"error":"Bucket not found"`) {
 				// Retry after creating bucket
 				if bucket, prefix := client.SplitBucketPrefix(dstPath); len(prefix) > 0 {
 					body := storage.CreateBucketRequest{Name: bucket}
-					if config, ok := remote.Storage.Buckets[bucket]; ok {
+					if config, ok := utils.Config.Storage.Buckets[bucket]; ok {
 						body.Public = config.Public
 						body.FileSizeLimit = int64(config.FileSizeLimit)
 						body.AllowedMimeTypes = config.AllowedMimeTypes
@@ -162,7 +161,7 @@ func UploadStorageObjectAll(ctx context.Context, api storage.StorageAPI, remoteP
 					if _, err := api.CreateBucket(ctx, body); err != nil {
 						return err
 					}
-					err = api.UploadObject(ctx, dstPath, filePath, fsys, opts...)
+					err = api.UploadObject(ctx, dstPath, filePath, utils.NewRootFS(fsys), opts...)
 				}
 			}
 			return err
diff --git a/internal/utils/config.go b/internal/utils/config.go
index 3f89dc75..06d42d44 100644
--- a/internal/utils/config.go
+++ b/internal/utils/config.go
@@ -2,7 +2,6 @@ package utils
 
 import (
 	_ "embed"
-	"fmt"
 	"io/fs"
 	"net"
 	"net/url"
@@ -101,17 +100,6 @@ func GetDockerIds() []string {
 
 var Config = config.NewConfig(config.WithHostname(GetHostname()))
 
-func LoadConfigFS(fsys afero.Fs) error {
-	if err := Config.Load("", NewRootFS(fsys)); err != nil {
-		if errors.Is(err, os.ErrNotExist) {
-			CmdSuggestion = fmt.Sprintf("Have you set up the project with %s?", Aqua("supabase init"))
-		}
-		return err
-	}
-	UpdateDockerIds()
-	return nil
-}
-
 // Adapts fs.FS to support absolute paths
 type rootFS struct {
 	fsys afero.Fs
diff --git a/internal/utils/deno.go b/internal/utils/deno.go
index 7a600620..978f0bb6 100644
--- a/internal/utils/deno.go
+++ b/internal/utils/deno.go
@@ -19,6 +19,7 @@ import (
 
 	"github.com/go-errors/errors"
 	"github.com/spf13/afero"
+	"github.com/tidwall/jsonc"
 )
 
 var (
@@ -215,13 +216,13 @@ type ImportMap struct {
 }
 
 func NewImportMap(absJsonPath string, fsys afero.Fs) (*ImportMap, error) {
-	contents, err := fsys.Open(absJsonPath)
+	data, err := afero.ReadFile(fsys, absJsonPath)
 	if err != nil {
 		return nil, errors.Errorf("failed to load import map: %w", err)
 	}
-	defer contents.Close()
+	data = jsonc.ToJSONInPlace(data)
 	result := ImportMap{}
-	decoder := json.NewDecoder(contents)
+	decoder := json.NewDecoder(bytes.NewReader(data))
 	if err := decoder.Decode(&result); err != nil {
 		return nil, errors.Errorf("failed to parse import map: %w", err)
 	}
diff --git a/internal/utils/flags/config_path.go b/internal/utils/flags/config_path.go
new file mode 100644
index 00000000..d0ed105c
--- /dev/null
+++ b/internal/utils/flags/config_path.go
@@ -0,0 +1,22 @@
+package flags
+
+import (
+	"fmt"
+	"os"
+
+	"github.com/go-errors/errors"
+	"github.com/spf13/afero"
+	"github.com/supabase/cli/internal/utils"
+)
+
+func LoadConfig(fsys afero.Fs) error {
+	utils.Config.ProjectId = ProjectRef
+	if err := utils.Config.Load("", utils.NewRootFS(fsys)); err != nil {
+		if errors.Is(err, os.ErrNotExist) {
+			utils.CmdSuggestion = fmt.Sprintf("Have you set up the project with %s?", utils.Aqua("supabase init"))
+		}
+		return err
+	}
+	utils.UpdateDockerIds()
+	return nil
+}
diff --git a/internal/utils/flags/db_url.go b/internal/utils/flags/db_url.go
index 013453b8..04565939 100644
--- a/internal/utils/flags/db_url.go
+++ b/internal/utils/flags/db_url.go
@@ -61,7 +61,7 @@ func ParseDatabaseConfig(flagSet *pflag.FlagSet, fsys afero.Fs) error {
 			DbConfig = *config
 		}
 	case local:
-		if err := utils.LoadConfigFS(fsys); err != nil {
+		if err := LoadConfig(fsys); err != nil {
 			return err
 		}
 		// Ignore other PG settings
@@ -71,10 +71,10 @@ func ParseDatabaseConfig(flagSet *pflag.FlagSet, fsys afero.Fs) error {
 		DbConfig.Password = utils.Config.Db.Password
 		DbConfig.Database = "postgres"
 	case linked:
-		if err := utils.LoadConfigFS(fsys); err != nil {
+		if err := LoadProjectRef(fsys); err != nil {
 			return err
 		}
-		if err := LoadProjectRef(fsys); err != nil {
+		if err := LoadConfig(fsys); err != nil {
 			return err
 		}
 		DbConfig = NewDbConfigWithPassword(ProjectRef)
diff --git a/pkg/cast/cast.go b/pkg/cast/cast.go
index 621ae9a6..89840c89 100644
--- a/pkg/cast/cast.go
+++ b/pkg/cast/cast.go
@@ -10,6 +10,14 @@ func UintToInt(value uint) int {
 	return math.MaxInt
 }
 
+// UIntToUInt16 converts a uint to an uint16, handling potential overflow
+func UIntToUInt16(value uint) uint16 {
+	if value <= math.MaxUint16 {
+		return uint16(value)
+	}
+	return math.MaxUint16
+}
+
 // IntToUint converts an int to a uint, handling negative values
 func IntToUint(value int) uint {
 	if value < 0 {
diff --git a/pkg/config/auth.go b/pkg/config/auth.go
index b2e6b0fa..33b6f9ea 100644
--- a/pkg/config/auth.go
+++ b/pkg/config/auth.go
@@ -119,7 +119,7 @@ type (
 		Host       string `toml:"host"`
 		Port       uint16 `toml:"port"`
 		User       string `toml:"user"`
-		Pass       string `toml:"pass"`
+		Pass       Secret `toml:"pass"`
 		AdminEmail string `toml:"admin_email"`
 		SenderName string `toml:"sender_name"`
 	}
@@ -174,7 +174,7 @@ type (
 	hookConfig struct {
 		Enabled bool   `toml:"enabled"`
 		URI     string `toml:"uri"`
-		Secrets string `toml:"secrets"`
+		Secrets Secret `toml:"secrets"`
 	}
 
 	sessions struct {
@@ -186,32 +186,32 @@ type (
 		Enabled           bool   `toml:"enabled"`
 		AccountSid        string `toml:"account_sid"`
 		MessageServiceSid string `toml:"message_service_sid"`
-		AuthToken         string `toml:"auth_token" mapstructure:"auth_token"`
+		AuthToken         Secret `toml:"auth_token" mapstructure:"auth_token"`
 	}
 
 	messagebirdConfig struct {
 		Enabled    bool   `toml:"enabled"`
 		Originator string `toml:"originator"`
-		AccessKey  string `toml:"access_key" mapstructure:"access_key"`
+		AccessKey  Secret `toml:"access_key" mapstructure:"access_key"`
 	}
 
 	textlocalConfig struct {
 		Enabled bool   `toml:"enabled"`
 		Sender  string `toml:"sender"`
-		ApiKey  string `toml:"api_key" mapstructure:"api_key"`
+		ApiKey  Secret `toml:"api_key" mapstructure:"api_key"`
 	}
 
 	vonageConfig struct {
 		Enabled   bool   `toml:"enabled"`
 		From      string `toml:"from"`
 		ApiKey    string `toml:"api_key" mapstructure:"api_key"`
-		ApiSecret string `toml:"api_secret" mapstructure:"api_secret"`
+		ApiSecret Secret `toml:"api_secret" mapstructure:"api_secret"`
 	}
 
 	provider struct {
 		Enabled        bool   `toml:"enabled"`
 		ClientId       string `toml:"client_id"`
-		Secret         string `toml:"secret"`
+		Secret         Secret `toml:"secret"`
 		Url            string `toml:"url"`
 		RedirectUri    string `toml:"redirect_uri"`
 		SkipNonceCheck bool   `toml:"skip_nonce_check"`
@@ -265,24 +265,24 @@ func (h hook) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
 	if hook := h.CustomAccessToken; hook != nil {
 		if body.HookCustomAccessTokenEnabled = &hook.Enabled; hook.Enabled {
 			body.HookCustomAccessTokenUri = &hook.URI
-			if len(hook.Secrets) > 0 {
-				body.HookCustomAccessTokenSecrets = &hook.Secrets
+			if len(hook.Secrets.SHA256) > 0 {
+				body.HookCustomAccessTokenSecrets = &hook.Secrets.Value
 			}
 		}
 	}
 	if hook := h.SendEmail; hook != nil {
 		if body.HookSendEmailEnabled = &hook.Enabled; hook.Enabled {
 			body.HookSendEmailUri = &hook.URI
-			if len(hook.Secrets) > 0 {
-				body.HookSendEmailSecrets = &hook.Secrets
+			if len(hook.Secrets.SHA256) > 0 {
+				body.HookSendEmailSecrets = &hook.Secrets.Value
 			}
 		}
 	}
 	if hook := h.SendSMS; hook != nil {
 		if body.HookSendSmsEnabled = &hook.Enabled; hook.Enabled {
 			body.HookSendSmsUri = &hook.URI
-			if len(hook.Secrets) > 0 {
-				body.HookSendSmsSecrets = &hook.Secrets
+			if len(hook.Secrets.SHA256) > 0 {
+				body.HookSendSmsSecrets = &hook.Secrets.Value
 			}
 		}
 	}
@@ -290,16 +290,16 @@ func (h hook) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
 	if hook := h.MFAVerificationAttempt; hook != nil {
 		if body.HookMfaVerificationAttemptEnabled = &hook.Enabled; hook.Enabled {
 			body.HookMfaVerificationAttemptUri = &hook.URI
-			if len(hook.Secrets) > 0 {
-				body.HookMfaVerificationAttemptSecrets = &hook.Secrets
+			if len(hook.Secrets.SHA256) > 0 {
+				body.HookMfaVerificationAttemptSecrets = &hook.Secrets.Value
 			}
 		}
 	}
 	if hook := h.PasswordVerificationAttempt; hook != nil {
 		if body.HookPasswordVerificationAttemptEnabled = &hook.Enabled; hook.Enabled {
 			body.HookPasswordVerificationAttemptUri = &hook.URI
-			if len(hook.Secrets) > 0 {
-				body.HookPasswordVerificationAttemptSecrets = &hook.Secrets
+			if len(hook.Secrets.SHA256) > 0 {
+				body.HookPasswordVerificationAttemptSecrets = &hook.Secrets.Value
 			}
 		}
 	}
@@ -310,21 +310,27 @@ func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 		// Ignore disabled hooks because their envs are not loaded
 		if hook.Enabled {
 			hook.URI = cast.Val(remoteConfig.HookCustomAccessTokenUri, "")
-			hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookCustomAccessTokenSecrets, "")
+			if len(hook.Secrets.SHA256) > 0 {
+				hook.Secrets.SHA256 = cast.Val(remoteConfig.HookCustomAccessTokenSecrets, "")
+			}
 		}
 		hook.Enabled = cast.Val(remoteConfig.HookCustomAccessTokenEnabled, false)
 	}
 	if hook := h.SendEmail; hook != nil {
 		if hook.Enabled {
 			hook.URI = cast.Val(remoteConfig.HookSendEmailUri, "")
-			hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookSendEmailSecrets, "")
+			if len(hook.Secrets.SHA256) > 0 {
+				hook.Secrets.SHA256 = cast.Val(remoteConfig.HookSendEmailSecrets, "")
+			}
 		}
 		hook.Enabled = cast.Val(remoteConfig.HookSendEmailEnabled, false)
 	}
 	if hook := h.SendSMS; hook != nil {
 		if hook.Enabled {
 			hook.URI = cast.Val(remoteConfig.HookSendSmsUri, "")
-			hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookSendSmsSecrets, "")
+			if len(hook.Secrets.SHA256) > 0 {
+				hook.Secrets.SHA256 = cast.Val(remoteConfig.HookSendSmsSecrets, "")
+			}
 		}
 		hook.Enabled = cast.Val(remoteConfig.HookSendSmsEnabled, false)
 	}
@@ -332,14 +338,18 @@ func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if hook := h.MFAVerificationAttempt; hook != nil {
 		if hook.Enabled {
 			hook.URI = cast.Val(remoteConfig.HookMfaVerificationAttemptUri, "")
-			hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookMfaVerificationAttemptSecrets, "")
+			if len(hook.Secrets.SHA256) > 0 {
+				hook.Secrets.SHA256 = cast.Val(remoteConfig.HookMfaVerificationAttemptSecrets, "")
+			}
 		}
 		hook.Enabled = cast.Val(remoteConfig.HookMfaVerificationAttemptEnabled, false)
 	}
 	if hook := h.PasswordVerificationAttempt; hook != nil {
 		if hook.Enabled {
 			hook.URI = cast.Val(remoteConfig.HookPasswordVerificationAttemptUri, "")
-			hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookPasswordVerificationAttemptSecrets, "")
+			if len(hook.Secrets.SHA256) > 0 {
+				hook.Secrets.SHA256 = cast.Val(remoteConfig.HookPasswordVerificationAttemptSecrets, "")
+			}
 		}
 		hook.Enabled = cast.Val(remoteConfig.HookPasswordVerificationAttemptEnabled, false)
 	}
@@ -432,60 +442,60 @@ func (e *email) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if len(e.Template) == 0 {
 		return
 	}
-	var tmpl emailTemplate
-	tmpl = e.Template["invite"]
-	if tmpl.Subject != nil {
-		tmpl.Subject = remoteConfig.MailerSubjectsInvite
-	}
-	if tmpl.Content != nil {
-		tmpl.Content = remoteConfig.MailerTemplatesInviteContent
-	}
-	e.Template["invite"] = tmpl
-
-	tmpl = e.Template["confirmation"]
-	if tmpl.Subject != nil {
-		tmpl.Subject = remoteConfig.MailerSubjectsConfirmation
-	}
-	if tmpl.Content != nil {
-		tmpl.Content = remoteConfig.MailerTemplatesConfirmationContent
-	}
-	e.Template["confirmation"] = tmpl
-
-	tmpl = e.Template["recovery"]
-	if tmpl.Subject != nil {
-		tmpl.Subject = remoteConfig.MailerSubjectsRecovery
-	}
-	if tmpl.Content != nil {
-		tmpl.Content = remoteConfig.MailerTemplatesRecoveryContent
-	}
-	e.Template["recovery"] = tmpl
-
-	tmpl = e.Template["magic_link"]
-	if tmpl.Subject != nil {
-		tmpl.Subject = remoteConfig.MailerSubjectsMagicLink
+	if t, ok := e.Template["invite"]; ok {
+		if t.Subject != nil {
+			t.Subject = remoteConfig.MailerSubjectsInvite
+		}
+		if t.Content != nil {
+			t.Content = remoteConfig.MailerTemplatesInviteContent
+		}
+		e.Template["invite"] = t
 	}
-	if tmpl.Content != nil {
-		tmpl.Content = remoteConfig.MailerTemplatesMagicLinkContent
+	if t, ok := e.Template["confirmation"]; ok {
+		if t.Subject != nil {
+			t.Subject = remoteConfig.MailerSubjectsConfirmation
+		}
+		if t.Content != nil {
+			t.Content = remoteConfig.MailerTemplatesConfirmationContent
+		}
+		e.Template["confirmation"] = t
 	}
-	e.Template["magic_link"] = tmpl
-
-	tmpl = e.Template["email_change"]
-	if tmpl.Subject != nil {
-		tmpl.Subject = remoteConfig.MailerSubjectsEmailChange
+	if t, ok := e.Template["recovery"]; ok {
+		if t.Subject != nil {
+			t.Subject = remoteConfig.MailerSubjectsRecovery
+		}
+		if t.Content != nil {
+			t.Content = remoteConfig.MailerTemplatesRecoveryContent
+		}
+		e.Template["recovery"] = t
 	}
-	if tmpl.Content != nil {
-		tmpl.Content = remoteConfig.MailerTemplatesEmailChangeContent
+	if t, ok := e.Template["magic_link"]; ok {
+		if t.Subject != nil {
+			t.Subject = remoteConfig.MailerSubjectsMagicLink
+		}
+		if t.Content != nil {
+			t.Content = remoteConfig.MailerTemplatesMagicLinkContent
+		}
+		e.Template["magic_link"] = t
 	}
-	e.Template["email_change"] = tmpl
-
-	tmpl = e.Template["reauthentication"]
-	if tmpl.Subject != nil {
-		tmpl.Subject = remoteConfig.MailerSubjectsReauthentication
+	if t, ok := e.Template["email_change"]; ok {
+		if t.Subject != nil {
+			t.Subject = remoteConfig.MailerSubjectsEmailChange
+		}
+		if t.Content != nil {
+			t.Content = remoteConfig.MailerTemplatesEmailChangeContent
+		}
+		e.Template["email_change"] = t
 	}
-	if tmpl.Content != nil {
-		tmpl.Content = remoteConfig.MailerTemplatesReauthenticationContent
+	if t, ok := e.Template["reauthentication"]; ok {
+		if t.Subject != nil {
+			t.Subject = remoteConfig.MailerSubjectsReauthentication
+		}
+		if t.Content != nil {
+			t.Content = remoteConfig.MailerTemplatesReauthenticationContent
+		}
+		e.Template["reauthentication"] = t
 	}
-	e.Template["reauthentication"] = tmpl
 }
 
 func (s smtp) IsEnabled() bool {
@@ -502,7 +512,9 @@ func (s smtp) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
 	body.SmtpHost = &s.Host
 	body.SmtpPort = cast.Ptr(strconv.Itoa(int(s.Port)))
 	body.SmtpUser = &s.User
-	body.SmtpPass = &s.Pass
+	if len(s.Pass.SHA256) > 0 {
+		body.SmtpPass = &s.Pass.Value
+	}
 	body.SmtpAdminEmail = &s.AdminEmail
 	body.SmtpSenderName = &s.SenderName
 }
@@ -518,7 +530,9 @@ func (s *smtp) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	}
 	s.Host = cast.Val(remoteConfig.SmtpHost, "")
 	s.User = cast.Val(remoteConfig.SmtpUser, "")
-	s.Pass = hashPrefix + cast.Val(remoteConfig.SmtpPass, "")
+	if len(s.Pass.SHA256) > 0 {
+		s.Pass.SHA256 = cast.Val(remoteConfig.SmtpPass, "")
+	}
 	s.AdminEmail = cast.Val(remoteConfig.SmtpAdminEmail, "")
 	s.SenderName = cast.Val(remoteConfig.SmtpSenderName, "")
 	portStr := cast.Val(remoteConfig.SmtpPort, "0")
@@ -542,25 +556,35 @@ func (s sms) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
 	switch {
 	case s.Twilio.Enabled:
 		body.SmsProvider = cast.Ptr("twilio")
-		body.SmsTwilioAuthToken = &s.Twilio.AuthToken
+		if len(s.Twilio.AuthToken.SHA256) > 0 {
+			body.SmsTwilioAuthToken = &s.Twilio.AuthToken.Value
+		}
 		body.SmsTwilioAccountSid = &s.Twilio.AccountSid
 		body.SmsTwilioMessageServiceSid = &s.Twilio.MessageServiceSid
 	case s.TwilioVerify.Enabled:
 		body.SmsProvider = cast.Ptr("twilio_verify")
-		body.SmsTwilioVerifyAuthToken = &s.TwilioVerify.AuthToken
+		if len(s.TwilioVerify.AuthToken.SHA256) > 0 {
+			body.SmsTwilioVerifyAuthToken = &s.TwilioVerify.AuthToken.Value
+		}
 		body.SmsTwilioVerifyAccountSid = &s.TwilioVerify.AccountSid
 		body.SmsTwilioVerifyMessageServiceSid = &s.TwilioVerify.MessageServiceSid
 	case s.Messagebird.Enabled:
 		body.SmsProvider = cast.Ptr("messagebird")
-		body.SmsMessagebirdAccessKey = &s.Messagebird.AccessKey
+		if len(s.Messagebird.AccessKey.SHA256) > 0 {
+			body.SmsMessagebirdAccessKey = &s.Messagebird.AccessKey.Value
+		}
 		body.SmsMessagebirdOriginator = &s.Messagebird.Originator
 	case s.Textlocal.Enabled:
 		body.SmsProvider = cast.Ptr("textlocal")
-		body.SmsTextlocalApiKey = &s.Textlocal.ApiKey
+		if len(s.Textlocal.ApiKey.SHA256) > 0 {
+			body.SmsTextlocalApiKey = &s.Textlocal.ApiKey.Value
+		}
 		body.SmsTextlocalSender = &s.Textlocal.Sender
 	case s.Vonage.Enabled:
 		body.SmsProvider = cast.Ptr("vonage")
-		body.SmsVonageApiSecret = &s.Vonage.ApiSecret
+		if len(s.Vonage.ApiSecret.SHA256) > 0 {
+			body.SmsVonageApiSecret = &s.Vonage.ApiSecret.Value
+		}
 		body.SmsVonageApiKey = &s.Vonage.ApiKey
 		body.SmsVonageFrom = &s.Vonage.From
 	}
@@ -575,21 +599,31 @@ func (s *sms) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	// We are only interested in the provider that's enabled locally
 	switch {
 	case s.Twilio.Enabled:
-		s.Twilio.AuthToken = hashPrefix + cast.Val(remoteConfig.SmsTwilioAuthToken, "")
+		if len(s.Twilio.AuthToken.SHA256) > 0 {
+			s.Twilio.AuthToken.SHA256 = cast.Val(remoteConfig.SmsTwilioAuthToken, "")
+		}
 		s.Twilio.AccountSid = cast.Val(remoteConfig.SmsTwilioAccountSid, "")
 		s.Twilio.MessageServiceSid = cast.Val(remoteConfig.SmsTwilioMessageServiceSid, "")
 	case s.TwilioVerify.Enabled:
-		s.TwilioVerify.AuthToken = hashPrefix + cast.Val(remoteConfig.SmsTwilioVerifyAuthToken, "")
+		if len(s.TwilioVerify.AuthToken.SHA256) > 0 {
+			s.TwilioVerify.AuthToken.SHA256 = cast.Val(remoteConfig.SmsTwilioVerifyAuthToken, "")
+		}
 		s.TwilioVerify.AccountSid = cast.Val(remoteConfig.SmsTwilioVerifyAccountSid, "")
 		s.TwilioVerify.MessageServiceSid = cast.Val(remoteConfig.SmsTwilioVerifyMessageServiceSid, "")
 	case s.Messagebird.Enabled:
-		s.Messagebird.AccessKey = hashPrefix + cast.Val(remoteConfig.SmsMessagebirdAccessKey, "")
+		if len(s.Messagebird.AccessKey.SHA256) > 0 {
+			s.Messagebird.AccessKey.SHA256 = cast.Val(remoteConfig.SmsMessagebirdAccessKey, "")
+		}
 		s.Messagebird.Originator = cast.Val(remoteConfig.SmsMessagebirdOriginator, "")
 	case s.Textlocal.Enabled:
-		s.Textlocal.ApiKey = hashPrefix + cast.Val(remoteConfig.SmsTextlocalApiKey, "")
+		if len(s.Textlocal.ApiKey.SHA256) > 0 {
+			s.Textlocal.ApiKey.SHA256 = cast.Val(remoteConfig.SmsTextlocalApiKey, "")
+		}
 		s.Textlocal.Sender = cast.Val(remoteConfig.SmsTextlocalSender, "")
 	case s.Vonage.Enabled:
-		s.Vonage.ApiSecret = hashPrefix + cast.Val(remoteConfig.SmsVonageApiSecret, "")
+		if len(s.Vonage.ApiSecret.SHA256) > 0 {
+			s.Vonage.ApiSecret.SHA256 = cast.Val(remoteConfig.SmsVonageApiSecret, "")
+		}
 		s.Vonage.ApiKey = cast.Val(remoteConfig.SmsVonageApiKey, "")
 		s.Vonage.From = cast.Val(remoteConfig.SmsVonageFrom, "")
 	case !s.EnableSignup:
@@ -613,120 +647,158 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
 	if p, ok := e["apple"]; ok {
 		if body.ExternalAppleEnabled = &p.Enabled; *body.ExternalAppleEnabled {
 			body.ExternalAppleClientId = &p.ClientId
-			body.ExternalAppleSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalAppleSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["azure"]; ok {
 		if body.ExternalAzureEnabled = &p.Enabled; *body.ExternalAzureEnabled {
 			body.ExternalAzureClientId = &p.ClientId
-			body.ExternalAzureSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalAzureSecret = &p.Secret.Value
+			}
 			body.ExternalAzureUrl = &p.Url
 		}
 	}
 	if p, ok := e["bitbucket"]; ok {
 		if body.ExternalBitbucketEnabled = &p.Enabled; *body.ExternalBitbucketEnabled {
 			body.ExternalBitbucketClientId = &p.ClientId
-			body.ExternalBitbucketSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalBitbucketSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["discord"]; ok {
 		if body.ExternalDiscordEnabled = &p.Enabled; *body.ExternalDiscordEnabled {
 			body.ExternalDiscordClientId = &p.ClientId
-			body.ExternalDiscordSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalDiscordSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["facebook"]; ok {
 		if body.ExternalFacebookEnabled = &p.Enabled; *body.ExternalFacebookEnabled {
 			body.ExternalFacebookClientId = &p.ClientId
-			body.ExternalFacebookSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalFacebookSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["figma"]; ok {
 		if body.ExternalFigmaEnabled = &p.Enabled; *body.ExternalFigmaEnabled {
 			body.ExternalFigmaClientId = &p.ClientId
-			body.ExternalFigmaSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalFigmaSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["github"]; ok {
 		if body.ExternalGithubEnabled = &p.Enabled; *body.ExternalGithubEnabled {
 			body.ExternalGithubClientId = &p.ClientId
-			body.ExternalGithubSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalGithubSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["gitlab"]; ok {
 		if body.ExternalGitlabEnabled = &p.Enabled; *body.ExternalGitlabEnabled {
 			body.ExternalGitlabClientId = &p.ClientId
-			body.ExternalGitlabSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalGitlabSecret = &p.Secret.Value
+			}
 			body.ExternalGitlabUrl = &p.Url
 		}
 	}
 	if p, ok := e["google"]; ok {
 		if body.ExternalGoogleEnabled = &p.Enabled; *body.ExternalGoogleEnabled {
 			body.ExternalGoogleClientId = &p.ClientId
-			body.ExternalGoogleSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalGoogleSecret = &p.Secret.Value
+			}
 			body.ExternalGoogleSkipNonceCheck = &p.SkipNonceCheck
 		}
 	}
 	if p, ok := e["kakao"]; ok {
 		if body.ExternalKakaoEnabled = &p.Enabled; *body.ExternalKakaoEnabled {
 			body.ExternalKakaoClientId = &p.ClientId
-			body.ExternalKakaoSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalKakaoSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["keycloak"]; ok {
 		if body.ExternalKeycloakEnabled = &p.Enabled; *body.ExternalKeycloakEnabled {
 			body.ExternalKeycloakClientId = &p.ClientId
-			body.ExternalKeycloakSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalKeycloakSecret = &p.Secret.Value
+			}
 			body.ExternalKeycloakUrl = &p.Url
 		}
 	}
 	if p, ok := e["linkedin_oidc"]; ok {
 		if body.ExternalLinkedinOidcEnabled = &p.Enabled; *body.ExternalLinkedinOidcEnabled {
 			body.ExternalLinkedinOidcClientId = &p.ClientId
-			body.ExternalLinkedinOidcSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalLinkedinOidcSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["notion"]; ok {
 		if body.ExternalNotionEnabled = &p.Enabled; *body.ExternalNotionEnabled {
 			body.ExternalNotionClientId = &p.ClientId
-			body.ExternalNotionSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalNotionSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["slack_oidc"]; ok {
 		if body.ExternalSlackOidcEnabled = &p.Enabled; *body.ExternalSlackOidcEnabled {
 			body.ExternalSlackOidcClientId = &p.ClientId
-			body.ExternalSlackOidcSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalSlackOidcSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["spotify"]; ok {
 		if body.ExternalSpotifyEnabled = &p.Enabled; *body.ExternalSpotifyEnabled {
 			body.ExternalSpotifyClientId = &p.ClientId
-			body.ExternalSpotifySecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalSpotifySecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["twitch"]; ok {
 		if body.ExternalTwitchEnabled = &p.Enabled; *body.ExternalTwitchEnabled {
 			body.ExternalTwitchClientId = &p.ClientId
-			body.ExternalTwitchSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalTwitchSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["twitter"]; ok {
 		if body.ExternalTwitterEnabled = &p.Enabled; *body.ExternalTwitterEnabled {
 			body.ExternalTwitterClientId = &p.ClientId
-			body.ExternalTwitterSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalTwitterSecret = &p.Secret.Value
+			}
 		}
 	}
 	if p, ok := e["workos"]; ok {
 		if body.ExternalWorkosEnabled = &p.Enabled; *body.ExternalWorkosEnabled {
 			body.ExternalWorkosClientId = &p.ClientId
-			body.ExternalWorkosSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalWorkosSecret = &p.Secret.Value
+			}
 			body.ExternalWorkosUrl = &p.Url
 		}
 	}
 	if p, ok := e["zoom"]; ok {
 		if body.ExternalZoomEnabled = &p.Enabled; *body.ExternalZoomEnabled {
 			body.ExternalZoomClientId = &p.ClientId
-			body.ExternalZoomSecret = &p.Secret
+			if len(p.Secret.SHA256) > 0 {
+				body.ExternalZoomSecret = &p.Secret.Value
+			}
 		}
 	}
 }
@@ -742,7 +814,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 			if ids := cast.Val(remoteConfig.ExternalAppleAdditionalClientIds, ""); len(ids) > 0 {
 				p.ClientId += "," + ids
 			}
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalAppleSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalAppleSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalAppleEnabled, false)
 		e["apple"] = p
@@ -751,7 +825,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["azure"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalAzureClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalAzureSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalAzureSecret, "")
+			}
 			p.Url = cast.Val(remoteConfig.ExternalAzureUrl, "")
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalAzureEnabled, false)
@@ -761,7 +837,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["bitbucket"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalBitbucketClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalBitbucketSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalBitbucketSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalBitbucketEnabled, false)
 		e["bitbucket"] = p
@@ -770,7 +848,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["discord"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalDiscordClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalDiscordSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalDiscordSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalDiscordEnabled, false)
 		e["discord"] = p
@@ -779,7 +859,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["facebook"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalFacebookClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalFacebookSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalFacebookSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalFacebookEnabled, false)
 		e["facebook"] = p
@@ -788,7 +870,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["figma"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalFigmaClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalFigmaSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalFigmaSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalFigmaEnabled, false)
 		e["figma"] = p
@@ -797,7 +881,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["github"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalGithubClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalGithubSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalGithubSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalGithubEnabled, false)
 		e["github"] = p
@@ -806,7 +892,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["gitlab"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalGitlabClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalGitlabSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalGitlabSecret, "")
+			}
 			p.Url = cast.Val(remoteConfig.ExternalGitlabUrl, "")
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalGitlabEnabled, false)
@@ -819,7 +907,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 			if ids := cast.Val(remoteConfig.ExternalGoogleAdditionalClientIds, ""); len(ids) > 0 {
 				p.ClientId += "," + ids
 			}
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalGoogleSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalGoogleSecret, "")
+			}
 			p.SkipNonceCheck = cast.Val(remoteConfig.ExternalGoogleSkipNonceCheck, false)
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalGoogleEnabled, false)
@@ -829,7 +919,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["kakao"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalKakaoClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalKakaoSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalKakaoSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalKakaoEnabled, false)
 		e["kakao"] = p
@@ -838,7 +930,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["keycloak"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalKeycloakClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalKeycloakSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalKeycloakSecret, "")
+			}
 			p.Url = cast.Val(remoteConfig.ExternalKeycloakUrl, "")
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalKeycloakEnabled, false)
@@ -848,7 +942,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["linkedin_oidc"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalLinkedinOidcClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalLinkedinOidcSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalLinkedinOidcSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalLinkedinOidcEnabled, false)
 		e["linkedin_oidc"] = p
@@ -857,7 +953,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["notion"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalNotionClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalNotionSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalNotionSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalNotionEnabled, false)
 		e["notion"] = p
@@ -866,7 +964,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["slack_oidc"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalSlackOidcClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalSlackOidcSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalSlackOidcSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalSlackOidcEnabled, false)
 		e["slack_oidc"] = p
@@ -875,7 +975,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["spotify"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalSpotifyClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalSpotifySecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalSpotifySecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalSpotifyEnabled, false)
 		e["spotify"] = p
@@ -884,7 +986,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["twitch"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalTwitchClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalTwitchSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalTwitchSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalTwitchEnabled, false)
 		e["twitch"] = p
@@ -893,7 +997,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["twitter"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalTwitterClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalTwitterSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalTwitterSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalTwitterEnabled, false)
 		e["twitter"] = p
@@ -902,7 +1008,9 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["workos"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalWorkosClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalWorkosSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalWorkosSecret, "")
+			}
 			p.Url = cast.Val(remoteConfig.ExternalWorkosUrl, "")
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalWorkosEnabled, false)
@@ -912,16 +1020,17 @@ func (e external) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
 	if p, ok := e["zoom"]; ok {
 		if p.Enabled {
 			p.ClientId = cast.Val(remoteConfig.ExternalZoomClientId, "")
-			p.Secret = hashPrefix + cast.Val(remoteConfig.ExternalZoomSecret, "")
+			if len(p.Secret.SHA256) > 0 {
+				p.Secret.SHA256 = cast.Val(remoteConfig.ExternalZoomSecret, "")
+			}
 		}
 		p.Enabled = cast.Val(remoteConfig.ExternalZoomEnabled, false)
 		e["zoom"] = p
 	}
 }
 
-func (a *auth) DiffWithRemote(projectRef string, remoteConfig v1API.AuthConfigResponse) ([]byte, error) {
+func (a *auth) DiffWithRemote(remoteConfig v1API.AuthConfigResponse) ([]byte, error) {
 	copy := a.Clone()
-	copy.HashSecrets(projectRef)
 	// Convert the config values into easily comparable remoteConfig values
 	currentValue, err := ToTomlBytes(copy)
 	if err != nil {
@@ -934,52 +1043,3 @@ func (a *auth) DiffWithRemote(projectRef string, remoteConfig v1API.AuthConfigRe
 	}
 	return diff.Diff("remote[auth]", remoteCompare, "local[auth]", currentValue), nil
 }
-
-const hashPrefix = "hash:"
-
-func (a *auth) HashSecrets(key string) {
-	hash := func(v string) string {
-		if len(v) == 0 {
-			return hashPrefix
-		}
-		return hashPrefix + sha256Hmac(key, v)
-	}
-	if a.Email.Smtp != nil && a.Email.Smtp.IsEnabled() {
-		a.Email.Smtp.Pass = hash(a.Email.Smtp.Pass)
-	}
-	// Only hash secrets for locally enabled providers because other envs won't be loaded
-	switch {
-	case a.Sms.Twilio.Enabled:
-		a.Sms.Twilio.AuthToken = hash(a.Sms.Twilio.AuthToken)
-	case a.Sms.TwilioVerify.Enabled:
-		a.Sms.TwilioVerify.AuthToken = hash(a.Sms.TwilioVerify.AuthToken)
-	case a.Sms.Messagebird.Enabled:
-		a.Sms.Messagebird.AccessKey = hash(a.Sms.Messagebird.AccessKey)
-	case a.Sms.Textlocal.Enabled:
-		a.Sms.Textlocal.ApiKey = hash(a.Sms.Textlocal.ApiKey)
-	case a.Sms.Vonage.Enabled:
-		a.Sms.Vonage.ApiSecret = hash(a.Sms.Vonage.ApiSecret)
-	}
-	if a.Hook.MFAVerificationAttempt != nil && a.Hook.MFAVerificationAttempt.Enabled {
-		a.Hook.MFAVerificationAttempt.Secrets = hash(a.Hook.MFAVerificationAttempt.Secrets)
-	}
-	if a.Hook.PasswordVerificationAttempt != nil && a.Hook.PasswordVerificationAttempt.Enabled {
-		a.Hook.PasswordVerificationAttempt.Secrets = hash(a.Hook.PasswordVerificationAttempt.Secrets)
-	}
-	if a.Hook.CustomAccessToken != nil && a.Hook.CustomAccessToken.Enabled {
-		a.Hook.CustomAccessToken.Secrets = hash(a.Hook.CustomAccessToken.Secrets)
-	}
-	if a.Hook.SendSMS != nil && a.Hook.SendSMS.Enabled {
-		a.Hook.SendSMS.Secrets = hash(a.Hook.SendSMS.Secrets)
-	}
-	if a.Hook.SendEmail != nil && a.Hook.SendEmail.Enabled {
-		a.Hook.SendEmail.Secrets = hash(a.Hook.SendEmail.Secrets)
-	}
-	for name, provider := range a.External {
-		if provider.Enabled {
-			provider.Secret = hash(provider.Secret)
-		}
-		a.External[name] = provider
-	}
-	// TODO: support SecurityCaptchaSecret in local config
-}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 5c7fc094..b2104e50 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -16,6 +16,7 @@ import (
 	"os"
 	"path"
 	"path/filepath"
+	"reflect"
 	"regexp"
 	"sort"
 	"strconv"
@@ -135,8 +136,7 @@ type (
 
 	config struct {
 		baseConfig `mapstructure:",squash"`
-		Overrides  map[string]interface{} `toml:"remotes"`
-		Remotes    map[string]baseConfig  `toml:"-"`
+		Remotes    map[string]baseConfig `toml:"remotes"`
 	}
 
 	realtime struct {
@@ -311,14 +311,7 @@ func NewConfig(editors ...ConfigEditor) config {
 		Auth: auth{
 			Image: gotrueImage,
 			Email: email{
-				Template: map[string]emailTemplate{
-					"invite":           {},
-					"confirmation":     {},
-					"recovery":         {},
-					"magic_link":       {},
-					"email_change":     {},
-					"reauthentication": {},
-				},
+				Template: map[string]emailTemplate{},
 			},
 			Sms: sms{
 				TestOTP: map[string]string{},
@@ -359,6 +352,7 @@ var (
 
 	invalidProjectId = regexp.MustCompile("[^a-zA-Z0-9_.-]+")
 	envPattern       = regexp.MustCompile(`^env\((.*)\)$`)
+	refPattern       = regexp.MustCompile(`^[a-z]{20}$`)
 )
 
 func (c *config) Eject(w io.Writer) error {
@@ -378,9 +372,88 @@ func (c *config) Eject(w io.Writer) error {
 	return nil
 }
 
+// Loads custom config file to struct fields tagged with toml.
+func (c *config) loadFromFile(filename string, fsys fs.FS) error {
+	v := viper.New()
+	v.SetConfigType("toml")
+	// Load default values
+	var buf bytes.Buffer
+	if err := initConfigTemplate.Option("missingkey=zero").Execute(&buf, c); err != nil {
+		return errors.Errorf("failed to initialise template config: %w", err)
+	} else if err := c.loadFromReader(v, &buf); err != nil {
+		return err
+	}
+	// Load custom config
+	if ext := filepath.Ext(filename); len(ext) > 0 {
+		v.SetConfigType(ext[1:])
+	}
+	f, err := fsys.Open(filename)
+	if err != nil {
+		return errors.Errorf("failed to read file config: %w", err)
+	}
+	defer f.Close()
+	return c.loadFromReader(v, f)
+}
+
+func (c *config) loadFromReader(v *viper.Viper, r io.Reader) error {
+	if err := v.MergeConfig(r); err != nil {
+		return errors.Errorf("failed to merge config: %w", err)
+	}
+	// Find [remotes.*] block to override base config
+	baseId := v.GetString("project_id")
+	idToName := map[string]string{baseId: "base"}
+	for name, remote := range v.GetStringMap("remotes") {
+		projectId := v.GetString(fmt.Sprintf("remotes.%s.project_id", name))
+		// Track remote project_id to check for duplication
+		if other, exists := idToName[projectId]; exists {
+			return errors.Errorf("duplicate project_id for [remotes.%s] and %s", name, other)
+		}
+		idToName[projectId] = fmt.Sprintf("[remotes.%s]", name)
+		if projectId == c.ProjectId {
+			fmt.Fprintln(os.Stderr, "Loading config override:", idToName[projectId])
+			if err := v.MergeConfigMap(remote.(map[string]any)); err != nil {
+				return err
+			}
+			v.Set("project_id", baseId)
+		}
+	}
+	// Manually parse [functions.*] to empty struct for backwards compatibility
+	for key, value := range v.GetStringMap("functions") {
+		if m, ok := value.(map[string]any); ok && len(m) == 0 {
+			v.Set("functions."+key, function{})
+		}
+	}
+	if err := v.UnmarshalExact(c, func(dc *mapstructure.DecoderConfig) {
+		dc.TagName = "toml"
+		dc.Squash = true
+		dc.ZeroFields = true
+		dc.DecodeHook = c.newDecodeHook(LoadEnvHook)
+	}); err != nil {
+		return errors.Errorf("failed to parse config: %w", err)
+	}
+	return nil
+}
+
+func (c *config) newDecodeHook(fs ...mapstructure.DecodeHookFunc) mapstructure.DecodeHookFunc {
+	fs = append(fs,
+		mapstructure.StringToTimeDurationHookFunc(),
+		mapstructure.StringToIPHookFunc(),
+		mapstructure.StringToSliceHookFunc(","),
+		mapstructure.TextUnmarshallerHookFunc(),
+		DecryptSecretHookFunc(c.ProjectId),
+	)
+	return mapstructure.ComposeDecodeHookFunc(fs...)
+}
+
+// Loads envs prefixed with supabase_ to struct fields tagged with mapstructure.
 func (c *config) loadFromEnv() error {
-	// Allow overriding base config object with automatic env
-	// Ref: https://github.com/spf13/viper/issues/761
+	v := viper.New()
+	v.SetEnvPrefix("SUPABASE")
+	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
+	v.AutomaticEnv()
+	// Viper does not parse env vars automatically. Instead of calling viper.BindEnv
+	// per key, we decode all keys from an existing struct, and merge them to viper.
+	// Ref: https://github.com/spf13/viper/issues/761#issuecomment-859306364
 	envKeysMap := map[string]interface{}{}
 	if dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
 		Result:               &envKeysMap,
@@ -389,47 +462,26 @@ func (c *config) loadFromEnv() error {
 		return errors.Errorf("failed to create decoder: %w", err)
 	} else if err := dec.Decode(c.baseConfig); err != nil {
 		return errors.Errorf("failed to decode env: %w", err)
+	} else if err := v.MergeConfigMap(envKeysMap); err != nil {
+		return errors.Errorf("failed to merge env config: %w", err)
 	}
-	v := viper.New()
-	v.SetEnvPrefix("SUPABASE")
-	v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
-	v.AutomaticEnv()
-	if err := v.MergeConfigMap(envKeysMap); err != nil {
-		return errors.Errorf("failed to merge config: %w", err)
-	} else if err := v.Unmarshal(c); err != nil {
-		return errors.Errorf("failed to parse env to config: %w", err)
+	// Writes viper state back to config struct, with automatic env substitution
+	if err := v.UnmarshalExact(c, viper.DecodeHook(c.newDecodeHook())); err != nil {
+		return errors.Errorf("failed to parse env override: %w", err)
 	}
 	return nil
 }
 
 func (c *config) Load(path string, fsys fs.FS) error {
 	builder := NewPathBuilder(path)
-	// Load default values
-	var buf bytes.Buffer
-	if err := initConfigTemplate.Option("missingkey=zero").Execute(&buf, c); err != nil {
-		return errors.Errorf("failed to initialise config template: %w", err)
-	}
-	dec := toml.NewDecoder(&buf)
-	if _, err := dec.Decode(c); err != nil {
-		return errors.Errorf("failed to decode config template: %w", err)
-	}
-	if metadata, err := toml.DecodeFS(fsys, builder.ConfigPath, c); err != nil {
-		cwd, osErr := os.Getwd()
-		if osErr != nil {
-			cwd = "current directory"
-		}
-		return errors.Errorf("cannot read config in %s: %w", cwd, err)
-	} else if undecoded := metadata.Undecoded(); len(undecoded) > 0 {
-		for _, key := range undecoded {
-			if key[0] != "remotes" {
-				fmt.Fprintf(os.Stderr, "Unknown config field: [%s]\n", key)
-			}
-		}
-	}
 	// Load secrets from .env file
 	if err := loadDefaultEnv(); err != nil {
 		return err
-	} else if err := c.loadFromEnv(); err != nil {
+	}
+	if err := c.loadFromFile(builder.ConfigPath, fsys); err != nil {
+		return err
+	}
+	if err := c.loadFromEnv(); err != nil {
 		return err
 	}
 	// Generate JWT tokens
@@ -492,6 +544,14 @@ func (c *config) Load(path string, fsys fs.FS) error {
 	if version, err := fs.ReadFile(fsys, builder.PgmetaVersionPath); err == nil && len(version) > 0 {
 		c.Studio.PgmetaImage = replaceImageTag(pgmetaImage, string(version))
 	}
+	// TODO: replace derived config resolution with viper decode hooks
+	if err := c.baseConfig.resolve(builder, fsys); err != nil {
+		return err
+	}
+	return c.Validate(fsys)
+}
+
+func (c *baseConfig) resolve(builder pathBuilder, fsys fs.FS) error {
 	// Update content paths
 	for name, tmpl := range c.Auth.Email.Template {
 		// FIXME: only email template is relative to repo directory
@@ -534,52 +594,22 @@ func (c *config) Load(path string, fsys fs.FS) error {
 		}
 		c.Functions[slug] = function
 	}
-	if err := c.Db.Seed.loadSeedPaths(builder.SupabaseDirPath, fsys); err != nil {
-		return err
-	}
-	if err := c.baseConfig.Validate(fsys); err != nil {
-		return err
-	}
-	idToName := map[string]string{}
-	c.Remotes = make(map[string]baseConfig, len(c.Overrides))
-	for name, remote := range c.Overrides {
-		base := c.baseConfig.Clone()
-		// On remotes branches set seed as disabled by default
-		base.Db.Seed.Enabled = false
-		// Encode a toml file with only config overrides
-		var buf bytes.Buffer
-		if err := toml.NewEncoder(&buf).Encode(remote); err != nil {
-			return errors.Errorf("failed to encode map to TOML: %w", err)
-		}
-		// Decode overrides using base config as defaults
-		if metadata, err := toml.NewDecoder(&buf).Decode(&base); err != nil {
-			return errors.Errorf("failed to decode remote config: %w", err)
-		} else if undecoded := metadata.Undecoded(); len(undecoded) > 0 {
-			fmt.Fprintf(os.Stderr, "WARN: unknown config fields: %+v\n", undecoded)
-		}
-		// Cross validate remote project id
-		if base.ProjectId == c.baseConfig.ProjectId {
-			fmt.Fprintf(os.Stderr, "WARN: project_id is missing for [remotes.%s]\n", name)
-		} else if other, exists := idToName[base.ProjectId]; exists {
-			return errors.Errorf("duplicate project_id for [remotes.%s] and [remotes.%s]", other, name)
-		} else {
-			idToName[base.ProjectId] = name
-		}
-		if err := base.Validate(fsys); err != nil {
-			return errors.Errorf("invalid config for [remotes.%s]: %w", name, err)
-		}
-		c.Remotes[name] = base
-	}
-	return nil
+	return c.Db.Seed.loadSeedPaths(builder.SupabaseDirPath, fsys)
 }
 
-func (c *baseConfig) Validate(fsys fs.FS) error {
+func (c *config) Validate(fsys fs.FS) error {
 	if c.ProjectId == "" {
 		return errors.New("Missing required field in config: project_id")
 	} else if sanitized := sanitizeProjectId(c.ProjectId); sanitized != c.ProjectId {
 		fmt.Fprintln(os.Stderr, "WARN: project_id field in config is invalid. Auto-fixing to", sanitized)
 		c.ProjectId = sanitized
 	}
+	// Since remote config is merged to base, we only need to validate the project_id field.
+	for name, remote := range c.Remotes {
+		if !refPattern.MatchString(remote.ProjectId) {
+			return errors.Errorf("Invalid config for remotes.%s.project_id. Must be like: abcdefghijklmnopqrst", name)
+		}
+	}
 	// Validate api config
 	if c.Api.Enabled {
 		if c.Api.Port == 0 {
@@ -590,7 +620,7 @@ func (c *baseConfig) Validate(fsys fs.FS) error {
 	if c.Db.Settings.SessionReplicationRole != nil {
 		allowedRoles := []SessionReplicationRole{SessionReplicationRoleOrigin, SessionReplicationRoleReplica, SessionReplicationRoleLocal}
 		if !sliceContains(allowedRoles, *c.Db.Settings.SessionReplicationRole) {
-			return errors.Errorf("Invalid config for db.session_replication_role: %s. Must be one of: %v", *c.Db.Settings.SessionReplicationRole, allowedRoles)
+			return errors.Errorf("Invalid config for db.session_replication_role. Must be one of: %v", allowedRoles)
 		}
 	}
 	if c.Db.Port == 0 {
@@ -608,17 +638,16 @@ func (c *baseConfig) Validate(fsys fs.FS) error {
 	case 15:
 		if len(c.Experimental.OrioleDBVersion) > 0 {
 			c.Db.Image = "supabase/postgres:orioledb-" + c.Experimental.OrioleDBVersion
-			var err error
-			if c.Experimental.S3Host, err = maybeLoadEnv(c.Experimental.S3Host); err != nil {
+			if err := assertEnvLoaded(c.Experimental.S3Host); err != nil {
 				return err
 			}
-			if c.Experimental.S3Region, err = maybeLoadEnv(c.Experimental.S3Region); err != nil {
+			if err := assertEnvLoaded(c.Experimental.S3Region); err != nil {
 				return err
 			}
-			if c.Experimental.S3AccessKey, err = maybeLoadEnv(c.Experimental.S3AccessKey); err != nil {
+			if err := assertEnvLoaded(c.Experimental.S3AccessKey); err != nil {
 				return err
 			}
-			if c.Experimental.S3SecretKey, err = maybeLoadEnv(c.Experimental.S3SecretKey); err != nil {
+			if err := assertEnvLoaded(c.Experimental.S3SecretKey); err != nil {
 				return err
 			}
 		}
@@ -655,7 +684,6 @@ func (c *baseConfig) Validate(fsys fs.FS) error {
 		} else if parsed.Host == "" || parsed.Host == c.Hostname {
 			c.Studio.ApiUrl = c.Api.ExternalUrl
 		}
-		c.Studio.OpenaiApiKey, _ = maybeLoadEnv(c.Studio.OpenaiApiKey)
 	}
 	// Validate smtp config
 	if c.Inbucket.Enabled {
@@ -668,12 +696,11 @@ func (c *baseConfig) Validate(fsys fs.FS) error {
 		if c.Auth.SiteUrl == "" {
 			return errors.New("Missing required field in config: auth.site_url")
 		}
-		var err error
-		if c.Auth.SiteUrl, err = maybeLoadEnv(c.Auth.SiteUrl); err != nil {
+		if err := assertEnvLoaded(c.Auth.SiteUrl); err != nil {
 			return err
 		}
 		for i, url := range c.Auth.AdditionalRedirectUrls {
-			if c.Auth.AdditionalRedirectUrls[i], err = maybeLoadEnv(url); err != nil {
+			if err := assertEnvLoaded(url); err != nil {
 				return errors.Errorf("Invalid config for auth.additional_redirect_urls[%d]: %v", i, err)
 			}
 		}
@@ -738,18 +765,24 @@ func (c *baseConfig) Validate(fsys fs.FS) error {
 	return nil
 }
 
-func maybeLoadEnv(s string) (string, error) {
-	matches := envPattern.FindStringSubmatch(s)
-	if len(matches) == 0 {
-		return s, nil
+func assertEnvLoaded(s string) error {
+	if matches := envPattern.FindStringSubmatch(s); len(matches) > 1 {
+		return errors.Errorf(`Error evaluating "%s": environment variable %s is unset.`, s, matches[1])
 	}
+	return nil
+}
 
-	envName := matches[1]
-	if value := os.Getenv(envName); value != "" {
-		return value, nil
+func LoadEnvHook(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) {
+	if f != reflect.String {
+		return data, nil
 	}
-
-	return "", errors.Errorf(`Error evaluating "%s": environment variable %s is unset.`, s, envName)
+	value := data.(string)
+	if matches := envPattern.FindStringSubmatch(value); len(matches) > 1 {
+		if env, exists := os.LookupEnv(matches[1]); exists {
+			value = env
+		}
+	}
+	return value, nil
 }
 
 func truncateText(text string, maxLen int) string {
@@ -857,13 +890,13 @@ func (e *email) validate(fsys fs.FS) (err error) {
 		if len(e.Smtp.User) == 0 {
 			return errors.New("Missing required field in config: auth.email.smtp.user")
 		}
-		if len(e.Smtp.Pass) == 0 {
+		if len(e.Smtp.Pass.Value) == 0 {
 			return errors.New("Missing required field in config: auth.email.smtp.pass")
 		}
 		if len(e.Smtp.AdminEmail) == 0 {
 			return errors.New("Missing required field in config: auth.email.smtp.admin_email")
 		}
-		if e.Smtp.Pass, err = maybeLoadEnv(e.Smtp.Pass); err != nil {
+		if err := assertEnvLoaded(e.Smtp.Pass.Value); err != nil {
 			return err
 		}
 	}
@@ -879,10 +912,10 @@ func (s *sms) validate() (err error) {
 		if len(s.Twilio.MessageServiceSid) == 0 {
 			return errors.New("Missing required field in config: auth.sms.twilio.message_service_sid")
 		}
-		if len(s.Twilio.AuthToken) == 0 {
+		if len(s.Twilio.AuthToken.Value) == 0 {
 			return errors.New("Missing required field in config: auth.sms.twilio.auth_token")
 		}
-		if s.Twilio.AuthToken, err = maybeLoadEnv(s.Twilio.AuthToken); err != nil {
+		if err := assertEnvLoaded(s.Twilio.AuthToken.Value); err != nil {
 			return err
 		}
 	case s.TwilioVerify.Enabled:
@@ -892,30 +925,30 @@ func (s *sms) validate() (err error) {
 		if len(s.TwilioVerify.MessageServiceSid) == 0 {
 			return errors.New("Missing required field in config: auth.sms.twilio_verify.message_service_sid")
 		}
-		if len(s.TwilioVerify.AuthToken) == 0 {
+		if len(s.TwilioVerify.AuthToken.Value) == 0 {
 			return errors.New("Missing required field in config: auth.sms.twilio_verify.auth_token")
 		}
-		if s.TwilioVerify.AuthToken, err = maybeLoadEnv(s.TwilioVerify.AuthToken); err != nil {
+		if err := assertEnvLoaded(s.TwilioVerify.AuthToken.Value); err != nil {
 			return err
 		}
 	case s.Messagebird.Enabled:
 		if len(s.Messagebird.Originator) == 0 {
 			return errors.New("Missing required field in config: auth.sms.messagebird.originator")
 		}
-		if len(s.Messagebird.AccessKey) == 0 {
+		if len(s.Messagebird.AccessKey.Value) == 0 {
 			return errors.New("Missing required field in config: auth.sms.messagebird.access_key")
 		}
-		if s.Messagebird.AccessKey, err = maybeLoadEnv(s.Messagebird.AccessKey); err != nil {
+		if err := assertEnvLoaded(s.Messagebird.AccessKey.Value); err != nil {
 			return err
 		}
 	case s.Textlocal.Enabled:
 		if len(s.Textlocal.Sender) == 0 {
 			return errors.New("Missing required field in config: auth.sms.textlocal.sender")
 		}
-		if len(s.Textlocal.ApiKey) == 0 {
+		if len(s.Textlocal.ApiKey.Value) == 0 {
 			return errors.New("Missing required field in config: auth.sms.textlocal.api_key")
 		}
-		if s.Textlocal.ApiKey, err = maybeLoadEnv(s.Textlocal.ApiKey); err != nil {
+		if err := assertEnvLoaded(s.Textlocal.ApiKey.Value); err != nil {
 			return err
 		}
 	case s.Vonage.Enabled:
@@ -925,13 +958,13 @@ func (s *sms) validate() (err error) {
 		if len(s.Vonage.ApiKey) == 0 {
 			return errors.New("Missing required field in config: auth.sms.vonage.api_key")
 		}
-		if len(s.Vonage.ApiSecret) == 0 {
+		if len(s.Vonage.ApiSecret.Value) == 0 {
 			return errors.New("Missing required field in config: auth.sms.vonage.api_secret")
 		}
-		if s.Vonage.ApiKey, err = maybeLoadEnv(s.Vonage.ApiKey); err != nil {
+		if err := assertEnvLoaded(s.Vonage.ApiKey); err != nil {
 			return err
 		}
-		if s.Vonage.ApiSecret, err = maybeLoadEnv(s.Vonage.ApiSecret); err != nil {
+		if err := assertEnvLoaded(s.Vonage.ApiSecret.Value); err != nil {
 			return err
 		}
 	case s.EnableSignup:
@@ -955,19 +988,19 @@ func (e external) validate() (err error) {
 		if provider.ClientId == "" {
 			return errors.Errorf("Missing required field in config: auth.external.%s.client_id", ext)
 		}
-		if !sliceContains([]string{"apple", "google"}, ext) && provider.Secret == "" {
+		if !sliceContains([]string{"apple", "google"}, ext) && len(provider.Secret.Value) == 0 {
 			return errors.Errorf("Missing required field in config: auth.external.%s.secret", ext)
 		}
-		if provider.ClientId, err = maybeLoadEnv(provider.ClientId); err != nil {
+		if err := assertEnvLoaded(provider.ClientId); err != nil {
 			return err
 		}
-		if provider.Secret, err = maybeLoadEnv(provider.Secret); err != nil {
+		if err := assertEnvLoaded(provider.Secret.Value); err != nil {
 			return err
 		}
-		if provider.RedirectUri, err = maybeLoadEnv(provider.RedirectUri); err != nil {
+		if err := assertEnvLoaded(provider.RedirectUri); err != nil {
 			return err
 		}
-		if provider.Url, err = maybeLoadEnv(provider.Url); err != nil {
+		if err := assertEnvLoaded(provider.Url); err != nil {
 			return err
 		}
 		e[ext] = provider
@@ -1020,18 +1053,18 @@ func (h *hookConfig) validate(hookType string) (err error) {
 	}
 	switch strings.ToLower(parsed.Scheme) {
 	case "http", "https":
-		if len(h.Secrets) == 0 {
+		if len(h.Secrets.Value) == 0 {
 			return errors.Errorf("Missing required field in config: auth.hook.%s.secrets", hookType)
-		} else if h.Secrets, err = maybeLoadEnv(h.Secrets); err != nil {
+		} else if err := assertEnvLoaded(h.Secrets.Value); err != nil {
 			return err
 		}
-		for _, secret := range strings.Split(h.Secrets, "|") {
+		for _, secret := range strings.Split(h.Secrets.Value, "|") {
 			if !hookSecretPattern.MatchString(secret) {
-				return errors.Errorf(`Invalid hook config: auth.hook.%s.secrets must be formatted as "v1,whsec_<base64_encoded_secret>"`, hookType)
+				return errors.Errorf(`Invalid hook config: auth.hook.%s.secrets must be formatted as "v1,whsec_<base64_encoded_secret>" with a minimum length of 32 characters.`, hookType)
 			}
 		}
 	case "pg-functions":
-		if len(h.Secrets) > 0 {
+		if len(h.Secrets.Value) > 0 {
 			return errors.Errorf("Invalid hook config: auth.hook.%s.secrets is unsupported for pg-functions URI", hookType)
 		}
 	default:
@@ -1108,13 +1141,13 @@ func (c *tpaCognito) issuerURL() string {
 func (c *tpaCognito) validate() (err error) {
 	if c.UserPoolID == "" {
 		return errors.New("Invalid config: auth.third_party.cognito is enabled but without a user_pool_id.")
-	} else if c.UserPoolID, err = maybeLoadEnv(c.UserPoolID); err != nil {
+	} else if err := assertEnvLoaded(c.UserPoolID); err != nil {
 		return err
 	}
 
 	if c.UserPoolRegion == "" {
 		return errors.New("Invalid config: auth.third_party.cognito is enabled but without a user_pool_region.")
-	} else if c.UserPoolRegion, err = maybeLoadEnv(c.UserPoolRegion); err != nil {
+	} else if err := assertEnvLoaded(c.UserPoolRegion); err != nil {
 		return err
 	}
 
@@ -1274,25 +1307,16 @@ func (c *baseConfig) GetServiceImages() []string {
 }
 
 // Retrieve the final base config to use taking into account the remotes override
+// Pre: config must be loaded after setting config.ProjectID = "ref"
 func (c *config) GetRemoteByProjectRef(projectRef string) (baseConfig, error) {
-	var result []string
-	// Iterate over all the config.Remotes
-	for name, remoteConfig := range c.Remotes {
-		// Check if there is one matching project_id
-		if remoteConfig.ProjectId == projectRef {
-			// Check for duplicate project IDs across remotes
-			result = append(result, name)
+	base := c.baseConfig.Clone()
+	for _, remote := range c.Remotes {
+		if remote.ProjectId == projectRef {
+			base.ProjectId = projectRef
+			return base, nil
 		}
 	}
-	// If no matching remote config is found, return the base config
-	if len(result) == 0 {
-		return c.baseConfig, errors.Errorf("no remote found for project_id: %s", projectRef)
-	}
-	remote := c.Remotes[result[0]]
-	if len(result) > 1 {
-		return remote, errors.Errorf("multiple remotes %v have the same project_id: %s", result, projectRef)
-	}
-	return remote, nil
+	return base, errors.Errorf("no remote found for project_id: %s", projectRef)
 }
 
 func ToTomlBytes(config any) ([]byte, error) {
diff --git a/pkg/config/constants.go b/pkg/config/constants.go
index 200c16da..3aa5c9d7 100644
--- a/pkg/config/constants.go
+++ b/pkg/config/constants.go
@@ -10,12 +10,12 @@ const (
 	inbucketImage    = "inbucket/inbucket:3.0.3"
 	postgrestImage   = "postgrest/postgrest:v12.2.0"
 	pgmetaImage      = "supabase/postgres-meta:v0.84.2"
-	studioImage      = "supabase/studio:20241202-71e5240"
+	studioImage      = "supabase/studio:20250113-83c9420"
 	imageProxyImage  = "darthsim/imgproxy:v3.8.0"
-	edgeRuntimeImage = "supabase/edge-runtime:v1.66.1"
+	edgeRuntimeImage = "supabase/edge-runtime:v1.66.4"
 	vectorImage      = "timberio/vector:0.28.1-alpine"
 	supavisorImage   = "supabase/supavisor:1.1.56"
-	gotrueImage      = "supabase/gotrue:v2.164.0"
+	gotrueImage      = "supabase/gotrue:v2.167.0"
 	realtimeImage    = "supabase/realtime:v2.33.70"
 	storageImage     = "supabase/storage-api:v1.14.5"
 	logflareImage    = "supabase/logflare:1.4.0"
diff --git a/pkg/config/secret.go b/pkg/config/secret.go
new file mode 100644
index 00000000..3f061167
--- /dev/null
+++ b/pkg/config/secret.go
@@ -0,0 +1,82 @@
+package config
+
+import (
+	"encoding/base64"
+	"os"
+	"reflect"
+	"strings"
+
+	ecies "github.com/ecies/go/v2"
+	"github.com/go-errors/errors"
+	"github.com/mitchellh/mapstructure"
+)
+
+type Secret struct {
+	Value  string
+	SHA256 string
+}
+
+const HASHED_PREFIX = "hash:"
+
+func (s Secret) MarshalText() (text []byte, err error) {
+	if len(s.SHA256) == 0 {
+		return []byte{}, nil
+	}
+	return []byte(HASHED_PREFIX + s.SHA256), nil
+}
+
+const ENCRYPTED_PREFIX = "encrypted:"
+
+// Decrypt secret values following dotenvx convention:
+// https://github.com/dotenvx/dotenvx/blob/main/src/lib/helpers/decryptKeyValue.js
+func decrypt(key, value string) (string, error) {
+	if !strings.HasPrefix(value, ENCRYPTED_PREFIX) {
+		return value, nil
+	}
+	if len(key) == 0 {
+		return value, errors.New("missing private key")
+	}
+	// Verify private key exists
+	privateKey, err := ecies.NewPrivateKeyFromHex(key)
+	if err != nil {
+		return value, errors.Errorf("failed to hex decode private key: %w", err)
+	}
+	// Verify ciphertext is base64 encoded
+	encoded := value[len(ENCRYPTED_PREFIX):]
+	ciphertext, err := base64.StdEncoding.DecodeString(encoded)
+	if err != nil {
+		return value, errors.Errorf("failed to base64 decode secret: %w", err)
+	}
+	// Return decrypted value
+	plaintext, err := ecies.Decrypt(privateKey, ciphertext)
+	if err != nil {
+		return value, errors.Errorf("failed to decrypt secret: %w", err)
+	}
+	return string(plaintext), nil
+}
+
+func DecryptSecretHookFunc(hashKey string) mapstructure.DecodeHookFunc {
+	return func(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
+		if f.Kind() != reflect.String {
+			return data, nil
+		}
+		var result Secret
+		if t != reflect.TypeOf(result) {
+			return data, nil
+		}
+		var err error
+		privKey := os.Getenv("DOTENV_PRIVATE_KEY")
+		for _, k := range strings.Split(privKey, ",") {
+			// Use the first private key that successfully decrypts the secret
+			if result.Value, err = decrypt(k, data.(string)); err == nil {
+				// Unloaded env() references may be returned verbatim.
+				// Don't hash those values as they are meaningless.
+				if !envPattern.MatchString(result.Value) {
+					result.SHA256 = sha256Hmac(hashKey, result.Value)
+				}
+				break
+			}
+		}
+		return result, err
+	}
+}
diff --git a/pkg/config/templates/config.toml b/pkg/config/templates/config.toml
index 5345f4d0..6c50b144 100644
--- a/pkg/config/templates/config.toml
+++ b/pkg/config/templates/config.toml
@@ -46,8 +46,8 @@ max_client_conn = 100
 # If enabled, seeds the database after migrations during a db reset.
 enabled = true
 # Specifies an ordered list of seed files to load during db reset.
-# Supports glob patterns relative to supabase directory: './seeds/*.sql'
-sql_paths = ['./seed.sql']
+# Supports glob patterns relative to supabase directory: "./seeds/*.sql"
+sql_paths = ["./seed.sql"]
 
 [realtime]
 enabled = true
diff --git a/pkg/config/updater.go b/pkg/config/updater.go
index 445000d0..e5f42ace 100644
--- a/pkg/config/updater.go
+++ b/pkg/config/updater.go
@@ -110,7 +110,7 @@ func (u *ConfigUpdater) UpdateAuthConfig(ctx context.Context, projectRef string,
 	} else if authConfig.JSON200 == nil {
 		return errors.Errorf("unexpected status %d: %s", authConfig.StatusCode(), string(authConfig.Body))
 	}
-	authDiff, err := c.DiffWithRemote(projectRef, *authConfig.JSON200)
+	authDiff, err := c.DiffWithRemote(*authConfig.JSON200)
 	if err != nil {
 		return err
 	} else if len(authDiff) == 0 {
diff --git a/pkg/storage/batch.go b/pkg/storage/batch.go
index 8a681242..63638e9a 100644
--- a/pkg/storage/batch.go
+++ b/pkg/storage/batch.go
@@ -91,17 +91,9 @@ func (s *StorageAPI) UpsertObjects(ctx context.Context, bucketConfig config.Buck
 			}
 			fmt.Fprintln(os.Stderr, "Uploading:", filePath, "=>", dstPath)
 			job := func() error {
-				f, err := fsys.Open(filePath)
-				if err != nil {
-					return errors.Errorf("failed to open file: %w", err)
-				}
-				defer f.Close()
-				fo, err := ParseFileOptions(f)
-				if err != nil {
-					return err
-				}
-				fo.Overwrite = true
-				return s.UploadObjectStream(ctx, dstPath, f, *fo)
+				return s.UploadObject(ctx, dstPath, filePath, fsys, func(fo *FileOptions) {
+					fo.Overwrite = true
+				})
 			}
 			return jq.Put(job)
 		}
diff --git a/pkg/storage/objects.go b/pkg/storage/objects.go
index f048cecf..f338a63b 100644
--- a/pkg/storage/objects.go
+++ b/pkg/storage/objects.go
@@ -4,9 +4,11 @@ import (
 	"context"
 	"io"
 	"io/fs"
+	"mime"
 	"net/http"
 	"os"
 	"path"
+	"path/filepath"
 	"strings"
 
 	"github.com/go-errors/errors"
@@ -88,7 +90,7 @@ func ParseFileOptions(f fs.File, opts ...func(*FileOptions)) (*FileOptions, erro
 	return fo, nil
 }
 
-func (s *StorageAPI) UploadObject(ctx context.Context, remotePath, localPath string, fsys afero.Fs, opts ...func(*FileOptions)) error {
+func (s *StorageAPI) UploadObject(ctx context.Context, remotePath, localPath string, fsys fs.FS, opts ...func(*FileOptions)) error {
 	f, err := fsys.Open(localPath)
 	if err != nil {
 		return errors.Errorf("failed to open file: %w", err)
@@ -98,6 +100,13 @@ func (s *StorageAPI) UploadObject(ctx context.Context, remotePath, localPath str
 	if err != nil {
 		return err
 	}
+	// For text/plain content types, we try to determine a more specific type
+	// based on the file extension, as the initial detection might be too generic
+	if strings.Contains(fo.ContentType, "text/plain") {
+		if extensionType := mime.TypeByExtension(filepath.Ext(localPath)); extensionType != "" {
+			fo.ContentType = extensionType
+		}
+	}
 	return s.UploadObjectStream(ctx, remotePath, f, *fo)
 }
 


Test patch:
diff --git a/internal/db/branch/switch_/switch__test.go b/internal/db/branch/switch_/switch__test.go
index 7c70959c..722229b7 100644
--- a/internal/db/branch/switch_/switch__test.go
+++ b/internal/db/branch/switch_/switch__test.go
@@ -79,7 +79,7 @@ func TestSwitchCommand(t *testing.T) {
 		// Run test
 		err := Run(context.Background(), "target", fsys)
 		// Check error
-		assert.ErrorContains(t, err, "toml: line 0: unexpected EOF; expected key separator '='")
+		assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there")
 	})
 
 	t.Run("throws error on missing database", func(t *testing.T) {
diff --git a/internal/db/start/start_test.go b/internal/db/start/start_test.go
index 475562f2..afdb8e28 100644
--- a/internal/db/start/start_test.go
+++ b/internal/db/start/start_test.go
@@ -89,7 +89,7 @@ func TestStartDatabase(t *testing.T) {
 		conn.Query(roles).
 			Reply("CREATE ROLE")
 		// Run test
-		err := StartDatabase(context.Background(), fsys, io.Discard, conn.Intercept)
+		err := StartDatabase(context.Background(), "", fsys, io.Discard, conn.Intercept)
 		// Check error
 		assert.NoError(t, err)
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -124,7 +124,7 @@ func TestStartDatabase(t *testing.T) {
 				},
 			}})
 		// Run test
-		err := StartDatabase(context.Background(), fsys, io.Discard)
+		err := StartDatabase(context.Background(), "", fsys, io.Discard)
 		// Check error
 		assert.NoError(t, err)
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -149,7 +149,7 @@ func TestStartDatabase(t *testing.T) {
 			Get("/v" + utils.Docker.ClientVersion() + "/images/" + utils.GetRegistryImageUrl(utils.Config.Db.Image) + "/json").
 			Reply(http.StatusInternalServerError)
 		// Run test
-		err := StartDatabase(context.Background(), fsys, io.Discard)
+		err := StartDatabase(context.Background(), "", fsys, io.Discard)
 		// Check error
 		assert.ErrorContains(t, err, "request returned Internal Server Error for API route and version")
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -161,7 +161,7 @@ func TestStartCommand(t *testing.T) {
 		// Setup in-memory fs
 		fsys := afero.NewMemMapFs()
 		// Run test
-		err := Run(context.Background(), fsys)
+		err := Run(context.Background(), "", fsys)
 		// Check error
 		assert.ErrorIs(t, err, os.ErrNotExist)
 	})
@@ -177,7 +177,7 @@ func TestStartCommand(t *testing.T) {
 			Get("/v" + utils.Docker.ClientVersion() + "/containers").
 			ReplyError(errors.New("network error"))
 		// Run test
-		err := Run(context.Background(), fsys)
+		err := Run(context.Background(), "", fsys)
 		// Check error
 		assert.ErrorContains(t, err, "network error")
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -195,7 +195,7 @@ func TestStartCommand(t *testing.T) {
 			Reply(http.StatusOK).
 			JSON(types.ContainerJSON{})
 		// Run test
-		err := Run(context.Background(), fsys)
+		err := Run(context.Background(), "", fsys)
 		// Check error
 		assert.NoError(t, err)
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -221,7 +221,7 @@ func TestStartCommand(t *testing.T) {
 		// Cleanup resources
 		apitest.MockDockerStop(utils.Docker)
 		// Run test
-		err := Run(context.Background(), fsys)
+		err := Run(context.Background(), "", fsys)
 		// Check error
 		assert.ErrorContains(t, err, "network error")
 		assert.Empty(t, apitest.ListUnmatchedRequests())
@@ -350,7 +350,7 @@ func TestStartDatabaseWithCustomSettings(t *testing.T) {
 		defer conn.Close(t)
 
 		// Run test
-		err := StartDatabase(context.Background(), fsys, io.Discard, conn.Intercept)
+		err := StartDatabase(context.Background(), "", fsys, io.Discard, conn.Intercept)
 
 		// Check error
 		assert.NoError(t, err)
diff --git a/internal/functions/new/new_test.go b/internal/functions/new/new_test.go
index d5e9c2fc..8e00fa65 100644
--- a/internal/functions/new/new_test.go
+++ b/internal/functions/new/new_test.go
@@ -24,6 +24,16 @@ func TestNewCommand(t *testing.T) {
 		assert.Contains(t, string(content),
 			"curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/test-func'",
 		)
+
+		// Verify deno.json exists
+		denoPath := filepath.Join(utils.FunctionsDir, "test-func", "deno.json")
+		_, err = afero.ReadFile(fsys, denoPath)
+		assert.NoError(t, err, "deno.json should be created")
+
+		// Verify .npmrc exists
+		npmrcPath := filepath.Join(utils.FunctionsDir, "test-func", ".npmrc")
+		_, err = afero.ReadFile(fsys, npmrcPath)
+		assert.NoError(t, err, ".npmrc should be created")
 	})
 
 	t.Run("throws error on malformed slug", func(t *testing.T) {
diff --git a/internal/start/start_test.go b/internal/start/start_test.go
index 6d07eb36..bbd73ab9 100644
--- a/internal/start/start_test.go
+++ b/internal/start/start_test.go
@@ -37,7 +37,7 @@ func TestStartCommand(t *testing.T) {
 		// Run test
 		err := Run(context.Background(), fsys, []string{}, false)
 		// Check error
-		assert.ErrorContains(t, err, "toml: line 0: unexpected EOF; expected key separator '='")
+		assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there")
 	})
 
 	t.Run("throws error on missing docker", func(t *testing.T) {
diff --git a/internal/status/status_test.go b/internal/status/status_test.go
index 391a8c99..175d28ca 100644
--- a/internal/status/status_test.go
+++ b/internal/status/status_test.go
@@ -59,7 +59,7 @@ func TestStatusCommand(t *testing.T) {
 		// Run test
 		err := Run(context.Background(), CustomName{}, utils.OutputPretty, fsys)
 		// Check error
-		assert.ErrorContains(t, err, "toml: line 0: unexpected EOF; expected key separator '='")
+		assert.ErrorContains(t, err, "toml: expected = after a key, but the document ends there")
 	})
 
 	t.Run("throws error on missing docker", func(t *testing.T) {
diff --git a/pkg/config/auth_test.go b/pkg/config/auth_test.go
index e659da16..b3413971 100644
--- a/pkg/config/auth_test.go
+++ b/pkg/config/auth_test.go
@@ -48,7 +48,7 @@ func TestAuthDiff(t *testing.T) {
 		c.MinimumPasswordLength = 6
 		c.PasswordRequirements = LettersDigits
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			SiteUrl:                           cast.Ptr("http://127.0.0.1:3000"),
 			UriAllowList:                      cast.Ptr("https://127.0.0.1:3000"),
 			JwtExp:                            cast.Ptr(3600),
@@ -78,7 +78,7 @@ func TestAuthDiff(t *testing.T) {
 		c.MinimumPasswordLength = 6
 		c.PasswordRequirements = LowerUpperLettersDigitsSymbols
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			SiteUrl:                           cast.Ptr(""),
 			UriAllowList:                      cast.Ptr("https://127.0.0.1:3000,https://ref.supabase.co"),
 			JwtExp:                            cast.Ptr(0),
@@ -99,7 +99,7 @@ func TestAuthDiff(t *testing.T) {
 		c := newWithDefaults()
 		c.EnableSignup = false
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			SiteUrl:                           cast.Ptr(""),
 			UriAllowList:                      cast.Ptr(""),
 			JwtExp:                            cast.Ptr(0),
@@ -124,22 +124,34 @@ func TestHookDiff(t *testing.T) {
 			CustomAccessToken: &hookConfig{
 				Enabled: true,
 				URI:     "http://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			SendSMS: &hookConfig{
 				Enabled: true,
 				URI:     "http://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			SendEmail: &hookConfig{
 				Enabled: true,
 				URI:     "https://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			MFAVerificationAttempt: &hookConfig{
 				Enabled: true,
 				URI:     "https://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			PasswordVerificationAttempt: &hookConfig{
 				Enabled: true,
@@ -147,7 +159,7 @@ func TestHookDiff(t *testing.T) {
 			},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			HookCustomAccessTokenEnabled:           cast.Ptr(true),
 			HookCustomAccessTokenUri:               cast.Ptr("http://example.com"),
 			HookCustomAccessTokenSecrets:           cast.Ptr("ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252"),
@@ -177,7 +189,7 @@ func TestHookDiff(t *testing.T) {
 			SendSMS: &hookConfig{
 				Enabled: false,
 				URI:     "https://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{Value: "test-secret"},
 			},
 			SendEmail: &hookConfig{
 				Enabled: false,
@@ -189,7 +201,7 @@ func TestHookDiff(t *testing.T) {
 			PasswordVerificationAttempt: nil,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			HookCustomAccessTokenEnabled:           cast.Ptr(true),
 			HookCustomAccessTokenUri:               cast.Ptr("http://example.com"),
 			HookCustomAccessTokenSecrets:           cast.Ptr("ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252"),
@@ -215,12 +227,18 @@ func TestHookDiff(t *testing.T) {
 			CustomAccessToken: &hookConfig{
 				Enabled: true,
 				URI:     "http://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			SendSMS: &hookConfig{
 				Enabled: true,
 				URI:     "https://example.com",
-				Secrets: "test-secret",
+				Secrets: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			SendEmail: &hookConfig{
 				Enabled: true,
@@ -233,7 +251,7 @@ func TestHookDiff(t *testing.T) {
 			PasswordVerificationAttempt: nil,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			HookCustomAccessTokenEnabled:           cast.Ptr(false),
 			HookCustomAccessTokenUri:               cast.Ptr("pg-functions://postgres/public/customToken"),
 			HookSendSmsEnabled:                     cast.Ptr(false),
@@ -261,7 +279,7 @@ func TestHookDiff(t *testing.T) {
 			PasswordVerificationAttempt: &hookConfig{Enabled: false},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			HookCustomAccessTokenEnabled:           cast.Ptr(false),
 			HookSendSmsEnabled:                     cast.Ptr(false),
 			HookSendEmailEnabled:                   cast.Ptr(false),
@@ -298,7 +316,7 @@ func TestMfaDiff(t *testing.T) {
 			MaxEnrolledFactors: 10,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			MfaMaxEnrolledFactors:    cast.Ptr(10),
 			MfaTotpEnrollEnabled:     cast.Ptr(true),
 			MfaTotpVerifyEnabled:     cast.Ptr(true),
@@ -330,7 +348,7 @@ func TestMfaDiff(t *testing.T) {
 			},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			MfaMaxEnrolledFactors:    cast.Ptr(10),
 			MfaTotpEnrollEnabled:     cast.Ptr(false),
 			MfaTotpVerifyEnabled:     cast.Ptr(false),
@@ -358,7 +376,7 @@ func TestMfaDiff(t *testing.T) {
 			},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			MfaMaxEnrolledFactors:    cast.Ptr(10),
 			MfaTotpEnrollEnabled:     cast.Ptr(false),
 			MfaTotpVerifyEnabled:     cast.Ptr(false),
@@ -411,11 +429,14 @@ func TestEmailDiff(t *testing.T) {
 				},
 			},
 			Smtp: &smtp{
-				Enabled:    cast.Ptr(true),
-				Host:       "smtp.sendgrid.net",
-				Port:       587,
-				User:       "apikey",
-				Pass:       "test-key",
+				Enabled: cast.Ptr(true),
+				Host:    "smtp.sendgrid.net",
+				Port:    587,
+				User:    "apikey",
+				Pass: Secret{
+					Value:  "test-key",
+					SHA256: "ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e",
+				},
 				AdminEmail: "admin@email.com",
 				SenderName: "Admin",
 			},
@@ -424,7 +445,7 @@ func TestEmailDiff(t *testing.T) {
 			OtpExpiry:    3600,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalEmailEnabled:           cast.Ptr(true),
 			MailerSecureEmailChangeEnabled: cast.Ptr(true),
 			MailerAutoconfirm:              cast.Ptr(false),
@@ -489,10 +510,13 @@ func TestEmailDiff(t *testing.T) {
 				},
 			},
 			Smtp: &smtp{
-				Host:       "smtp.sendgrid.net",
-				Port:       587,
-				User:       "apikey",
-				Pass:       "test-key",
+				Host: "smtp.sendgrid.net",
+				Port: 587,
+				User: "apikey",
+				Pass: Secret{
+					Value:  "test-key",
+					SHA256: "ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e",
+				},
 				AdminEmail: "admin@email.com",
 				SenderName: "Admin",
 			},
@@ -501,7 +525,7 @@ func TestEmailDiff(t *testing.T) {
 			OtpExpiry:    86400,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalEmailEnabled:           cast.Ptr(false),
 			MailerSecureEmailChangeEnabled: cast.Ptr(false),
 			MailerAutoconfirm:              cast.Ptr(true),
@@ -537,7 +561,7 @@ func TestEmailDiff(t *testing.T) {
 			OtpExpiry:    86400,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalEmailEnabled:           cast.Ptr(true),
 			MailerSecureEmailChangeEnabled: cast.Ptr(true),
 			MailerAutoconfirm:              cast.Ptr(false),
@@ -583,11 +607,14 @@ func TestEmailDiff(t *testing.T) {
 				"reauthentication": {},
 			},
 			Smtp: &smtp{
-				Enabled:    cast.Ptr(false),
-				Host:       "smtp.sendgrid.net",
-				Port:       587,
-				User:       "apikey",
-				Pass:       "test-key",
+				Enabled: cast.Ptr(false),
+				Host:    "smtp.sendgrid.net",
+				Port:    587,
+				User:    "apikey",
+				Pass: Secret{
+					Value:  "test-key",
+					SHA256: "ed64b7695a606bc6ab4fcb41fe815b5ddf1063ccbc87afe1fa89756635db520e",
+				},
 				AdminEmail: "admin@email.com",
 				SenderName: "Admin",
 			},
@@ -596,7 +623,7 @@ func TestEmailDiff(t *testing.T) {
 			OtpExpiry:    3600,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalEmailEnabled:           cast.Ptr(false),
 			MailerSecureEmailChangeEnabled: cast.Ptr(false),
 			MailerAutoconfirm:              cast.Ptr(true),
@@ -624,11 +651,14 @@ func TestSmsDiff(t *testing.T) {
 				Enabled:           true,
 				AccountSid:        "test-account",
 				MessageServiceSid: "test-service",
-				AuthToken:         "test-token",
+				AuthToken: Secret{
+					Value:  "test-token",
+					SHA256: "c84443bc59b92caef8ec8500ff443584793756749523811eb333af2bbc74fc88",
+				},
 			},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalPhoneEnabled:       cast.Ptr(true),
 			SmsAutoconfirm:             cast.Ptr(true),
 			SmsMaxFrequency:            cast.Ptr(60),
@@ -662,7 +692,7 @@ func TestSmsDiff(t *testing.T) {
 	t.Run("local disabled remote enabled", func(t *testing.T) {
 		c := newWithDefaults()
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalPhoneEnabled:       cast.Ptr(true),
 			SmsAutoconfirm:             cast.Ptr(true),
 			SmsMaxFrequency:            cast.Ptr(60),
@@ -693,11 +723,14 @@ func TestSmsDiff(t *testing.T) {
 			Messagebird: messagebirdConfig{
 				Enabled:    true,
 				Originator: "test-originator",
-				AccessKey:  "test-access-key",
+				AccessKey: Secret{
+					Value:  "test-access-key",
+					SHA256: "ab60d03fc809fb02dae838582f3ddc13d1d6cb32ffba77c4b969dd3caa496f13",
+				},
 			},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalPhoneEnabled:       cast.Ptr(false),
 			SmsAutoconfirm:             cast.Ptr(false),
 			SmsMaxFrequency:            cast.Ptr(0),
@@ -725,7 +758,7 @@ func TestSmsDiff(t *testing.T) {
 			MaxFrequency:        time.Minute,
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalPhoneEnabled:     cast.Ptr(false),
 			SmsAutoconfirm:           cast.Ptr(true),
 			SmsMaxFrequency:          cast.Ptr(60),
@@ -749,7 +782,7 @@ func TestSmsDiff(t *testing.T) {
 		c := newWithDefaults()
 		c.Sms.EnableSignup = true
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalPhoneEnabled: cast.Ptr(false),
 			SmsProvider:          cast.Ptr("twilio"),
 		})
@@ -762,7 +795,7 @@ func TestSmsDiff(t *testing.T) {
 		c := newWithDefaults()
 		c.Sms.Messagebird.Enabled = true
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalPhoneEnabled:    cast.Ptr(false),
 			SmsProvider:             cast.Ptr("messagebird"),
 			SmsMessagebirdAccessKey: cast.Ptr(""),
@@ -798,7 +831,7 @@ func TestExternalDiff(t *testing.T) {
 			"zoom":          {Enabled: true},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalAppleAdditionalClientIds:  cast.Ptr(""),
 			ExternalAppleClientId:             cast.Ptr(""),
 			ExternalAppleEnabled:              cast.Ptr(true),
@@ -879,12 +912,18 @@ func TestExternalDiff(t *testing.T) {
 			"apple": {
 				Enabled:  true,
 				ClientId: "test-client-1,test-client-2",
-				Secret:   "test-secret",
+				Secret: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			"azure": {
 				Enabled:  true,
 				ClientId: "test-client-1",
-				Secret:   "test-secret",
+				Secret: Secret{
+					Value:  "test-secret",
+					SHA256: "ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252",
+				},
 			},
 			"bitbucket": {},
 			"discord":   {},
@@ -895,7 +934,7 @@ func TestExternalDiff(t *testing.T) {
 			"google": {
 				Enabled:        false,
 				ClientId:       "test-client-2",
-				Secret:         "env(test_secret)",
+				Secret:         Secret{Value: "env(test_secret)"},
 				SkipNonceCheck: false,
 			},
 			// "kakao":         {},
@@ -910,7 +949,7 @@ func TestExternalDiff(t *testing.T) {
 			"zoom":          {},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalAppleAdditionalClientIds:  cast.Ptr("test-client-2"),
 			ExternalAppleClientId:             cast.Ptr("test-client-1"),
 			ExternalAppleEnabled:              cast.Ptr(false),
@@ -953,7 +992,7 @@ func TestExternalDiff(t *testing.T) {
 			"zoom":          {},
 		}
 		// Run test
-		diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{
+		diff, err := c.DiffWithRemote(v1API.AuthConfigResponse{
 			ExternalAppleEnabled:         cast.Ptr(false),
 			ExternalAzureEnabled:         cast.Ptr(false),
 			ExternalBitbucketEnabled:     cast.Ptr(false),
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index e1678f2e..e13e67e5 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -45,7 +45,7 @@ func TestConfigParsing(t *testing.T) {
 		assert.NoError(t, config.Load("", fsys))
 		// Check error
 		assert.Equal(t, "hello", config.Auth.External["azure"].ClientId)
-		assert.Equal(t, "this is cool", config.Auth.External["azure"].Secret)
+		assert.Equal(t, "this is cool", config.Auth.External["azure"].Secret.Value)
 		assert.Equal(t, []string{
 			"https://127.0.0.1:3000",
 			"http://localhost:3000/auth/callback",
@@ -88,7 +88,7 @@ func TestConfigParsing(t *testing.T) {
 		staging, ok := config.Remotes["staging"]
 		assert.True(t, ok)
 		// Check the values for production override
-		assert.Equal(t, config.ProjectId, production.ProjectId)
+		assert.Equal(t, "vpefcjyosynxeiebfscx", production.ProjectId)
 		assert.Equal(t, "http://feature-auth-branch.com/", production.Auth.SiteUrl)
 		assert.Equal(t, false, production.Auth.EnableSignup)
 		assert.Equal(t, false, production.Auth.External["azure"].Enabled)
@@ -96,7 +96,7 @@ func TestConfigParsing(t *testing.T) {
 		// Check seed should be disabled by default for remote configs
 		assert.Equal(t, false, production.Db.Seed.Enabled)
 		// Check the values for the staging override
-		assert.Equal(t, "staging-project", staging.ProjectId)
+		assert.Equal(t, "bvikqvbczudanvggcord", staging.ProjectId)
 		assert.Equal(t, []string{"image/png"}, staging.Storage.Buckets["images"].AllowedMimeTypes)
 		assert.Equal(t, true, staging.Db.Seed.Enabled)
 	})
@@ -214,7 +214,7 @@ func TestValidateHookURI(t *testing.T) {
 			hookConfig: hookConfig{
 				Enabled: true,
 				URI:     "http://example.com",
-				Secrets: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw==",
+				Secrets: Secret{Value: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw=="},
 			},
 		},
 		{
@@ -222,7 +222,7 @@ func TestValidateHookURI(t *testing.T) {
 			hookConfig: hookConfig{
 				Enabled: true,
 				URI:     "https://example.com",
-				Secrets: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw==",
+				Secrets: Secret{Value: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw=="},
 			},
 		},
 		{
@@ -237,7 +237,7 @@ func TestValidateHookURI(t *testing.T) {
 			hookConfig: hookConfig{
 				Enabled: true,
 				URI:     "ftp://example.com",
-				Secrets: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw==",
+				Secrets: Secret{Value: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw=="},
 			},
 			errorMsg: "Invalid hook config: auth.hook.invalid URI with unsupported scheme.uri should be a HTTP, HTTPS, or pg-functions URI",
 		},
@@ -246,7 +246,7 @@ func TestValidateHookURI(t *testing.T) {
 			hookConfig: hookConfig{
 				Enabled: true,
 				URI:     "http://a b.com",
-				Secrets: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw==",
+				Secrets: Secret{Value: "v1,whsec_aWxpa2VzdXBhYmFzZXZlcnltdWNoYW5kaWhvcGV5b3Vkb3Rvbw=="},
 			},
 			errorMsg: "failed to parse template url: parse \"http://a b.com\": invalid character \" \" in host name",
 		},
@@ -263,7 +263,7 @@ func TestValidateHookURI(t *testing.T) {
 			hookConfig: hookConfig{
 				Enabled: true,
 				URI:     "pg-functions://functionName",
-				Secrets: "test-secret",
+				Secrets: Secret{Value: "test-secret"},
 			},
 			errorMsg: "Invalid hook config: auth.hook.valid pg-functions URI with unsupported secrets.secrets is unsupported for pg-functions URI",
 		},
@@ -386,7 +386,7 @@ func TestLoadFunctionImportMap(t *testing.T) {
 		config := NewConfig()
 		fsys := fs.MapFS{
 			"supabase/config.toml": &fs.MapFile{Data: []byte(`
-			project_id = "test"
+			project_id = "bvikqvbczudanvggcord"
 			[functions.hello]
 			`)},
 			"supabase/functions/hello/deno.json": &fs.MapFile{},
@@ -402,7 +402,7 @@ func TestLoadFunctionImportMap(t *testing.T) {
 		config := NewConfig()
 		fsys := fs.MapFS{
 			"supabase/config.toml": &fs.MapFile{Data: []byte(`
-			project_id = "test"
+			project_id = "bvikqvbczudanvggcord"
 			[functions.hello]
 			`)},
 			"supabase/functions/hello/deno.jsonc": &fs.MapFile{},
@@ -410,7 +410,7 @@ func TestLoadFunctionImportMap(t *testing.T) {
 		}
 		// Run test
 		assert.NoError(t, config.Load("", fsys))
-		// Check that deno.json was set as import map
+		// Check that deno.jsonc was set as import map
 		assert.Equal(t, "supabase/functions/hello/deno.jsonc", config.Functions["hello"].ImportMap)
 	})
 
@@ -418,7 +418,7 @@ func TestLoadFunctionImportMap(t *testing.T) {
 		config := NewConfig()
 		fsys := fs.MapFS{
 			"supabase/config.toml": &fs.MapFile{Data: []byte(`
-			project_id = "test"
+			project_id = "bvikqvbczudanvggcord"
 			[functions]
 			hello.import_map = "custom_import_map.json"
 			`)},
diff --git a/pkg/config/secret_test.go b/pkg/config/secret_test.go
new file mode 100644
index 00000000..c4bf74e5
--- /dev/null
+++ b/pkg/config/secret_test.go
@@ -0,0 +1,52 @@
+package config
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestDecryptSecret(t *testing.T) {
+	key := "7fd7210cef8f331ee8c55897996aaaafd853a2b20a4dc73d6d75759f65d2a7eb"
+	value := "encrypted:BKiXH15AyRzeohGyUrmB6cGjSklCrrBjdesQlX1VcXo/Xp20Bi2gGZ3AlIqxPQDmjVAALnhZamKnuY73l8Dz1P+BYiZUgxTSLzdCvdYUyVbNekj2UudbdUizBViERtZkuQwZHIv/"
+
+	t.Run("decrypts secret value", func(t *testing.T) {
+		// Run test
+		plaintext, err := decrypt(key, value)
+		// Check error
+		assert.NoError(t, err)
+		assert.Equal(t, "value", plaintext)
+	})
+
+	t.Run("throws error on missing key", func(t *testing.T) {
+		// Run test
+		plaintext, err := decrypt("", value)
+		// Check error
+		assert.ErrorContains(t, err, "missing private key")
+		assert.Equal(t, value, plaintext)
+	})
+
+	t.Run("throws error on non-hex key", func(t *testing.T) {
+		// Run test
+		plaintext, err := decrypt("invalid", value)
+		// Check error
+		assert.ErrorContains(t, err, "failed to hex decode private key: cannot decode hex string")
+		assert.Equal(t, value, plaintext)
+	})
+
+	t.Run("throws error on non-base64 value", func(t *testing.T) {
+		// Run test
+		plaintext, err := decrypt(key, "encrypted:invalid")
+		// Check error
+		assert.ErrorContains(t, err, "failed to base64 decode secret: illegal base64 data at input byte 4")
+		assert.Equal(t, "encrypted:invalid", plaintext)
+	})
+
+	t.Run("throws error on empty ciphertext", func(t *testing.T) {
+		// Run test
+		plaintext, err := decrypt(key, "encrypted:")
+		// Check error
+		assert.ErrorContains(t, err, "failed to decrypt secret: invalid length of message")
+		assert.Equal(t, "encrypted:", plaintext)
+	})
+}
diff --git a/pkg/config/testdata/TestEmailDiff/local_enabled_remote_disabled.diff b/pkg/config/testdata/TestEmailDiff/local_enabled_remote_disabled.diff
index 85d30362..ad89a5d1 100644
--- a/pkg/config/testdata/TestEmailDiff/local_enabled_remote_disabled.diff
+++ b/pkg/config/testdata/TestEmailDiff/local_enabled_remote_disabled.diff
@@ -46,7 +46,7 @@ diff remote[auth] local[auth]
 -host = ""
 -port = 0
 -user = ""
--pass = "hash:"
+-pass = ""
 -admin_email = ""
 -sender_name = ""
 +host = "smtp.sendgrid.net"
diff --git a/pkg/config/testdata/TestExternalDiff/local_enabled_and_disabled.diff b/pkg/config/testdata/TestExternalDiff/local_enabled_and_disabled.diff
index 089d74ee..8b78fb24 100644
--- a/pkg/config/testdata/TestExternalDiff/local_enabled_and_disabled.diff
+++ b/pkg/config/testdata/TestExternalDiff/local_enabled_and_disabled.diff
@@ -16,7 +16,7 @@ diff remote[auth] local[auth]
  [external.azure]
 -enabled = false
 -client_id = ""
--secret = "hash:"
+-secret = ""
 +enabled = true
 +client_id = "test-client-1"
 +secret = "hash:ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252"
@@ -30,5 +30,5 @@ diff remote[auth] local[auth]
 -enabled = true
 +enabled = false
  client_id = "test-client-2"
- secret = "env(test_secret)"
+ secret = ""
  url = ""
diff --git a/pkg/config/testdata/TestHookDiff/local_disabled_remote_enabled.diff b/pkg/config/testdata/TestHookDiff/local_disabled_remote_enabled.diff
index c8cf4c5f..247618f0 100644
--- a/pkg/config/testdata/TestHookDiff/local_disabled_remote_enabled.diff
+++ b/pkg/config/testdata/TestHookDiff/local_disabled_remote_enabled.diff
@@ -18,7 +18,7 @@ diff remote[auth] local[auth]
 -enabled = true
 +enabled = false
  uri = "https://example.com"
- secrets = "test-secret"
+ secrets = ""
  [hook.send_email]
 -enabled = true
 +enabled = false
diff --git a/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff b/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff
index e5f26740..556b13ff 100644
--- a/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff
+++ b/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff
@@ -1,18 +1,18 @@
 diff remote[auth] local[auth]
 --- remote[auth]
 +++ local[auth]
-@@ -11,21 +11,21 @@
+@@ -11,20 +11,20 @@
  
  [hook]
  [hook.mfa_verification_attempt]
 -enabled = false
 +enabled = true
  uri = "pg-functions://postgres/public/verifyMFA"
- secrets = "hash:"
+ secrets = ""
  [hook.custom_access_token]
 -enabled = false
 -uri = "pg-functions://postgres/public/customToken"
--secrets = "hash:"
+-secrets = ""
 +enabled = true
 +uri = "http://example.com"
 +secrets = "hash:ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252"
@@ -24,10 +24,8 @@ diff remote[auth] local[auth]
  [hook.send_email]
 -enabled = false
 -uri = "https://example.com"
--secrets = "hash:ce62bb9bcced294fd4afe668f8ab3b50a89cf433093c526fffa3d0e46bf55252"
 +enabled = true
 +uri = "pg-functions://postgres/public/sendEmail"
-+secrets = "hash:"
+ secrets = ""
  
  [mfa]
- max_enrolled_factors = 0
diff --git a/pkg/config/testdata/TestSmsDiff/local_enabled_remote_disabled.diff b/pkg/config/testdata/TestSmsDiff/local_enabled_remote_disabled.diff
index 4418013b..02f0b76c 100644
--- a/pkg/config/testdata/TestSmsDiff/local_enabled_remote_disabled.diff
+++ b/pkg/config/testdata/TestSmsDiff/local_enabled_remote_disabled.diff
@@ -25,7 +25,7 @@ diff remote[auth] local[auth]
  [sms.messagebird]
 -enabled = false
 -originator = ""
--access_key = "hash:"
+-access_key = ""
 +enabled = true
 +originator = "test-originator"
 +access_key = "hash:ab60d03fc809fb02dae838582f3ddc13d1d6cb32ffba77c4b969dd3caa496f13"
diff --git a/pkg/config/testdata/config.toml b/pkg/config/testdata/config.toml
index 11362686..65705646 100644
--- a/pkg/config/testdata/config.toml
+++ b/pkg/config/testdata/config.toml
@@ -46,8 +46,8 @@ max_client_conn = 100
 # If enabled, seeds the database after migrations during a db reset.
 enabled = true
 # Specifies an ordered list of seed files to load during db reset.
-# Supports glob patterns relative to supabase directory: './seeds/*.sql'
-sql_paths = ['./seed.sql']
+# Supports glob patterns relative to supabase directory: "./seeds/*.sql"
+sql_paths = ["./seed.sql"]
 
 [realtime]
 enabled = true
@@ -251,6 +251,9 @@ s3_access_key = ""
 # Configures AWS_SECRET_ACCESS_KEY for S3 bucket
 s3_secret_key = ""
 
+[remotes.production]
+project_id = "vpefcjyosynxeiebfscx"
+
 [remotes.production.auth]
 site_url = "http://feature-auth-branch.com/"
 enable_signup = false
@@ -260,7 +263,7 @@ enabled = false
 client_id = "nope"
 
 [remotes.staging]
-project_id = "staging-project"
+project_id = "bvikqvbczudanvggcord"
 
 [remotes.staging.db.seed]
 enabled = true
diff --git a/pkg/storage/objects_test.go b/pkg/storage/objects_test.go
new file mode 100644
index 00000000..a2e132a9
--- /dev/null
+++ b/pkg/storage/objects_test.go
@@ -0,0 +1,92 @@
+package storage
+
+import (
+	"context"
+	"mime"
+	"net/http"
+	"testing"
+	fs "testing/fstest"
+
+	"github.com/h2non/gock"
+	"github.com/stretchr/testify/assert"
+	"github.com/supabase/cli/internal/testing/apitest"
+	"github.com/supabase/cli/pkg/fetcher"
+)
+
+var mockApi = StorageAPI{Fetcher: fetcher.NewFetcher(
+	"http://127.0.0.1",
+)}
+
+func TestParseFileOptionsContentTypeDetection(t *testing.T) {
+	tests := []struct {
+		name          string
+		content       []byte
+		filename      string
+		opts          []func(*FileOptions)
+		wantMimeType  string
+		wantCacheCtrl string
+	}{
+		{
+			name:          "detects PNG image",
+			content:       []byte{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}, // PNG header
+			filename:      "test.image",
+			wantMimeType:  "image/png",
+			wantCacheCtrl: "max-age=3600",
+		},
+		{
+			name:          "detects JavaScript file",
+			content:       []byte("const hello = () => console.log('Hello, World!');"),
+			filename:      "script.js",
+			wantMimeType:  mime.TypeByExtension(".js"),
+			wantCacheCtrl: "max-age=3600",
+		},
+		{
+			name:          "detects CSS file",
+			content:       []byte(".header { color: #333; font-size: 16px; }"),
+			filename:      "styles.css",
+			wantMimeType:  mime.TypeByExtension(".css"),
+			wantCacheCtrl: "max-age=3600",
+		},
+		{
+			name:          "detects SQL file",
+			content:       []byte("SELECT * FROM users WHERE id = 1;"),
+			filename:      "query.sql",
+			wantMimeType:  mime.TypeByExtension(".sql"),
+			wantCacheCtrl: "max-age=3600",
+		},
+		{
+			name:          "use text/plain as fallback for unrecognized extensions",
+			content:       []byte("const hello = () => console.log('Hello, World!');"),
+			filename:      "main.nonexistent",
+			wantMimeType:  "text/plain; charset=utf-8",
+			wantCacheCtrl: "max-age=3600",
+		},
+		{
+			name:          "respects custom content type",
+			content:       []byte("const hello = () => console.log('Hello, World!');"),
+			filename:      "custom.js",
+			wantMimeType:  "application/custom",
+			wantCacheCtrl: "max-age=3600",
+			opts:          []func(*FileOptions){func(fo *FileOptions) { fo.ContentType = "application/custom" }},
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			// Create a temporary file with test content
+			fsys := fs.MapFS{tt.filename: &fs.MapFile{Data: tt.content}}
+			// Setup mock api
+			defer gock.OffAll()
+			gock.New("http://127.0.0.1").
+				Post("/storage/v1/object/"+tt.filename).
+				MatchHeader("Content-Type", tt.wantMimeType).
+				MatchHeader("Cache-Control", tt.wantCacheCtrl).
+				Reply(http.StatusOK)
+			// Parse options
+			err := mockApi.UploadObject(context.Background(), tt.filename, tt.filename, fsys, tt.opts...)
+			// Assert results
+			assert.NoError(t, err)
+			assert.Empty(t, apitest.ListUnmatchedRequests())
+		})
+	}
+}