From 7a513e346ab55ad2e3a90a8675445121b66c3761 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Wed, 1 Jan 2025 21:10:01 +0800 Subject: [PATCH 01/34] fix: resolve file paths in remote config (#3002) * Update config.go * Update config.go * Update config.go * Update config.go * Update config.go * Update config.go * Update config.go --- pkg/config/config.go | 85 +++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 37 deletions(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index 5c7fc0946..6903b6b24 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -492,6 +492,53 @@ 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)) } + // Resolve remote config, then base config + 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.resolve(builder, fsys); err != nil { + return err + } + c.Remotes[name] = base + } + if err := c.baseConfig.resolve(builder, fsys); err != nil { + return err + } + // Validate base config, then remote config + if err := c.baseConfig.Validate(fsys); err != nil { + return err + } + for name, base := range c.Remotes { + if err := base.Validate(fsys); err != nil { + return errors.Errorf("invalid config for [remotes.%s]: %w", name, err) + } + } + return nil +} + +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,43 +581,7 @@ 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 { From d412bc065811ec6a61951063203b82b7fa73cafc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 2 Jan 2025 04:09:20 +0000 Subject: [PATCH 02/34] chore(deps): bump github.com/golangci/golangci-lint from 1.62.2 to 1.63.1 (#3004) chore(deps): bump github.com/golangci/golangci-lint Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.62.2 to 1.63.1. - [Release notes](https://github.com/golangci/golangci-lint/releases) - [Changelog](https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md) - [Commits](https://github.com/golangci/golangci-lint/compare/v1.62.2...v1.63.1) --- updated-dependencies: - dependency-name: github.com/golangci/golangci-lint dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 69 +++++++++++++----------- go.sum | 167 ++++++++++++++++++++++++++++++++------------------------- 2 files changed, 130 insertions(+), 106 deletions(-) diff --git a/go.mod b/go.mod index 77f62b252..89f024e3c 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/go-git/go-git/v5 v5.13.0 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.1 github.com/google/go-github/v62 v62.0.0 github.com/google/go-querystring v1.1.0 github.com/google/uuid v1.6.0 @@ -60,10 +60,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 +74,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 +89,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,19 +101,19 @@ 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/curioswitch/go-reassign v0.3.0 // indirect github.com/cyphar/filepath-securejoin v0.3.4 // 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/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 @@ -152,9 +153,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 +170,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 +184,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 +197,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.0 // 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.1 // 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 @@ -228,7 +233,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 @@ -247,7 +252,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 +260,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 +276,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 @@ -321,7 +326,7 @@ require ( golang.org/x/sync v0.10.0 // indirect golang.org/x/sys v0.28.0 // indirect golang.org/x/text v0.21.0 // indirect - golang.org/x/tools v0.27.0 // indirect + golang.org/x/tools v0.28.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 diff --git a/go.sum b/go.sum index 6195b3eac..d71db5ed3 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,8 +203,8 @@ 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/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.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8= github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM= github.com/daixiang0/gci v0.13.5 h1:kThgmH1yBmZSBCh1EJVxQ7JsHpm5Oms0AMed/0LaH4c= @@ -220,8 +222,8 @@ 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= @@ -399,14 +401,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.1 h1:fr7zu2W0qexDkTvYwtdrsYJwYIx+tS09ujM1CIjIpCQ= +github.com/golangci/golangci-lint v1.63.1/go.mod h1:O2+mo4qsJuG4cSXBzLbEV+5NAtntoNIbAv428zaEY/s= 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 +476,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 +486,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 +571,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 +589,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 +623,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.0 h1:iKdMtUedzov89jDvuwmo0qpo+ARpZJg9hMp3428WwNg= +github.com/ldez/exptostd v0.3.0/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.1 h1:T/4Bk3YDX6XUBtdNDDFymlr5GBekKA4j7HUtrv1YaaI= +github.com/ldez/usetesting v0.4.1/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= @@ -718,8 +730,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= @@ -807,8 +819,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 +844,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= @@ -892,8 +904,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 +928,34 @@ 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/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,6 +1068,7 @@ 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= @@ -1099,7 +1112,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 +1119,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 +1165,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= @@ -1181,6 +1196,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 +1241,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,6 +1263,7 @@ 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= @@ -1261,9 +1277,11 @@ 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= @@ -1279,6 +1297,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= @@ -1344,23 +1363,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= From 37438c4c291ef97ea49bd4569fa8b3d07857a81b Mon Sep 17 00:00:00 2001 From: Qiao Han Date: Thu, 2 Jan 2025 13:18:28 +0800 Subject: [PATCH 03/34] fix: assume platform defaults when local sms keys are unset --- pkg/config/auth.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/pkg/config/auth.go b/pkg/config/auth.go index b2e6b0fa6..d0d41aa43 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -542,25 +542,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) > 0 { + body.SmsTwilioAuthToken = &s.Twilio.AuthToken + } 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) > 0 { + body.SmsTwilioVerifyAuthToken = &s.TwilioVerify.AuthToken + } 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) > 0 { + body.SmsMessagebirdAccessKey = &s.Messagebird.AccessKey + } body.SmsMessagebirdOriginator = &s.Messagebird.Originator case s.Textlocal.Enabled: body.SmsProvider = cast.Ptr("textlocal") - body.SmsTextlocalApiKey = &s.Textlocal.ApiKey + if len(s.Textlocal.ApiKey) > 0 { + body.SmsTextlocalApiKey = &s.Textlocal.ApiKey + } body.SmsTextlocalSender = &s.Textlocal.Sender case s.Vonage.Enabled: body.SmsProvider = cast.Ptr("vonage") - body.SmsVonageApiSecret = &s.Vonage.ApiSecret + if len(s.Vonage.ApiSecret) > 0 { + body.SmsVonageApiSecret = &s.Vonage.ApiSecret + } body.SmsVonageApiKey = &s.Vonage.ApiKey body.SmsVonageFrom = &s.Vonage.From } From 185ec6e732490fcce5d30517aa6f469dd9401d91 Mon Sep 17 00:00:00 2001 From: Qiao Han Date: Thu, 2 Jan 2025 15:52:48 +0800 Subject: [PATCH 04/34] chore: use double quote consistently --- pkg/config/templates/config.toml | 4 ++-- pkg/config/testdata/config.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/config/templates/config.toml b/pkg/config/templates/config.toml index 5345f4d0d..6c50b1447 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/testdata/config.toml b/pkg/config/testdata/config.toml index 113626868..e3093924a 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 From 0bf473b3695cc8f3d0db71ee19c26c0ca727b13f Mon Sep 17 00:00:00 2001 From: Monica Date: Thu, 2 Jan 2025 12:59:40 +0200 Subject: [PATCH 05/34] fix: bump gotrue to 2.166.0 --- pkg/config/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/constants.go b/pkg/config/constants.go index 200c16da8..aedecd659 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -15,7 +15,7 @@ const ( edgeRuntimeImage = "supabase/edge-runtime:v1.66.1" vectorImage = "timberio/vector:0.28.1-alpine" supavisorImage = "supabase/supavisor:1.1.56" - gotrueImage = "supabase/gotrue:v2.164.0" + gotrueImage = "supabase/gotrue:v2.166.0" realtimeImage = "supabase/realtime:v2.33.70" storageImage = "supabase/storage-api:v1.14.5" logflareImage = "supabase/logflare:1.4.0" From d10322d8144846dab2228375285e902434e2b23c Mon Sep 17 00:00:00 2001 From: Monica Date: Thu, 2 Jan 2025 13:22:49 +0200 Subject: [PATCH 06/34] bump to the latest version v2.167.0 --- pkg/config/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/constants.go b/pkg/config/constants.go index aedecd659..d86112ea4 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -15,7 +15,7 @@ const ( edgeRuntimeImage = "supabase/edge-runtime:v1.66.1" vectorImage = "timberio/vector:0.28.1-alpine" supavisorImage = "supabase/supavisor:1.1.56" - gotrueImage = "supabase/gotrue:v2.166.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" From b36952eecc90171a7c98980b21b12fea583e079c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 04:39:26 +0000 Subject: [PATCH 07/34] chore(deps): bump github.com/go-git/go-git/v5 from 5.13.0 to 5.13.1 (#3008) Bumps [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) from 5.13.0 to 5.13.1. - [Release notes](https://github.com/go-git/go-git/releases) - [Commits](https://github.com/go-git/go-git/compare/v5.13.0...v5.13.1) --- updated-dependencies: - dependency-name: github.com/go-git/go-git/v5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 89f024e3c..e129eb761 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/docker/go-units v0.5.0 github.com/getsentry/sentry-go v0.30.0 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.63.1 @@ -107,7 +107,7 @@ require ( github.com/containerd/log v0.1.0 // indirect github.com/containers/storage v1.56.0 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect - github.com/cyphar/filepath-securejoin v0.3.4 // 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 @@ -132,7 +132,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 diff --git a/go.sum b/go.sum index d71db5ed3..c71759c65 100644 --- a/go.sum +++ b/go.sum @@ -205,8 +205,8 @@ 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.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.4 h1:VBWugsJh2ZxJmLFSM06/0qzQyiQX2Qs0ViKrUAcqdZ8= -github.com/cyphar/filepath-securejoin v0.3.4/go.mod h1:8s/MCNJREmFK0H02MF6Ihv1nakJe4L/w3WZLHNkvlYM= +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= @@ -248,8 +248,8 @@ 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/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= @@ -293,12 +293,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= From f4a59ab63974ddca1638556f2f9357b6204fe47b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 04:44:18 +0000 Subject: [PATCH 08/34] chore(deps): bump github.com/golangci/golangci-lint from 1.63.1 to 1.63.3 (#3009) chore(deps): bump github.com/golangci/golangci-lint Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.63.1 to 1.63.3. - [Release notes](https://github.com/golangci/golangci-lint/releases) - [Changelog](https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md) - [Commits](https://github.com/golangci/golangci-lint/compare/v1.63.1...v1.63.3) --- updated-dependencies: - dependency-name: github.com/golangci/golangci-lint dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index e129eb761..301390179 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( 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.63.1 + github.com/golangci/golangci-lint v1.63.3 github.com/google/go-github/v62 v62.0.0 github.com/google/go-querystring v1.1.0 github.com/google/uuid v1.6.0 @@ -197,11 +197,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/exptostd v0.3.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.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 diff --git a/go.sum b/go.sum index c71759c65..0cf38017a 100644 --- a/go.sum +++ b/go.sum @@ -403,8 +403,8 @@ github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUP github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= 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.1 h1:fr7zu2W0qexDkTvYwtdrsYJwYIx+tS09ujM1CIjIpCQ= -github.com/golangci/golangci-lint v1.63.1/go.mod h1:O2+mo4qsJuG4cSXBzLbEV+5NAtntoNIbAv428zaEY/s= +github.com/golangci/golangci-lint v1.63.3 h1:Q/UZqLRuqo3mmwA/EN2pq9y+JV4S2IqmqrS3t855ZMc= +github.com/golangci/golangci-lint v1.63.3/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/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= @@ -623,16 +623,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/exptostd v0.3.0 h1:iKdMtUedzov89jDvuwmo0qpo+ARpZJg9hMp3428WwNg= -github.com/ldez/exptostd v0.3.0/go.mod h1:iZBRYaUmcW5jwCR3KROEZ1KivQQp6PHXbDPk9hqJKCQ= +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.1 h1:T/4Bk3YDX6XUBtdNDDFymlr5GBekKA4j7HUtrv1YaaI= -github.com/ldez/usetesting v0.4.1/go.mod h1:eEs46T3PpQ+9RgN9VjpY6qWdiw2/QmfiDeWmdZdrjIQ= +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= From 8b8a876fd1c6ce22549b30859b129408b05d29c0 Mon Sep 17 00:00:00 2001 From: Nyannyacha Date: Fri, 3 Jan 2025 14:51:57 +0900 Subject: [PATCH 09/34] fix: bump edge-runtime to 1.66.2 --- pkg/config/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/constants.go b/pkg/config/constants.go index d86112ea4..fb6bdd51b 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -12,7 +12,7 @@ const ( pgmetaImage = "supabase/postgres-meta:v0.84.2" studioImage = "supabase/studio:20241202-71e5240" imageProxyImage = "darthsim/imgproxy:v3.8.0" - edgeRuntimeImage = "supabase/edge-runtime:v1.66.1" + edgeRuntimeImage = "supabase/edge-runtime:v1.66.2" vectorImage = "timberio/vector:0.28.1-alpine" supavisorImage = "supabase/supavisor:1.1.56" gotrueImage = "supabase/gotrue:v2.167.0" From 7c9f8c9a66781332544676c9c46d402941e629b6 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Fri, 3 Jan 2025 17:21:10 +0800 Subject: [PATCH 10/34] fix: ignore hash if local secret is unset (#3012) * fix: ignore hash if local secret is unset * chore: update unit tests --- pkg/config/auth.go | 40 ++++++++++++++----- .../local_enabled_remote_disabled.diff | 6 +-- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/pkg/config/auth.go b/pkg/config/auth.go index d0d41aa43..b93123bd2 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -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 hook.Secrets != hashPrefix { + hook.Secrets = hashPrefix + 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 hook.Secrets != hashPrefix { + hook.Secrets = hashPrefix + 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 hook.Secrets != hashPrefix { + hook.Secrets = hashPrefix + 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 hook.Secrets != hashPrefix { + hook.Secrets = hashPrefix + 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 hook.Secrets != hashPrefix { + hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookPasswordVerificationAttemptSecrets, "") + } } hook.Enabled = cast.Val(remoteConfig.HookPasswordVerificationAttemptEnabled, false) } @@ -585,21 +595,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 s.Twilio.AuthToken != hashPrefix { + s.Twilio.AuthToken = hashPrefix + 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 s.TwilioVerify.AuthToken != hashPrefix { + s.TwilioVerify.AuthToken = hashPrefix + 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 s.Messagebird.AccessKey != hashPrefix { + s.Messagebird.AccessKey = hashPrefix + cast.Val(remoteConfig.SmsMessagebirdAccessKey, "") + } s.Messagebird.Originator = cast.Val(remoteConfig.SmsMessagebirdOriginator, "") case s.Textlocal.Enabled: - s.Textlocal.ApiKey = hashPrefix + cast.Val(remoteConfig.SmsTextlocalApiKey, "") + if s.Textlocal.ApiKey != hashPrefix { + s.Textlocal.ApiKey = hashPrefix + cast.Val(remoteConfig.SmsTextlocalApiKey, "") + } s.Textlocal.Sender = cast.Val(remoteConfig.SmsTextlocalSender, "") case s.Vonage.Enabled: - s.Vonage.ApiSecret = hashPrefix + cast.Val(remoteConfig.SmsVonageApiSecret, "") + if s.Vonage.ApiSecret != hashPrefix { + s.Vonage.ApiSecret = hashPrefix + cast.Val(remoteConfig.SmsVonageApiSecret, "") + } s.Vonage.ApiKey = cast.Val(remoteConfig.SmsVonageApiKey, "") s.Vonage.From = cast.Val(remoteConfig.SmsVonageFrom, "") case !s.EnableSignup: diff --git a/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff b/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff index e5f26740e..dc80e57a3 100644 --- a/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff +++ b/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff @@ -1,7 +1,7 @@ diff remote[auth] local[auth] --- remote[auth] +++ local[auth] -@@ -11,21 +11,21 @@ +@@ -11,20 +11,20 @@ [hook] [hook.mfa_verification_attempt] @@ -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 = "hash:" [mfa] - max_enrolled_factors = 0 From 2cca98ceed8e699a172e4cf5d54263141fb00654 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 3 Jan 2025 17:52:40 +0800 Subject: [PATCH 11/34] chore(deps): bump github.com/getsentry/sentry-go from 0.30.0 to 0.31.1 (#3010) Bumps [github.com/getsentry/sentry-go](https://github.com/getsentry/sentry-go) from 0.30.0 to 0.31.1. - [Release notes](https://github.com/getsentry/sentry-go/releases) - [Changelog](https://github.com/getsentry/sentry-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/getsentry/sentry-go/compare/v0.30.0...v0.31.1) --- updated-dependencies: - dependency-name: github.com/getsentry/sentry-go dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Han Qiao --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 301390179..2a7b49ac3 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/docker/docker v27.4.1+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/getsentry/sentry-go v0.31.1 github.com/go-errors/errors v1.5.1 github.com/go-git/go-git/v5 v5.13.1 github.com/go-xmlfmt/xmlfmt v1.1.3 diff --git a/go.sum b/go.sum index 0cf38017a..9b19db7e3 100644 --- a/go.sum +++ b/go.sum @@ -281,8 +281,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= From 1bdc4efa6789af5bbbf6b478ac59d066c1c42e2c Mon Sep 17 00:00:00 2001 From: Yaten Dhingra <129659514+yaten2302@users.noreply.github.com> Date: Sun, 5 Jan 2025 16:02:38 +0530 Subject: [PATCH 12/34] fix: obtain Postgres URL from branches get command (#2996) * fix:2964/obtain Postgres DB URL from ENV using branches get command Signed-off-by: Yaten Dhingra * added --output-env flag in branches get command Signed-off-by: Yaten Dhingra * fixed typo in internal/branches/get/get.go Signed-off-by: Yaten Dhingra * updated the output-env flag in branches.go Signed-off-by: Yaten Dhingra * changed output var to postgres_url var in branches.go Signed-off-by: Yaten Dhingra * changed postgres_url to output Signed-off-by: Yaten Dhingra * changed checks condition from env to utils.OutputEnv Signed-off-by: Yaten Dhingra * remove cmdFlags condition in cmd/branches.go Co-authored-by: Han Qiao * remove cmdFlags in cmd/branches.go Co-authored-by: Han Qiao * remove pgconn.Config{} param in get.Run() Co-authored-by: Han Qiao * remove unused import in cmd/branches.go Co-authored-by: Han Qiao * get DB URL from utils.GetSupabaseDbHost(...) Signed-off-by: Yaten Dhingra * revert to prev table render structure Signed-off-by: Yaten Dhingra * update get.go Signed-off-by: Yaten Dhingra * added postgres connection string Signed-off-by: Yaten Dhingra * removed GetPostgresURLNonPooling func from bootstrap.go Signed-off-by: Yaten Dhingra * remove vars which are not required Signed-off-by: Yaten Dhingra * minor changes in get.go & branches.go Signed-off-by: Yaten Dhingra * convert port from int to uint Signed-off-by: Yaten Dhingra * attempt to fix linter errors Signed-off-by: Yaten Dhingra * attempt to fix uint->uint16 linter error Signed-off-by: Yaten Dhingra * fixed uint->uint16 overflow error Signed-off-by: Yaten Dhingra --------- Signed-off-by: Yaten Dhingra Co-authored-by: Han Qiao --- cmd/branches.go | 4 +++- internal/branches/get/get.go | 29 +++++++++++++++++++++++++---- pkg/cast/cast.go | 8 ++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/cmd/branches.go b/cmd/branches.go index 0248e7f31..b541704bf 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/internal/branches/get/get.go b/internal/branches/get/get.go index ee5bc332c..22f3274e7 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/pkg/cast/cast.go b/pkg/cast/cast.go index 621ae9a61..89840c895 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 { From e93f6fe66d39dda0c3176f909bd65d8aea7eb91a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 04:13:55 +0000 Subject: [PATCH 13/34] chore(deps): bump github.com/golangci/golangci-lint from 1.63.3 to 1.63.4 (#3018) chore(deps): bump github.com/golangci/golangci-lint Bumps [github.com/golangci/golangci-lint](https://github.com/golangci/golangci-lint) from 1.63.3 to 1.63.4. - [Release notes](https://github.com/golangci/golangci-lint/releases) - [Changelog](https://github.com/golangci/golangci-lint/blob/master/CHANGELOG.md) - [Commits](https://github.com/golangci/golangci-lint/compare/v1.63.3...v1.63.4) --- updated-dependencies: - dependency-name: github.com/golangci/golangci-lint dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 2a7b49ac3..8a039b40e 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( 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.63.3 + 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 diff --git a/go.sum b/go.sum index 9b19db7e3..221a9a558 100644 --- a/go.sum +++ b/go.sum @@ -403,8 +403,8 @@ github.com/golangci/go-printf-func-name v0.1.0 h1:dVokQP+NMTO7jwO4bwsRwLWeudOVUP github.com/golangci/go-printf-func-name v0.1.0/go.mod h1:wqhWFH5mUdJQhweRnldEywnR5021wTdZSNgwYceV14s= 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.3 h1:Q/UZqLRuqo3mmwA/EN2pq9y+JV4S2IqmqrS3t855ZMc= -github.com/golangci/golangci-lint v1.63.3/go.mod h1:Hx0B7Lg5/NXbaOHem8+KU+ZUIzMI6zNj/7tFwdnn10I= +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/plugin-module-register v0.1.1 h1:TCmesur25LnyJkpsVrupv1Cdzo+2f7zX0H6Jkw1Ol6c= From 7b4a96844cf6262c4f4f6d5240b0554f1e58643b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 12:43:29 +0800 Subject: [PATCH 14/34] chore(deps): bump golang.org/x/term from 0.27.0 to 0.28.0 (#3017) --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 8a039b40e..0e1a0ae0a 100644 --- a/go.mod +++ b/go.mod @@ -49,7 +49,7 @@ require ( 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 + golang.org/x/term v0.28.0 google.golang.org/grpc v1.69.2 gopkg.in/yaml.v3 v3.0.1 gotest.tools/gotestsum v1.12.0 @@ -324,7 +324,7 @@ require ( 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.28.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241015192408-796eee8c2d53 // indirect diff --git a/go.sum b/go.sum index 221a9a558..947e58501 100644 --- a/go.sum +++ b/go.sum @@ -1267,8 +1267,8 @@ 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= @@ -1284,8 +1284,8 @@ 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= From 96de7636320be74c61b489c9112fc5b0ad655bff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:12:48 +0800 Subject: [PATCH 15/34] chore(deps): bump golang.org/x/oauth2 from 0.24.0 to 0.25.0 (#3016) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0e1a0ae0a..62b544b34 100644 --- a/go.mod +++ b/go.mod @@ -48,7 +48,7 @@ require ( 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/oauth2 v0.25.0 golang.org/x/term v0.28.0 google.golang.org/grpc v1.69.2 gopkg.in/yaml.v3 v3.0.1 diff --git a/go.sum b/go.sum index 947e58501..8b6bf5eda 100644 --- a/go.sum +++ b/go.sum @@ -1180,8 +1180,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= From 8e17f033bc6bd7b5e0bf0dd3336affd87844a79f Mon Sep 17 00:00:00 2001 From: Lakshan Perera Date: Tue, 7 Jan 2025 10:50:46 +1100 Subject: [PATCH 16/34] fix: pass NPM_CONFIG_REGISTRY env variable when bundling functions --- internal/functions/deploy/bundle.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/internal/functions/deploy/bundle.go b/internal/functions/deploy/bundle.go index 0119a559c..02f31863f 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), }, From 805dcd08c6a7c95a2e6da96a6e4bf10f42a29dbd Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Tue, 7 Jan 2025 13:21:00 +0800 Subject: [PATCH 17/34] feat: support restoring local db from backup (#3015) --- cmd/db.go | 6 +- internal/db/start/start.go | 42 ++++- internal/db/start/start_test.go | 16 +- internal/db/start/templates/restore.sh | 41 +++++ internal/db/start/templates/schema.sql | 233 ------------------------ internal/db/start/templates/webhook.sql | 232 +++++++++++++++++++++++ internal/start/start.go | 2 +- 7 files changed, 325 insertions(+), 247 deletions(-) create mode 100755 internal/db/start/templates/restore.sh create mode 100644 internal/db/start/templates/webhook.sql diff --git a/cmd/db.go b/cmd/db.go index 13f29401f..bcc7ac5e7 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/internal/db/start/start.go b/internal/db/start/start.go index c4722f22f..aa8b9cee5 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" @@ -29,11 +30,15 @@ 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 { +func Run(ctx context.Context, fromBackup string, fsys afero.Fs) error { if err := utils.LoadConfigFS(fsys); err != nil { return err } @@ -43,7 +48,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 +91,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 +122,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 +143,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 +182,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/start_test.go b/internal/db/start/start_test.go index 475562f2f..afdb8e28b 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/db/start/templates/restore.sh b/internal/db/start/templates/restore.sh new file mode 100755 index 000000000..26f6418e3 --- /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 534dd1207..810d9506e 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 000000000..52cd09747 --- /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/start/start.go b/internal/start/start.go index f5a24d8c4..c3684c14b 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -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 } } From 1b58c87b51c3d1399ba6e0220eb59da3a067cbbf Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Wed, 8 Jan 2025 13:24:29 +0800 Subject: [PATCH 18/34] feat: support env loading for all string fields (#3019) * feat: support env loading for all string fields * chore: update unit tests * chore: assert env loaded for backwards compatibility --- internal/db/branch/switch_/switch__test.go | 2 +- internal/start/start_test.go | 2 +- internal/status/status_test.go | 2 +- pkg/config/config.go | 176 +++++++++++++-------- 4 files changed, 113 insertions(+), 69 deletions(-) diff --git a/internal/db/branch/switch_/switch__test.go b/internal/db/branch/switch_/switch__test.go index 7c70959ce..722229b79 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/start/start_test.go b/internal/start/start_test.go index 6d07eb364..bbd73ab93 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 391a8c998..175d28ca0 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/config.go b/pkg/config/config.go index 6903b6b24..35b84eb68 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -16,6 +16,7 @@ import ( "os" "path" "path/filepath" + "reflect" "regexp" "sort" "strconv" @@ -378,9 +379,64 @@ 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) + } + // 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, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToIPHookFunc(), + mapstructure.StringToSliceHookFunc(","), + mapstructure.TextUnmarshallerHookFunc(), + LoadEnvHook, + // TODO: include decrypt secret hook + )), func(dc *mapstructure.DecoderConfig) { + dc.TagName = "toml" + dc.Squash = true + }); err != nil { + return errors.Errorf("failed to parse config: %w", err) + } + return nil +} + +// 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 +445,32 @@ 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) - } - 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) + } else if err := v.MergeConfigMap(envKeysMap); err != nil { + return errors.Errorf("failed to merge env config: %w", err) + } + // Writes viper state back to config struct, with automatic env substitution + if err := v.UnmarshalExact(c, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( + mapstructure.StringToTimeDurationHookFunc(), + mapstructure.StringToIPHookFunc(), + mapstructure.StringToSliceHookFunc(","), + mapstructure.TextUnmarshallerHookFunc(), + // TODO: include decrypt secret hook + ))); 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 @@ -619,17 +660,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 } } @@ -666,7 +706,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 { @@ -679,12 +718,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) } } @@ -749,18 +787,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 || t != 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 v, exists := os.LookupEnv(matches[1]); exists { + value = v + } + } + return value, nil } func truncateText(text string, maxLen int) string { @@ -874,7 +918,7 @@ func (e *email) validate(fsys fs.FS) (err error) { 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); err != nil { return err } } @@ -893,7 +937,7 @@ func (s *sms) validate() (err error) { if len(s.Twilio.AuthToken) == 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); err != nil { return err } case s.TwilioVerify.Enabled: @@ -906,7 +950,7 @@ func (s *sms) validate() (err error) { if len(s.TwilioVerify.AuthToken) == 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); err != nil { return err } case s.Messagebird.Enabled: @@ -916,7 +960,7 @@ func (s *sms) validate() (err error) { if len(s.Messagebird.AccessKey) == 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); err != nil { return err } case s.Textlocal.Enabled: @@ -926,7 +970,7 @@ func (s *sms) validate() (err error) { if len(s.Textlocal.ApiKey) == 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); err != nil { return err } case s.Vonage.Enabled: @@ -939,10 +983,10 @@ func (s *sms) validate() (err error) { if len(s.Vonage.ApiSecret) == 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); err != nil { return err } case s.EnableSignup: @@ -969,16 +1013,16 @@ func (e external) validate() (err error) { if !sliceContains([]string{"apple", "google"}, ext) && provider.Secret == "" { 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); 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 @@ -1033,7 +1077,7 @@ func (h *hookConfig) validate(hookType string) (err error) { case "http", "https": if len(h.Secrets) == 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); err != nil { return err } for _, secret := range strings.Split(h.Secrets, "|") { @@ -1119,13 +1163,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 } From 89df6b9538d06f5fad6511c80d27e8d766015a3c Mon Sep 17 00:00:00 2001 From: Andrew Valleteau Date: Wed, 8 Jan 2025 18:26:26 +0900 Subject: [PATCH 19/34] fix(edge-functions): add warning for edge-functions configuration (#2984) * feat(functions): auto add deno.jsonc and .npmrc to new functions * feat(deploy): add warning for functions imports structure * Update internal/functions/new/templates/.npmrc Co-authored-by: Han Qiao * fix: function prototype --------- Co-authored-by: Han Qiao --- internal/functions/deploy/deploy.go | 14 +++++++ internal/functions/new/new.go | 41 +++++++++++++++------ internal/functions/new/new_test.go | 10 +++++ internal/functions/new/templates/.npmrc | 3 ++ internal/functions/new/templates/deno.jsonc | 6 +++ 5 files changed, 62 insertions(+), 12 deletions(-) create mode 100644 internal/functions/new/templates/.npmrc create mode 100644 internal/functions/new/templates/deno.jsonc diff --git a/internal/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go index 529b78976..5ee2ae845 100644 --- a/internal/functions/deploy/deploy.go +++ b/internal/functions/deploy/deploy.go @@ -71,6 +71,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 { @@ -94,12 +96,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 +114,12 @@ 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.jsonc):", 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/new/new.go b/internal/functions/new/new.go index 3656e9b5f..f787ce90c 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -15,8 +15,13 @@ import ( var ( //go:embed templates/index.ts - indexEmbed string - indexTemplate = template.Must(template.New("indexl").Parse(indexEmbed)) + indexEmbed string + //go:embed templates/deno.jsonc + denoEmbed string + //go:embed templates/.npmrc + npmrcEmbed string + + indexTemplate = template.Must(template.New("index").Parse(indexEmbed)) ) type indexConfig struct { @@ -38,25 +43,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 + + // Load config if available if err := utils.LoadConfigFS(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.jsonc"), []byte(denoEmbed), 0644); err != nil { + return errors.Errorf("failed to create deno.jsonc 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/new_test.go b/internal/functions/new/new_test.go index d5e9c2fc8..56a24f705 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.jsonc exists + denoPath := filepath.Join(utils.FunctionsDir, "test-func", "deno.jsonc") + _, err = afero.ReadFile(fsys, denoPath) + assert.NoError(t, err, "deno.jsonc 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/functions/new/templates/.npmrc b/internal/functions/new/templates/.npmrc new file mode 100644 index 000000000..48c638863 --- /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.jsonc b/internal/functions/new/templates/deno.jsonc new file mode 100644 index 000000000..97275ba5e --- /dev/null +++ b/internal/functions/new/templates/deno.jsonc @@ -0,0 +1,6 @@ +{ + "imports": { + // Add your dependencies here + // See: https://supabase.com/docs/guides/functions/import-maps#using-denojson-recommended + } +} From b0c7523b455beae9f8503a7cd785824fccb49d68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=83=A5=EB=83=90=EC=B1=A0?= Date: Thu, 9 Jan 2025 14:05:14 +0900 Subject: [PATCH 20/34] fix: bump edge-runtime to 1.66.3 (#3025) --- pkg/config/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/constants.go b/pkg/config/constants.go index fb6bdd51b..e39d799a9 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -12,7 +12,7 @@ const ( pgmetaImage = "supabase/postgres-meta:v0.84.2" studioImage = "supabase/studio:20241202-71e5240" imageProxyImage = "darthsim/imgproxy:v3.8.0" - edgeRuntimeImage = "supabase/edge-runtime:v1.66.2" + edgeRuntimeImage = "supabase/edge-runtime:v1.66.3" vectorImage = "timberio/vector:0.28.1-alpine" supavisorImage = "supabase/supavisor:1.1.56" gotrueImage = "supabase/gotrue:v2.167.0" From 3429667d5775884831784cc7a510abd907d32d7c Mon Sep 17 00:00:00 2001 From: Andrew Valleteau Date: Thu, 9 Jan 2025 19:04:47 +0900 Subject: [PATCH 21/34] feat(storage): autodetect narrow down text/plain contentype (#3022) * feat(storage): autodetect narrow down text/plain contentype based on extension - Add content type detection for JavaScript (text/javascript) - Add content type detection for CSS (text/css) - Add content type detection for SQL (application/x-sql) - Default to text/plain for unrecognized text files like .go * fix: tests for cross platform run * chore: reuse upload object method --------- Co-authored-by: Qiao Han --- internal/storage/cp/cp.go | 6 +-- pkg/storage/batch.go | 14 ++---- pkg/storage/objects.go | 11 ++++- pkg/storage/objects_test.go | 92 +++++++++++++++++++++++++++++++++++++ 4 files changed, 108 insertions(+), 15 deletions(-) create mode 100644 pkg/storage/objects_test.go diff --git a/internal/storage/cp/cp.go b/internal/storage/cp/cp.go index e55120a1c..e2e304ced 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") } @@ -149,7 +149,7 @@ 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 { @@ -162,7 +162,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/pkg/storage/batch.go b/pkg/storage/batch.go index 8a681242d..63638e9a9 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 f048cecf6..f338a63b2 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) } diff --git a/pkg/storage/objects_test.go b/pkg/storage/objects_test.go new file mode 100644 index 000000000..a2e132a9b --- /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()) + }) + } +} From ce47b342b0452606b04108fb654e3afebb87d53b Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Fri, 10 Jan 2025 12:01:20 +0800 Subject: [PATCH 22/34] feat: support encrypted values in config (#3013) * feat: support encrypted values in config * feat: parse smtp pass as encrypted secret * chore: parse encrypted sms secret * chore: parse encrypted hook secret * chore: parse encrypted external secret * chore: remove project ref arg from auth diff * chore: increase dupl detection threshold --- .golangci.yml | 2 +- cmd/link.go | 1 + go.mod | 7 +- go.sum | 12 +- internal/config/push/push.go | 7 +- internal/link/link.go | 1 - internal/start/start.go | 24 +- pkg/config/auth.go | 306 ++++++++++-------- pkg/config/auth_test.go | 137 +++++--- pkg/config/config.go | 71 ++-- pkg/config/config_test.go | 12 +- pkg/config/secret.go | 83 +++++ pkg/config/secret_test.go | 52 +++ .../local_enabled_remote_disabled.diff | 2 +- .../local_enabled_and_disabled.diff | 4 +- .../local_disabled_remote_enabled.diff | 2 +- .../local_enabled_remote_disabled.diff | 6 +- .../local_enabled_remote_disabled.diff | 2 +- pkg/config/updater.go | 2 +- 19 files changed, 472 insertions(+), 261 deletions(-) create mode 100644 pkg/config/secret.go create mode 100644 pkg/config/secret_test.go diff --git a/.golangci.yml b/.golangci.yml index 9d5189836..b91c1afd6 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/link.go b/cmd/link.go index b1aec1d7a..59c93545c 100644 --- a/cmd/link.go +++ b/cmd/link.go @@ -31,6 +31,7 @@ var ( return err } fsys := afero.NewOsFs() + utils.Config.ProjectId = flags.ProjectRef if err := utils.LoadConfigFS(fsys); err != nil { return err } diff --git a/go.mod b/go.mod index 62b544b34..4e5fcaff0 100644 --- a/go.mod +++ b/go.mod @@ -17,6 +17,7 @@ require ( github.com/docker/docker v27.4.1+incompatible github.com/docker/go-connections v0.5.0 github.com/docker/go-units v0.5.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.1 @@ -111,6 +112,7 @@ require ( 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.11.0 // indirect @@ -120,6 +122,7 @@ require ( 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 @@ -215,7 +218,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 @@ -244,7 +247,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 diff --git a/go.sum b/go.sum index 8b6bf5eda..d475808d6 100644 --- a/go.sum +++ b/go.sum @@ -215,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= @@ -248,6 +250,8 @@ 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/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= @@ -257,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= @@ -678,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= @@ -792,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= diff --git a/internal/config/push/push.go b/internal/config/push/push.go index a4c901473..b1b887765 100644 --- a/internal/config/push/push.go +++ b/internal/config/push/push.go @@ -11,15 +11,12 @@ import ( ) func Run(ctx context.Context, ref string, fsys afero.Fs) error { + utils.Config.ProjectId = ref if err := utils.LoadConfigFS(fsys); err != nil { return err } client := config.NewConfigUpdater(*utils.GetSupabase()) - remote, err := utils.Config.GetRemoteByProjectRef(ref) - if err != nil { - // Use base config when no remote is declared - remote.ProjectId = ref - } + remote, _ := utils.Config.GetRemoteByProjectRef(ref) fmt.Fprintln(os.Stderr, "Pushing config to project:", remote.ProjectId) console := utils.NewConsole() keep := func(name string) bool { diff --git a/internal/link/link.go b/internal/link/link.go index e791271b8..d35321e2e 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/start/start.go b/internal/start/start.go index c3684c14b..6f75d1377 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -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/pkg/config/auth.go b/pkg/config/auth.go index b93123bd2..098764fff 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 0 { + body.HookPasswordVerificationAttemptSecrets = &hook.Secrets.Value } } } @@ -310,8 +310,8 @@ 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, "") - if hook.Secrets != hashPrefix { - 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) @@ -319,8 +319,8 @@ func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { if hook := h.SendEmail; hook != nil { if hook.Enabled { hook.URI = cast.Val(remoteConfig.HookSendEmailUri, "") - if hook.Secrets != hashPrefix { - 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) @@ -328,8 +328,8 @@ func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { if hook := h.SendSMS; hook != nil { if hook.Enabled { hook.URI = cast.Val(remoteConfig.HookSendSmsUri, "") - if hook.Secrets != hashPrefix { - 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) @@ -338,8 +338,8 @@ func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { if hook := h.MFAVerificationAttempt; hook != nil { if hook.Enabled { hook.URI = cast.Val(remoteConfig.HookMfaVerificationAttemptUri, "") - if hook.Secrets != hashPrefix { - 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) @@ -347,8 +347,8 @@ func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { if hook := h.PasswordVerificationAttempt; hook != nil { if hook.Enabled { hook.URI = cast.Val(remoteConfig.HookPasswordVerificationAttemptUri, "") - if hook.Secrets != hashPrefix { - 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) @@ -512,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.Value) > 0 { + body.SmtpPass = &s.Pass.Value + } body.SmtpAdminEmail = &s.AdminEmail body.SmtpSenderName = &s.SenderName } @@ -528,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") @@ -552,34 +556,34 @@ func (s sms) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { switch { case s.Twilio.Enabled: body.SmsProvider = cast.Ptr("twilio") - if len(s.Twilio.AuthToken) > 0 { - body.SmsTwilioAuthToken = &s.Twilio.AuthToken + if len(s.Twilio.AuthToken.Value) > 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") - if len(s.TwilioVerify.AuthToken) > 0 { - body.SmsTwilioVerifyAuthToken = &s.TwilioVerify.AuthToken + if len(s.TwilioVerify.AuthToken.Value) > 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") - if len(s.Messagebird.AccessKey) > 0 { - body.SmsMessagebirdAccessKey = &s.Messagebird.AccessKey + if len(s.Messagebird.AccessKey.Value) > 0 { + body.SmsMessagebirdAccessKey = &s.Messagebird.AccessKey.Value } body.SmsMessagebirdOriginator = &s.Messagebird.Originator case s.Textlocal.Enabled: body.SmsProvider = cast.Ptr("textlocal") - if len(s.Textlocal.ApiKey) > 0 { - body.SmsTextlocalApiKey = &s.Textlocal.ApiKey + if len(s.Textlocal.ApiKey.Value) > 0 { + body.SmsTextlocalApiKey = &s.Textlocal.ApiKey.Value } body.SmsTextlocalSender = &s.Textlocal.Sender case s.Vonage.Enabled: body.SmsProvider = cast.Ptr("vonage") - if len(s.Vonage.ApiSecret) > 0 { - body.SmsVonageApiSecret = &s.Vonage.ApiSecret + if len(s.Vonage.ApiSecret.Value) > 0 { + body.SmsVonageApiSecret = &s.Vonage.ApiSecret.Value } body.SmsVonageApiKey = &s.Vonage.ApiKey body.SmsVonageFrom = &s.Vonage.From @@ -595,30 +599,30 @@ func (s *sms) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { // We are only interested in the provider that's enabled locally switch { case s.Twilio.Enabled: - if s.Twilio.AuthToken != hashPrefix { - 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: - if s.TwilioVerify.AuthToken != hashPrefix { - 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: - if s.Messagebird.AccessKey != hashPrefix { - 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: - if s.Textlocal.ApiKey != hashPrefix { - 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: - if s.Vonage.ApiSecret != hashPrefix { - 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, "") @@ -643,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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 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.Value) > 0 { + body.ExternalZoomSecret = &p.Secret.Value + } } } } @@ -772,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 @@ -781,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) @@ -791,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 @@ -800,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 @@ -809,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 @@ -818,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 @@ -827,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 @@ -836,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) @@ -849,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) @@ -859,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 @@ -868,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) @@ -878,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 @@ -887,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 @@ -896,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 @@ -905,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 @@ -914,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 @@ -923,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 @@ -932,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) @@ -942,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 { @@ -964,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/auth_test.go b/pkg/config/auth_test.go index e659da166..b34139715 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.go b/pkg/config/config.go index 35b84eb68..837f305a9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -412,22 +412,27 @@ func (c *config) loadFromReader(v *viper.Viper, r io.Reader) error { v.Set("functions."+key, function{}) } } - if err := v.UnmarshalExact(c, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( - mapstructure.StringToTimeDurationHookFunc(), - mapstructure.StringToIPHookFunc(), - mapstructure.StringToSliceHookFunc(","), - mapstructure.TextUnmarshallerHookFunc(), - LoadEnvHook, - // TODO: include decrypt secret hook - )), func(dc *mapstructure.DecoderConfig) { + if err := v.UnmarshalExact(c, func(dc *mapstructure.DecoderConfig) { dc.TagName = "toml" dc.Squash = 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 { v := viper.New() @@ -449,13 +454,7 @@ func (c *config) loadFromEnv() error { return errors.Errorf("failed to merge env config: %w", err) } // Writes viper state back to config struct, with automatic env substitution - if err := v.UnmarshalExact(c, viper.DecodeHook(mapstructure.ComposeDecodeHookFunc( - mapstructure.StringToTimeDurationHookFunc(), - mapstructure.StringToIPHookFunc(), - mapstructure.StringToSliceHookFunc(","), - mapstructure.TextUnmarshallerHookFunc(), - // TODO: include decrypt secret hook - ))); err != nil { + if err := v.UnmarshalExact(c, viper.DecodeHook(c.newDecodeHook())); err != nil { return errors.Errorf("failed to parse env override: %w", err) } return nil @@ -795,13 +794,13 @@ func assertEnvLoaded(s string) error { } func LoadEnvHook(f reflect.Kind, t reflect.Kind, data interface{}) (interface{}, error) { - if f != reflect.String || t != reflect.String { + if f != reflect.String { return data, nil } value := data.(string) if matches := envPattern.FindStringSubmatch(value); len(matches) > 1 { - if v, exists := os.LookupEnv(matches[1]); exists { - value = v + if env, exists := os.LookupEnv(matches[1]); exists { + value = env } } return value, nil @@ -912,13 +911,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 err := assertEnvLoaded(e.Smtp.Pass); err != nil { + if err := assertEnvLoaded(e.Smtp.Pass.Value); err != nil { return err } } @@ -934,10 +933,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 err := assertEnvLoaded(s.Twilio.AuthToken); err != nil { + if err := assertEnvLoaded(s.Twilio.AuthToken.Value); err != nil { return err } case s.TwilioVerify.Enabled: @@ -947,30 +946,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 err := assertEnvLoaded(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 err := assertEnvLoaded(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 err := assertEnvLoaded(s.Textlocal.ApiKey); err != nil { + if err := assertEnvLoaded(s.Textlocal.ApiKey.Value); err != nil { return err } case s.Vonage.Enabled: @@ -980,13 +979,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 err := assertEnvLoaded(s.Vonage.ApiKey); err != nil { return err } - if err := assertEnvLoaded(s.Vonage.ApiSecret); err != nil { + if err := assertEnvLoaded(s.Vonage.ApiSecret.Value); err != nil { return err } case s.EnableSignup: @@ -1010,13 +1009,13 @@ 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 err := assertEnvLoaded(provider.ClientId); err != nil { return err } - if err := assertEnvLoaded(provider.Secret); err != nil { + if err := assertEnvLoaded(provider.Secret.Value); err != nil { return err } if err := assertEnvLoaded(provider.RedirectUri); err != nil { @@ -1075,18 +1074,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 err := assertEnvLoaded(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_"`, 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: diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index e1678f2ed..45b2d04f6 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", @@ -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", }, diff --git a/pkg/config/secret.go b/pkg/config/secret.go new file mode 100644 index 000000000..64da04d77 --- /dev/null +++ b/pkg/config/secret.go @@ -0,0 +1,83 @@ +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 + } + ciphertext := data.(string) + // Skip hashing unloaded env + if matches := envPattern.FindStringSubmatch(ciphertext); len(matches) > 1 { + return result, nil + } + var err error + privKey := os.Getenv("DOTENV_PRIVATE_KEY") + for _, k := range strings.Split(privKey, ",") { + result.Value, err = decrypt(k, ciphertext) + if err == nil && len(result.Value) > 0 { + result.SHA256 = sha256Hmac(hashKey, result.Value) + break + } + } + return result, err + } +} diff --git a/pkg/config/secret_test.go b/pkg/config/secret_test.go new file mode 100644 index 000000000..c4bf74e5b --- /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 85d30362a..ad89a5d1e 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 089d74eee..8b78fb240 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 c8cf4c5f0..247618f0c 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 dc80e57a3..556b13ff5 100644 --- a/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff +++ b/pkg/config/testdata/TestHookDiff/local_enabled_remote_disabled.diff @@ -8,11 +8,11 @@ diff remote[auth] local[auth] -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" @@ -26,6 +26,6 @@ diff remote[auth] local[auth] -uri = "https://example.com" +enabled = true +uri = "pg-functions://postgres/public/sendEmail" - secrets = "hash:" + secrets = "" [mfa] diff --git a/pkg/config/testdata/TestSmsDiff/local_enabled_remote_disabled.diff b/pkg/config/testdata/TestSmsDiff/local_enabled_remote_disabled.diff index 4418013bf..02f0b76cd 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/updater.go b/pkg/config/updater.go index 445000d0b..e5f42aceb 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 { From 98984514541b84bd2e5288e776128e3d686117ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 05:03:32 +0000 Subject: [PATCH 23/34] chore(deps): bump github.com/spf13/afero from 1.11.0 to 1.12.0 (#3027) Bumps [github.com/spf13/afero](https://github.com/spf13/afero) from 1.11.0 to 1.12.0. - [Release notes](https://github.com/spf13/afero/releases) - [Commits](https://github.com/spf13/afero/compare/v1.11.0...v1.12.0) --- updated-dependencies: - dependency-name: github.com/spf13/afero dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 4e5fcaff0..6a14704f6 100644 --- a/go.mod +++ b/go.mod @@ -39,7 +39,7 @@ 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 @@ -322,7 +322,7 @@ 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 @@ -330,9 +330,9 @@ require ( golang.org/x/sys v0.29.0 // indirect golang.org/x/text v0.21.0 // indirect golang.org/x/tools v0.28.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 + 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 d475808d6..556191612 100644 --- a/go.sum +++ b/go.sum @@ -894,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= @@ -1080,8 +1080,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf 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= @@ -1315,8 +1315,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= @@ -1445,10 +1445,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= @@ -1476,8 +1476,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= From 88cd60986ae2bbe46abcabd980a4023b8ae8a8c3 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Fri, 10 Jan 2025 18:00:20 +0800 Subject: [PATCH 24/34] fix: unmarshal remote override into base config (#3028) * fix: unmarshal remote override into base config * chore: account for project ref flag when loading config * fix: restore project id from base config --- cmd/link.go | 4 +- internal/bootstrap/bootstrap.go | 2 +- internal/config/push/push.go | 10 ++- internal/db/branch/create/create.go | 3 +- internal/db/branch/delete/delete.go | 3 +- internal/db/branch/switch_/switch_.go | 3 +- internal/db/diff/diff.go | 3 +- internal/db/diff/pgadmin.go | 3 +- internal/db/pull/pull.go | 3 +- internal/db/push/push.go | 7 +- internal/db/remote/changes/changes.go | 3 +- internal/db/remote/commit/commit.go | 3 +- internal/db/reset/reset.go | 9 +-- internal/db/start/start.go | 3 +- internal/functions/deploy/deploy.go | 8 +- internal/functions/download/download.go | 3 +- internal/functions/new/new.go | 3 +- internal/functions/serve/serve.go | 3 +- internal/gen/types/types.go | 3 +- internal/migration/squash/squash.go | 3 +- internal/seed/buckets/buckets.go | 5 +- internal/start/start.go | 2 +- internal/status/status.go | 3 +- internal/stop/stop.go | 3 +- internal/storage/cp/cp.go | 3 +- internal/utils/config.go | 12 --- internal/utils/flags/config_path.go | 22 ++++++ internal/utils/flags/db_url.go | 6 +- pkg/config/config.go | 98 ++++++++++--------------- pkg/config/config_test.go | 10 +-- pkg/config/testdata/config.toml | 5 +- 31 files changed, 124 insertions(+), 127 deletions(-) create mode 100644 internal/utils/flags/config_path.go diff --git a/cmd/link.go b/cmd/link.go index 59c93545c..65b8b5f08 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,8 +30,7 @@ var ( return err } fsys := afero.NewOsFs() - utils.Config.ProjectId = flags.ProjectRef - 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/internal/bootstrap/bootstrap.go b/internal/bootstrap/bootstrap.go index 677ef1530..8310a82fb 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/config/push/push.go b/internal/config/push/push.go index b1b887765..d2dadddc3 100644 --- a/internal/config/push/push.go +++ b/internal/config/push/push.go @@ -7,16 +7,20 @@ 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 { - utils.Config.ProjectId = ref - if err := utils.LoadConfigFS(fsys); err != nil { + if err := flags.LoadConfig(fsys); err != nil { return err } client := config.NewConfigUpdater(*utils.GetSupabase()) - remote, _ := utils.Config.GetRemoteByProjectRef(ref) + remote, err := utils.Config.GetRemoteByProjectRef(ref) + if err != nil { + // Use base config when no remote is declared + remote.ProjectId = ref + } fmt.Fprintln(os.Stderr, "Pushing config to project:", remote.ProjectId) console := utils.NewConsole() keep := func(name string) bool { diff --git a/internal/db/branch/create/create.go b/internal/db/branch/create/create.go index 085e10f9d..550128376 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 f59f5e51c..ea14cd34d 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 462b26c69..d11803e88 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 6c5faa892..d54f5e534 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 298023580..55046bf24 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 f6a235e11..6cc8dccab 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 2141255ae..7e5241558 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 c735b5984..9aa4a47b0 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 f9062d492..6e00a0295 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 3830a019d..307f14f55 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 aa8b9cee5..4180fe05c 100644 --- a/internal/db/start/start.go +++ b/internal/db/start/start.go @@ -23,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" ) @@ -39,7 +40,7 @@ var ( ) func Run(ctx context.Context, fromBackup 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/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go index 5ee2ae845..5b6bb8e47 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 @@ -82,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 { diff --git a/internal/functions/download/download.go b/internal/functions/download/download.go index e3b68cae9..ca99c1bcf 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 f787ce90c..5eca5b67a 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -11,6 +11,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 ( @@ -45,7 +46,7 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error { } // Load config if available - if err := utils.LoadConfigFS(fsys); err != nil { + if err := flags.LoadConfig(fsys); err != nil { utils.CmdSuggestion = "" } diff --git a/internal/functions/serve/serve.go b/internal/functions/serve/serve.go index 62811d769..485d8c7cf 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 b399cfb5c..9ffc7dc72 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/migration/squash/squash.go b/internal/migration/squash/squash.go index 2ed9e6252..4aad8b832 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 b460fdc79..365c3a395 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 6f75d1377..2501d5b8d 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 { diff --git a/internal/status/status.go b/internal/status/status.go index 1b9d02f90..68eae2fe3 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 39c5e00e5..da98f1600 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 e2e304ced..4ead44639 100644 --- a/internal/storage/cp/cp.go +++ b/internal/storage/cp/cp.go @@ -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 @@ -154,7 +153,7 @@ func UploadStorageObjectAll(ctx context.Context, api storage.StorageAPI, remoteP // 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 diff --git a/internal/utils/config.go b/internal/utils/config.go index 3f89dc75c..06d42d443 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/flags/config_path.go b/internal/utils/flags/config_path.go new file mode 100644 index 000000000..d0ed105c7 --- /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 013453b86..04565939d 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/config/config.go b/pkg/config/config.go index 837f305a9..93cc252c9 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -136,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 { @@ -360,6 +359,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 { @@ -406,6 +406,24 @@ 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 { @@ -532,50 +550,11 @@ 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)) } - // Resolve remote config, then base config - 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.resolve(builder, fsys); err != nil { - return err - } - c.Remotes[name] = base - } + // TODO: replace derived config resolution with viper decode hooks if err := c.baseConfig.resolve(builder, fsys); err != nil { return err } - // Validate base config, then remote config - if err := c.baseConfig.Validate(fsys); err != nil { - return err - } - for name, base := range c.Remotes { - if err := base.Validate(fsys); err != nil { - return errors.Errorf("invalid config for [remotes.%s]: %w", name, err) - } - } - return nil + return c.Validate(fsys) } func (c *baseConfig) resolve(builder pathBuilder, fsys fs.FS) error { @@ -624,13 +603,19 @@ func (c *baseConfig) resolve(builder pathBuilder, fsys fs.FS) error { 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 { @@ -641,7 +626,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 { @@ -1328,25 +1313,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/config_test.go b/pkg/config/config_test.go index 45b2d04f6..2280ae40b 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -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) }) @@ -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{}, @@ -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/testdata/config.toml b/pkg/config/testdata/config.toml index e3093924a..65705646c 100644 --- a/pkg/config/testdata/config.toml +++ b/pkg/config/testdata/config.toml @@ -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 From 55fc7042155fd8d9caaaada07ca19f4caf57d340 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Sat, 11 Jan 2025 03:22:01 +0800 Subject: [PATCH 25/34] fix: skip hashing unloaded env reference (#3029) * fix: skip hashing unloaded env reference * fix: zero maps and arrays before unmarshaling --- pkg/config/auth.go | 60 ++++++++++++++++++++++---------------------- pkg/config/config.go | 1 + pkg/config/secret.go | 15 ++++++----- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/pkg/config/auth.go b/pkg/config/auth.go index 098764fff..0a7aa66a8 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -265,7 +265,7 @@ 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.Value) > 0 { + if len(hook.Secrets.SHA256) > 0 { body.HookCustomAccessTokenSecrets = &hook.Secrets.Value } } @@ -273,7 +273,7 @@ func (h hook) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if hook := h.SendEmail; hook != nil { if body.HookSendEmailEnabled = &hook.Enabled; hook.Enabled { body.HookSendEmailUri = &hook.URI - if len(hook.Secrets.Value) > 0 { + if len(hook.Secrets.SHA256) > 0 { body.HookSendEmailSecrets = &hook.Secrets.Value } } @@ -281,7 +281,7 @@ func (h hook) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if hook := h.SendSMS; hook != nil { if body.HookSendSmsEnabled = &hook.Enabled; hook.Enabled { body.HookSendSmsUri = &hook.URI - if len(hook.Secrets.Value) > 0 { + if len(hook.Secrets.SHA256) > 0 { body.HookSendSmsSecrets = &hook.Secrets.Value } } @@ -290,7 +290,7 @@ 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.Value) > 0 { + if len(hook.Secrets.SHA256) > 0 { body.HookMfaVerificationAttemptSecrets = &hook.Secrets.Value } } @@ -298,7 +298,7 @@ func (h hook) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if hook := h.PasswordVerificationAttempt; hook != nil { if body.HookPasswordVerificationAttemptEnabled = &hook.Enabled; hook.Enabled { body.HookPasswordVerificationAttemptUri = &hook.URI - if len(hook.Secrets.Value) > 0 { + if len(hook.Secrets.SHA256) > 0 { body.HookPasswordVerificationAttemptSecrets = &hook.Secrets.Value } } @@ -512,7 +512,7 @@ func (s smtp) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { body.SmtpHost = &s.Host body.SmtpPort = cast.Ptr(strconv.Itoa(int(s.Port))) body.SmtpUser = &s.User - if len(s.Pass.Value) > 0 { + if len(s.Pass.SHA256) > 0 { body.SmtpPass = &s.Pass.Value } body.SmtpAdminEmail = &s.AdminEmail @@ -556,33 +556,33 @@ func (s sms) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { switch { case s.Twilio.Enabled: body.SmsProvider = cast.Ptr("twilio") - if len(s.Twilio.AuthToken.Value) > 0 { + 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") - if len(s.TwilioVerify.AuthToken.Value) > 0 { + 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") - if len(s.Messagebird.AccessKey.Value) > 0 { + 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") - if len(s.Textlocal.ApiKey.Value) > 0 { + 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") - if len(s.Vonage.ApiSecret.Value) > 0 { + if len(s.Vonage.ApiSecret.SHA256) > 0 { body.SmsVonageApiSecret = &s.Vonage.ApiSecret.Value } body.SmsVonageApiKey = &s.Vonage.ApiKey @@ -647,7 +647,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["apple"]; ok { if body.ExternalAppleEnabled = &p.Enabled; *body.ExternalAppleEnabled { body.ExternalAppleClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalAppleSecret = &p.Secret.Value } } @@ -655,7 +655,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["azure"]; ok { if body.ExternalAzureEnabled = &p.Enabled; *body.ExternalAzureEnabled { body.ExternalAzureClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalAzureSecret = &p.Secret.Value } body.ExternalAzureUrl = &p.Url @@ -664,7 +664,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["bitbucket"]; ok { if body.ExternalBitbucketEnabled = &p.Enabled; *body.ExternalBitbucketEnabled { body.ExternalBitbucketClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalBitbucketSecret = &p.Secret.Value } } @@ -672,7 +672,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["discord"]; ok { if body.ExternalDiscordEnabled = &p.Enabled; *body.ExternalDiscordEnabled { body.ExternalDiscordClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalDiscordSecret = &p.Secret.Value } } @@ -680,7 +680,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["facebook"]; ok { if body.ExternalFacebookEnabled = &p.Enabled; *body.ExternalFacebookEnabled { body.ExternalFacebookClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalFacebookSecret = &p.Secret.Value } } @@ -688,7 +688,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["figma"]; ok { if body.ExternalFigmaEnabled = &p.Enabled; *body.ExternalFigmaEnabled { body.ExternalFigmaClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalFigmaSecret = &p.Secret.Value } } @@ -696,7 +696,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["github"]; ok { if body.ExternalGithubEnabled = &p.Enabled; *body.ExternalGithubEnabled { body.ExternalGithubClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalGithubSecret = &p.Secret.Value } } @@ -704,7 +704,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["gitlab"]; ok { if body.ExternalGitlabEnabled = &p.Enabled; *body.ExternalGitlabEnabled { body.ExternalGitlabClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalGitlabSecret = &p.Secret.Value } body.ExternalGitlabUrl = &p.Url @@ -713,7 +713,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["google"]; ok { if body.ExternalGoogleEnabled = &p.Enabled; *body.ExternalGoogleEnabled { body.ExternalGoogleClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalGoogleSecret = &p.Secret.Value } body.ExternalGoogleSkipNonceCheck = &p.SkipNonceCheck @@ -722,7 +722,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["kakao"]; ok { if body.ExternalKakaoEnabled = &p.Enabled; *body.ExternalKakaoEnabled { body.ExternalKakaoClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalKakaoSecret = &p.Secret.Value } } @@ -730,7 +730,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["keycloak"]; ok { if body.ExternalKeycloakEnabled = &p.Enabled; *body.ExternalKeycloakEnabled { body.ExternalKeycloakClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalKeycloakSecret = &p.Secret.Value } body.ExternalKeycloakUrl = &p.Url @@ -739,7 +739,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["linkedin_oidc"]; ok { if body.ExternalLinkedinOidcEnabled = &p.Enabled; *body.ExternalLinkedinOidcEnabled { body.ExternalLinkedinOidcClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalLinkedinOidcSecret = &p.Secret.Value } } @@ -747,7 +747,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["notion"]; ok { if body.ExternalNotionEnabled = &p.Enabled; *body.ExternalNotionEnabled { body.ExternalNotionClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalNotionSecret = &p.Secret.Value } } @@ -755,7 +755,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["slack_oidc"]; ok { if body.ExternalSlackOidcEnabled = &p.Enabled; *body.ExternalSlackOidcEnabled { body.ExternalSlackOidcClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalSlackOidcSecret = &p.Secret.Value } } @@ -763,7 +763,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["spotify"]; ok { if body.ExternalSpotifyEnabled = &p.Enabled; *body.ExternalSpotifyEnabled { body.ExternalSpotifyClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalSpotifySecret = &p.Secret.Value } } @@ -771,7 +771,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["twitch"]; ok { if body.ExternalTwitchEnabled = &p.Enabled; *body.ExternalTwitchEnabled { body.ExternalTwitchClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalTwitchSecret = &p.Secret.Value } } @@ -779,7 +779,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["twitter"]; ok { if body.ExternalTwitterEnabled = &p.Enabled; *body.ExternalTwitterEnabled { body.ExternalTwitterClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalTwitterSecret = &p.Secret.Value } } @@ -787,7 +787,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["workos"]; ok { if body.ExternalWorkosEnabled = &p.Enabled; *body.ExternalWorkosEnabled { body.ExternalWorkosClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalWorkosSecret = &p.Secret.Value } body.ExternalWorkosUrl = &p.Url @@ -796,7 +796,7 @@ func (e external) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { if p, ok := e["zoom"]; ok { if body.ExternalZoomEnabled = &p.Enabled; *body.ExternalZoomEnabled { body.ExternalZoomClientId = &p.ClientId - if len(p.Secret.Value) > 0 { + if len(p.Secret.SHA256) > 0 { body.ExternalZoomSecret = &p.Secret.Value } } diff --git a/pkg/config/config.go b/pkg/config/config.go index 93cc252c9..c5862a995 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -433,6 +433,7 @@ func (c *config) loadFromReader(v *viper.Viper, r io.Reader) error { 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) diff --git a/pkg/config/secret.go b/pkg/config/secret.go index 64da04d77..3f0611673 100644 --- a/pkg/config/secret.go +++ b/pkg/config/secret.go @@ -64,17 +64,16 @@ func DecryptSecretHookFunc(hashKey string) mapstructure.DecodeHookFunc { if t != reflect.TypeOf(result) { return data, nil } - ciphertext := data.(string) - // Skip hashing unloaded env - if matches := envPattern.FindStringSubmatch(ciphertext); len(matches) > 1 { - return result, nil - } var err error privKey := os.Getenv("DOTENV_PRIVATE_KEY") for _, k := range strings.Split(privKey, ",") { - result.Value, err = decrypt(k, ciphertext) - if err == nil && len(result.Value) > 0 { - result.SHA256 = sha256Hmac(hashKey, result.Value) + // 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 } } From 76272d38274f74ee0d735b4283f9511a8db42f3d Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Sun, 12 Jan 2025 00:22:00 +0800 Subject: [PATCH 26/34] fix: initialise empty map for email template (#3032) --- pkg/config/auth.go | 96 ++++++++++++++++++++++---------------------- pkg/config/config.go | 9 +---- 2 files changed, 49 insertions(+), 56 deletions(-) diff --git a/pkg/config/auth.go b/pkg/config/auth.go index 0a7aa66a8..33b6f9ea2 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -442,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 { diff --git a/pkg/config/config.go b/pkg/config/config.go index c5862a995..e9d3c1243 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -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{}, From d3de6378791bd0aa8022796591ac2eb8e2aa4925 Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Mon, 13 Jan 2025 13:06:42 +0800 Subject: [PATCH 27/34] fix: handle comments in import map jsonc (#3035) * fix: handle comments in import map jsonc * fix: handle comments in vscode settings * fix: use decoder to handle empty data --- go.mod | 1 + go.sum | 2 ++ internal/init/init.go | 9 +++++---- internal/utils/deno.go | 7 ++++--- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 6a14704f6..20dee1296 100644 --- a/go.mod +++ b/go.mod @@ -45,6 +45,7 @@ require ( 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 diff --git a/go.sum b/go.sum index 556191612..022e25c75 100644 --- a/go.sum +++ b/go.sum @@ -946,6 +946,8 @@ 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/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= diff --git a/internal/init/init.go b/internal/init/init.go index f4e470b02..72241a0e0 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/utils/deno.go b/internal/utils/deno.go index 7a6006202..978f0bb63 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) } From bce4f666341e4da39ae6235c4653a0fce1e80f5a Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Mon, 13 Jan 2025 13:44:04 +0800 Subject: [PATCH 28/34] fix: clarify minimum length of auth hook secret (#3036) --- pkg/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/config.go b/pkg/config/config.go index e9d3c1243..b2104e507 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -1060,7 +1060,7 @@ func (h *hookConfig) validate(hookType string) (err error) { } 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_"`, hookType) + return errors.Errorf(`Invalid hook config: auth.hook.%s.secrets must be formatted as "v1,whsec_" with a minimum length of 32 characters.`, hookType) } } case "pg-functions": From 888c236929949eaaaaea5387597464cbccc0fca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=83=A5=EB=83=90=EC=B1=A0?= Date: Mon, 13 Jan 2025 15:36:02 +0900 Subject: [PATCH 29/34] fix: bump edge-runtime to 1.66.4 (#3034) --- pkg/config/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/constants.go b/pkg/config/constants.go index e39d799a9..9b0bec9dc 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -12,7 +12,7 @@ const ( pgmetaImage = "supabase/postgres-meta:v0.84.2" studioImage = "supabase/studio:20241202-71e5240" imageProxyImage = "darthsim/imgproxy:v3.8.0" - edgeRuntimeImage = "supabase/edge-runtime:v1.66.3" + edgeRuntimeImage = "supabase/edge-runtime:v1.66.4" vectorImage = "timberio/vector:0.28.1-alpine" supavisorImage = "supabase/supavisor:1.1.56" gotrueImage = "supabase/gotrue:v2.167.0" From f9f9d958711bc679f2d8473cc9f1d70bb36aa98a Mon Sep 17 00:00:00 2001 From: Han Qiao Date: Tue, 14 Jan 2025 00:59:21 +0800 Subject: [PATCH 30/34] fix: defaults to json when initialising import map (#3038) fix: defaults to json import map --- internal/functions/deploy/deploy.go | 17 ++++++++++++++--- internal/functions/new/new.go | 6 +++--- internal/functions/new/new_test.go | 6 +++--- internal/functions/new/templates/deno.json | 3 +++ internal/functions/new/templates/deno.jsonc | 6 ------ pkg/config/config_test.go | 2 +- 6 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 internal/functions/new/templates/deno.json delete mode 100644 internal/functions/new/templates/deno.jsonc diff --git a/internal/functions/deploy/deploy.go b/internal/functions/deploy/deploy.go index 5b6bb8e47..196d2e8a7 100644 --- a/internal/functions/deploy/deploy.go +++ b/internal/functions/deploy/deploy.go @@ -113,11 +113,22 @@ 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.jsonc):", utils.Aqua(strings.Join(functionsUsingDeprecatedImportMap, ", "))) + 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")) + 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/new/new.go b/internal/functions/new/new.go index 5eca5b67a..67a9893e2 100644 --- a/internal/functions/new/new.go +++ b/internal/functions/new/new.go @@ -17,7 +17,7 @@ import ( var ( //go:embed templates/index.ts indexEmbed string - //go:embed templates/deno.jsonc + //go:embed templates/deno.json denoEmbed string //go:embed templates/.npmrc npmrcEmbed string @@ -57,8 +57,8 @@ func Run(ctx context.Context, slug string, fsys afero.Fs) error { return errors.Errorf("failed to create function entrypoint: %w", err) } - if err := afero.WriteFile(fsys, filepath.Join(funcDir, "deno.jsonc"), []byte(denoEmbed), 0644); err != nil { - return errors.Errorf("failed to create deno.jsonc config: %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 { diff --git a/internal/functions/new/new_test.go b/internal/functions/new/new_test.go index 56a24f705..8e00fa656 100644 --- a/internal/functions/new/new_test.go +++ b/internal/functions/new/new_test.go @@ -25,10 +25,10 @@ func TestNewCommand(t *testing.T) { "curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/test-func'", ) - // Verify deno.jsonc exists - denoPath := filepath.Join(utils.FunctionsDir, "test-func", "deno.jsonc") + // Verify deno.json exists + denoPath := filepath.Join(utils.FunctionsDir, "test-func", "deno.json") _, err = afero.ReadFile(fsys, denoPath) - assert.NoError(t, err, "deno.jsonc should be created") + assert.NoError(t, err, "deno.json should be created") // Verify .npmrc exists npmrcPath := filepath.Join(utils.FunctionsDir, "test-func", ".npmrc") diff --git a/internal/functions/new/templates/deno.json b/internal/functions/new/templates/deno.json new file mode 100644 index 000000000..f6ca8454c --- /dev/null +++ b/internal/functions/new/templates/deno.json @@ -0,0 +1,3 @@ +{ + "imports": {} +} diff --git a/internal/functions/new/templates/deno.jsonc b/internal/functions/new/templates/deno.jsonc deleted file mode 100644 index 97275ba5e..000000000 --- a/internal/functions/new/templates/deno.jsonc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "imports": { - // Add your dependencies here - // See: https://supabase.com/docs/guides/functions/import-maps#using-denojson-recommended - } -} diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 2280ae40b..e13e67e59 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -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) }) From 0eaa4b977ac1804e50e8645d405cedfc8c0c86fa Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Mon, 13 Jan 2025 18:04:36 +0100 Subject: [PATCH 31/34] fix(studio): Bump studio version to 20250113-83c9420 (#3037) Bump studio version. --- pkg/config/constants.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/config/constants.go b/pkg/config/constants.go index 9b0bec9dc..3aa5c9d7d 100644 --- a/pkg/config/constants.go +++ b/pkg/config/constants.go @@ -10,7 +10,7 @@ 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.4" vectorImage = "timberio/vector:0.28.1-alpine" From 7536f94c69f84af0030f6e0ad3af79e009257e70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 04:51:27 +0000 Subject: [PATCH 32/34] chore(deps): bump github.com/docker/docker from 27.4.1+incompatible to 27.5.0+incompatible (#3041) chore(deps): bump github.com/docker/docker Bumps [github.com/docker/docker](https://github.com/docker/docker) from 27.4.1+incompatible to 27.5.0+incompatible. - [Release notes](https://github.com/docker/docker/releases) - [Commits](https://github.com/docker/docker/compare/v27.4.1...v27.5.0) --- updated-dependencies: - dependency-name: github.com/docker/docker dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 20dee1296..61ab941e3 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( 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/docker v27.5.0+incompatible github.com/docker/go-connections v0.5.0 github.com/docker/go-units v0.5.0 github.com/ecies/go/v2 v2.0.10 diff --git a/go.sum b/go.sum index 022e25c75..20750229f 100644 --- a/go.sum +++ b/go.sum @@ -233,8 +233,8 @@ github.com/docker/cli v27.4.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvM 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= From 52cc07d506b26fa2fbefc10027336c7731b75e10 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 04:56:18 +0000 Subject: [PATCH 33/34] chore(deps): bump github.com/docker/cli from 27.4.1+incompatible to 27.5.0+incompatible (#3040) chore(deps): bump github.com/docker/cli Bumps [github.com/docker/cli](https://github.com/docker/cli) from 27.4.1+incompatible to 27.5.0+incompatible. - [Commits](https://github.com/docker/cli/compare/v27.4.1...v27.5.0) --- updated-dependencies: - dependency-name: github.com/docker/cli dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 61ab941e3..9bae3cbe8 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ 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/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 diff --git a/go.sum b/go.sum index 20750229f..14de6fa09 100644 --- a/go.sum +++ b/go.sum @@ -228,8 +228,8 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK 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= From 4665c044f6b06a19b3b0e93c754e42e51e16a716 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Jan 2025 05:01:47 +0000 Subject: [PATCH 34/34] chore(deps): bump google.golang.org/grpc from 1.69.2 to 1.69.4 (#3039) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.69.2 to 1.69.4. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.69.2...v1.69.4) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9bae3cbe8..efa4c92b8 100644 --- a/go.mod +++ b/go.mod @@ -52,7 +52,7 @@ require ( golang.org/x/mod v0.22.0 golang.org/x/oauth2 v0.25.0 golang.org/x/term v0.28.0 - google.golang.org/grpc v1.69.2 + google.golang.org/grpc v1.69.4 gopkg.in/yaml.v3 v3.0.1 gotest.tools/gotestsum v1.12.0 ) diff --git a/go.sum b/go.sum index 14de6fa09..aa602cf62 100644 --- a/go.sum +++ b/go.sum @@ -1464,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=