diff --git a/cmd/lint/main.go b/cmd/lint/main.go index 80cf81531a..1e03e20945 100644 --- a/cmd/lint/main.go +++ b/cmd/lint/main.go @@ -189,6 +189,7 @@ var properNouns = []string{ "ksqlDB Server", "ksqlDB", "Node.js", + "Organization", "Prometheus", "Python", "Real Time Context Engine", @@ -337,6 +338,7 @@ var vocabWords = []string{ "savepoints", "scala", "schemas", + "scim", "server", "signup", "siv", diff --git a/go.mod b/go.mod index 0b7635c561..b2940a2313 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/confluentinc/ccloud-sdk-go-v2/networking-gateway v0.7.0 github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0 github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.3.0 - github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0 + github.com/confluentinc/ccloud-sdk-go-v2/org v0.11.0 github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.2.0 github.com/confluentinc/ccloud-sdk-go-v2/rtce v0.1.0 github.com/confluentinc/ccloud-sdk-go-v2/service-quota v0.2.0 @@ -297,3 +297,5 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) + +replace github.com/confluentinc/ccloud-sdk-go-v2/org => /Users/ameliadong/git/go/src/github.com/confluentinc/cli-terraform-generator/test-suites/specs/org diff --git a/go.sum b/go.sum index 5261469a72..915671120d 100644 --- a/go.sum +++ b/go.sum @@ -250,8 +250,6 @@ github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0 h1:ZHNF2DeqVlNPuKG github.com/confluentinc/ccloud-sdk-go-v2/networking-ip v0.2.0/go.mod h1:KTShFBZA7WG8LcxlWjJpoZFdWkJ+uOw3dDuwAHs5eKU= github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.3.0 h1:mC0E1nKUt57AxMM4Lpdfd+KA/YZwJVwro9ER+dCUFi8= github.com/confluentinc/ccloud-sdk-go-v2/networking-privatelink v0.3.0/go.mod h1:GIHF2cYOUKx+6ycYokr4i8E4cuNBC22xqvO/IhqZ31U= -github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0 h1:FtaqHX0kBTK7fCQK+9SJcOso+XpWCWzY2roT3gBQGfw= -github.com/confluentinc/ccloud-sdk-go-v2/org v0.9.0/go.mod h1:X0uaTYPp+mr19W1R/Z1LuB1ePZJZrH7kxnQckDx6zoc= github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.2.0 h1:UN2a+aqYhk95ro+wVLkeB/8W7n+UV2KsE3jNFbbDCSw= github.com/confluentinc/ccloud-sdk-go-v2/provider-integration v0.2.0/go.mod h1:TzompS9F0G6awN5xMC+nguNG8ULElN5UqX2XOBOIPuM= github.com/confluentinc/ccloud-sdk-go-v2/rtce v0.1.0 h1:OBa2vm09bOG1oojOP1vNj8V7+M2AfUkYP1sRQ+xlRm4= diff --git a/internal/command.go b/internal/command.go index 75ab94af7b..5f07e6c559 100644 --- a/internal/command.go +++ b/internal/command.go @@ -36,6 +36,7 @@ import ( "github.com/confluentinc/cli/v4/internal/login" "github.com/confluentinc/cli/v4/internal/logout" "github.com/confluentinc/cli/v4/internal/network" + "github.com/confluentinc/cli/v4/internal/org" "github.com/confluentinc/cli/v4/internal/organization" "github.com/confluentinc/cli/v4/internal/plugin" "github.com/confluentinc/cli/v4/internal/prompt" @@ -128,6 +129,7 @@ func NewConfluentCommand(cfg *config.Config) *cobra.Command { cmd.AddCommand(login.New(cfg, prerunner, ccloudClientFactory, mdsClientManager, loginCredentialsManager, loginOrganizationManager, authTokenHandler)) cmd.AddCommand(logout.New(cfg, prerunner, authTokenHandler)) cmd.AddCommand(network.New(cfg, prerunner)) + cmd.AddCommand(org.New(cfg, prerunner)) cmd.AddCommand(organization.New(prerunner)) cmd.AddCommand(plugin.New(cfg, prerunner)) cmd.AddCommand(prompt.New(cfg)) diff --git a/internal/org/command.go b/internal/org/command.go new file mode 100644 index 0000000000..6db32a6095 --- /dev/null +++ b/internal/org/command.go @@ -0,0 +1,22 @@ +package org + +import ( + "github.com/spf13/cobra" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/config" +) + +func New(cfg *config.Config, prerunner pcmd.PreRunner) *cobra.Command { + cmd := &cobra.Command{ + Use: "org", + Short: "Manage Organization.", + } + + cmd.AddCommand( + newScimTokenCommand(cfg, prerunner), + // cli-tfgen:cli-subcommands + ) + + return cmd +} diff --git a/internal/org/command_scim_token.go b/internal/org/command_scim_token.go new file mode 100644 index 0000000000..566a1662e1 --- /dev/null +++ b/internal/org/command_scim_token.go @@ -0,0 +1,85 @@ +package org + +import ( + "github.com/spf13/cobra" + + orgv2 "github.com/confluentinc/ccloud-sdk-go-v2/org/v2" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/config" + "github.com/confluentinc/cli/v4/pkg/output" +) + +type scimTokenCommand struct { + *pcmd.AuthenticatedCLICommand +} + +type scimTokenOut struct { + ID string `human:"ID" serialized:"id"` + ConnectionName string `human:"Connection Name" serialized:"connection_name"` + Token string `human:"Token" serialized:"token"` + CreatedAt string `human:"Created At" serialized:"created_at"` + ExpiresAt string `human:"Expires At" serialized:"expires_at"` +} + +func newScimTokenCommand(cfg *config.Config, prerunner pcmd.PreRunner) *cobra.Command { //nolint:unparam + cmd := &cobra.Command{ + Use: "scim-token", + Short: "Manage org scim tokens.", + Annotations: map[string]string{pcmd.RunRequirement: pcmd.RequireNonAPIKeyCloudLogin}, + } + + c := &scimTokenCommand{ + AuthenticatedCLICommand: pcmd.NewAuthenticatedCLICommand(cmd, prerunner), + } + + cmd.AddCommand( + c.newCreateCommand(), + c.newDeleteCommand(), + c.newListCommand(), + ) + + return cmd +} + +func printScimToken(cmd *cobra.Command, scimToken orgv2.OrgV2ScimToken) error { + table := output.NewTable(cmd) + out := &scimTokenOut{ + ID: scimToken.GetId(), + ConnectionName: scimToken.GetConnectionName(), + Token: scimToken.GetToken(), + CreatedAt: scimToken.GetCreatedAt().String(), + ExpiresAt: scimToken.GetExpiresAt().String(), + } + table.Add(out) + return table.Print() +} + +func (c *scimTokenCommand) validArgs(cmd *cobra.Command, args []string) []string { + if len(args) > 0 { + return nil + } + + return c.validArgsMultiple(cmd, args) +} + +func (c *scimTokenCommand) validArgsMultiple(cmd *cobra.Command, args []string) []string { + if err := c.PersistentPreRunE(cmd, args); err != nil { + return nil + } + + return c.autocompleteScimTokens() +} + +func (c *scimTokenCommand) autocompleteScimTokens() []string { + scimTokens, err := c.V2Client.ListOrgScimTokens() + if err != nil { + return nil + } + + suggestions := make([]string, len(scimTokens)) + for i, scimToken := range scimTokens { + suggestions[i] = scimToken.GetId() + } + return suggestions +} diff --git a/internal/org/command_scim_token_create.go b/internal/org/command_scim_token_create.go new file mode 100644 index 0000000000..5880fae3a2 --- /dev/null +++ b/internal/org/command_scim_token_create.go @@ -0,0 +1,39 @@ +package org + +import ( + "github.com/spf13/cobra" + + orgv2 "github.com/confluentinc/ccloud-sdk-go-v2/org/v2" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/errors" +) + +func (c *scimTokenCommand) newCreateCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "create", + Short: "Create an org scim token.", + Args: cobra.NoArgs, + RunE: c.create, + } + + // Required flags + + // Optional flags + + pcmd.AddContextFlag(cmd, c.CLICommand) + pcmd.AddOutputFlag(cmd) + + return cmd +} + +func (c *scimTokenCommand) create(cmd *cobra.Command, args []string) error { + createReq := orgv2.InlineObject{} + + scimToken, httpResp, err := c.V2Client.CreateOrgScimToken(createReq) + if err != nil { + return errors.CatchCCloudV2Error(err, httpResp) + } + + return printScimToken(cmd, scimToken) +} diff --git a/internal/org/command_scim_token_delete.go b/internal/org/command_scim_token_delete.go new file mode 100644 index 0000000000..1cd200fa40 --- /dev/null +++ b/internal/org/command_scim_token_delete.go @@ -0,0 +1,38 @@ +package org + +import ( + "github.com/spf13/cobra" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/deletion" +) + +func (c *scimTokenCommand) newDeleteCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "delete [id-2] ... [id-n]", + Short: "Delete one or more org scim tokens.", + Args: cobra.MinimumNArgs(1), + ValidArgsFunction: pcmd.NewValidArgsFunction(c.validArgsMultiple), + RunE: c.delete, + } + + // Required flags + + // Optional flags + + pcmd.AddContextFlag(cmd, c.CLICommand) + pcmd.AddForceFlag(cmd) + + return cmd +} + +func (c *scimTokenCommand) delete(cmd *cobra.Command, args []string) error { + // Note: existence check skipped because Get operation is not available for this resource + + deleteFunc := func(primaryId string) error { + return c.V2Client.DeleteOrgScimToken(primaryId) + } + + _, err := deletion.Delete(cmd, args, deleteFunc, "org scim token") + return err +} diff --git a/internal/org/command_scim_token_list.go b/internal/org/command_scim_token_list.go new file mode 100644 index 0000000000..b43477ddd1 --- /dev/null +++ b/internal/org/command_scim_token_list.go @@ -0,0 +1,47 @@ +package org + +import ( + "github.com/spf13/cobra" + + pcmd "github.com/confluentinc/cli/v4/pkg/cmd" + "github.com/confluentinc/cli/v4/pkg/output" +) + +func (c *scimTokenCommand) newListCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "list", + Short: "List org scim tokens.", + Args: cobra.NoArgs, + RunE: c.list, + } + + // Required flags + + // Optional flags + + pcmd.AddContextFlag(cmd, c.CLICommand) + pcmd.AddOutputFlag(cmd) + + return cmd +} + +func (c *scimTokenCommand) list(cmd *cobra.Command, _ []string) error { + + scimTokens, err := c.V2Client.ListOrgScimTokens() + if err != nil { + return err + } + + list := output.NewList(cmd) + for _, scimToken := range scimTokens { + out := &scimTokenOut{ + ID: scimToken.GetId(), + ConnectionName: scimToken.GetConnectionName(), + Token: scimToken.GetToken(), + CreatedAt: scimToken.GetCreatedAt().String(), + ExpiresAt: scimToken.GetExpiresAt().String(), + } + list.Add(out) + } + return list.Print() +} diff --git a/pkg/ccloudv2/org.go b/pkg/ccloudv2/org.go index 835c9d0568..acd95e3682 100644 --- a/pkg/ccloudv2/org.go +++ b/pkg/ccloudv2/org.go @@ -106,3 +106,50 @@ func (c *Client) executeListOrganizations(pageToken string) (orgv2.OrgV2Organiza } return req.Execute() } + +// ===== org scim tokens API calls ===== + +func (c *Client) CreateOrgScimToken(req orgv2.InlineObject) (orgv2.OrgV2ScimToken, *http.Response, error) { + createReq := c.OrgClient.ScimTokensOrgV2Api. + CreateOrgV2ScimToken(c.orgApiContext()). + InlineObject(req) + return createReq.Execute() +} + +func (c *Client) DeleteOrgScimToken(id string) error { + deleteReq := c.OrgClient.ScimTokensOrgV2Api. + DeleteOrgV2ScimToken(c.orgApiContext(), id) + httpResp, err := deleteReq.Execute() + return errors.CatchCCloudV2Error(err, httpResp) +} + +func (c *Client) ListOrgScimTokens() ([]orgv2.OrgV2ScimToken, error) { + var list []orgv2.OrgV2ScimToken + + done := false + pageToken := "" + for !done { + page, httpResp, err := c.executeListScimTokens(pageToken) + if err != nil { + return nil, errors.CatchCCloudV2Error(err, httpResp) + } + list = append(list, page.GetData()...) + + pageToken, done, err = extractNextPageToken(page.GetMetadata().Next) + if err != nil { + return nil, err + } + } + + return list, nil +} + +func (c *Client) executeListScimTokens(pageToken string) (orgv2.OrgV2ScimTokenList, *http.Response, error) { + req := c.OrgClient.ScimTokensOrgV2Api. + ListOrgV2ScimTokens(c.orgApiContext()). + PageSize(ccloudV2ListPageSize) + if pageToken != "" { + req = req.PageToken(pageToken) + } + return req.Execute() +} diff --git a/test/fixtures/input/org/scim_token/create_scim_token.json b/test/fixtures/input/org/scim_token/create_scim_token.json new file mode 100644 index 0000000000..09ac05bfb8 --- /dev/null +++ b/test/fixtures/input/org/scim_token/create_scim_token.json @@ -0,0 +1,16 @@ +{ + "api_version": "org/v2", + "connection_name": "test-connection", + "created_at": "2026-04-16T10:00:00Z", + "expires_at": "2026-10-16T10:00:00Z", + "id": "dlz-f3a90de", + "kind": "ScimToken", + "metadata": { + "created_at": "2006-01-02T15:04:05-07:00", + "deleted_at": "2006-01-02T15:04:05-07:00", + "resource_name": "crn://confluent.cloud/organization=9bb441c4-edef-46ac-8a41-c49e44a3fd9a/scim-token=st-12345", + "self": "https://api.confluent.cloud/org/v2/scim-tokens/st-12345", + "updated_at": "2006-01-02T15:04:05-07:00" + }, + "token": "cflt-scim_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} diff --git a/test/fixtures/input/org/scim_token/read_created_scim_token.json b/test/fixtures/input/org/scim_token/read_created_scim_token.json new file mode 100644 index 0000000000..09ac05bfb8 --- /dev/null +++ b/test/fixtures/input/org/scim_token/read_created_scim_token.json @@ -0,0 +1,16 @@ +{ + "api_version": "org/v2", + "connection_name": "test-connection", + "created_at": "2026-04-16T10:00:00Z", + "expires_at": "2026-10-16T10:00:00Z", + "id": "dlz-f3a90de", + "kind": "ScimToken", + "metadata": { + "created_at": "2006-01-02T15:04:05-07:00", + "deleted_at": "2006-01-02T15:04:05-07:00", + "resource_name": "crn://confluent.cloud/organization=9bb441c4-edef-46ac-8a41-c49e44a3fd9a/scim-token=st-12345", + "self": "https://api.confluent.cloud/org/v2/scim-tokens/st-12345", + "updated_at": "2006-01-02T15:04:05-07:00" + }, + "token": "cflt-scim_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." +} diff --git a/test/fixtures/output/help.golden b/test/fixtures/output/help.golden index e705038f57..f17daba4e2 100644 --- a/test/fixtures/output/help.golden +++ b/test/fixtures/output/help.golden @@ -28,6 +28,7 @@ Available Commands: login Log in to Confluent Cloud or Confluent Platform. logout Log out of Confluent Cloud. network Manage Confluent Cloud networks. + org Manage Organization. organization Manage your Confluent Cloud organizations. plugin Manage Confluent plugins. prompt Add Confluent CLI context to your terminal prompt. diff --git a/test/fixtures/output/org/help.golden b/test/fixtures/output/org/help.golden new file mode 100644 index 0000000000..38f707f415 --- /dev/null +++ b/test/fixtures/output/org/help.golden @@ -0,0 +1,14 @@ +Manage Organization. + +Usage: + confluent org [command] + +Available Commands: + scim-token Manage org scim tokens. + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). + +Use "confluent org [command] --help" for more information about a command. diff --git a/test/fixtures/output/org/scim-token/create-help.golden b/test/fixtures/output/org/scim-token/create-help.golden new file mode 100644 index 0000000000..80f1effa7d --- /dev/null +++ b/test/fixtures/output/org/scim-token/create-help.golden @@ -0,0 +1,13 @@ +Create an org scim token. + +Usage: + confluent org scim-token create [flags] + +Flags: + --context string CLI context name. + -o, --output string Specify the output format as "human", "json", or "yaml". (default "human") + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). diff --git a/test/fixtures/output/org/scim-token/create.golden b/test/fixtures/output/org/scim-token/create.golden new file mode 100644 index 0000000000..7812d5ae96 --- /dev/null +++ b/test/fixtures/output/org/scim-token/create.golden @@ -0,0 +1,7 @@ ++-----------------+---------------------------------------------------+ +| ID | dlz-f3a90de | +| Connection Name | test-connection | +| Token | cflt-scim_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | +| Created At | 2026-04-16 10:00:00 +0000 UTC | +| Expires At | 2026-10-16 10:00:00 +0000 UTC | ++-----------------+---------------------------------------------------+ diff --git a/test/fixtures/output/org/scim-token/delete-help.golden b/test/fixtures/output/org/scim-token/delete-help.golden new file mode 100644 index 0000000000..d4b40ff9aa --- /dev/null +++ b/test/fixtures/output/org/scim-token/delete-help.golden @@ -0,0 +1,13 @@ +Delete one or more org scim tokens. + +Usage: + confluent org scim-token delete [id-2] ... [id-n] [flags] + +Flags: + --context string CLI context name. + --force Skip the deletion confirmation prompt. + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). diff --git a/test/fixtures/output/org/scim-token/delete-invalid.golden b/test/fixtures/output/org/scim-token/delete-invalid.golden new file mode 100644 index 0000000000..1005309fc7 --- /dev/null +++ b/test/fixtures/output/org/scim-token/delete-invalid.golden @@ -0,0 +1 @@ +Error: failed to delete invalid: 404 Not Found diff --git a/test/fixtures/output/org/scim-token/delete-multiple.golden b/test/fixtures/output/org/scim-token/delete-multiple.golden new file mode 100644 index 0000000000..fc901c97a3 --- /dev/null +++ b/test/fixtures/output/org/scim-token/delete-multiple.golden @@ -0,0 +1 @@ +Deleted org scim tokens "id-1" and "id-2". diff --git a/test/fixtures/output/org/scim-token/delete-no-force.golden b/test/fixtures/output/org/scim-token/delete-no-force.golden new file mode 100644 index 0000000000..46eb78fc9a --- /dev/null +++ b/test/fixtures/output/org/scim-token/delete-no-force.golden @@ -0,0 +1 @@ +Deleted org scim token "id-1". diff --git a/test/fixtures/output/org/scim-token/delete.golden b/test/fixtures/output/org/scim-token/delete.golden new file mode 100644 index 0000000000..46eb78fc9a --- /dev/null +++ b/test/fixtures/output/org/scim-token/delete.golden @@ -0,0 +1 @@ +Deleted org scim token "id-1". diff --git a/test/fixtures/output/org/scim-token/help.golden b/test/fixtures/output/org/scim-token/help.golden new file mode 100644 index 0000000000..f245f82fe4 --- /dev/null +++ b/test/fixtures/output/org/scim-token/help.golden @@ -0,0 +1,16 @@ +Manage org scim tokens. + +Usage: + confluent org scim-token [command] + +Available Commands: + create Create an org scim token. + delete Delete one or more org scim tokens. + list List org scim tokens. + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). + +Use "confluent org scim-token [command] --help" for more information about a command. diff --git a/test/fixtures/output/org/scim-token/list-help.golden b/test/fixtures/output/org/scim-token/list-help.golden new file mode 100644 index 0000000000..0f5949c7e9 --- /dev/null +++ b/test/fixtures/output/org/scim-token/list-help.golden @@ -0,0 +1,13 @@ +List org scim tokens. + +Usage: + confluent org scim-token list [flags] + +Flags: + --context string CLI context name. + -o, --output string Specify the output format as "human", "json", or "yaml". (default "human") + +Global Flags: + -h, --help Show help for this command. + --unsafe-trace Equivalent to -vvvv, but also log HTTP requests and responses which might contain plaintext secrets. + -v, --verbose count Increase verbosity (-v for warn, -vv for info, -vvv for debug, -vvvv for trace). diff --git a/test/fixtures/output/org/scim-token/list-json.golden b/test/fixtures/output/org/scim-token/list-json.golden new file mode 100644 index 0000000000..0e1bf653aa --- /dev/null +++ b/test/fixtures/output/org/scim-token/list-json.golden @@ -0,0 +1,9 @@ +[ + { + "id": "dlz-f3a90de", + "connection_name": "test-connection", + "token": "cflt-scim_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", + "created_at": "2026-04-16 10:00:00 +0000 UTC", + "expires_at": "2026-10-16 10:00:00 +0000 UTC" + } +] diff --git a/test/fixtures/output/org/scim-token/list-yaml.golden b/test/fixtures/output/org/scim-token/list-yaml.golden new file mode 100644 index 0000000000..a14f5883db --- /dev/null +++ b/test/fixtures/output/org/scim-token/list-yaml.golden @@ -0,0 +1,5 @@ +- id: dlz-f3a90de + connection_name: test-connection + token: cflt-scim_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... + created_at: 2026-04-16 10:00:00 +0000 UTC + expires_at: 2026-10-16 10:00:00 +0000 UTC diff --git a/test/fixtures/output/org/scim-token/list.golden b/test/fixtures/output/org/scim-token/list.golden new file mode 100644 index 0000000000..361915e149 --- /dev/null +++ b/test/fixtures/output/org/scim-token/list.golden @@ -0,0 +1,3 @@ + ID | Connection Name | Token | Created At | Expires At +--------------+-----------------+---------------------------------------------------+-------------------------------+-------------------------------- + dlz-f3a90de | test-connection | cflt-scim_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | 2026-04-16 10:00:00 +0000 UTC | 2026-10-16 10:00:00 +0000 UTC diff --git a/test/live/scim_token_live_test.go b/test/live/scim_token_live_test.go new file mode 100644 index 0000000000..34662b04d1 --- /dev/null +++ b/test/live/scim_token_live_test.go @@ -0,0 +1,55 @@ +//go:build live_test && (all || core) + +package live + +import ( + "testing" +) + +func (s *CLILiveTestSuite) TestScimTokenCRUDLive() { + t := s.T() + t.Parallel() + state := s.setupTestContext(t) + + // Variables + scimTokenName := uniqueName("scimto") + + // Cleanup (LIFO) + s.registerCleanup(t, "org scim-token delete {{.scim_token_id}} --force", state) + + steps := []CLILiveTest{ + { + Name: "Create org scim token", + Args: "org scim-token create " + scimTokenName + " -o json", + ExitCode: 0, + JSONFields: map[string]string{}, + JSONFieldsExist: []string{"id"}, + CaptureID: "scim_token_id", + }, + { + Name: "List org scim tokens", + Args: "org scim-token list", + UseStateVars: true, + ExitCode: 0, + Contains: []string{scimTokenName}, + }, + { + Name: "Delete org scim token", + Args: "org scim-token delete {{.scim_token_id}} --force", + UseStateVars: true, + ExitCode: 0, + }, + { + Name: "Verify deletion", + Args: "org scim-token describe {{.scim_token_id}}", + UseStateVars: true, + ExitCode: 1, + }, + } + + for _, step := range steps { + t.Run(step.Name, func(t *testing.T) { + s.runLiveCommand(t, step, state) + }) + } +} diff --git a/test/scim_token_test.go b/test/scim_token_test.go new file mode 100644 index 0000000000..83c22d055b --- /dev/null +++ b/test/scim_token_test.go @@ -0,0 +1,50 @@ +package test + +func (s *CLITestSuite) TestOrgScimTokenCreate() { + tests := []CLITest{ + {args: "org scim-token create", fixture: "org/scim-token/create.golden"}, + } + + for _, test := range tests { + test.login = "cloud" + s.runIntegrationTest(test) + } +} + +func (s *CLITestSuite) TestOrgScimTokenDelete() { + tests := []CLITest{ + {args: "org scim-token delete id-1 --force", fixture: "org/scim-token/delete.golden"}, + {args: "org scim-token delete id-1", input: "y\n", fixture: "org/scim-token/delete-no-force.golden"}, + {args: "org scim-token delete id-1 id-2", input: "y\n", fixture: "org/scim-token/delete-multiple.golden"}, + {args: "org scim-token delete invalid", fixture: "org/scim-token/delete-invalid.golden", exitCode: 1}, + } + + for _, test := range tests { + test.login = "cloud" + s.runIntegrationTest(test) + } +} + +func (s *CLITestSuite) TestOrgScimTokenList() { + tests := []CLITest{ + {args: "org scim-token list", fixture: "org/scim-token/list.golden"}, + {args: "org scim-token list -o json", fixture: "org/scim-token/list-json.golden"}, + {args: "org scim-token list -o yaml", fixture: "org/scim-token/list-yaml.golden"}, + } + + for _, test := range tests { + test.login = "cloud" + s.runIntegrationTest(test) + } +} + +func (s *CLITestSuite) TestOrgScimToken_Autocomplete() { + tests := []CLITest{ + {args: "__complete org scim-token delete \"\"", fixture: "org/scim-token/delete-autocomplete.golden"}, + } + + for _, test := range tests { + test.login = "cloud" + s.runIntegrationTest(test) + } +} diff --git a/test/test-server/ccloudv2_router.go b/test/test-server/ccloudv2_router.go index 002eaf9c99..8c11c8f1cd 100644 --- a/test/test-server/ccloudv2_router.go +++ b/test/test-server/ccloudv2_router.go @@ -117,6 +117,8 @@ var ccloudV2Routes = []route{ {"/org/v2/environments/{id}", handleOrgEnvironment}, {"/org/v2/organizations", handleOrgOrganizations}, {"/org/v2/organizations/{id}", handleOrgOrganization}, + {"/org/v2/scim-tokens", handleOrgV2ScimTokens}, + {"/org/v2/scim-tokens/{id}", handleOrgV2ScimTokensId}, {"/pim/v1/integrations", handleProviderIntegrations}, {"/pim/v1/integrations/{id}", handleProviderIntegration}, {"/pim/v2/integrations", handleProviderIntegrationsV2}, diff --git a/test/test-server/scim_token_handler.go b/test/test-server/scim_token_handler.go new file mode 100644 index 0000000000..ba894680bc --- /dev/null +++ b/test/test-server/scim_token_handler.go @@ -0,0 +1,68 @@ +package testserver + +import ( + "encoding/json" + "net/http" + "os" + "path/filepath" + "testing" + + "github.com/gorilla/mux" + "github.com/stretchr/testify/require" + + orgv2 "github.com/confluentinc/ccloud-sdk-go-v2/org/v2" +) + +// Handler for "/org/v2/scim-tokens" +func handleOrgV2ScimTokens(t *testing.T) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + scimToken := readOrgV2ScimTokenFile(t, "read_created_scim_token.json") + + scimTokenList := &orgv2.OrgV2ScimTokenList{ + Data: []orgv2.OrgV2ScimToken{scimToken}, + } + + err := json.NewEncoder(w).Encode(scimTokenList) + require.NoError(t, err) + case http.MethodPost: + scimToken := readOrgV2ScimTokenFile(t, "create_scim_token.json") + + // Overwrite updated fields using the request body + err := json.NewDecoder(r.Body).Decode(&scimToken) + require.NoError(t, err) + + err = json.NewEncoder(w).Encode(scimToken) + require.NoError(t, err) + } + } +} + +// Handler for "/org/v2/scim-tokens/{id}" +func handleOrgV2ScimTokensId(t *testing.T) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + id := mux.Vars(r)["id"] + switch r.Method { + case http.MethodDelete: + switch id { + case "invalid": + w.WriteHeader(http.StatusNotFound) + default: + w.WriteHeader(http.StatusNoContent) + } + } + } +} + +func readOrgV2ScimTokenFile(t *testing.T, filename string) orgv2.OrgV2ScimToken { + jsonPath := filepath.Join("test", "fixtures", "input", "org", "scim_token", filename) + jsonData, err := os.ReadFile(jsonPath) + require.NoError(t, err) + + scimToken := orgv2.OrgV2ScimToken{} + err = json.Unmarshal(jsonData, &scimToken) + require.NoError(t, err) + + return scimToken +}