From 47e29547376a0b90dc12180ea9dccc90b028b189 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 09:47:10 +0200 Subject: [PATCH 1/7] add project validation function, errors and apply for list command --- internal/cmd/ske/cluster/list/list.go | 19 +++------ internal/pkg/errors/errors.go | 28 ++++++++++++ internal/pkg/validation/project.go | 61 +++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 internal/pkg/validation/project.go diff --git a/internal/cmd/ske/cluster/list/list.go b/internal/cmd/ske/cluster/list/list.go index 8c357924a..980f06b35 100644 --- a/internal/cmd/ske/cluster/list/list.go +++ b/internal/cmd/ske/cluster/list/list.go @@ -13,12 +13,12 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" serviceEnablementClient "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/client" serviceEnablementUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/client" "github.com/stackitcloud/stackit-cli/internal/pkg/tables" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/spf13/cobra" "github.com/stackitcloud/stackit-sdk-go/services/ske" @@ -57,6 +57,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } + // Validate project ID (exists and user has access) + projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + if err != nil { + return err + } + // Configure API client apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -91,14 +97,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { clusters = clusters[:*model.Limit] } - projectLabel := model.ProjectId - if len(clusters) == 0 { - projectLabel, err = projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) - if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - } - } - return outputResult(params.Printer, model.OutputFormat, projectLabel, clusters) }, } @@ -113,9 +111,6 @@ func configureFlags(cmd *cobra.Command) { func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } limit := flags.FlagToInt64Pointer(p, cmd, limitFlag) if limit != nil && *limit < 1 { diff --git a/internal/pkg/errors/errors.go b/internal/pkg/errors/errors.go index 9c83fb4f1..e6303f86d 100644 --- a/internal/pkg/errors/errors.go +++ b/internal/pkg/errors/errors.go @@ -178,6 +178,16 @@ To list all profiles, run: $ stackit config profile list` FILE_ALREADY_EXISTS = `file %q already exists in the export path. Delete the existing file or define a different export path` + + PROJECT_NOT_FOUND = `the project %[2]q (ID: %[1]s) does not exist. + +To list all available projects, run: + $ stackit project list` + + PROJECT_ACCESS_DENIED = `you don't have access to the project %[2]q (ID: %[1]s). + +To list all available projects, run: + $ stackit project list` ) type ServerNicAttachMissingNicIdError struct { @@ -499,3 +509,21 @@ type FileAlreadyExistsError struct { } func (e *FileAlreadyExistsError) Error() string { return fmt.Sprintf(FILE_ALREADY_EXISTS, e.Filename) } + +type ProjectNotFoundError struct { + ProjectId string + ProjectLabel string +} + +func (e *ProjectNotFoundError) Error() string { + return fmt.Sprintf(PROJECT_NOT_FOUND, e.ProjectId, e.ProjectLabel) +} + +type ProjectAccessDeniedError struct { + ProjectId string + ProjectLabel string +} + +func (e *ProjectAccessDeniedError) Error() string { + return fmt.Sprintf(PROJECT_ACCESS_DENIED, e.ProjectId, e.ProjectLabel) +} diff --git a/internal/pkg/validation/project.go b/internal/pkg/validation/project.go new file mode 100644 index 000000000..3d3bbb333 --- /dev/null +++ b/internal/pkg/validation/project.go @@ -0,0 +1,61 @@ +package validation + +import ( + "context" + "fmt" + "net/http" + + "github.com/stackitcloud/stackit-cli/internal/pkg/errors" + "github.com/stackitcloud/stackit-cli/internal/pkg/print" + "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" + "github.com/stackitcloud/stackit-cli/internal/pkg/services/resourcemanager/client" + + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-sdk-go/core/oapierror" +) + +// ValidateProject validates that the project ID is not empty, exists, and the user has access to it. +// It returns the project name for display purposes. +func ValidateProject(ctx context.Context, p *print.Printer, cliVersion string, cmd *cobra.Command, projectId string) (string, error) { + // Check if project ID is empty + if projectId == "" { + return "", &errors.ProjectIdError{} + } + + // Configure Resource Manager API client + apiClient, err := client.ConfigureClient(p, cliVersion) + if err != nil { + return "", fmt.Errorf("configure resource manager client: %w", err) + } + + // Try to get project details to validate existence and access + req := apiClient.GetProject(ctx, projectId) + resp, err := req.Execute() + if err != nil { + // Check for specific HTTP status codes + if httpErr, ok := err.(*oapierror.GenericOpenAPIError); ok { + switch httpErr.StatusCode { + case http.StatusNotFound: + // Try to get project name for better error message + projectLabel := projectId + if projectName, nameErr := projectname.GetProjectName(ctx, p, cliVersion, cmd); nameErr == nil { + projectLabel = projectName + } + return "", &errors.ProjectNotFoundError{ProjectId: projectId, ProjectLabel: projectLabel} + case http.StatusForbidden: + // Try to get project name for better error message + projectLabel := projectId + if projectName, nameErr := projectname.GetProjectName(ctx, p, cliVersion, cmd); nameErr == nil { + projectLabel = projectName + } + return "", &errors.ProjectAccessDeniedError{ProjectId: projectId, ProjectLabel: projectLabel} + case http.StatusUnauthorized: + return "", &errors.AuthError{} + } + } + return "", fmt.Errorf("validate project: %w", err) + } + + // Project exists and user has access, returning the project name + return *resp.Name, nil +} From 4eb0fc947140ccad0f218759667431392ddcb697 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 09:47:35 +0200 Subject: [PATCH 2/7] adjust all commands of ske service to use validate project function --- internal/cmd/ske/cluster/create/create.go | 15 ++++++--------- internal/cmd/ske/cluster/delete/delete.go | 11 +++++++---- internal/cmd/ske/cluster/describe/describe.go | 12 ++++++++---- internal/cmd/ske/describe/describe.go | 12 ++++++++---- internal/cmd/ske/disable/disable.go | 16 ++++++---------- internal/cmd/ske/enable/enable.go | 16 ++++++---------- internal/cmd/ske/kubeconfig/create/create.go | 10 +++++++--- 7 files changed, 48 insertions(+), 44 deletions(-) diff --git a/internal/cmd/ske/cluster/create/create.go b/internal/cmd/ske/cluster/create/create.go index af9ba2336..4e58d32df 100644 --- a/internal/cmd/ske/cluster/create/create.go +++ b/internal/cmd/ske/cluster/create/create.go @@ -14,13 +14,13 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/flags" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" serviceEnablementClient "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/client" serviceEnablementUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/client" skeUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/stackitcloud/stackit-sdk-go/services/ske" "github.com/stackitcloud/stackit-sdk-go/services/ske/wait" ) @@ -70,16 +70,16 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Configure API client - apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + // Validate project ID (exists and user has access) + projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId + return err } if !model.AssumeYes { @@ -159,9 +159,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu clusterName := inputArgs[0] globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } payloadValue := flags.FlagToStringPointer(p, cmd, payloadFlag) var payload *ske.CreateOrUpdateClusterPayload diff --git a/internal/cmd/ske/cluster/delete/delete.go b/internal/cmd/ske/cluster/delete/delete.go index 12068d9e3..7caa0ca05 100644 --- a/internal/cmd/ske/cluster/delete/delete.go +++ b/internal/cmd/ske/cluster/delete/delete.go @@ -6,12 +6,12 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" - "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/client" "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/spf13/cobra" "github.com/stackitcloud/stackit-sdk-go/services/ske" @@ -45,6 +45,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } + // Validate project ID (exists and user has access) + _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + if err != nil { + return err + } + // Configure API client apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -92,9 +98,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu clusterName := inputArgs[0] globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } model := inputModel{ GlobalFlagModel: globalFlags, diff --git a/internal/cmd/ske/cluster/describe/describe.go b/internal/cmd/ske/cluster/describe/describe.go index a983f442e..08829ffa5 100644 --- a/internal/cmd/ske/cluster/describe/describe.go +++ b/internal/cmd/ske/cluster/describe/describe.go @@ -10,13 +10,13 @@ import ( "github.com/spf13/cobra" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" - "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/client" "github.com/stackitcloud/stackit-cli/internal/pkg/tables" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/stackitcloud/stackit-sdk-go/services/ske" ) @@ -49,6 +49,13 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return err } + + // Validate project ID (exists and user has access) + _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + if err != nil { + return err + } + // Configure API client apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -72,9 +79,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu clusterName := inputArgs[0] globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } model := inputModel{ GlobalFlagModel: globalFlags, diff --git a/internal/cmd/ske/describe/describe.go b/internal/cmd/ske/describe/describe.go index da717570e..0f49b2ef2 100644 --- a/internal/cmd/ske/describe/describe.go +++ b/internal/cmd/ske/describe/describe.go @@ -9,7 +9,6 @@ import ( "github.com/spf13/cobra" "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" - "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" @@ -17,6 +16,7 @@ import ( skeUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/tables" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/stackitcloud/stackit-sdk-go/services/serviceenablement" ) @@ -41,6 +41,13 @@ func NewCmd(params *params.CmdParams) *cobra.Command { if err != nil { return err } + + // Validate project ID (exists and user has access) + _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + if err != nil { + return err + } + // Configure API client apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -62,9 +69,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } model := inputModel{ GlobalFlagModel: globalFlags, diff --git a/internal/cmd/ske/disable/disable.go b/internal/cmd/ske/disable/disable.go index ea355ada1..8a42a5906 100644 --- a/internal/cmd/ske/disable/disable.go +++ b/internal/cmd/ske/disable/disable.go @@ -6,14 +6,13 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" - "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/client" "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/spf13/cobra" "github.com/stackitcloud/stackit-sdk-go/services/serviceenablement" @@ -42,16 +41,16 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Configure API client - apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + // Validate project ID (exists and user has access) + projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId + return err } if !model.AssumeYes { @@ -93,9 +92,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } model := inputModel{ GlobalFlagModel: globalFlags, diff --git a/internal/cmd/ske/enable/enable.go b/internal/cmd/ske/enable/enable.go index 91431b5e3..71c27658d 100644 --- a/internal/cmd/ske/enable/enable.go +++ b/internal/cmd/ske/enable/enable.go @@ -6,14 +6,13 @@ import ( "github.com/stackitcloud/stackit-cli/internal/cmd/params" "github.com/stackitcloud/stackit-cli/internal/pkg/args" - "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" "github.com/stackitcloud/stackit-cli/internal/pkg/globalflags" "github.com/stackitcloud/stackit-cli/internal/pkg/print" - "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/client" "github.com/stackitcloud/stackit-cli/internal/pkg/services/service-enablement/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/spinner" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/spf13/cobra" "github.com/stackitcloud/stackit-sdk-go/services/serviceenablement" @@ -42,16 +41,16 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Configure API client - apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) + // Validate project ID (exists and user has access) + projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } - projectLabel, err := projectname.GetProjectName(ctx, params.Printer, params.CliVersion, cmd) + // Configure API client + apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { - params.Printer.Debug(print.ErrorLevel, "get project name: %v", err) - projectLabel = model.ProjectId + return err } if !model.AssumeYes { @@ -93,9 +92,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } model := inputModel{ GlobalFlagModel: globalFlags, diff --git a/internal/cmd/ske/kubeconfig/create/create.go b/internal/cmd/ske/kubeconfig/create/create.go index f420009f0..876d3dc4e 100644 --- a/internal/cmd/ske/kubeconfig/create/create.go +++ b/internal/cmd/ske/kubeconfig/create/create.go @@ -16,6 +16,7 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/client" skeUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/ske/utils" "github.com/stackitcloud/stackit-cli/internal/pkg/utils" + "github.com/stackitcloud/stackit-cli/internal/pkg/validation" "github.com/spf13/cobra" "github.com/stackitcloud/stackit-sdk-go/services/ske" @@ -83,6 +84,12 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } + // Validate project ID (exists and user has access) + _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + if err != nil { + return err + } + // Configure API client apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -180,9 +187,6 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu clusterName := inputArgs[0] globalFlags := globalflags.Parse(p, cmd) - if globalFlags.ProjectId == "" { - return nil, &errors.ProjectIdError{} - } expTime := flags.FlagToStringPointer(p, cmd, expirationFlag) From 1cdfb3e9a16af4ed3faf148ebba4b5f8c1df34fb Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 10:22:00 +0200 Subject: [PATCH 3/7] fix type assertion lint error --- internal/pkg/validation/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/pkg/validation/project.go b/internal/pkg/validation/project.go index 3d3bbb333..6c07c535c 100644 --- a/internal/pkg/validation/project.go +++ b/internal/pkg/validation/project.go @@ -33,7 +33,7 @@ func ValidateProject(ctx context.Context, p *print.Printer, cliVersion string, c resp, err := req.Execute() if err != nil { // Check for specific HTTP status codes - if httpErr, ok := err.(*oapierror.GenericOpenAPIError); ok { + if httpErr, ok := err.(*oapierror.GenericOpenAPIError); ok { //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped switch httpErr.StatusCode { case http.StatusNotFound: // Try to get project name for better error message From 75e9764045834f1879a4c496f8230e1cf8157328 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 11:03:38 +0200 Subject: [PATCH 4/7] simplify project-not-found error warning --- internal/pkg/errors/errors.go | 16 +--------------- internal/pkg/validation/project.go | 9 +-------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/internal/pkg/errors/errors.go b/internal/pkg/errors/errors.go index e6303f86d..a9d065a8d 100644 --- a/internal/pkg/errors/errors.go +++ b/internal/pkg/errors/errors.go @@ -179,12 +179,7 @@ To list all profiles, run: FILE_ALREADY_EXISTS = `file %q already exists in the export path. Delete the existing file or define a different export path` - PROJECT_NOT_FOUND = `the project %[2]q (ID: %[1]s) does not exist. - -To list all available projects, run: - $ stackit project list` - - PROJECT_ACCESS_DENIED = `you don't have access to the project %[2]q (ID: %[1]s). + PROJECT_NOT_FOUND = `the project %[2]q (ID: %[1]s) does not exist or you don't have access to it. To list all available projects, run: $ stackit project list` @@ -518,12 +513,3 @@ type ProjectNotFoundError struct { func (e *ProjectNotFoundError) Error() string { return fmt.Sprintf(PROJECT_NOT_FOUND, e.ProjectId, e.ProjectLabel) } - -type ProjectAccessDeniedError struct { - ProjectId string - ProjectLabel string -} - -func (e *ProjectAccessDeniedError) Error() string { - return fmt.Sprintf(PROJECT_ACCESS_DENIED, e.ProjectId, e.ProjectLabel) -} diff --git a/internal/pkg/validation/project.go b/internal/pkg/validation/project.go index 6c07c535c..43f4bf19f 100644 --- a/internal/pkg/validation/project.go +++ b/internal/pkg/validation/project.go @@ -35,20 +35,13 @@ func ValidateProject(ctx context.Context, p *print.Printer, cliVersion string, c // Check for specific HTTP status codes if httpErr, ok := err.(*oapierror.GenericOpenAPIError); ok { //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped switch httpErr.StatusCode { - case http.StatusNotFound: + case http.StatusNotFound, http.StatusForbidden: // Try to get project name for better error message projectLabel := projectId if projectName, nameErr := projectname.GetProjectName(ctx, p, cliVersion, cmd); nameErr == nil { projectLabel = projectName } return "", &errors.ProjectNotFoundError{ProjectId: projectId, ProjectLabel: projectLabel} - case http.StatusForbidden: - // Try to get project name for better error message - projectLabel := projectId - if projectName, nameErr := projectname.GetProjectName(ctx, p, cliVersion, cmd); nameErr == nil { - projectLabel = projectName - } - return "", &errors.ProjectAccessDeniedError{ProjectId: projectId, ProjectLabel: projectLabel} case http.StatusUnauthorized: return "", &errors.AuthError{} } From ec7a3dd50893a5e268e211141be0066a4aa86db5 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 11:12:58 +0200 Subject: [PATCH 5/7] fix http status check --- internal/pkg/validation/project.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/pkg/validation/project.go b/internal/pkg/validation/project.go index 43f4bf19f..4944a939c 100644 --- a/internal/pkg/validation/project.go +++ b/internal/pkg/validation/project.go @@ -35,7 +35,7 @@ func ValidateProject(ctx context.Context, p *print.Printer, cliVersion string, c // Check for specific HTTP status codes if httpErr, ok := err.(*oapierror.GenericOpenAPIError); ok { //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped switch httpErr.StatusCode { - case http.StatusNotFound, http.StatusForbidden: + case http.StatusForbidden: // Try to get project name for better error message projectLabel := projectId if projectName, nameErr := projectname.GetProjectName(ctx, p, cliVersion, cmd); nameErr == nil { From f287833f54367aac43fc18a1a7e33b65fe823183 Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 11:19:26 +0200 Subject: [PATCH 6/7] rename validateProject function --- internal/cmd/ske/cluster/create/create.go | 2 +- internal/cmd/ske/cluster/delete/delete.go | 2 +- internal/cmd/ske/cluster/describe/describe.go | 2 +- internal/cmd/ske/cluster/list/list.go | 2 +- internal/cmd/ske/describe/describe.go | 2 +- internal/cmd/ske/disable/disable.go | 2 +- internal/cmd/ske/enable/enable.go | 2 +- internal/cmd/ske/kubeconfig/create/create.go | 2 +- internal/pkg/validation/project.go | 6 +++--- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/internal/cmd/ske/cluster/create/create.go b/internal/cmd/ske/cluster/create/create.go index 4e58d32df..c707c1f31 100644 --- a/internal/cmd/ske/cluster/create/create.go +++ b/internal/cmd/ske/cluster/create/create.go @@ -71,7 +71,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/cluster/delete/delete.go b/internal/cmd/ske/cluster/delete/delete.go index 7caa0ca05..6f39ed549 100644 --- a/internal/cmd/ske/cluster/delete/delete.go +++ b/internal/cmd/ske/cluster/delete/delete.go @@ -46,7 +46,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/cluster/describe/describe.go b/internal/cmd/ske/cluster/describe/describe.go index 08829ffa5..71ff667ad 100644 --- a/internal/cmd/ske/cluster/describe/describe.go +++ b/internal/cmd/ske/cluster/describe/describe.go @@ -51,7 +51,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/cluster/list/list.go b/internal/cmd/ske/cluster/list/list.go index 980f06b35..ee7308049 100644 --- a/internal/cmd/ske/cluster/list/list.go +++ b/internal/cmd/ske/cluster/list/list.go @@ -58,7 +58,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/describe/describe.go b/internal/cmd/ske/describe/describe.go index 0f49b2ef2..08be69a38 100644 --- a/internal/cmd/ske/describe/describe.go +++ b/internal/cmd/ske/describe/describe.go @@ -43,7 +43,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/disable/disable.go b/internal/cmd/ske/disable/disable.go index 8a42a5906..aa501e685 100644 --- a/internal/cmd/ske/disable/disable.go +++ b/internal/cmd/ske/disable/disable.go @@ -42,7 +42,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/enable/enable.go b/internal/cmd/ske/enable/enable.go index 71c27658d..f99f7413a 100644 --- a/internal/cmd/ske/enable/enable.go +++ b/internal/cmd/ske/enable/enable.go @@ -42,7 +42,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - projectLabel, err := validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/cmd/ske/kubeconfig/create/create.go b/internal/cmd/ske/kubeconfig/create/create.go index 876d3dc4e..a0fc0cbf7 100644 --- a/internal/cmd/ske/kubeconfig/create/create.go +++ b/internal/cmd/ske/kubeconfig/create/create.go @@ -85,7 +85,7 @@ func NewCmd(params *params.CmdParams) *cobra.Command { } // Validate project ID (exists and user has access) - _, err = validation.ValidateProject(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) + _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err } diff --git a/internal/pkg/validation/project.go b/internal/pkg/validation/project.go index 4944a939c..324bbac8b 100644 --- a/internal/pkg/validation/project.go +++ b/internal/pkg/validation/project.go @@ -14,9 +14,9 @@ import ( "github.com/stackitcloud/stackit-sdk-go/core/oapierror" ) -// ValidateProject validates that the project ID is not empty, exists, and the user has access to it. -// It returns the project name for display purposes. -func ValidateProject(ctx context.Context, p *print.Printer, cliVersion string, cmd *cobra.Command, projectId string) (string, error) { +// ValidateAndGetProjectLabel validates that the project ID is not empty, exists, and the user has access to it. +// It returns the project label (name or ID) for display purposes. +func ValidateAndGetProjectLabel(ctx context.Context, p *print.Printer, cliVersion string, cmd *cobra.Command, projectId string) (string, error) { // Check if project ID is empty if projectId == "" { return "", &errors.ProjectIdError{} From 0588cf2509935283c5e094e92d11fcd300db78ca Mon Sep 17 00:00:00 2001 From: Benjosh95 Date: Thu, 25 Sep 2025 11:21:14 +0200 Subject: [PATCH 7/7] reduce comments due to clear naming of function --- internal/cmd/ske/cluster/create/create.go | 1 - internal/cmd/ske/cluster/delete/delete.go | 1 - internal/cmd/ske/cluster/describe/describe.go | 1 - internal/cmd/ske/cluster/list/list.go | 1 - internal/cmd/ske/describe/describe.go | 1 - internal/cmd/ske/disable/disable.go | 1 - internal/cmd/ske/enable/enable.go | 1 - internal/cmd/ske/kubeconfig/create/create.go | 1 - 8 files changed, 8 deletions(-) diff --git a/internal/cmd/ske/cluster/create/create.go b/internal/cmd/ske/cluster/create/create.go index c707c1f31..24ac7a8a2 100644 --- a/internal/cmd/ske/cluster/create/create.go +++ b/internal/cmd/ske/cluster/create/create.go @@ -70,7 +70,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/cluster/delete/delete.go b/internal/cmd/ske/cluster/delete/delete.go index 6f39ed549..72f6d0ff4 100644 --- a/internal/cmd/ske/cluster/delete/delete.go +++ b/internal/cmd/ske/cluster/delete/delete.go @@ -45,7 +45,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/cluster/describe/describe.go b/internal/cmd/ske/cluster/describe/describe.go index 71ff667ad..69008b8e9 100644 --- a/internal/cmd/ske/cluster/describe/describe.go +++ b/internal/cmd/ske/cluster/describe/describe.go @@ -50,7 +50,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/cluster/list/list.go b/internal/cmd/ske/cluster/list/list.go index ee7308049..1c5b5e028 100644 --- a/internal/cmd/ske/cluster/list/list.go +++ b/internal/cmd/ske/cluster/list/list.go @@ -57,7 +57,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/describe/describe.go b/internal/cmd/ske/describe/describe.go index 08be69a38..4ebf285bd 100644 --- a/internal/cmd/ske/describe/describe.go +++ b/internal/cmd/ske/describe/describe.go @@ -42,7 +42,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/disable/disable.go b/internal/cmd/ske/disable/disable.go index aa501e685..46cecb176 100644 --- a/internal/cmd/ske/disable/disable.go +++ b/internal/cmd/ske/disable/disable.go @@ -41,7 +41,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/enable/enable.go b/internal/cmd/ske/enable/enable.go index f99f7413a..6dd3c86eb 100644 --- a/internal/cmd/ske/enable/enable.go +++ b/internal/cmd/ske/enable/enable.go @@ -41,7 +41,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) projectLabel, err := validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err diff --git a/internal/cmd/ske/kubeconfig/create/create.go b/internal/cmd/ske/kubeconfig/create/create.go index a0fc0cbf7..51eef66c2 100644 --- a/internal/cmd/ske/kubeconfig/create/create.go +++ b/internal/cmd/ske/kubeconfig/create/create.go @@ -84,7 +84,6 @@ func NewCmd(params *params.CmdParams) *cobra.Command { return err } - // Validate project ID (exists and user has access) _, err = validation.ValidateAndGetProjectLabel(ctx, params.Printer, params.CliVersion, cmd, model.ProjectId) if err != nil { return err