diff --git a/cmd/vault.go b/cmd/encryption.go similarity index 58% rename from cmd/vault.go rename to cmd/encryption.go index 9f7d732c9..d3b654afc 100644 --- a/cmd/vault.go +++ b/cmd/encryption.go @@ -4,16 +4,16 @@ import ( "os" "github.com/spf13/cobra" + "github.com/supabase/cli/internal/encryption/get" + "github.com/supabase/cli/internal/encryption/update" "github.com/supabase/cli/internal/utils/flags" - "github.com/supabase/cli/internal/vault/get" - "github.com/supabase/cli/internal/vault/update" ) var ( - vaultCmd = &cobra.Command{ + encryptionCmd = &cobra.Command{ GroupID: groupManagementAPI, - Use: "vault", - Short: "Manage column encryption of Supabase projects", + Use: "encryption", + Short: "Manage encryption keys of Supabase projects", } rootKeyGetCmd = &cobra.Command{ @@ -34,8 +34,8 @@ var ( ) func init() { - vaultCmd.PersistentFlags().StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.") - vaultCmd.AddCommand(rootKeyUpdateCmd) - vaultCmd.AddCommand(rootKeyGetCmd) - rootCmd.AddCommand(vaultCmd) + encryptionCmd.PersistentFlags().StringVar(&flags.ProjectRef, "project-ref", "", "Project ref of the Supabase project.") + encryptionCmd.AddCommand(rootKeyUpdateCmd) + encryptionCmd.AddCommand(rootKeyGetCmd) + rootCmd.AddCommand(encryptionCmd) } diff --git a/internal/vault/get/get.go b/internal/encryption/get/get.go similarity index 100% rename from internal/vault/get/get.go rename to internal/encryption/get/get.go diff --git a/internal/encryption/get/get_test.go b/internal/encryption/get/get_test.go new file mode 100644 index 000000000..6e148a50d --- /dev/null +++ b/internal/encryption/get/get_test.go @@ -0,0 +1,52 @@ +package get + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/pkg/api" + "gopkg.in/h2non/gock.v1" +) + +func TestGetRootKey(t *testing.T) { + t.Run("fetches project encryption key", func(t *testing.T) { + // Setup valid project ref + project := apitest.RandomProjectRef() + // Setup valid access token + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + // Flush pending mocks after test execution + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + project + "/pgsodium"). + Reply(http.StatusOK). + JSON(api.PgsodiumConfigResponse{RootKey: "test-key"}) + // Run test + err := Run(context.Background(), project) + // Check error + assert.NoError(t, err) + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) + + t.Run("throws on invalid credentials", func(t *testing.T) { + // Setup valid project ref + project := apitest.RandomProjectRef() + // Setup valid access token + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + // Flush pending mocks after test execution + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Get("/v1/projects/" + project + "/pgsodium"). + Reply(http.StatusForbidden) + // Run test + err := Run(context.Background(), project) + // Check error + assert.ErrorContains(t, err, "Unexpected error retrieving project root key:") + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) +} diff --git a/internal/vault/update/update.go b/internal/encryption/update/update.go similarity index 100% rename from internal/vault/update/update.go rename to internal/encryption/update/update.go diff --git a/internal/encryption/update/update_test.go b/internal/encryption/update/update_test.go new file mode 100644 index 000000000..34ee5aa02 --- /dev/null +++ b/internal/encryption/update/update_test.go @@ -0,0 +1,61 @@ +package update + +import ( + "context" + "net/http" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/supabase/cli/internal/testing/apitest" + "github.com/supabase/cli/internal/utils" + "github.com/supabase/cli/pkg/api" + "gopkg.in/h2non/gock.v1" +) + +func TestUpdateRootKey(t *testing.T) { + t.Run("updates project encryption key", func(t *testing.T) { + // Setup valid project ref + project := apitest.RandomProjectRef() + // Setup valid access token + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + // Setup root key + r, w, err := os.Pipe() + require.NoError(t, err) + _, err = w.WriteString("test-key") + require.NoError(t, err) + require.NoError(t, w.Close()) + // Flush pending mocks after test execution + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Put("/v1/projects/" + project + "/pgsodium"). + JSON(api.UpdatePgsodiumConfigBody{RootKey: "test-key"}). + Reply(http.StatusOK). + JSON(api.PgsodiumConfigResponse{RootKey: "test-key"}) + // Run test + err = Run(context.Background(), project, r) + // Check error + assert.NoError(t, err) + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) + + t.Run("throws on invalid credentials", func(t *testing.T) { + // Setup valid project ref + project := apitest.RandomProjectRef() + // Setup valid access token + token := apitest.RandomAccessToken(t) + t.Setenv("SUPABASE_ACCESS_TOKEN", string(token)) + // Flush pending mocks after test execution + defer gock.OffAll() + gock.New(utils.DefaultApiHost). + Put("/v1/projects/" + project + "/pgsodium"). + Reply(http.StatusForbidden) + // Run test + err := Run(context.Background(), project, nil) + // Check error + assert.ErrorContains(t, err, "Unexpected error updating project root key:") + assert.Empty(t, apitest.ListUnmatchedRequests()) + }) +}