diff --git a/docs/stackit_beta_alb_observability-credentials_update.md b/docs/stackit_beta_alb_observability-credentials_update.md index 61994726d..88666470f 100644 --- a/docs/stackit_beta_alb_observability-credentials_update.md +++ b/docs/stackit_beta_alb_observability-credentials_update.md @@ -22,7 +22,7 @@ stackit beta alb observability-credentials update CREDENTIAL_REF_ARG [flags] ``` -d, --displayname string Displayname for the credentials -h, --help Help for "stackit beta alb observability-credentials update" - --password string Password. Can be a string or a file path, if prefixed with "@" (example: @./password.txt). + --password string Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. -u, --username string Username for the credentials ``` diff --git a/docs/stackit_beta_cdn_distribution_create.md b/docs/stackit_beta_cdn_distribution_create.md index f52da0cf1..d14f16f21 100644 --- a/docs/stackit_beta_cdn_distribution_create.md +++ b/docs/stackit_beta_cdn_distribution_create.md @@ -35,6 +35,7 @@ stackit beta cdn distribution create [flags] --blocked-ips strings Comma-separated list of IPv4 addresses to block (e.g., '10.0.0.8,127.0.0.1') --bucket Use Object Storage backend --bucket-credentials-access-key-id string Access Key ID for Object Storage backend + --bucket-password string Bucket-Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. --bucket-region string Region for Object Storage backend --bucket-url string Bucket URL for Object Storage backend --default-cache-duration string ISO8601 duration string for default cache duration (e.g., 'PT1H30M' for 1 hour and 30 minutes) @@ -44,6 +45,7 @@ stackit beta cdn distribution create [flags] --http-origin-request-headers strings Origin request headers for HTTP backend in the format 'HeaderName: HeaderValue', repeatable. WARNING: do not store sensitive values in the headers! --http-origin-url string Origin URL for HTTP backend --loki Enable Loki log sink for the CDN distribution + --loki-password string Loki-Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. --loki-push-url string Push URL for log sink --loki-username string Username for log sink --monthly-limit-bytes int Monthly limit in bytes for the CDN distribution diff --git a/docs/stackit_beta_cdn_distribution_update.md b/docs/stackit_beta_cdn_distribution_update.md index 435429c6a..b7e8de147 100644 --- a/docs/stackit_beta_cdn_distribution_update.md +++ b/docs/stackit_beta_cdn_distribution_update.md @@ -24,6 +24,7 @@ stackit beta cdn distribution update [flags] --blocked-ips strings Comma-separated list of IPv4 addresses to block (e.g., '10.0.0.8,127.0.0.1') --bucket Use Object Storage backend --bucket-credentials-access-key-id string Access Key ID for Object Storage backend + --bucket-password string Bucket-Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. --bucket-region string Region for Object Storage backend --bucket-url string Bucket URL for Object Storage backend --default-cache-duration string ISO8601 duration string for default cache duration (e.g., 'PT1H30M' for 1 hour and 30 minutes) @@ -33,6 +34,7 @@ stackit beta cdn distribution update [flags] --http-origin-request-headers strings Origin request headers for HTTP backend in the format 'HeaderName: HeaderValue', repeatable. WARNING: do not store sensitive values in the headers! --http-origin-url string Origin URL for HTTP backend --loki Enable Loki log sink for the CDN distribution + --loki-password string Loki-Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. --loki-push-url string Push URL for log sink --loki-username string Username for log sink --monthly-limit-bytes int Monthly limit in bytes for the CDN distribution diff --git a/docs/stackit_beta_intake_user_create.md b/docs/stackit_beta_intake_user_create.md index 84ec49bdf..0912dfaaa 100644 --- a/docs/stackit_beta_intake_user_create.md +++ b/docs/stackit_beta_intake_user_create.md @@ -28,7 +28,7 @@ stackit beta intake user create [flags] -h, --help Help for "stackit beta intake user create" --intake-id string The UUID of the Intake to associate the user with --labels stringToString Labels in key=value format, separated by commas (default []) - --password string Password for the user. Must contain lower, upper, number, and special characters (min 12 chars) + --password string Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. Must contain lower, upper, number, and special characters (min 12 chars) --type string Type of user. One of 'intake' (default) or 'dead-letter' (default "intake") ``` diff --git a/docs/stackit_beta_intake_user_update.md b/docs/stackit_beta_intake_user_update.md index 93c591a15..6df5dafd2 100644 --- a/docs/stackit_beta_intake_user_update.md +++ b/docs/stackit_beta_intake_user_update.md @@ -28,7 +28,7 @@ stackit beta intake user update USER_ID [flags] -h, --help Help for "stackit beta intake user update" --intake-id string Intake ID --labels stringToString Labels in key=value format, separated by commas. Example: --labels "key1=value1,key2=value2". (default []) - --password string Password for the user. Must contain lower, upper, number, and special characters (min 12 chars) + --password string Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. Must contain lower, upper, number, and special characters (min 12 chars) --type string Type of user. One of 'intake' or 'dead-letter' ``` diff --git a/docs/stackit_load-balancer_observability-credentials_add.md b/docs/stackit_load-balancer_observability-credentials_add.md index 97afccbf4..18144470f 100644 --- a/docs/stackit_load-balancer_observability-credentials_add.md +++ b/docs/stackit_load-balancer_observability-credentials_add.md @@ -25,7 +25,7 @@ stackit load-balancer observability-credentials add [flags] ``` --display-name string Credentials display name -h, --help Help for "stackit load-balancer observability-credentials add" - --password string Password. Can be a string or a file path, if prefixed with "@" (example: @./password.txt). + --password string Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. --username string Username ``` diff --git a/docs/stackit_load-balancer_observability-credentials_update.md b/docs/stackit_load-balancer_observability-credentials_update.md index c0d95a31d..e89f89047 100644 --- a/docs/stackit_load-balancer_observability-credentials_update.md +++ b/docs/stackit_load-balancer_observability-credentials_update.md @@ -25,7 +25,7 @@ stackit load-balancer observability-credentials update CREDENTIALS_REF [flags] ``` --display-name string Credentials name -h, --help Help for "stackit load-balancer observability-credentials update" - --password string Password. Can be a string or a file path, if prefixed with "@" (example: @./password.txt). + --password string Password. Can be a string (deprecated) or a file path, if prefixed with '@' (example: @./secret.txt). Will be read from stdin when empty. --username string Username ``` diff --git a/internal/cmd/beta/alb/observability-credentials/update/update.go b/internal/cmd/beta/alb/observability-credentials/update/update.go index 18cbf8eb2..d353dc8b4 100644 --- a/internal/cmd/beta/alb/observability-credentials/update/update.go +++ b/internal/cmd/beta/alb/observability-credentials/update/update.go @@ -82,14 +82,15 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return outputResult(params.Printer, model, resp) }, } - configureFlags(cmd) + configureFlags(cmd, params) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, params *types.CmdParams) { cmd.Flags().StringP(usernameFlag, "u", "", "Username for the credentials") cmd.Flags().StringP(displaynameFlag, "d", "", "Displayname for the credentials") - cmd.Flags().Var(flags.ReadFromFileFlag(), passwordFlag, `Password. Can be a string or a file path, if prefixed with "@" (example: @./password.txt).`) + password := flags.SecretFlag(passwordFlag, params) + cmd.Flags().Var(password, passwordFlag, password.Usage()) cobra.CheckErr(flags.MarkFlagsRequired(cmd, displaynameFlag, usernameFlag)) } @@ -116,7 +117,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) inputM Username: flags.FlagToStringPointer(p, cmd, usernameFlag), Displayname: flags.FlagToStringPointer(p, cmd, displaynameFlag), CredentialsRef: &inputArgs[0], - Password: flags.FlagToStringPointer(p, cmd, passwordFlag), + Password: flags.SecretFlagToStringPointer(p, cmd, passwordFlag), } p.DebugInputModel(model) diff --git a/internal/cmd/beta/cdn/distribution/create/create.go b/internal/cmd/beta/cdn/distribution/create/create.go index d372af381..32a479ce6 100644 --- a/internal/cmd/beta/cdn/distribution/create/create.go +++ b/internal/cmd/beta/cdn/distribution/create/create.go @@ -30,12 +30,14 @@ const ( flagBucket = "bucket" flagBucketURL = "bucket-url" flagBucketCredentialsAccessKeyID = "bucket-credentials-access-key-id" //nolint:gosec // linter false positive + flagBucketPassword = "bucket-password" flagBucketRegion = "bucket-region" flagBlockedCountries = "blocked-countries" flagBlockedIPs = "blocked-ips" flagDefaultCacheDuration = "default-cache-duration" flagLoki = "loki" flagLokiUsername = "loki-username" + flagLokiPassword = "loki-password" flagLokiPushURL = "loki-push-url" flagMonthlyLimitBytes = "monthly-limit-bytes" flagOptimizer = "optimizer" @@ -119,20 +121,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { return err } - if model.Bucket != nil { - pw, err := params.Printer.PromptForPassword("enter your secret access key for the object storage bucket: ") - if err != nil { - return fmt.Errorf("reading secret access key: %w", err) - } - model.Bucket.Password = pw - } - if model.Loki != nil { - pw, err := params.Printer.PromptForPassword("enter your password for the loki log sink: ") - if err != nil { - return fmt.Errorf("reading loki password: %w", err) - } - model.Loki.Password = pw - } apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -161,11 +149,11 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return outputResult(params.Printer, model.OutputFormat, projectLabel, resp) }, } - configureFlags(cmd) + configureFlags(cmd, params) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, params *types.CmdParams) { cmd.Flags().Var(flags.EnumSliceFlag(false, []string{}, sdkUtils.EnumSliceToStringSlice(cdn.AllowedRegionEnumValues)...), flagRegion, fmt.Sprintf("Regions in which content should be cached, multiple of: %q", cdn.AllowedRegionEnumValues)) cmd.Flags().Bool(flagHTTP, false, "Use HTTP backend") cmd.Flags().String(flagHTTPOriginURL, "", "Origin URL for HTTP backend") @@ -174,12 +162,16 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Bool(flagBucket, false, "Use Object Storage backend") cmd.Flags().String(flagBucketURL, "", "Bucket URL for Object Storage backend") cmd.Flags().String(flagBucketCredentialsAccessKeyID, "", "Access Key ID for Object Storage backend") + bucketPassword := flags.SecretFlag(flagBucketPassword, params) + cmd.Flags().Var(bucketPassword, flagBucketPassword, bucketPassword.Usage()) cmd.Flags().String(flagBucketRegion, "", "Region for Object Storage backend") cmd.Flags().StringSlice(flagBlockedCountries, []string{}, "Comma-separated list of ISO 3166-1 alpha-2 country codes to block (e.g., 'US,DE,FR')") cmd.Flags().StringSlice(flagBlockedIPs, []string{}, "Comma-separated list of IPv4 addresses to block (e.g., '10.0.0.8,127.0.0.1')") cmd.Flags().String(flagDefaultCacheDuration, "", "ISO8601 duration string for default cache duration (e.g., 'PT1H30M' for 1 hour and 30 minutes)") cmd.Flags().Bool(flagLoki, false, "Enable Loki log sink for the CDN distribution") cmd.Flags().String(flagLokiUsername, "", "Username for log sink") + lokiPassword := flags.SecretFlag(flagLokiPassword, params) + cmd.Flags().Var(lokiPassword, flagLokiPassword, lokiPassword.Usage()) cmd.Flags().String(flagLokiPushURL, "", "Push URL for log sink") cmd.Flags().Int64(flagMonthlyLimitBytes, 0, "Monthly limit in bytes for the CDN distribution") cmd.Flags().Bool(flagOptimizer, false, "Enable optimizer for the CDN distribution (paid feature).") @@ -229,11 +221,12 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, bucketURL := flags.FlagToStringValue(p, cmd, flagBucketURL) accessKeyID := flags.FlagToStringValue(p, cmd, flagBucketCredentialsAccessKeyID) region := flags.FlagToStringValue(p, cmd, flagBucketRegion) + password := flags.SecretFlagToString(p, cmd, flagBucketPassword) bucket = &bucketInputModel{ URL: bucketURL, AccessKeyID: accessKeyID, - Password: "", + Password: password, Region: region, } } @@ -248,7 +241,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, loki = &lokiInputModel{ Username: flags.FlagToStringValue(p, cmd, flagLokiUsername), PushURL: flags.FlagToStringValue(p, cmd, flagLokiPushURL), - Password: "", + Password: flags.SecretFlagToString(p, cmd, flagLokiPassword), } } diff --git a/internal/cmd/beta/cdn/distribution/update/update.go b/internal/cmd/beta/cdn/distribution/update/update.go index 5bb66942f..42a660eef 100644 --- a/internal/cmd/beta/cdn/distribution/update/update.go +++ b/internal/cmd/beta/cdn/distribution/update/update.go @@ -31,12 +31,14 @@ const ( flagBucket = "bucket" flagBucketURL = "bucket-url" flagBucketCredentialsAccessKeyID = "bucket-credentials-access-key-id" //nolint:gosec // linter false positive + flagBucketPassword = "bucket-password" flagBucketRegion = "bucket-region" flagBlockedCountries = "blocked-countries" flagBlockedIPs = "blocked-ips" flagDefaultCacheDuration = "default-cache-duration" flagLoki = "loki" flagLokiUsername = "loki-username" + flagLokiPassword = "loki-password" flagLokiPushURL = "loki-push-url" flagMonthlyLimitBytes = "monthly-limit-bytes" flagOptimizer = "optimizer" @@ -93,20 +95,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { if err != nil { return err } - if model.Bucket != nil { - pw, err := params.Printer.PromptForPassword("enter your secret access key for the object storage bucket: ") - if err != nil { - return fmt.Errorf("reading secret access key: %w", err) - } - model.Bucket.Password = pw - } - if model.Loki != nil { - pw, err := params.Printer.PromptForPassword("enter your password for the loki log sink: ") - if err != nil { - return fmt.Errorf("reading loki password: %w", err) - } - model.Loki.Password = pw - } apiClient, err := client.ConfigureClient(params.Printer, params.CliVersion) if err != nil { @@ -134,11 +122,11 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return outputResult(params.Printer, model.OutputFormat, projectLabel, resp) }, } - configureFlags(cmd) + configureFlags(cmd, params) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, params *types.CmdParams) { cmd.Flags().Var(flags.EnumSliceFlag(false, []string{}, sdkUtils.EnumSliceToStringSlice(cdn.AllowedRegionEnumValues)...), flagRegions, fmt.Sprintf("Regions in which content should be cached, multiple of: %q", cdn.AllowedRegionEnumValues)) cmd.Flags().Bool(flagHTTP, false, "Use HTTP backend") cmd.Flags().String(flagHTTPOriginURL, "", "Origin URL for HTTP backend") @@ -147,12 +135,16 @@ func configureFlags(cmd *cobra.Command) { cmd.Flags().Bool(flagBucket, false, "Use Object Storage backend") cmd.Flags().String(flagBucketURL, "", "Bucket URL for Object Storage backend") cmd.Flags().String(flagBucketCredentialsAccessKeyID, "", "Access Key ID for Object Storage backend") + bucketPassword := flags.SecretFlag(flagBucketPassword, params) + cmd.Flags().Var(bucketPassword, flagBucketPassword, bucketPassword.Usage()) cmd.Flags().String(flagBucketRegion, "", "Region for Object Storage backend") cmd.Flags().StringSlice(flagBlockedCountries, []string{}, "Comma-separated list of ISO 3166-1 alpha-2 country codes to block (e.g., 'US,DE,FR')") cmd.Flags().StringSlice(flagBlockedIPs, []string{}, "Comma-separated list of IPv4 addresses to block (e.g., '10.0.0.8,127.0.0.1')") cmd.Flags().String(flagDefaultCacheDuration, "", "ISO8601 duration string for default cache duration (e.g., 'PT1H30M' for 1 hour and 30 minutes)") cmd.Flags().Bool(flagLoki, false, "Enable Loki log sink for the CDN distribution") cmd.Flags().String(flagLokiUsername, "", "Username for log sink") + lokiPassword := flags.SecretFlag(flagLokiPassword, params) + cmd.Flags().Var(lokiPassword, flagLokiPassword, lokiPassword.Usage()) cmd.Flags().String(flagLokiPushURL, "", "Push URL for log sink") cmd.Flags().Int64(flagMonthlyLimitBytes, 0, "Monthly limit in bytes for the CDN distribution") cmd.Flags().Bool(flagOptimizer, false, "Enable optimizer for the CDN distribution (paid feature).") @@ -200,11 +192,12 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu bucketURL := flags.FlagToStringValue(p, cmd, flagBucketURL) accessKeyID := flags.FlagToStringValue(p, cmd, flagBucketCredentialsAccessKeyID) region := flags.FlagToStringValue(p, cmd, flagBucketRegion) + password := flags.SecretFlagToString(p, cmd, flagBucketPassword) bucket = &bucketInputModel{ URL: bucketURL, AccessKeyID: accessKeyID, - Password: "", + Password: password, Region: region, } } @@ -219,7 +212,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu loki = &lokiInputModel{ Username: flags.FlagToStringValue(p, cmd, flagLokiUsername), PushURL: flags.FlagToStringValue(p, cmd, flagLokiPushURL), - Password: "", + Password: flags.SecretFlagToString(p, cmd, flagLokiPassword), } } diff --git a/internal/cmd/beta/intake/user/create/create.go b/internal/cmd/beta/intake/user/create/create.go index 436560060..e95a2367f 100644 --- a/internal/cmd/beta/intake/user/create/create.go +++ b/internal/cmd/beta/intake/user/create/create.go @@ -101,14 +101,15 @@ func NewCmd(p *types.CmdParams) *cobra.Command { return outputResult(p.Printer, model, projectLabel, resp) }, } - configureFlags(cmd) + configureFlags(cmd, p) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, params *types.CmdParams) { cmd.Flags().String(displayNameFlag, "", "Display name") cmd.Flags().Var(flags.UUIDFlag(), intakeIdFlag, "The UUID of the Intake to associate the user with") - cmd.Flags().String(passwordFlag, "", "Password for the user. Must contain lower, upper, number, and special characters (min 12 chars)") + password := flags.SecretFlag(passwordFlag, params) + cmd.Flags().Var(password, passwordFlag, password.Usage()+" Must contain lower, upper, number, and special characters (min 12 chars)") cmd.Flags().String(userTypeFlag, string(intake.USERTYPE_INTAKE), "Type of user. One of 'intake' (default) or 'dead-letter'") cmd.Flags().String(descriptionFlag, "", "Description") cmd.Flags().StringToString(labelsFlag, nil, "Labels in key=value format, separated by commas") @@ -127,7 +128,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command) (*inputModel, error) { GlobalFlagModel: globalFlags, DisplayName: flags.FlagToStringPointer(p, cmd, displayNameFlag), IntakeId: flags.FlagToStringPointer(p, cmd, intakeIdFlag), - Password: flags.FlagToStringPointer(p, cmd, passwordFlag), + Password: flags.SecretFlagToStringPointer(p, cmd, passwordFlag), UserType: flags.FlagToStringPointer(p, cmd, userTypeFlag), Description: flags.FlagToStringPointer(p, cmd, descriptionFlag), Labels: flags.FlagToStringToStringPointer(p, cmd, labelsFlag), diff --git a/internal/cmd/beta/intake/user/update/update.go b/internal/cmd/beta/intake/user/update/update.go index a2b1b881c..7a2ef9b98 100644 --- a/internal/cmd/beta/intake/user/update/update.go +++ b/internal/cmd/beta/intake/user/update/update.go @@ -91,15 +91,16 @@ func NewCmd(p *types.CmdParams) *cobra.Command { return outputResult(p.Printer, model, resp) }, } - configureFlags(cmd) + configureFlags(cmd, p) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, p *types.CmdParams) { cmd.Flags().Var(flags.UUIDFlag(), intakeIdFlag, "Intake ID") cmd.Flags().String(displayNameFlag, "", "Display name") cmd.Flags().String(descriptionFlag, "", "Description") - cmd.Flags().String(passwordFlag, "", "Password for the user. Must contain lower, upper, number, and special characters (min 12 chars)") + password := flags.SecretFlag(passwordFlag, p) + cmd.Flags().Var(password, passwordFlag, password.Usage()+" Must contain lower, upper, number, and special characters (min 12 chars)") cmd.Flags().String(userTypeFlag, "", "Type of user. One of 'intake' or 'dead-letter'") cmd.Flags().StringToString(labelsFlag, nil, `Labels in key=value format, separated by commas. Example: --labels "key1=value1,key2=value2".`) @@ -121,7 +122,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu UserId: userId, DisplayName: flags.FlagToStringPointer(p, cmd, displayNameFlag), Description: flags.FlagToStringPointer(p, cmd, descriptionFlag), - Password: flags.FlagToStringPointer(p, cmd, passwordFlag), + Password: flags.SecretFlagToStringPointer(p, cmd, passwordFlag), UserType: flags.FlagToStringPointer(p, cmd, userTypeFlag), Labels: flags.FlagToStringToStringPointer(p, cmd, labelsFlag), } diff --git a/internal/cmd/load-balancer/observability-credentials/add/add.go b/internal/cmd/load-balancer/observability-credentials/add/add.go index 89435c3fc..f37491852 100644 --- a/internal/cmd/load-balancer/observability-credentials/add/add.go +++ b/internal/cmd/load-balancer/observability-credentials/add/add.go @@ -68,15 +68,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { projectLabel = model.ProjectId } - // Prompt for password if not passed in as a flag - if model.Password == nil { - pwd, err := params.Printer.PromptForPassword("Enter user password: ") - if err != nil { - return fmt.Errorf("prompt for password: %w", err) - } - model.Password = utils.Ptr(pwd) - } - prompt := fmt.Sprintf("Are you sure you want to add observability credentials for Load Balancer on project %q?", projectLabel) err = params.Printer.PromptForConfirmation(prompt) if err != nil { @@ -93,14 +84,15 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return outputResult(params.Printer, model.OutputFormat, projectLabel, resp) }, } - configureFlags(cmd) + configureFlags(cmd, params) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, params *types.CmdParams) { cmd.Flags().String(displayNameFlag, "", "Credentials display name") cmd.Flags().String(usernameFlag, "", "Username") - cmd.Flags().Var(flags.ReadFromFileFlag(), passwordFlag, `Password. Can be a string or a file path, if prefixed with "@" (example: @./password.txt).`) + password := flags.SecretFlag(passwordFlag, params) + cmd.Flags().Var(password, passwordFlag, password.Usage()) err := flags.MarkFlagsRequired(cmd, displayNameFlag, usernameFlag) cobra.CheckErr(err) @@ -116,7 +108,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, _ []string) (*inputModel, GlobalFlagModel: globalFlags, DisplayName: flags.FlagToStringPointer(p, cmd, displayNameFlag), Username: flags.FlagToStringPointer(p, cmd, usernameFlag), - Password: flags.FlagToStringPointer(p, cmd, passwordFlag), + Password: flags.SecretFlagToStringPointer(p, cmd, passwordFlag), } p.DebugInputModel(model) diff --git a/internal/cmd/load-balancer/observability-credentials/update/update.go b/internal/cmd/load-balancer/observability-credentials/update/update.go index f19afb714..5b7e6d95e 100644 --- a/internal/cmd/load-balancer/observability-credentials/update/update.go +++ b/internal/cmd/load-balancer/observability-credentials/update/update.go @@ -6,6 +6,9 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/types" + "github.com/spf13/cobra" + "github.com/stackitcloud/stackit-sdk-go/services/loadbalancer" + "github.com/stackitcloud/stackit-cli/internal/pkg/args" "github.com/stackitcloud/stackit-cli/internal/pkg/errors" "github.com/stackitcloud/stackit-cli/internal/pkg/examples" @@ -15,10 +18,6 @@ import ( "github.com/stackitcloud/stackit-cli/internal/pkg/projectname" "github.com/stackitcloud/stackit-cli/internal/pkg/services/load-balancer/client" loadBalancerUtils "github.com/stackitcloud/stackit-cli/internal/pkg/services/load-balancer/utils" - "github.com/stackitcloud/stackit-cli/internal/pkg/utils" - - "github.com/spf13/cobra" - "github.com/stackitcloud/stackit-sdk-go/services/loadbalancer" ) const ( @@ -86,15 +85,6 @@ func NewCmd(params *types.CmdParams) *cobra.Command { credentialsLabel = model.CredentialsRef } - // Prompt for password if not passed in as a flag - if model.Password == nil { - pwd, err := params.Printer.PromptForPassword("Enter new password: ") - if err != nil { - return fmt.Errorf("prompt for password: %w", err) - } - model.Password = utils.Ptr(pwd) - } - prompt := fmt.Sprintf("Are you sure you want to update observability credentials %q for Load Balancer on project %q?", credentialsLabel, projectLabel) err = params.Printer.PromptForConfirmation(prompt) if err != nil { @@ -116,14 +106,15 @@ func NewCmd(params *types.CmdParams) *cobra.Command { return nil }, } - configureFlags(cmd) + configureFlags(cmd, params) return cmd } -func configureFlags(cmd *cobra.Command) { +func configureFlags(cmd *cobra.Command, params *types.CmdParams) { cmd.Flags().String(displayNameFlag, "", "Credentials name") cmd.Flags().String(usernameFlag, "", "Username") - cmd.Flags().Var(flags.ReadFromFileFlag(), passwordFlag, `Password. Can be a string or a file path, if prefixed with "@" (example: @./password.txt).`) + password := flags.SecretFlag(passwordFlag, params) + cmd.Flags().Var(password, passwordFlag, password.Usage()) } func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inputModel, error) { @@ -136,7 +127,7 @@ func parseInput(p *print.Printer, cmd *cobra.Command, inputArgs []string) (*inpu displayName := flags.FlagToStringPointer(p, cmd, displayNameFlag) username := flags.FlagToStringPointer(p, cmd, usernameFlag) - password := flags.FlagToStringPointer(p, cmd, passwordFlag) + password := flags.SecretFlagToStringPointer(p, cmd, passwordFlag) return &inputModel{ GlobalFlagModel: globalFlags, diff --git a/internal/pkg/flags/secret.go b/internal/pkg/flags/secret.go index 8d2611dca..9dc0ba1b5 100644 --- a/internal/pkg/flags/secret.go +++ b/internal/pkg/flags/secret.go @@ -79,3 +79,11 @@ func SecretFlagToStringPointer(p *print.Printer, cmd *cobra.Command, flag string } return nil } + +func SecretFlagToString(p *print.Printer, cmd *cobra.Command, flag string) string { + pointer := SecretFlagToStringPointer(p, cmd, flag) + if pointer == nil { + return "" + } + return *pointer +}