From 07c17d6e7d2bb3efd82d6370aa495eebfa797203 Mon Sep 17 00:00:00 2001 From: dhernando Date: Thu, 2 Apr 2026 15:56:06 +0200 Subject: [PATCH 1/3] feat: add access command group for qdrant cloud --- internal/cli/root.go | 1 + internal/cmd/access/access.go | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) create mode 100644 internal/cmd/access/access.go diff --git a/internal/cli/root.go b/internal/cli/root.go index ccc784a..74aa84d 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -5,6 +5,7 @@ import ( "github.com/spf13/cobra" + "github.com/qdrant/qcloud-cli/internal/cmd/access" "github.com/qdrant/qcloud-cli/internal/cmd/backup" "github.com/qdrant/qcloud-cli/internal/cmd/cloudprovider" "github.com/qdrant/qcloud-cli/internal/cmd/cloudregion" diff --git a/internal/cmd/access/access.go b/internal/cmd/access/access.go new file mode 100644 index 0000000..4cd12d9 --- /dev/null +++ b/internal/cmd/access/access.go @@ -0,0 +1,18 @@ +package access + +import ( + "github.com/spf13/cobra" + + "github.com/qdrant/qcloud-cli/internal/state" +) + +// NewCommand creates the access command group. +func NewCommand(s *state.State) *cobra.Command { + cmd := &cobra.Command{ + Use: "access", + Short: "Manage access to Qdrant Cloud", + Long: `Manage access settings for the Qdrant Cloud account.`, + Args: cobra.NoArgs, + } + return cmd +} From f6fa296604b9a024b2cdab45f4fb18bafba13723 Mon Sep 17 00:00:00 2001 From: dhernando Date: Thu, 2 Apr 2026 15:56:18 +0200 Subject: [PATCH 2/3] feat: add access key commands for qdrant cloud auth management Adds `qcloud access key list`, `create`, and `delete` subcommands for managing Qdrant Cloud auth access keys. --- internal/cmd/access/access.go | 1 + internal/cmd/access/key.go | 25 ++++++++ internal/cmd/access/key_create.go | 66 +++++++++++++++++++ internal/cmd/access/key_create_test.go | 66 +++++++++++++++++++ internal/cmd/access/key_delete.go | 71 +++++++++++++++++++++ internal/cmd/access/key_delete_test.go | 72 +++++++++++++++++++++ internal/cmd/access/key_list.go | 63 +++++++++++++++++++ internal/cmd/access/key_list_test.go | 87 ++++++++++++++++++++++++++ 8 files changed, 451 insertions(+) create mode 100644 internal/cmd/access/key.go create mode 100644 internal/cmd/access/key_create.go create mode 100644 internal/cmd/access/key_create_test.go create mode 100644 internal/cmd/access/key_delete.go create mode 100644 internal/cmd/access/key_delete_test.go create mode 100644 internal/cmd/access/key_list.go create mode 100644 internal/cmd/access/key_list_test.go diff --git a/internal/cmd/access/access.go b/internal/cmd/access/access.go index 4cd12d9..afb5755 100644 --- a/internal/cmd/access/access.go +++ b/internal/cmd/access/access.go @@ -14,5 +14,6 @@ func NewCommand(s *state.State) *cobra.Command { Long: `Manage access settings for the Qdrant Cloud account.`, Args: cobra.NoArgs, } + cmd.AddCommand(newKeyCommand(s)) return cmd } diff --git a/internal/cmd/access/key.go b/internal/cmd/access/key.go new file mode 100644 index 0000000..f08a4d9 --- /dev/null +++ b/internal/cmd/access/key.go @@ -0,0 +1,25 @@ +package access + +import ( + "github.com/spf13/cobra" + + "github.com/qdrant/qcloud-cli/internal/state" +) + +func newKeyCommand(s *state.State) *cobra.Command { + cmd := &cobra.Command{ + Use: "key", + Short: "Manage cloud management keys", + Long: `Manage cloud management keys for the account. + +Management keys authenticate requests to the Qdrant Cloud API. Use them to authorize +the CLI, automation scripts, or any other tooling that calls the Qdrant Cloud API.`, + Args: cobra.NoArgs, + } + cmd.AddCommand( + newKeyListCommand(s), + newKeyCreateCommand(s), + newKeyDeleteCommand(s), + ) + return cmd +} diff --git a/internal/cmd/access/key_create.go b/internal/cmd/access/key_create.go new file mode 100644 index 0000000..7c9372f --- /dev/null +++ b/internal/cmd/access/key_create.go @@ -0,0 +1,66 @@ +package access + +import ( + "fmt" + "io" + + "github.com/spf13/cobra" + + authv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/auth/v1" + + "github.com/qdrant/qcloud-cli/internal/cmd/base" + "github.com/qdrant/qcloud-cli/internal/state" +) + +func newKeyCreateCommand(s *state.State) *cobra.Command { + return base.CreateCmd[*authv1.ManagementKey]{ + Long: `Create a new cloud management key for the account. + +Management keys grant access to the Qdrant Cloud API. The full key value is returned +only once at creation time — store it securely, as it cannot be retrieved again. If a +key is lost, delete it and create a new one.`, + Example: `# Create a new management key +qcloud access key create + +# Create and capture the key value in a script +qcloud access key create --json | jq -r '.key'`, + BaseCobraCommand: func() *cobra.Command { + return &cobra.Command{ + Use: "create", + Short: "Create a cloud management key", + Args: cobra.NoArgs, + } + }, + Run: func(s *state.State, cmd *cobra.Command, args []string) (*authv1.ManagementKey, error) { + ctx := cmd.Context() + client, err := s.Client(ctx) + if err != nil { + return nil, err + } + + accountID, err := s.AccountID() + if err != nil { + return nil, err + } + + resp, err := client.Auth().CreateManagementKey(ctx, &authv1.CreateManagementKeyRequest{ + ManagementKey: &authv1.ManagementKey{ + AccountId: accountID, + }, + }) + if err != nil { + return nil, fmt.Errorf("failed to create management key: %w", err) + } + + return resp.GetManagementKey(), nil + }, + PrintResource: func(_ *cobra.Command, out io.Writer, key *authv1.ManagementKey) { + fmt.Fprintf(out, "Management key %s created.\n", key.GetId()) + if k := key.GetKey(); k != "" { + fmt.Fprintln(out, "") + fmt.Fprintln(out, "Save this key now — it will not be shown again:") + fmt.Fprintf(out, " %s\n", k) + } + }, + }.CobraCommand(s) +} diff --git a/internal/cmd/access/key_create_test.go b/internal/cmd/access/key_create_test.go new file mode 100644 index 0000000..ef26184 --- /dev/null +++ b/internal/cmd/access/key_create_test.go @@ -0,0 +1,66 @@ +package access_test + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + authv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/auth/v1" + + "github.com/qdrant/qcloud-cli/internal/testutil" +) + +func TestKeyCreate_PrintsIDAndKey(t *testing.T) { + env := testutil.NewTestEnv(t, testutil.WithAccountID("test-account-id")) + + env.AuthServer.CreateManagementKeyCalls.Returns(&authv1.CreateManagementKeyResponse{ + ManagementKey: &authv1.ManagementKey{ + Id: "new-key-id", + Key: "super-secret-value", + }, + }, nil) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "create") + require.NoError(t, err) + assert.Contains(t, stdout, "new-key-id") + assert.Contains(t, stdout, "super-secret-value") + assert.Contains(t, stdout, "Save this key now") + + req, ok := env.AuthServer.CreateManagementKeyCalls.Last() + require.True(t, ok) + assert.Equal(t, "test-account-id", req.GetManagementKey().GetAccountId()) +} + +func TestKeyCreate_BackendError(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.CreateManagementKeyCalls.Returns(nil, fmt.Errorf("internal server error")) + + _, _, err := testutil.Exec(t, env, "access", "key", "create") + require.Error(t, err) +} + +func TestKeyCreate_JSONOutput(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.CreateManagementKeyCalls.Returns(&authv1.CreateManagementKeyResponse{ + ManagementKey: &authv1.ManagementKey{ + Id: "json-key-id", + Key: "secret", + }, + }, nil) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "create", "--json") + require.NoError(t, err) + + var result struct { + ID string `json:"id"` + Key string `json:"key"` + } + require.NoError(t, json.Unmarshal([]byte(stdout), &result)) + assert.Equal(t, "json-key-id", result.ID) + assert.Equal(t, "secret", result.Key) +} diff --git a/internal/cmd/access/key_delete.go b/internal/cmd/access/key_delete.go new file mode 100644 index 0000000..09c1815 --- /dev/null +++ b/internal/cmd/access/key_delete.go @@ -0,0 +1,71 @@ +package access + +import ( + "fmt" + + "github.com/spf13/cobra" + + authv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/auth/v1" + + "github.com/qdrant/qcloud-cli/internal/cmd/base" + "github.com/qdrant/qcloud-cli/internal/cmd/completion" + "github.com/qdrant/qcloud-cli/internal/cmd/util" + "github.com/qdrant/qcloud-cli/internal/state" +) + +func newKeyDeleteCommand(s *state.State) *cobra.Command { + return base.Cmd{ + Long: `Delete a cloud management key from the account. + +Deleting a key immediately revokes its access to the Qdrant Cloud API. Any client +using the deleted key will receive authentication errors. This action cannot be undone. + +A confirmation prompt is shown unless --force is passed.`, + Example: `# Delete a management key (with confirmation prompt) +qcloud access key delete a1b2c3d4-e5f6-7890-abcd-ef1234567890 + +# Delete without confirmation +qcloud access key delete a1b2c3d4-e5f6-7890-abcd-ef1234567890 --force`, + BaseCobraCommand: func() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete ", + Short: "Delete a cloud management key", + Args: util.ExactArgs(1, "a management key ID"), + } + cmd.Flags().BoolP("force", "f", false, "Skip confirmation prompt") + return cmd + }, + ValidArgsFunction: completion.ManagementKeyIDCompletion(s), + Run: func(s *state.State, cmd *cobra.Command, args []string) error { + keyID := args[0] + + force, _ := cmd.Flags().GetBool("force") + if !util.ConfirmAction(force, cmd.ErrOrStderr(), fmt.Sprintf("Are you sure you want to delete management key %s?", keyID)) { + fmt.Fprintln(cmd.OutOrStdout(), "Aborted.") + return nil + } + + ctx := cmd.Context() + client, err := s.Client(ctx) + if err != nil { + return err + } + + accountID, err := s.AccountID() + if err != nil { + return err + } + + _, err = client.Auth().DeleteManagementKey(ctx, &authv1.DeleteManagementKeyRequest{ + AccountId: accountID, + ManagementKeyId: keyID, + }) + if err != nil { + return fmt.Errorf("failed to delete management key: %w", err) + } + + fmt.Fprintf(cmd.OutOrStdout(), "Management key %s deleted.\n", keyID) + return nil + }, + }.CobraCommand(s) +} diff --git a/internal/cmd/access/key_delete_test.go b/internal/cmd/access/key_delete_test.go new file mode 100644 index 0000000..f2f1d39 --- /dev/null +++ b/internal/cmd/access/key_delete_test.go @@ -0,0 +1,72 @@ +package access_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + authv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/auth/v1" + + "github.com/qdrant/qcloud-cli/internal/testutil" +) + +func TestKeyDelete_WithForce(t *testing.T) { + env := testutil.NewTestEnv(t, testutil.WithAccountID("test-account-id")) + + env.AuthServer.DeleteManagementKeyCalls.Returns(&authv1.DeleteManagementKeyResponse{}, nil) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "delete", "key-abc", "--force") + require.NoError(t, err) + assert.Contains(t, stdout, "key-abc") + assert.Contains(t, stdout, "deleted") + + req, ok := env.AuthServer.DeleteManagementKeyCalls.Last() + require.True(t, ok) + assert.Equal(t, "test-account-id", req.GetAccountId()) + assert.Equal(t, "key-abc", req.GetManagementKeyId()) +} + +func TestKeyDelete_Aborted(t *testing.T) { + env := testutil.NewTestEnv(t) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "delete", "key-abc") + require.NoError(t, err) + assert.Contains(t, stdout, "Aborted.") + assert.Equal(t, 0, env.AuthServer.DeleteManagementKeyCalls.Count()) +} + +func TestKeyDelete_BackendError(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.DeleteManagementKeyCalls.Returns(nil, fmt.Errorf("internal server error")) + + _, _, err := testutil.Exec(t, env, "access", "key", "delete", "key-abc", "--force") + require.Error(t, err) +} + +func TestKeyDelete_MissingArg(t *testing.T) { + env := testutil.NewTestEnv(t) + + _, _, err := testutil.Exec(t, env, "access", "key", "delete") + require.Error(t, err) +} + +func TestKeyDeleteCompletion(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.ListManagementKeysCalls.Returns(&authv1.ListManagementKeysResponse{ + Items: []*authv1.ManagementKey{ + {Id: "key-uuid-1", Prefix: "abc123"}, + {Id: "key-uuid-2", Prefix: "def456"}, + }, + }, nil) + + stdout, _, err := testutil.Exec(t, env, "__complete", "access", "key", "delete", "") + require.NoError(t, err) + assert.Contains(t, stdout, "key-uuid-1") + assert.Contains(t, stdout, "abc123") + assert.Contains(t, stdout, "key-uuid-2") + assert.Contains(t, stdout, "def456") +} diff --git a/internal/cmd/access/key_list.go b/internal/cmd/access/key_list.go new file mode 100644 index 0000000..3433d87 --- /dev/null +++ b/internal/cmd/access/key_list.go @@ -0,0 +1,63 @@ +package access + +import ( + "io" + + "github.com/spf13/cobra" + + authv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/auth/v1" + + "github.com/qdrant/qcloud-cli/internal/cmd/base" + "github.com/qdrant/qcloud-cli/internal/cmd/output" + "github.com/qdrant/qcloud-cli/internal/state" +) + +func newKeyListCommand(s *state.State) *cobra.Command { + return base.ListCmd[*authv1.ListManagementKeysResponse]{ + Use: "list", + Short: "List cloud management keys", + Long: `List all cloud management keys for the account. + +Management keys grant access to the Qdrant Cloud API and are used to authenticate CLI +and API requests. Each key is identified by its ID and a prefix — the prefix represents +the first bytes of the key value and is safe to display.`, + Example: `# List all management keys for the account +qcloud access key list + +# Output as JSON +qcloud access key list --json`, + Fetch: func(s *state.State, cmd *cobra.Command) (*authv1.ListManagementKeysResponse, error) { + ctx := cmd.Context() + client, err := s.Client(ctx) + if err != nil { + return nil, err + } + + accountID, err := s.AccountID() + if err != nil { + return nil, err + } + + return client.Auth().ListManagementKeys(ctx, &authv1.ListManagementKeysRequest{ + AccountId: accountID, + }) + }, + PrintText: func(_ *cobra.Command, w io.Writer, resp *authv1.ListManagementKeysResponse) error { + t := output.NewTable[*authv1.ManagementKey](w) + t.AddField("ID", func(v *authv1.ManagementKey) string { + return v.GetId() + }) + t.AddField("PREFIX", func(v *authv1.ManagementKey) string { + return v.GetPrefix() + }) + t.AddField("CREATED", func(v *authv1.ManagementKey) string { + if v.GetCreatedAt() != nil { + return output.HumanTime(v.GetCreatedAt().AsTime()) + } + return "" + }) + t.Write(resp.GetItems()) + return nil + }, + }.CobraCommand(s) +} diff --git a/internal/cmd/access/key_list_test.go b/internal/cmd/access/key_list_test.go new file mode 100644 index 0000000..09261ef --- /dev/null +++ b/internal/cmd/access/key_list_test.go @@ -0,0 +1,87 @@ +package access_test + +import ( + "encoding/json" + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + + authv1 "github.com/qdrant/qdrant-cloud-public-api/gen/go/qdrant/cloud/auth/v1" + + "github.com/qdrant/qcloud-cli/internal/testutil" +) + +func TestKeyList_TableOutput(t *testing.T) { + env := testutil.NewTestEnv(t, testutil.WithAccountID("test-account-id")) + + env.AuthServer.ListManagementKeysCalls.Returns(&authv1.ListManagementKeysResponse{ + Items: []*authv1.ManagementKey{ + { + Id: "key-abc", + Prefix: "abc123", + CreatedAt: timestamppb.New(time.Now().Add(-1 * time.Hour)), + }, + }, + }, nil) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "list") + require.NoError(t, err) + assert.Contains(t, stdout, "ID") + assert.Contains(t, stdout, "PREFIX") + assert.Contains(t, stdout, "CREATED") + assert.Contains(t, stdout, "key-abc") + assert.Contains(t, stdout, "abc123") + assert.Contains(t, stdout, "ago") + + req, ok := env.AuthServer.ListManagementKeysCalls.Last() + require.True(t, ok) + assert.Equal(t, "test-account-id", req.GetAccountId()) +} + +func TestKeyList_JSONOutput(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.ListManagementKeysCalls.Returns(&authv1.ListManagementKeysResponse{ + Items: []*authv1.ManagementKey{ + {Id: "key-json", Prefix: "pref"}, + }, + }, nil) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "list", "--json") + require.NoError(t, err) + + var result struct { + Items []struct { + ID string `json:"id"` + Prefix string `json:"prefix"` + } `json:"items"` + } + require.NoError(t, json.Unmarshal([]byte(stdout), &result)) + require.Len(t, result.Items, 1) + assert.Equal(t, "key-json", result.Items[0].ID) + assert.Equal(t, "pref", result.Items[0].Prefix) +} + +func TestKeyList_BackendError(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.ListManagementKeysCalls.Returns(nil, fmt.Errorf("internal server error")) + + _, _, err := testutil.Exec(t, env, "access", "key", "list") + require.Error(t, err) +} + +func TestKeyList_Empty(t *testing.T) { + env := testutil.NewTestEnv(t) + + env.AuthServer.ListManagementKeysCalls.Returns(&authv1.ListManagementKeysResponse{}, nil) + + stdout, _, err := testutil.Exec(t, env, "access", "key", "list") + require.NoError(t, err) + assert.Contains(t, stdout, "ID") + assert.Contains(t, stdout, "PREFIX") +} From e1dbc8afd9db45b82011c9843fe4e88df7afc675 Mon Sep 17 00:00:00 2001 From: dhernando Date: Thu, 2 Apr 2026 17:20:43 +0200 Subject: [PATCH 3/3] refactor: access -> iam --- internal/cli/root.go | 1 - internal/cmd/access/access.go | 19 ------------------- internal/cmd/iam/iam.go | 1 + internal/cmd/{access => iam}/key.go | 2 +- internal/cmd/{access => iam}/key_create.go | 6 +++--- .../cmd/{access => iam}/key_create_test.go | 8 ++++---- internal/cmd/{access => iam}/key_delete.go | 6 +++--- .../cmd/{access => iam}/key_delete_test.go | 12 ++++++------ internal/cmd/{access => iam}/key_list.go | 6 +++--- internal/cmd/{access => iam}/key_list_test.go | 10 +++++----- 10 files changed, 26 insertions(+), 45 deletions(-) delete mode 100644 internal/cmd/access/access.go rename internal/cmd/{access => iam}/key.go (97%) rename internal/cmd/{access => iam}/key_create.go (95%) rename internal/cmd/{access => iam}/key_create_test.go (87%) rename internal/cmd/{access => iam}/key_delete.go (93%) rename internal/cmd/{access => iam}/key_delete_test.go (80%) rename internal/cmd/{access => iam}/key_list.go (96%) rename internal/cmd/{access => iam}/key_list_test.go (88%) diff --git a/internal/cli/root.go b/internal/cli/root.go index 74aa84d..ccc784a 100644 --- a/internal/cli/root.go +++ b/internal/cli/root.go @@ -5,7 +5,6 @@ import ( "github.com/spf13/cobra" - "github.com/qdrant/qcloud-cli/internal/cmd/access" "github.com/qdrant/qcloud-cli/internal/cmd/backup" "github.com/qdrant/qcloud-cli/internal/cmd/cloudprovider" "github.com/qdrant/qcloud-cli/internal/cmd/cloudregion" diff --git a/internal/cmd/access/access.go b/internal/cmd/access/access.go deleted file mode 100644 index afb5755..0000000 --- a/internal/cmd/access/access.go +++ /dev/null @@ -1,19 +0,0 @@ -package access - -import ( - "github.com/spf13/cobra" - - "github.com/qdrant/qcloud-cli/internal/state" -) - -// NewCommand creates the access command group. -func NewCommand(s *state.State) *cobra.Command { - cmd := &cobra.Command{ - Use: "access", - Short: "Manage access to Qdrant Cloud", - Long: `Manage access settings for the Qdrant Cloud account.`, - Args: cobra.NoArgs, - } - cmd.AddCommand(newKeyCommand(s)) - return cmd -} diff --git a/internal/cmd/iam/iam.go b/internal/cmd/iam/iam.go index 4113e3e..52545d5 100644 --- a/internal/cmd/iam/iam.go +++ b/internal/cmd/iam/iam.go @@ -14,5 +14,6 @@ func NewCommand(s *state.State) *cobra.Command { Long: `Manage IAM resources for the Qdrant Cloud account.`, Args: cobra.NoArgs, } + cmd.AddCommand(newKeyCommand(s)) return cmd } diff --git a/internal/cmd/access/key.go b/internal/cmd/iam/key.go similarity index 97% rename from internal/cmd/access/key.go rename to internal/cmd/iam/key.go index f08a4d9..6a97f95 100644 --- a/internal/cmd/access/key.go +++ b/internal/cmd/iam/key.go @@ -1,4 +1,4 @@ -package access +package iam import ( "github.com/spf13/cobra" diff --git a/internal/cmd/access/key_create.go b/internal/cmd/iam/key_create.go similarity index 95% rename from internal/cmd/access/key_create.go rename to internal/cmd/iam/key_create.go index 7c9372f..51d1562 100644 --- a/internal/cmd/access/key_create.go +++ b/internal/cmd/iam/key_create.go @@ -1,4 +1,4 @@ -package access +package iam import ( "fmt" @@ -20,10 +20,10 @@ Management keys grant access to the Qdrant Cloud API. The full key value is retu only once at creation time — store it securely, as it cannot be retrieved again. If a key is lost, delete it and create a new one.`, Example: `# Create a new management key -qcloud access key create +qcloud iam key create # Create and capture the key value in a script -qcloud access key create --json | jq -r '.key'`, +qcloud iam key create --json | jq -r '.key'`, BaseCobraCommand: func() *cobra.Command { return &cobra.Command{ Use: "create", diff --git a/internal/cmd/access/key_create_test.go b/internal/cmd/iam/key_create_test.go similarity index 87% rename from internal/cmd/access/key_create_test.go rename to internal/cmd/iam/key_create_test.go index ef26184..0909dc0 100644 --- a/internal/cmd/access/key_create_test.go +++ b/internal/cmd/iam/key_create_test.go @@ -1,4 +1,4 @@ -package access_test +package iam_test import ( "encoding/json" @@ -23,7 +23,7 @@ func TestKeyCreate_PrintsIDAndKey(t *testing.T) { }, }, nil) - stdout, _, err := testutil.Exec(t, env, "access", "key", "create") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "create") require.NoError(t, err) assert.Contains(t, stdout, "new-key-id") assert.Contains(t, stdout, "super-secret-value") @@ -39,7 +39,7 @@ func TestKeyCreate_BackendError(t *testing.T) { env.AuthServer.CreateManagementKeyCalls.Returns(nil, fmt.Errorf("internal server error")) - _, _, err := testutil.Exec(t, env, "access", "key", "create") + _, _, err := testutil.Exec(t, env, "iam", "key", "create") require.Error(t, err) } @@ -53,7 +53,7 @@ func TestKeyCreate_JSONOutput(t *testing.T) { }, }, nil) - stdout, _, err := testutil.Exec(t, env, "access", "key", "create", "--json") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "create", "--json") require.NoError(t, err) var result struct { diff --git a/internal/cmd/access/key_delete.go b/internal/cmd/iam/key_delete.go similarity index 93% rename from internal/cmd/access/key_delete.go rename to internal/cmd/iam/key_delete.go index 09c1815..ac302cb 100644 --- a/internal/cmd/access/key_delete.go +++ b/internal/cmd/iam/key_delete.go @@ -1,4 +1,4 @@ -package access +package iam import ( "fmt" @@ -22,10 +22,10 @@ using the deleted key will receive authentication errors. This action cannot be A confirmation prompt is shown unless --force is passed.`, Example: `# Delete a management key (with confirmation prompt) -qcloud access key delete a1b2c3d4-e5f6-7890-abcd-ef1234567890 +qcloud iam key delete a1b2c3d4-e5f6-7890-abcd-ef1234567890 # Delete without confirmation -qcloud access key delete a1b2c3d4-e5f6-7890-abcd-ef1234567890 --force`, +qcloud iam key delete a1b2c3d4-e5f6-7890-abcd-ef1234567890 --force`, BaseCobraCommand: func() *cobra.Command { cmd := &cobra.Command{ Use: "delete ", diff --git a/internal/cmd/access/key_delete_test.go b/internal/cmd/iam/key_delete_test.go similarity index 80% rename from internal/cmd/access/key_delete_test.go rename to internal/cmd/iam/key_delete_test.go index f2f1d39..79e2436 100644 --- a/internal/cmd/access/key_delete_test.go +++ b/internal/cmd/iam/key_delete_test.go @@ -1,4 +1,4 @@ -package access_test +package iam_test import ( "fmt" @@ -17,7 +17,7 @@ func TestKeyDelete_WithForce(t *testing.T) { env.AuthServer.DeleteManagementKeyCalls.Returns(&authv1.DeleteManagementKeyResponse{}, nil) - stdout, _, err := testutil.Exec(t, env, "access", "key", "delete", "key-abc", "--force") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "delete", "key-abc", "--force") require.NoError(t, err) assert.Contains(t, stdout, "key-abc") assert.Contains(t, stdout, "deleted") @@ -31,7 +31,7 @@ func TestKeyDelete_WithForce(t *testing.T) { func TestKeyDelete_Aborted(t *testing.T) { env := testutil.NewTestEnv(t) - stdout, _, err := testutil.Exec(t, env, "access", "key", "delete", "key-abc") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "delete", "key-abc") require.NoError(t, err) assert.Contains(t, stdout, "Aborted.") assert.Equal(t, 0, env.AuthServer.DeleteManagementKeyCalls.Count()) @@ -42,14 +42,14 @@ func TestKeyDelete_BackendError(t *testing.T) { env.AuthServer.DeleteManagementKeyCalls.Returns(nil, fmt.Errorf("internal server error")) - _, _, err := testutil.Exec(t, env, "access", "key", "delete", "key-abc", "--force") + _, _, err := testutil.Exec(t, env, "iam", "key", "delete", "key-abc", "--force") require.Error(t, err) } func TestKeyDelete_MissingArg(t *testing.T) { env := testutil.NewTestEnv(t) - _, _, err := testutil.Exec(t, env, "access", "key", "delete") + _, _, err := testutil.Exec(t, env, "iam", "key", "delete") require.Error(t, err) } @@ -63,7 +63,7 @@ func TestKeyDeleteCompletion(t *testing.T) { }, }, nil) - stdout, _, err := testutil.Exec(t, env, "__complete", "access", "key", "delete", "") + stdout, _, err := testutil.Exec(t, env, "__complete", "iam", "key", "delete", "") require.NoError(t, err) assert.Contains(t, stdout, "key-uuid-1") assert.Contains(t, stdout, "abc123") diff --git a/internal/cmd/access/key_list.go b/internal/cmd/iam/key_list.go similarity index 96% rename from internal/cmd/access/key_list.go rename to internal/cmd/iam/key_list.go index 3433d87..4969264 100644 --- a/internal/cmd/access/key_list.go +++ b/internal/cmd/iam/key_list.go @@ -1,4 +1,4 @@ -package access +package iam import ( "io" @@ -22,10 +22,10 @@ Management keys grant access to the Qdrant Cloud API and are used to authenticat and API requests. Each key is identified by its ID and a prefix — the prefix represents the first bytes of the key value and is safe to display.`, Example: `# List all management keys for the account -qcloud access key list +qcloud iam key list # Output as JSON -qcloud access key list --json`, +qcloud iam key list --json`, Fetch: func(s *state.State, cmd *cobra.Command) (*authv1.ListManagementKeysResponse, error) { ctx := cmd.Context() client, err := s.Client(ctx) diff --git a/internal/cmd/access/key_list_test.go b/internal/cmd/iam/key_list_test.go similarity index 88% rename from internal/cmd/access/key_list_test.go rename to internal/cmd/iam/key_list_test.go index 09261ef..afc1263 100644 --- a/internal/cmd/access/key_list_test.go +++ b/internal/cmd/iam/key_list_test.go @@ -1,4 +1,4 @@ -package access_test +package iam_test import ( "encoding/json" @@ -28,7 +28,7 @@ func TestKeyList_TableOutput(t *testing.T) { }, }, nil) - stdout, _, err := testutil.Exec(t, env, "access", "key", "list") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "list") require.NoError(t, err) assert.Contains(t, stdout, "ID") assert.Contains(t, stdout, "PREFIX") @@ -51,7 +51,7 @@ func TestKeyList_JSONOutput(t *testing.T) { }, }, nil) - stdout, _, err := testutil.Exec(t, env, "access", "key", "list", "--json") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "list", "--json") require.NoError(t, err) var result struct { @@ -71,7 +71,7 @@ func TestKeyList_BackendError(t *testing.T) { env.AuthServer.ListManagementKeysCalls.Returns(nil, fmt.Errorf("internal server error")) - _, _, err := testutil.Exec(t, env, "access", "key", "list") + _, _, err := testutil.Exec(t, env, "iam", "key", "list") require.Error(t, err) } @@ -80,7 +80,7 @@ func TestKeyList_Empty(t *testing.T) { env.AuthServer.ListManagementKeysCalls.Returns(&authv1.ListManagementKeysResponse{}, nil) - stdout, _, err := testutil.Exec(t, env, "access", "key", "list") + stdout, _, err := testutil.Exec(t, env, "iam", "key", "list") require.NoError(t, err) assert.Contains(t, stdout, "ID") assert.Contains(t, stdout, "PREFIX")