From 62e111e26398c04e6611927990926bc6c59a7436 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Wed, 11 Feb 2026 17:45:17 +0530 Subject: [PATCH 01/11] fix(go.mod): update go-auth0 dependency to point DXCDT-1069/add_bot_detection branch commit - Updated the go-auth0 dependency from v1.33.0 to v1.33.1-0.20260211120643-ac1cfcb90495. - This change ensures compatibility with the latest features and fixes provided by the go-auth0 library. --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 46de237e1..bdec299fd 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/PuerkitoBio/rehttp v1.4.0 github.com/atotto/clipboard v0.1.4 - github.com/auth0/go-auth0 v1.33.0 + github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495 github.com/briandowns/spinner v1.23.2 github.com/charmbracelet/glamour v0.10.0 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e diff --git a/go.sum b/go.sum index ec3d81e44..2a9b5eec4 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,8 @@ github.com/auth0/go-auth0 v1.32.1 h1:AAXQqaNaFZWkRm2bg5mVVXpqDLmusv7v238uIaxuFpo github.com/auth0/go-auth0 v1.32.1/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= github.com/auth0/go-auth0 v1.33.0 h1:7qx0UCA6Tn2udnEVA35xzKsseh/R9559f+nnGcUI0Ss= github.com/auth0/go-auth0 v1.33.0/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= +github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495 h1:RMJY2JenrbX8RiEIihcEJFnsQVwjs1njavZAgKTwIzg= +github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= From 2ae4aff46c5af806610a4f40478927092db4b628 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Wed, 11 Feb 2026 19:08:09 +0530 Subject: [PATCH 02/11] feat(attack_protection): add bot detection management commands - Introduced new commands for managing bot detection settings, including: - `bot-detection show`: Displays current bot detection settings. - `bot-detection update`: Updates bot detection settings with user-defined parameters. - Added `GetBotDetection` and `UpdateBotDetection` methods to the AttackProtectionAPI interface for retrieving and updating settings. - Implemented a new `botDetectionView` struct for rendering bot detection settings in the CLI. - Enhanced the attack protection command structure to include bot detection management. --- internal/auth0/attack_protection.go | 14 ++ internal/cli/attack_protection.go | 1 + .../cli/attack_protection_bot_detection.go | 238 ++++++++++++++++++ internal/display/attack_protection.go | 61 +++++ 4 files changed, 314 insertions(+) create mode 100644 internal/cli/attack_protection_bot_detection.go diff --git a/internal/auth0/attack_protection.go b/internal/auth0/attack_protection.go index c3d6afc11..0e71bd2c4 100644 --- a/internal/auth0/attack_protection.go +++ b/internal/auth0/attack_protection.go @@ -63,4 +63,18 @@ type AttackProtectionAPI interface { ctx context.Context, sit *management.SuspiciousIPThrottling, opts ...management.RequestOption, ) (err error) + + // GetBotDetection retrieves bot detection settings. + // + // Required scope: `read:attack_protection` + // + // See: https://auth0.com/docs/api/management/v2#!/attack-protection/get-bot-detection + GetBotDetection(ctx context.Context, opts ...management.RequestOption) (bd *management.BotDetection, err error) + + // UpdateBotDetection updates the bot detection settings. + // + // Required scope: `update:attack_protection` + // + // See: https://auth0.com/docs/api/management/v2#!/attack-protection/patch-bot-detection + UpdateBotDetection(ctx context.Context, bd *management.BotDetection, opts ...management.RequestOption) (err error) } diff --git a/internal/cli/attack_protection.go b/internal/cli/attack_protection.go index ecf0b5dd1..d5b0a9d3b 100644 --- a/internal/cli/attack_protection.go +++ b/internal/cli/attack_protection.go @@ -19,6 +19,7 @@ func attackProtectionCmd(cli *cli) *cobra.Command { cmd.AddCommand(breachedPasswordDetectionCmd(cli)) cmd.AddCommand(bruteForceProtectionCmd(cli)) cmd.AddCommand(suspiciousIPThrottlingCmd(cli)) + cmd.AddCommand(botDetectionCmd(cli)) return cmd } diff --git a/internal/cli/attack_protection_bot_detection.go b/internal/cli/attack_protection_bot_detection.go new file mode 100644 index 000000000..110e00c95 --- /dev/null +++ b/internal/cli/attack_protection_bot_detection.go @@ -0,0 +1,238 @@ +package cli + +import ( + "strings" + + "github.com/auth0/go-auth0/management" + "github.com/spf13/cobra" + + "github.com/auth0/auth0-cli/internal/ansi" +) + +var ( + botDetectionLevelPossibleValues = []string{"low", "medium", "high"} + passwordPolicyPossibleValues = []string{"never", "when_risky", "always"} +) + +var bdFlags = botDetectionFlags{ + BotDetectionLevel: Flag{ + Name: "Bot Detection Level", + LongForm: "bot-detection-level", + ShortForm: "l", + Help: "The level of bot detection sensitivity. Possible values: " + strings.Join(botDetectionLevelPossibleValues, ", ") + ".", + AlwaysPrompt: true, + }, + ChallengePasswordPolicy: Flag{ + Name: "Challenge Password Policy", + LongForm: "challenge-password-policy", + Help: "Determines how often to challenge users with a CAPTCHA for password-based login. Possible values: " + + strings.Join(passwordPolicyPossibleValues, ", ") + ".", + AlwaysPrompt: true, + }, + ChallengePasswordlessPolicy: Flag{ + Name: "Challenge Passwordless Policy", + LongForm: "challenge-passwordless-policy", + Help: "Determines how often to challenge users with a CAPTCHA for passwordless login. Possible values: " + + strings.Join(passwordPolicyPossibleValues, ", ") + ".", + AlwaysPrompt: true, + }, + ChallengePasswordResetPolicy: Flag{ + Name: "Challenge Password Reset Policy", + LongForm: "challenge-password-reset-policy", + Help: "Determines how often to challenge users with a CAPTCHA for password reset. Possible values: " + + strings.Join(passwordPolicyPossibleValues, ", ") + ".", + AlwaysPrompt: true, + }, + AllowList: Flag{ + Name: "Allow List", + LongForm: "allowlist", + ShortForm: "a", + Help: "List of comma-separated trusted IP addresses that will not have bot detection enforced against them. " + + "Supports IPv4, IPv6 and CIDR notations.", + AlwaysPrompt: true, + }, + MonitoringModeEnabled: Flag{ + Name: "Monitoring Mode Enabled", + LongForm: "monitoring-mode", + ShortForm: "m", + Help: "Enable (or disable) monitoring mode. When enabled, logs but does not block.", + AlwaysPrompt: true, + }, +} + +type ( + botDetectionFlags struct { + BotDetectionLevel Flag + ChallengePasswordPolicy Flag + ChallengePasswordlessPolicy Flag + ChallengePasswordResetPolicy Flag + AllowList Flag + MonitoringModeEnabled Flag + } + + botDetectionInputs struct { + BotDetectionLevel string + ChallengePasswordPolicy string + ChallengePasswordlessPolicy string + ChallengePasswordResetPolicy string + AllowList []string + MonitoringModeEnabled bool + } +) + +func botDetectionCmd(cli *cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "bot-detection", + Args: cobra.MaximumNArgs(1), + Aliases: []string{"bd"}, + Short: "Manage bot detection settings", + Long: "Bot detection protects your applications from automated attacks by detecting and blocking bot traffic. " + + "Auth0 can challenge suspicious requests with CAPTCHA or block them entirely. " + + "Configure detection sensitivity, CAPTCHA policies for different authentication flows, and allowlists for trusted IP addresses.", + } + + cmd.SetUsageTemplate(resourceUsageTemplate()) + + cmd.AddCommand(showBotDetectionCmd(cli)) + cmd.AddCommand(updateBotDetectionCmd(cli)) + + return cmd +} + +func showBotDetectionCmd(cli *cli) *cobra.Command { + cmd := &cobra.Command{ + Use: "show", + Args: cobra.NoArgs, + Short: "Show bot detection settings", + Long: "Display the current bot detection settings.", + Example: ` auth0 protection bot-detection show + auth0 ap bd show --json + auth0 ap bd show --json-compact`, + RunE: showBotDetectionCmdRun(cli), + } + + cmd.Flags().BoolVar(&cli.json, "json", false, "Output in json format.") + cmd.Flags().BoolVar(&cli.jsonCompact, "json-compact", false, "Output in compact json format.") + cmd.MarkFlagsMutuallyExclusive("json", "json-compact") + + return cmd +} + +func updateBotDetectionCmd(cli *cli) *cobra.Command { + var inputs botDetectionInputs + + cmd := &cobra.Command{ + Use: "update", + Args: cobra.NoArgs, + Short: "Update bot detection settings", + Long: "Update the bot detection settings.", + Example: ` auth0 protection bot-detection update + auth0 ap bd update --bot-detection-level medium --json-compact + auth0 ap bd update --bot-detection-level low --challenge-password-policy never + auth0 ap bd update --monitoring-mode=true --allowlist "198.51.100.42,10.0.0.0/24" + auth0 ap bd update -l high -a "198.51.100.42" -m=false --json`, + RunE: updateBotDetectionCmdRun(cli, &inputs), + } + + bdFlags.BotDetectionLevel.RegisterStringU(cmd, &inputs.BotDetectionLevel, "") + bdFlags.ChallengePasswordPolicy.RegisterStringU(cmd, &inputs.ChallengePasswordPolicy, "") + bdFlags.ChallengePasswordlessPolicy.RegisterStringU(cmd, &inputs.ChallengePasswordlessPolicy, "") + bdFlags.ChallengePasswordResetPolicy.RegisterStringU(cmd, &inputs.ChallengePasswordResetPolicy, "") + bdFlags.AllowList.RegisterStringSliceU(cmd, &inputs.AllowList, []string{}) + bdFlags.MonitoringModeEnabled.RegisterBoolU(cmd, &inputs.MonitoringModeEnabled, false) + + cmd.Flags().BoolVar(&cli.json, "json", false, "Output in json format.") + cmd.Flags().BoolVar(&cli.jsonCompact, "json-compact", false, "Output in compact json format.") + cmd.MarkFlagsMutuallyExclusive("json", "json-compact") + + return cmd +} + +func showBotDetectionCmdRun(cli *cli) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + var bd *management.BotDetection + err := ansi.Waiting(func() (err error) { + bd, err = cli.api.AttackProtection.GetBotDetection(cmd.Context()) + return err + }) + if err != nil { + return err + } + + cli.renderer.BotDetectionShow(bd) + + return nil + } +} + +func updateBotDetectionCmdRun( + cli *cli, + inputs *botDetectionInputs, +) func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, args []string) error { + var bd *management.BotDetection + err := ansi.Waiting(func() (err error) { + bd, err = cli.api.AttackProtection.GetBotDetection(cmd.Context()) + return err + }) + if err != nil { + return err + } + + if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, bd.BotDetectionLevel); err != nil { + return err + } + if inputs.BotDetectionLevel == "" { + inputs.BotDetectionLevel = bd.GetBotDetectionLevel() + } + bd.BotDetectionLevel = &inputs.BotDetectionLevel + + if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, bd.ChallengePasswordPolicy); err != nil { + return err + } + if inputs.ChallengePasswordPolicy == "" { + inputs.ChallengePasswordPolicy = bd.GetChallengePasswordPolicy() + } + bd.ChallengePasswordPolicy = &inputs.ChallengePasswordPolicy + + if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, bd.ChallengePasswordlessPolicy); err != nil { + return err + } + if inputs.ChallengePasswordlessPolicy == "" { + inputs.ChallengePasswordlessPolicy = bd.GetChallengePasswordlessPolicy() + } + bd.ChallengePasswordlessPolicy = &inputs.ChallengePasswordlessPolicy + + if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, bd.ChallengePasswordResetPolicy); err != nil { + return err + } + if inputs.ChallengePasswordResetPolicy == "" { + inputs.ChallengePasswordResetPolicy = bd.GetChallengePasswordResetPolicy() + } + bd.ChallengePasswordResetPolicy = &inputs.ChallengePasswordResetPolicy + + allowListString := strings.Join(bd.GetAllowList(), ",") + if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { + return err + } + if len(inputs.AllowList) == 0 { + inputs.AllowList = bd.GetAllowList() + } + bd.AllowList = &inputs.AllowList + + if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, bd.MonitoringModeEnabled); err != nil { + return err + } + bd.MonitoringModeEnabled = &inputs.MonitoringModeEnabled + + if err := ansi.Waiting(func() error { + return cli.api.AttackProtection.UpdateBotDetection(cmd.Context(), bd) + }); err != nil { + return err + } + + cli.renderer.BotDetectionUpdate(bd) + + return nil + } +} diff --git a/internal/display/attack_protection.go b/internal/display/attack_protection.go index 6f8a422b5..a97aad602 100644 --- a/internal/display/attack_protection.go +++ b/internal/display/attack_protection.go @@ -182,3 +182,64 @@ func makeSuspiciousIPThrottlingView(sit *management.SuspiciousIPThrottling) *sus return view } + +type botDetectionView struct { + BotDetectionLevel string + ChallengePasswordPolicy string + ChallengePasswordlessPolicy string + ChallengePasswordResetPolicy string + AllowList []string + MonitoringModeEnabled string + + raw interface{} +} + +func (bd *botDetectionView) AsTableHeader() []string { + // There is no list command for this resource, hence this func never gets called. + // Dummy implementation to satisfy View interface. + return []string{} +} + +func (bd *botDetectionView) AsTableRow() []string { + // There is no list command for this resource, hence this func never gets called. + // Dummy implementation to satisfy View interface. + return []string{} +} + +func (bd *botDetectionView) KeyValues() [][]string { + return [][]string{ + {ansi.Bold("BOT_DETECTION_LEVEL"), bd.BotDetectionLevel}, + {ansi.Bold("CHALLENGE_PASSWORD_POLICY"), bd.ChallengePasswordPolicy}, + {ansi.Bold("CHALLENGE_PASSWORDLESS_POLICY"), bd.ChallengePasswordlessPolicy}, + {ansi.Bold("CHALLENGE_PASSWORD_RESET_POLICY"), bd.ChallengePasswordResetPolicy}, + {ansi.Bold("ALLOW_LIST"), strings.Join(bd.AllowList, ", ")}, + {ansi.Bold("MONITORING_MODE_ENABLED"), bd.MonitoringModeEnabled}, + } +} + +func (bd *botDetectionView) Object() interface{} { + return bd.raw +} + +func (r *Renderer) BotDetectionShow(bd *management.BotDetection) { + r.Heading("bot detection") + r.Result(makeBotDetectionView(bd)) +} + +func (r *Renderer) BotDetectionUpdate(bd *management.BotDetection) { + r.Heading("bot detection updated") + r.Result(makeBotDetectionView(bd)) +} + +func makeBotDetectionView(bd *management.BotDetection) *botDetectionView { + return &botDetectionView{ + BotDetectionLevel: bd.GetBotDetectionLevel(), + ChallengePasswordPolicy: bd.GetChallengePasswordPolicy(), + ChallengePasswordlessPolicy: bd.GetChallengePasswordlessPolicy(), + ChallengePasswordResetPolicy: bd.GetChallengePasswordResetPolicy(), + AllowList: bd.GetAllowList(), + MonitoringModeEnabled: boolean(bd.GetMonitoringModeEnabled()), + + raw: bd, + } +} From d6fe6001ce62fb3c72b14069b3a8c73f86ac0ee1 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Thu, 12 Feb 2026 12:06:25 +0530 Subject: [PATCH 03/11] feat(attack_protection): add bot detection test cases - Introduced new test cases for bot detection functionality. - Added tests for both showing and updating bot detection settings. - Ensured that the output contains relevant fields. - These changes enhance the coverage of the attack protection feature. --- test/integration/test-cases.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/integration/test-cases.yaml b/test/integration/test-cases.yaml index 4461a0320..3e424b987 100644 --- a/test/integration/test-cases.yaml +++ b/test/integration/test-cases.yaml @@ -49,6 +49,18 @@ tests: - STAGE_PRE_USER_REGISTRATION_RATE exit-code: 0 + attack protection bot detection show: + command: auth0 attack-protection bot-detection show + stdout: + contains: + - BOT_DETECTION_LEVEL + - CHALLENGE_PASSWORD_POLICY + - CHALLENGE_PASSWORDLESS_POLICY + - CHALLENGE_PASSWORD_RESET_POLICY + - ALLOW_LIST + - MONITORING_MODE_ENABLED + exit-code: 0 + attack protection suspicious ip throttling ips check: command: auth0 attack-protection suspicious-ip-throttling ips check 127.0.0.1 stderr: @@ -97,6 +109,18 @@ tests: - STAGE_PRE_USER_REGISTRATION_RATE exit-code: 0 + attack protection update bot detection: + command: auth0 attack-protection bot-detection update --bot-detection-level medium + stdout: + contains: + - BOT_DETECTION_LEVEL + - CHALLENGE_PASSWORD_POLICY + - CHALLENGE_PASSWORDLESS_POLICY + - CHALLENGE_PASSWORD_RESET_POLICY + - ALLOW_LIST + - MONITORING_MODE_ENABLED + exit-code: 0 + tenants list: command: auth0 tenants list exit-code: 0 From d76a29cf8a023e3a1410aa211cabae2753a2c646 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Thu, 12 Feb 2026 12:11:10 +0530 Subject: [PATCH 04/11] feat(attack_protection): move attack protection test cases to a dedicated file - Created a new YAML file for integration test cases specifically for attack protection features, including bot detection. - Moved existing test cases related to attack protection from `test-cases.yaml` to `attack-protection-test-cases.yaml` for better organization and clarity. - Each test case verifies the expected output and exit codes for various attack protection commands, ensuring functionality and reliability of the bot detection feature. --- .../attack-protection-test-cases.yaml | 110 ++++++++++++++++++ test/integration/test-cases.yaml | 106 ----------------- 2 files changed, 110 insertions(+), 106 deletions(-) create mode 100644 test/integration/attack-protection-test-cases.yaml diff --git a/test/integration/attack-protection-test-cases.yaml b/test/integration/attack-protection-test-cases.yaml new file mode 100644 index 000000000..711307ed0 --- /dev/null +++ b/test/integration/attack-protection-test-cases.yaml @@ -0,0 +1,110 @@ +config: + inherit-env: true + retries: 1 + +tests: + 001 - attack protection breached password detection show: + command: auth0 attack-protection breached-password-detection show + stdout: + contains: + - ENABLED + - SHIELDS + - ADMIN_NOTIFICATION_FREQUENCY + - METHOD + exit-code: 0 + + 002 - attack protection brute force protection show: + command: auth0 attack-protection brute-force-protection show + stdout: + contains: + - ENABLED + - SHIELDS + - ALLOW_LIST + - MODE + - MAX_ATTEMPTS + exit-code: 0 + + 003 - attack protection suspicious ip throttling show: + command: auth0 attack-protection suspicious-ip-throttling show + stdout: + contains: + - ENABLED + - SHIELDS + - ALLOW_LIST + - STAGE_PRE_LOGIN_MAX_ATTEMPTS + - STAGE_PRE_LOGIN_RATE + - STAGE_PRE_USER_REGISTRATION_MAX_ATTEMPTS + - STAGE_PRE_USER_REGISTRATION_RATE + exit-code: 0 + + 004 - attack protection bot detection show: + command: auth0 attack-protection bot-detection show + stdout: + contains: + - BOT_DETECTION_LEVEL + - CHALLENGE_PASSWORD_POLICY + - CHALLENGE_PASSWORDLESS_POLICY + - CHALLENGE_PASSWORD_RESET_POLICY + - ALLOW_LIST + - MONITORING_MODE_ENABLED + exit-code: 0 + + 005 - attack protection suspicious ip throttling ips check: + command: auth0 attack-protection suspicious-ip-throttling ips check 127.0.0.1 + stderr: + contains: + - "The IP 127.0.0.1 is not blocked." + exit-code: 0 + + 006 - attack protection suspicious ip throttling ips unblock: + command: auth0 attack-protection suspicious-ip-throttling ips unblock 127.0.0.1 + stderr: + contains: + - "The IP 127.0.0.1 was unblocked." + exit-code: 0 + + 007 - attack protection update breached password detection: + command: auth0 attack-protection breached-password-detection update --enabled + stdout: + contains: + - ENABLED + - SHIELDS + - ADMIN_NOTIFICATION_FREQUENCY + - METHOD + exit-code: 0 + + 008 - attack protection update brute force protection: + command: auth0 attack-protection brute-force-protection update --enabled + stdout: + contains: + - ENABLED + - SHIELDS + - ALLOW_LIST + - MODE + - MAX_ATTEMPTS + exit-code: 0 + + 009 - attack protection update suspicious ip throttling: + command: auth0 attack-protection suspicious-ip-throttling update --enabled + stdout: + contains: + - ENABLED + - SHIELDS + - ALLOW_LIST + - STAGE_PRE_LOGIN_MAX_ATTEMPTS + - STAGE_PRE_LOGIN_RATE + - STAGE_PRE_USER_REGISTRATION_MAX_ATTEMPTS + - STAGE_PRE_USER_REGISTRATION_RATE + exit-code: 0 + + 010 - attack protection update bot detection: + command: auth0 attack-protection bot-detection update --bot-detection-level medium + stdout: + contains: + - BOT_DETECTION_LEVEL + - CHALLENGE_PASSWORD_POLICY + - CHALLENGE_PASSWORDLESS_POLICY + - CHALLENGE_PASSWORD_RESET_POLICY + - ALLOW_LIST + - MONITORING_MODE_ENABLED + exit-code: 0 diff --git a/test/integration/test-cases.yaml b/test/integration/test-cases.yaml index 3e424b987..f3ef6da43 100644 --- a/test/integration/test-cases.yaml +++ b/test/integration/test-cases.yaml @@ -15,112 +15,6 @@ tests: auth0 completion powershell: exit-code: 0 - attack protection breached password detection show: - command: auth0 attack-protection breached-password-detection show - stdout: - contains: - - ENABLED - - SHIELDS - - ADMIN_NOTIFICATION_FREQUENCY - - METHOD - exit-code: 0 - - attack protection brute force protection show: - command: auth0 attack-protection brute-force-protection show - stdout: - contains: - - ENABLED - - SHIELDS - - ALLOW_LIST - - MODE - - MAX_ATTEMPTS - exit-code: 0 - - attack protection suspicious ip throttling show: - command: auth0 attack-protection suspicious-ip-throttling show - stdout: - contains: - - ENABLED - - SHIELDS - - ALLOW_LIST - - STAGE_PRE_LOGIN_MAX_ATTEMPTS - - STAGE_PRE_LOGIN_RATE - - STAGE_PRE_USER_REGISTRATION_MAX_ATTEMPTS - - STAGE_PRE_USER_REGISTRATION_RATE - exit-code: 0 - - attack protection bot detection show: - command: auth0 attack-protection bot-detection show - stdout: - contains: - - BOT_DETECTION_LEVEL - - CHALLENGE_PASSWORD_POLICY - - CHALLENGE_PASSWORDLESS_POLICY - - CHALLENGE_PASSWORD_RESET_POLICY - - ALLOW_LIST - - MONITORING_MODE_ENABLED - exit-code: 0 - - attack protection suspicious ip throttling ips check: - command: auth0 attack-protection suspicious-ip-throttling ips check 127.0.0.1 - stderr: - contains: - - "The IP 127.0.0.1 is not blocked." - exit-code: 0 - - attack protection suspicious ip throttling ips unblock: - command: auth0 attack-protection suspicious-ip-throttling ips unblock 127.0.0.1 - stderr: - contains: - - "The IP 127.0.0.1 was unblocked." - exit-code: 0 - - attack protection update breached password detection: - command: auth0 attack-protection breached-password-detection update --enabled - stdout: - contains: - - ENABLED - - SHIELDS - - ADMIN_NOTIFICATION_FREQUENCY - - METHOD - exit-code: 0 - - attack protection update brute force protection: - command: auth0 attack-protection brute-force-protection update --enabled - stdout: - contains: - - ENABLED - - SHIELDS - - ALLOW_LIST - - MODE - - MAX_ATTEMPTS - exit-code: 0 - - attack protection update suspicious ip throttling: - command: auth0 attack-protection suspicious-ip-throttling update --enabled - stdout: - contains: - - ENABLED - - SHIELDS - - ALLOW_LIST - - STAGE_PRE_LOGIN_MAX_ATTEMPTS - - STAGE_PRE_LOGIN_RATE - - STAGE_PRE_USER_REGISTRATION_MAX_ATTEMPTS - - STAGE_PRE_USER_REGISTRATION_RATE - exit-code: 0 - - attack protection update bot detection: - command: auth0 attack-protection bot-detection update --bot-detection-level medium - stdout: - contains: - - BOT_DETECTION_LEVEL - - CHALLENGE_PASSWORD_POLICY - - CHALLENGE_PASSWORDLESS_POLICY - - CHALLENGE_PASSWORD_RESET_POLICY - - ALLOW_LIST - - MONITORING_MODE_ENABLED - exit-code: 0 - tenants list: command: auth0 tenants list exit-code: 0 From e042e74d1ac9a03eed8d5c7f33986fa77c973f11 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Thu, 12 Feb 2026 13:12:46 +0530 Subject: [PATCH 05/11] feat(attack_protection): add bot detection commands documentation - Updated `auth0_protection.md` to include a link to the new bot detection management commands. - Created `auth0_protection_bot-detection.md` to describe bot detection features and settings. - Added `auth0_protection_bot-detection_show.md` for displaying current bot detection settings. - Added `auth0_protection_bot-detection_update.md` for updating bot detection settings. --- docs/auth0_protection.md | 1 + docs/auth0_protection_bot-detection.md | 14 +++++ docs/auth0_protection_bot-detection_show.md | 47 ++++++++++++++++ docs/auth0_protection_bot-detection_update.md | 55 +++++++++++++++++++ 4 files changed, 117 insertions(+) create mode 100644 docs/auth0_protection_bot-detection.md create mode 100644 docs/auth0_protection_bot-detection_show.md create mode 100644 docs/auth0_protection_bot-detection_update.md diff --git a/docs/auth0_protection.md b/docs/auth0_protection.md index 33d3008dd..86ae6b799 100644 --- a/docs/auth0_protection.md +++ b/docs/auth0_protection.md @@ -8,6 +8,7 @@ Auth0 can detect attacks and stop malicious attempts to access your application ## Commands +- [auth0 protection bot-detection](auth0_protection_bot-detection.md) - Manage bot detection settings - [auth0 protection breached-password-detection](auth0_protection_breached-password-detection.md) - Manage breached password detection settings - [auth0 protection brute-force-protection](auth0_protection_brute-force-protection.md) - Manage brute force protection settings - [auth0 protection suspicious-ip-throttling](auth0_protection_suspicious-ip-throttling.md) - Manage suspicious ip throttling settings diff --git a/docs/auth0_protection_bot-detection.md b/docs/auth0_protection_bot-detection.md new file mode 100644 index 000000000..92b93cd9b --- /dev/null +++ b/docs/auth0_protection_bot-detection.md @@ -0,0 +1,14 @@ +--- +layout: default +has_toc: false +has_children: true +--- +# auth0 protection bot-detection + +Bot detection protects your applications from automated attacks by detecting and blocking bot traffic. Auth0 can challenge suspicious requests with CAPTCHA or block them entirely. Configure detection sensitivity, CAPTCHA policies for different authentication flows, and allowlists for trusted IP addresses. + +## Commands + +- [auth0 protection bot-detection show](auth0_protection_bot-detection_show.md) - Show bot detection settings +- [auth0 protection bot-detection update](auth0_protection_bot-detection_update.md) - Update bot detection settings + diff --git a/docs/auth0_protection_bot-detection_show.md b/docs/auth0_protection_bot-detection_show.md new file mode 100644 index 000000000..36e358479 --- /dev/null +++ b/docs/auth0_protection_bot-detection_show.md @@ -0,0 +1,47 @@ +--- +layout: default +parent: auth0 protection bot-detection +has_toc: false +--- +# auth0 protection bot-detection show + +Display the current bot detection settings. + +## Usage +``` +auth0 protection bot-detection show [flags] +``` + +## Examples + +``` + auth0 protection bot-detection show + auth0 ap bd show --json + auth0 ap bd show --json-compact +``` + + +## Flags + +``` + --json Output in json format. + --json-compact Output in compact json format. +``` + + +## Inherited Flags + +``` + --debug Enable debug mode. + --no-color Disable colors. + --no-input Disable interactivity. + --tenant string Specific tenant to use. +``` + + +## Related Commands + +- [auth0 protection bot-detection show](auth0_protection_bot-detection_show.md) - Show bot detection settings +- [auth0 protection bot-detection update](auth0_protection_bot-detection_update.md) - Update bot detection settings + + diff --git a/docs/auth0_protection_bot-detection_update.md b/docs/auth0_protection_bot-detection_update.md new file mode 100644 index 000000000..69e1eea76 --- /dev/null +++ b/docs/auth0_protection_bot-detection_update.md @@ -0,0 +1,55 @@ +--- +layout: default +parent: auth0 protection bot-detection +has_toc: false +--- +# auth0 protection bot-detection update + +Update the bot detection settings. + +## Usage +``` +auth0 protection bot-detection update [flags] +``` + +## Examples + +``` + auth0 protection bot-detection update + auth0 ap bd update --bot-detection-level medium --json-compact + auth0 ap bd update --bot-detection-level low --challenge-password-policy never + auth0 ap bd update --monitoring-mode=true --allowlist "198.51.100.42,10.0.0.0/24" + auth0 ap bd update -l high -a "198.51.100.42" -m=false --json +``` + + +## Flags + +``` + -a, --allowlist strings List of comma-separated trusted IP addresses that will not have bot detection enforced against them. Supports IPv4, IPv6 and CIDR notations. + -l, --bot-detection-level string The level of bot detection sensitivity. Possible values: low, medium, high. + --challenge-password-policy string Determines how often to challenge users with a CAPTCHA for password-based login. Possible values: never, when_risky, always. + --challenge-password-reset-policy string Determines how often to challenge users with a CAPTCHA for password reset. Possible values: never, when_risky, always. + --challenge-passwordless-policy string Determines how often to challenge users with a CAPTCHA for passwordless login. Possible values: never, when_risky, always. + --json Output in json format. + --json-compact Output in compact json format. + -m, --monitoring-mode Enable (or disable) monitoring mode. When enabled, logs but does not block. +``` + + +## Inherited Flags + +``` + --debug Enable debug mode. + --no-color Disable colors. + --no-input Disable interactivity. + --tenant string Specific tenant to use. +``` + + +## Related Commands + +- [auth0 protection bot-detection show](auth0_protection_bot-detection_show.md) - Show bot detection settings +- [auth0 protection bot-detection update](auth0_protection_bot-detection_update.md) - Update bot detection settings + + From a6944f6ac43cbdeb4b518ce77a1eebaa3972428c Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Fri, 13 Feb 2026 15:59:10 +0530 Subject: [PATCH 06/11] feat(management): add v2 management client initialization - Introduced a new function `initializeManagementClientV2` to create a management client using the v2 API. - This function utilizes the `github.com/auth0/go-auth0/v2` package for improved management capabilities. - Updated `go.mod` and `go.sum` to include the v2 dependency. --- go.mod | 1 + go.sum | 6 ++---- internal/cli/management.go | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index bdec299fd..7902f9c4a 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/PuerkitoBio/rehttp v1.4.0 github.com/atotto/clipboard v0.1.4 github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495 + github.com/auth0/go-auth0/v2 v2.5.0 github.com/briandowns/spinner v1.23.2 github.com/charmbracelet/glamour v0.10.0 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e diff --git a/go.sum b/go.sum index 2a9b5eec4..84e2cdc82 100644 --- a/go.sum +++ b/go.sum @@ -22,12 +22,10 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= -github.com/auth0/go-auth0 v1.32.1 h1:AAXQqaNaFZWkRm2bg5mVVXpqDLmusv7v238uIaxuFpo= -github.com/auth0/go-auth0 v1.32.1/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= -github.com/auth0/go-auth0 v1.33.0 h1:7qx0UCA6Tn2udnEVA35xzKsseh/R9559f+nnGcUI0Ss= -github.com/auth0/go-auth0 v1.33.0/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495 h1:RMJY2JenrbX8RiEIihcEJFnsQVwjs1njavZAgKTwIzg= github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= +github.com/auth0/go-auth0/v2 v2.5.0 h1:IBfiYGsqFwOu4hsxV1JDtB6+ayRinybUIUCU/fRBE8Y= +github.com/auth0/go-auth0/v2 v2.5.0/go.mod h1:XVRck9fw1EIw1z4guYcbKFGmElnexb+xOvQ/0U1hHd0= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0/go.mod h1:6L7zgvqo0idzI7IO8de6ZC051AfXb5ipkIJ7bIA2tGA= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= diff --git a/internal/cli/management.go b/internal/cli/management.go index 5f0286c8f..fc0a65bf6 100644 --- a/internal/cli/management.go +++ b/internal/cli/management.go @@ -13,6 +13,8 @@ import ( "github.com/PuerkitoBio/rehttp" "github.com/auth0/go-auth0/management" + managementv2 "github.com/auth0/go-auth0/v2/management/client" + "github.com/auth0/go-auth0/v2/management/option" "github.com/auth0/auth0-cli/internal/buildinfo" ) @@ -30,6 +32,21 @@ func initializeManagementClient(tenantDomain string, accessToken string) (*manag return client, err } +func initializeManagementClientV2(tenantDomain string, accessToken string) (*managementv2.Management, error) { + client, err := managementv2.New( + tenantDomain, + option.WithToken(accessToken), + option.WithUserAgent(fmt.Sprintf("%v/%v", userAgent, strings.TrimPrefix(buildinfo.Version, "v"))), + option.WithAuth0ClientEnvEntry("Auth0-CLI", strings.TrimPrefix(buildinfo.Version, "v")), + // If not set, it defaults to 2 as per v2@v2.5.0/management/internal/retrier.go:43. + // Setting it to 1 to avoid retries from `go-auth0` since we have our own retry logic in the custom HTTP client. + // TODO: confirm this assumption, or check if this needs to be excluded like terraform provider. + option.WithMaxAttempts(1), + option.WithHTTPClient(customClientWithRetries()), + ) + return client, err +} + func customClientWithRetries() *http.Client { client := &http.Client{ Transport: rateLimitTransport( From ea9379377a337149347b4e0fb51adf0097de88b2 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Fri, 13 Feb 2026 16:05:54 +0530 Subject: [PATCH 07/11] feat(attack_protection): integrate api-v2 in bot detection management - Added support for v2 management client in the attack protection module. - Added the AttackProtectionBotDetectionAPIV2 interface to use v2 types. - Refactored bot detection show command to utilize new v2 API methods. - Adjusted display functions to handle v2 bot detection response types. - Enhanced the CLI to initialize and use the v2 management client. --- internal/auth0/attack_protection.go | 12 +- internal/auth0/auth0.go | 11 ++ .../cli/attack_protection_bot_detection.go | 130 +++++++++--------- internal/cli/cli.go | 7 + internal/display/attack_protection.go | 17 +-- 5 files changed, 100 insertions(+), 77 deletions(-) diff --git a/internal/auth0/attack_protection.go b/internal/auth0/attack_protection.go index 0e71bd2c4..abbe0c559 100644 --- a/internal/auth0/attack_protection.go +++ b/internal/auth0/attack_protection.go @@ -4,6 +4,8 @@ import ( "context" "github.com/auth0/go-auth0/management" + managementv2 "github.com/auth0/go-auth0/v2/management" + "github.com/auth0/go-auth0/v2/management/option" ) type AttackProtectionAPI interface { @@ -63,18 +65,20 @@ type AttackProtectionAPI interface { ctx context.Context, sit *management.SuspiciousIPThrottling, opts ...management.RequestOption, ) (err error) +} - // GetBotDetection retrieves bot detection settings. +type AttackProtectionBotDetectionAPIV2 interface { + // Get the Bot Detection configuration of tenant. // // Required scope: `read:attack_protection` // // See: https://auth0.com/docs/api/management/v2#!/attack-protection/get-bot-detection - GetBotDetection(ctx context.Context, opts ...management.RequestOption) (bd *management.BotDetection, err error) + Get(ctx context.Context, opts ...option.RequestOption) (*managementv2.GetBotDetectionSettingsResponseContent, error) - // UpdateBotDetection updates the bot detection settings. + // Update the Bot Detection configuration of tenant. // // Required scope: `update:attack_protection` // // See: https://auth0.com/docs/api/management/v2#!/attack-protection/patch-bot-detection - UpdateBotDetection(ctx context.Context, bd *management.BotDetection, opts ...management.RequestOption) (err error) + Update(ctx context.Context, request *managementv2.UpdateBotDetectionSettingsRequestContent, opts ...option.RequestOption) (*managementv2.UpdateBotDetectionSettingsResponseContent, error) } diff --git a/internal/auth0/auth0.go b/internal/auth0/auth0.go index 514aea343..4f1f7eba8 100644 --- a/internal/auth0/auth0.go +++ b/internal/auth0/auth0.go @@ -3,6 +3,7 @@ package auth0 import ( "github.com/auth0/go-auth0" "github.com/auth0/go-auth0/management" + managementv2 "github.com/auth0/go-auth0/v2/management/client" ) // API mimics `management.Management`s general interface, except it refers to @@ -76,6 +77,16 @@ func NewAPI(m *management.Management) *API { } } +type APIV2 struct { + AttackProtectionBotDetection AttackProtectionBotDetectionAPIV2 +} + +func NewAPIV2(m *managementv2.Management) *APIV2 { + return &APIV2{ + AttackProtectionBotDetection: m.AttackProtection.BotDetection, + } +} + // Alias all the helper methods so we can keep just typing `auth0.Bool` and the // compiler can autocomplete our internal package. var ( diff --git a/internal/cli/attack_protection_bot_detection.go b/internal/cli/attack_protection_bot_detection.go index 110e00c95..4caf5a249 100644 --- a/internal/cli/attack_protection_bot_detection.go +++ b/internal/cli/attack_protection_bot_detection.go @@ -3,7 +3,7 @@ package cli import ( "strings" - "github.com/auth0/go-auth0/management" + managementv2 "github.com/auth0/go-auth0/v2/management" "github.com/spf13/cobra" "github.com/auth0/auth0-cli/internal/ansi" @@ -150,9 +150,9 @@ func updateBotDetectionCmd(cli *cli) *cobra.Command { func showBotDetectionCmdRun(cli *cli) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - var bd *management.BotDetection + var bd *managementv2.GetBotDetectionSettingsResponseContent err := ansi.Waiting(func() (err error) { - bd, err = cli.api.AttackProtection.GetBotDetection(cmd.Context()) + bd, err = cli.apiv2.AttackProtectionBotDetection.Get(cmd.Context()) return err }) if err != nil { @@ -170,68 +170,68 @@ func updateBotDetectionCmdRun( inputs *botDetectionInputs, ) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - var bd *management.BotDetection - err := ansi.Waiting(func() (err error) { - bd, err = cli.api.AttackProtection.GetBotDetection(cmd.Context()) - return err - }) - if err != nil { - return err - } - - if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, bd.BotDetectionLevel); err != nil { - return err - } - if inputs.BotDetectionLevel == "" { - inputs.BotDetectionLevel = bd.GetBotDetectionLevel() - } - bd.BotDetectionLevel = &inputs.BotDetectionLevel - - if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, bd.ChallengePasswordPolicy); err != nil { - return err - } - if inputs.ChallengePasswordPolicy == "" { - inputs.ChallengePasswordPolicy = bd.GetChallengePasswordPolicy() - } - bd.ChallengePasswordPolicy = &inputs.ChallengePasswordPolicy - - if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, bd.ChallengePasswordlessPolicy); err != nil { - return err - } - if inputs.ChallengePasswordlessPolicy == "" { - inputs.ChallengePasswordlessPolicy = bd.GetChallengePasswordlessPolicy() - } - bd.ChallengePasswordlessPolicy = &inputs.ChallengePasswordlessPolicy - - if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, bd.ChallengePasswordResetPolicy); err != nil { - return err - } - if inputs.ChallengePasswordResetPolicy == "" { - inputs.ChallengePasswordResetPolicy = bd.GetChallengePasswordResetPolicy() - } - bd.ChallengePasswordResetPolicy = &inputs.ChallengePasswordResetPolicy - - allowListString := strings.Join(bd.GetAllowList(), ",") - if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { - return err - } - if len(inputs.AllowList) == 0 { - inputs.AllowList = bd.GetAllowList() - } - bd.AllowList = &inputs.AllowList - - if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, bd.MonitoringModeEnabled); err != nil { - return err - } - bd.MonitoringModeEnabled = &inputs.MonitoringModeEnabled - - if err := ansi.Waiting(func() error { - return cli.api.AttackProtection.UpdateBotDetection(cmd.Context(), bd) - }); err != nil { - return err - } - - cli.renderer.BotDetectionUpdate(bd) + // var bd *management.BotDetection + // err := ansi.Waiting(func() (err error) { + // bd, err = cli.api.AttackProtection.GetBotDetection(cmd.Context()) + // return err + // }) + // if err != nil { + // return err + // } + + // if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, bd.BotDetectionLevel); err != nil { + // return err + // } + // if inputs.BotDetectionLevel == "" { + // inputs.BotDetectionLevel = bd.GetBotDetectionLevel() + // } + // bd.BotDetectionLevel = &inputs.BotDetectionLevel + + // if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, bd.ChallengePasswordPolicy); err != nil { + // return err + // } + // if inputs.ChallengePasswordPolicy == "" { + // inputs.ChallengePasswordPolicy = string(bd.GetChallengePasswordPolicy()) + // } + // bd.ChallengePasswordPolicy = &inputs.ChallengePasswordPolicy + + // if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, bd.ChallengePasswordlessPolicy); err != nil { + // return err + // } + // if inputs.ChallengePasswordlessPolicy == "" { + // inputs.ChallengePasswordlessPolicy = bd.GetChallengePasswordlessPolicy() + // } + // bd.ChallengePasswordlessPolicy = &inputs.ChallengePasswordlessPolicy + + // if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, bd.ChallengePasswordResetPolicy); err != nil { + // return err + // } + // if inputs.ChallengePasswordResetPolicy == "" { + // inputs.ChallengePasswordResetPolicy = bd.GetChallengePasswordResetPolicy() + // } + // bd.ChallengePasswordResetPolicy = &inputs.ChallengePasswordResetPolicy + + // allowListString := strings.Join(bd.GetAllowList(), ",") + // if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { + // return err + // } + // if len(inputs.AllowList) == 0 { + // inputs.AllowList = bd.GetAllowList() + // } + // bd.AllowList = &inputs.AllowList + + // if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, bd.MonitoringModeEnabled); err != nil { + // return err + // } + // bd.MonitoringModeEnabled = &inputs.MonitoringModeEnabled + + // if err := ansi.Waiting(func() error { + // return cli.api.AttackProtection.UpdateBotDetection(cmd.Context(), bd) + // }); err != nil { + // return err + // } + + // cli.renderer.BotDetectionUpdate(bd) return nil } diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 61d1fb5d7..9c4f56106 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -35,6 +35,7 @@ const userAgent = "Auth0 CLI" type cli struct { // Core primitives exposed to command builders. api *auth0.API + apiv2 *auth0.APIV2 renderer *display.Renderer tracker *analytics.Tracker @@ -132,7 +133,13 @@ func (c *cli) setupWithAuthentication(ctx context.Context) error { return err } + apiv2, err := initializeManagementClientV2(tenant.Domain, tenant.GetAccessToken()) + if err != nil { + return err + } + c.api = auth0.NewAPI(api) + c.apiv2 = auth0.NewAPIV2(apiv2) return nil } diff --git a/internal/display/attack_protection.go b/internal/display/attack_protection.go index a97aad602..9422f97f1 100644 --- a/internal/display/attack_protection.go +++ b/internal/display/attack_protection.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/auth0/go-auth0/management" + managementv2 "github.com/auth0/go-auth0/v2/management" "github.com/auth0/auth0-cli/internal/ansi" ) @@ -221,23 +222,23 @@ func (bd *botDetectionView) Object() interface{} { return bd.raw } -func (r *Renderer) BotDetectionShow(bd *management.BotDetection) { +func (r *Renderer) BotDetectionShow(bd *managementv2.GetBotDetectionSettingsResponseContent) { r.Heading("bot detection") r.Result(makeBotDetectionView(bd)) } -func (r *Renderer) BotDetectionUpdate(bd *management.BotDetection) { +func (r *Renderer) BotDetectionUpdate(bd *managementv2.GetBotDetectionSettingsResponseContent) { r.Heading("bot detection updated") r.Result(makeBotDetectionView(bd)) } -func makeBotDetectionView(bd *management.BotDetection) *botDetectionView { +func makeBotDetectionView(bd *managementv2.GetBotDetectionSettingsResponseContent) *botDetectionView { return &botDetectionView{ - BotDetectionLevel: bd.GetBotDetectionLevel(), - ChallengePasswordPolicy: bd.GetChallengePasswordPolicy(), - ChallengePasswordlessPolicy: bd.GetChallengePasswordlessPolicy(), - ChallengePasswordResetPolicy: bd.GetChallengePasswordResetPolicy(), - AllowList: bd.GetAllowList(), + BotDetectionLevel: string(bd.GetBotDetectionLevel()), + ChallengePasswordPolicy: string(bd.GetChallengePasswordPolicy()), + ChallengePasswordlessPolicy: string(bd.GetChallengePasswordlessPolicy()), + ChallengePasswordResetPolicy: string(bd.GetChallengePasswordResetPolicy()), + AllowList: bd.GetAllowlist(), MonitoringModeEnabled: boolean(bd.GetMonitoringModeEnabled()), raw: bd, From 43763e527ceeb18310dea33656cabc9d1c472211 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Mon, 16 Feb 2026 17:24:39 +0530 Subject: [PATCH 08/11] feat(attack_protection): add bot detection update command with go-auth0-v2 - Updated the `updateBotDetectionCmdRun` function to utilize the new go-auth0 v2 for bot detection settings. - Introduced a new `stringPtr` utility function to handle string-derived pointer conversions. - Added tests for `stringPtr` to ensure correct behavior with nil and custom string types. - Refactored rendering functions to accommodate changes in the bot detection settings response structure. - Improved user prompts for bot detection configuration options. --- .../cli/attack_protection_bot_detection.go | 159 ++++++++++-------- internal/cli/cli.go | 17 ++ internal/cli/utils_shared.go | 10 ++ internal/cli/utils_shared_test.go | 24 +++ internal/display/attack_protection.go | 21 ++- 5 files changed, 161 insertions(+), 70 deletions(-) diff --git a/internal/cli/attack_protection_bot_detection.go b/internal/cli/attack_protection_bot_detection.go index 4caf5a249..2f0a58e13 100644 --- a/internal/cli/attack_protection_bot_detection.go +++ b/internal/cli/attack_protection_bot_detection.go @@ -165,73 +165,100 @@ func showBotDetectionCmdRun(cli *cli) func(cmd *cobra.Command, args []string) er } } -func updateBotDetectionCmdRun( - cli *cli, - inputs *botDetectionInputs, -) func(cmd *cobra.Command, args []string) error { +func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - // var bd *management.BotDetection - // err := ansi.Waiting(func() (err error) { - // bd, err = cli.api.AttackProtection.GetBotDetection(cmd.Context()) - // return err - // }) - // if err != nil { - // return err - // } - - // if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, bd.BotDetectionLevel); err != nil { - // return err - // } - // if inputs.BotDetectionLevel == "" { - // inputs.BotDetectionLevel = bd.GetBotDetectionLevel() - // } - // bd.BotDetectionLevel = &inputs.BotDetectionLevel - - // if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, bd.ChallengePasswordPolicy); err != nil { - // return err - // } - // if inputs.ChallengePasswordPolicy == "" { - // inputs.ChallengePasswordPolicy = string(bd.GetChallengePasswordPolicy()) - // } - // bd.ChallengePasswordPolicy = &inputs.ChallengePasswordPolicy - - // if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, bd.ChallengePasswordlessPolicy); err != nil { - // return err - // } - // if inputs.ChallengePasswordlessPolicy == "" { - // inputs.ChallengePasswordlessPolicy = bd.GetChallengePasswordlessPolicy() - // } - // bd.ChallengePasswordlessPolicy = &inputs.ChallengePasswordlessPolicy - - // if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, bd.ChallengePasswordResetPolicy); err != nil { - // return err - // } - // if inputs.ChallengePasswordResetPolicy == "" { - // inputs.ChallengePasswordResetPolicy = bd.GetChallengePasswordResetPolicy() - // } - // bd.ChallengePasswordResetPolicy = &inputs.ChallengePasswordResetPolicy - - // allowListString := strings.Join(bd.GetAllowList(), ",") - // if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { - // return err - // } - // if len(inputs.AllowList) == 0 { - // inputs.AllowList = bd.GetAllowList() - // } - // bd.AllowList = &inputs.AllowList - - // if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, bd.MonitoringModeEnabled); err != nil { - // return err - // } - // bd.MonitoringModeEnabled = &inputs.MonitoringModeEnabled - - // if err := ansi.Waiting(func() error { - // return cli.api.AttackProtection.UpdateBotDetection(cmd.Context(), bd) - // }); err != nil { - // return err - // } - - // cli.renderer.BotDetectionUpdate(bd) + var bd *managementv2.GetBotDetectionSettingsResponseContent + err := ansi.Waiting(func() (err error) { + bd, err = cli.apiv2.AttackProtectionBotDetection.Get(cmd.Context()) + return err + }) + if err != nil { + return err + } + + bdUpdate := &managementv2.UpdateBotDetectionSettingsRequestContent{} + + // set bot detection level + if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, stringPtr(bd.BotDetectionLevel.Ptr())); err != nil { + return err + } + if inputs.BotDetectionLevel == "" { + inputs.BotDetectionLevel = string(bd.GetBotDetectionLevel()) + } + botDetectionLevel, err := managementv2.NewBotDetectionLevelEnumFromString(inputs.BotDetectionLevel) + if err != nil { + return err + } + bdUpdate.SetBotDetectionLevel(&botDetectionLevel) + + // set challenge password policy + if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, stringPtr(bd.ChallengePasswordPolicy.Ptr())); err != nil { + return err + } + if inputs.ChallengePasswordPolicy == "" { + inputs.ChallengePasswordPolicy = string(bd.GetChallengePasswordPolicy()) + } + challengePasswordPolicy, err := managementv2.NewBotDetectionChallengePolicyPasswordFlowEnumFromString(inputs.ChallengePasswordPolicy) + if err != nil { + return err + } + bdUpdate.SetChallengePasswordPolicy(&challengePasswordPolicy) + + // set challenge passwordless policy + if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, stringPtr(bd.ChallengePasswordlessPolicy.Ptr())); err != nil { + return err + } + if inputs.ChallengePasswordlessPolicy == "" { + inputs.ChallengePasswordlessPolicy = string(bd.GetChallengePasswordlessPolicy()) + } + challengePasswordlessPolicy, err := managementv2.NewBotDetectionChallengePolicyPasswordlessFlowEnumFromString(inputs.ChallengePasswordlessPolicy) + if err != nil { + return err + } + bdUpdate.SetChallengePasswordlessPolicy(&challengePasswordlessPolicy) + + // set challenge password reset policy + if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, stringPtr(bd.ChallengePasswordResetPolicy.Ptr())); err != nil { + return err + } + if inputs.ChallengePasswordResetPolicy == "" { + inputs.ChallengePasswordResetPolicy = string(bd.GetChallengePasswordResetPolicy()) + } + challengePasswordResetPolicy, err := managementv2.NewBotDetectionChallengePolicyPasswordResetFlowEnumFromString(inputs.ChallengePasswordResetPolicy) + if err != nil { + return err + } + bdUpdate.SetChallengePasswordResetPolicy(&challengePasswordResetPolicy) + + // set allowlist + allowListString := strings.Join(bd.GetAllowlist(), ",") + if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { + return err + } + if len(inputs.AllowList) == 0 { + inputs.AllowList = bd.GetAllowlist() + } + allowlist := managementv2.BotDetectionAllowlist(inputs.AllowList) + bdUpdate.SetAllowlist(&allowlist) + + // set monitoring mode enabled + if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, &bd.MonitoringModeEnabled); err != nil { + return err + } + if bdFlags.MonitoringModeEnabled.IsSet(cmd) || noInputValueFlagSet(cmd) { + bdUpdate.SetMonitoringModeEnabled(&inputs.MonitoringModeEnabled) + } + + var updatedBD *managementv2.UpdateBotDetectionSettingsResponseContent + if err := ansi.Waiting(func() error { + var err error + updatedBD, err = cli.apiv2.AttackProtectionBotDetection.Update(cmd.Context(), bdUpdate) + return err + }); err != nil { + return err + } + + cli.renderer.BotDetectionUpdate(updatedBD) return nil } diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 9c4f56106..ec43e2bff 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -179,6 +179,23 @@ func shouldPromptWhenNoLocalFlagsSet(cmd *cobra.Command) bool { return canPrompt(cmd) && !localFlagIsSet } +// nonInputValueFlags is a set of flags that do not take any data input values but only control the command’s output or behavior. +var nonInputValueFlags map[string]struct{} = map[string]struct{}{ + "json": {}, "json-compact": {}, "csv": {}, "force": {}, "no-input": {}, "no-color": {}, "debug": {}, "tenant": {}, +} + +// noInputValueFlagSet returns true if no data input value is passed as flag in the command. +func noInputValueFlagSet(cmd *cobra.Command) bool { + inputValueFlagSet := false + cmd.Flags().VisitAll(func(f *pflag.Flag) { + if _, ok := nonInputValueFlags[f.Name]; !ok && f.Changed { + inputValueFlagSet = true + return + } + }) + return !inputValueFlagSet +} + func prepareInteractivity(cmd *cobra.Command) { if canPrompt(cmd) || !iostream.IsInputTerminal() { cmd.Flags().VisitAll(func(flag *pflag.Flag) { diff --git a/internal/cli/utils_shared.go b/internal/cli/utils_shared.go index 2b7b9901b..2d3f710c5 100644 --- a/internal/cli/utils_shared.go +++ b/internal/cli/utils_shared.go @@ -322,6 +322,16 @@ func formatManageTenantURL(tenant string, cfg *config.Config) string { ) } +// stringPtr converts a pointer of string-derived type to pointer of string. +// Returns nil if the input pointer is nil. +func stringPtr[strPtrType ~string](ptr *strPtrType) *string { + if ptr == nil { + return nil + } + s := string(*ptr) + return &s +} + func parseFlexibleDate(input string) (string, error) { now := time.Now().UTC() input = strings.TrimSpace(input) diff --git a/internal/cli/utils_shared_test.go b/internal/cli/utils_shared_test.go index 67a4d3cd5..090d543c8 100644 --- a/internal/cli/utils_shared_test.go +++ b/internal/cli/utils_shared_test.go @@ -14,6 +14,30 @@ import ( "github.com/auth0/auth0-cli/internal/config" ) +func TestStringPtr(t *testing.T) { + t.Run("returns nil when input is nil", func(t *testing.T) { + type CustomString string + var nilPtr *CustomString = nil + result := stringPtr(nilPtr) + assert.Nil(t, result) + }) + + t.Run("converts custom string pointer to string pointer", func(t *testing.T) { + type CustomString string + value := CustomString("test-value") + result := stringPtr(&value) + assert.NotNil(t, result) + assert.Equal(t, "test-value", *result) + }) + + t.Run("converts regular string pointer to string pointer", func(t *testing.T) { + value := "regular-string" + result := stringPtr(&value) + assert.NotNil(t, result) + assert.Equal(t, "regular-string", *result) + }) +} + func TestBuildOauthTokenURL(t *testing.T) { url := BuildOauthTokenURL("cli-demo.us.auth0.com") assert.Equal(t, "https://cli-demo.us.auth0.com/oauth/token", url) diff --git a/internal/display/attack_protection.go b/internal/display/attack_protection.go index 9422f97f1..4d20a73af 100644 --- a/internal/display/attack_protection.go +++ b/internal/display/attack_protection.go @@ -224,15 +224,28 @@ func (bd *botDetectionView) Object() interface{} { func (r *Renderer) BotDetectionShow(bd *managementv2.GetBotDetectionSettingsResponseContent) { r.Heading("bot detection") - r.Result(makeBotDetectionView(bd)) + r.Result(makeBotDetectionShowView(bd)) } -func (r *Renderer) BotDetectionUpdate(bd *managementv2.GetBotDetectionSettingsResponseContent) { +func (r *Renderer) BotDetectionUpdate(bd *managementv2.UpdateBotDetectionSettingsResponseContent) { r.Heading("bot detection updated") - r.Result(makeBotDetectionView(bd)) + r.Result(makeBotDetectionUpdateView(bd)) } -func makeBotDetectionView(bd *managementv2.GetBotDetectionSettingsResponseContent) *botDetectionView { +func makeBotDetectionShowView(bd *managementv2.GetBotDetectionSettingsResponseContent) *botDetectionView { + return &botDetectionView{ + BotDetectionLevel: string(bd.GetBotDetectionLevel()), + ChallengePasswordPolicy: string(bd.GetChallengePasswordPolicy()), + ChallengePasswordlessPolicy: string(bd.GetChallengePasswordlessPolicy()), + ChallengePasswordResetPolicy: string(bd.GetChallengePasswordResetPolicy()), + AllowList: bd.GetAllowlist(), + MonitoringModeEnabled: boolean(bd.GetMonitoringModeEnabled()), + + raw: bd, + } +} + +func makeBotDetectionUpdateView(bd *managementv2.UpdateBotDetectionSettingsResponseContent) *botDetectionView { return &botDetectionView{ BotDetectionLevel: string(bd.GetBotDetectionLevel()), ChallengePasswordPolicy: string(bd.GetChallengePasswordPolicy()), From 0931b830ccfdd9c5312b68179235e3718e49f1ec Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Mon, 16 Feb 2026 17:30:11 +0530 Subject: [PATCH 09/11] chore(go.mod, go.sum): revert go-auth0 version to v1.33.0 - Updated go-auth0 dependency from v1.33.1 to v1.33.0 in go.mod and go.sum --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 7902f9c4a..107a60481 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/PuerkitoBio/rehttp v1.4.0 github.com/atotto/clipboard v0.1.4 - github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495 + github.com/auth0/go-auth0 v1.33.0 github.com/auth0/go-auth0/v2 v2.5.0 github.com/briandowns/spinner v1.23.2 github.com/charmbracelet/glamour v0.10.0 diff --git a/go.sum b/go.sum index 84e2cdc82..276f70ee2 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/auth0/go-auth0 v1.33.0 h1:7qx0UCA6Tn2udnEVA35xzKsseh/R9559f+nnGcUI0Ss= +github.com/auth0/go-auth0 v1.33.0/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495 h1:RMJY2JenrbX8RiEIihcEJFnsQVwjs1njavZAgKTwIzg= github.com/auth0/go-auth0 v1.33.1-0.20260211120643-ac1cfcb90495/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= github.com/auth0/go-auth0/v2 v2.5.0 h1:IBfiYGsqFwOu4hsxV1JDtB6+ayRinybUIUCU/fRBE8Y= From bb171d93d4ed14a58dd63fc8ba7dced36d7b8cb2 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Mon, 16 Feb 2026 17:40:47 +0530 Subject: [PATCH 10/11] refactor(cli): improve comments and simplify nonInputValueFlags initialization --- internal/cli/attack_protection_bot_detection.go | 15 +++++++-------- internal/cli/cli.go | 2 +- internal/cli/utils_shared_test.go | 2 +- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/internal/cli/attack_protection_bot_detection.go b/internal/cli/attack_protection_bot_detection.go index 2f0a58e13..393595c2c 100644 --- a/internal/cli/attack_protection_bot_detection.go +++ b/internal/cli/attack_protection_bot_detection.go @@ -178,7 +178,7 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co bdUpdate := &managementv2.UpdateBotDetectionSettingsRequestContent{} - // set bot detection level + // Set bot detection level. if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, stringPtr(bd.BotDetectionLevel.Ptr())); err != nil { return err } @@ -191,7 +191,7 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co } bdUpdate.SetBotDetectionLevel(&botDetectionLevel) - // set challenge password policy + // Set challenge password policy. if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, stringPtr(bd.ChallengePasswordPolicy.Ptr())); err != nil { return err } @@ -204,7 +204,7 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co } bdUpdate.SetChallengePasswordPolicy(&challengePasswordPolicy) - // set challenge passwordless policy + // Set challenge passwordless policy. if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, stringPtr(bd.ChallengePasswordlessPolicy.Ptr())); err != nil { return err } @@ -217,7 +217,7 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co } bdUpdate.SetChallengePasswordlessPolicy(&challengePasswordlessPolicy) - // set challenge password reset policy + // Set challenge password reset policy. if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, stringPtr(bd.ChallengePasswordResetPolicy.Ptr())); err != nil { return err } @@ -230,7 +230,7 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co } bdUpdate.SetChallengePasswordResetPolicy(&challengePasswordResetPolicy) - // set allowlist + // Set allowlist. allowListString := strings.Join(bd.GetAllowlist(), ",") if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { return err @@ -238,10 +238,9 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co if len(inputs.AllowList) == 0 { inputs.AllowList = bd.GetAllowlist() } - allowlist := managementv2.BotDetectionAllowlist(inputs.AllowList) - bdUpdate.SetAllowlist(&allowlist) + bdUpdate.SetAllowlist(&inputs.AllowList) - // set monitoring mode enabled + // Set monitoring mode enabled. if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, &bd.MonitoringModeEnabled); err != nil { return err } diff --git a/internal/cli/cli.go b/internal/cli/cli.go index ec43e2bff..9a87947c6 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -180,7 +180,7 @@ func shouldPromptWhenNoLocalFlagsSet(cmd *cobra.Command) bool { } // nonInputValueFlags is a set of flags that do not take any data input values but only control the command’s output or behavior. -var nonInputValueFlags map[string]struct{} = map[string]struct{}{ +var nonInputValueFlags = map[string]struct{}{ "json": {}, "json-compact": {}, "csv": {}, "force": {}, "no-input": {}, "no-color": {}, "debug": {}, "tenant": {}, } diff --git a/internal/cli/utils_shared_test.go b/internal/cli/utils_shared_test.go index 090d543c8..fb2ff9c8c 100644 --- a/internal/cli/utils_shared_test.go +++ b/internal/cli/utils_shared_test.go @@ -17,7 +17,7 @@ import ( func TestStringPtr(t *testing.T) { t.Run("returns nil when input is nil", func(t *testing.T) { type CustomString string - var nilPtr *CustomString = nil + var nilPtr *CustomString result := stringPtr(nilPtr) assert.Nil(t, result) }) From 720ef372a0ccfa7b198b118e8b026c81e5d2d531 Mon Sep 17 00:00:00 2001 From: Kiran Kumar Date: Mon, 16 Feb 2026 18:27:02 +0530 Subject: [PATCH 11/11] refactor(cli): simplify bot detection update command logic - Renamed variable `bd` to `current` for clarity in the `updateBotDetectionCmdRun` function. - Removed the `noInputValueFlagSet` function and its associated logic to streamline command behavior. --- .../cli/attack_protection_bot_detection.go | 33 ++++++++++--------- internal/cli/cli.go | 17 ---------- 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/internal/cli/attack_protection_bot_detection.go b/internal/cli/attack_protection_bot_detection.go index 393595c2c..e2d90168f 100644 --- a/internal/cli/attack_protection_bot_detection.go +++ b/internal/cli/attack_protection_bot_detection.go @@ -167,9 +167,9 @@ func showBotDetectionCmdRun(cli *cli) func(cmd *cobra.Command, args []string) er func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - var bd *managementv2.GetBotDetectionSettingsResponseContent + var current *managementv2.GetBotDetectionSettingsResponseContent err := ansi.Waiting(func() (err error) { - bd, err = cli.apiv2.AttackProtectionBotDetection.Get(cmd.Context()) + current, err = cli.apiv2.AttackProtectionBotDetection.Get(cmd.Context()) return err }) if err != nil { @@ -179,11 +179,11 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co bdUpdate := &managementv2.UpdateBotDetectionSettingsRequestContent{} // Set bot detection level. - if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, stringPtr(bd.BotDetectionLevel.Ptr())); err != nil { + if err := bdFlags.BotDetectionLevel.AskU(cmd, &inputs.BotDetectionLevel, stringPtr(current.BotDetectionLevel.Ptr())); err != nil { return err } if inputs.BotDetectionLevel == "" { - inputs.BotDetectionLevel = string(bd.GetBotDetectionLevel()) + inputs.BotDetectionLevel = string(current.GetBotDetectionLevel()) } botDetectionLevel, err := managementv2.NewBotDetectionLevelEnumFromString(inputs.BotDetectionLevel) if err != nil { @@ -192,11 +192,11 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co bdUpdate.SetBotDetectionLevel(&botDetectionLevel) // Set challenge password policy. - if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, stringPtr(bd.ChallengePasswordPolicy.Ptr())); err != nil { + if err := bdFlags.ChallengePasswordPolicy.AskU(cmd, &inputs.ChallengePasswordPolicy, stringPtr(current.ChallengePasswordPolicy.Ptr())); err != nil { return err } if inputs.ChallengePasswordPolicy == "" { - inputs.ChallengePasswordPolicy = string(bd.GetChallengePasswordPolicy()) + inputs.ChallengePasswordPolicy = string(current.GetChallengePasswordPolicy()) } challengePasswordPolicy, err := managementv2.NewBotDetectionChallengePolicyPasswordFlowEnumFromString(inputs.ChallengePasswordPolicy) if err != nil { @@ -205,11 +205,11 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co bdUpdate.SetChallengePasswordPolicy(&challengePasswordPolicy) // Set challenge passwordless policy. - if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, stringPtr(bd.ChallengePasswordlessPolicy.Ptr())); err != nil { + if err := bdFlags.ChallengePasswordlessPolicy.AskU(cmd, &inputs.ChallengePasswordlessPolicy, stringPtr(current.ChallengePasswordlessPolicy.Ptr())); err != nil { return err } if inputs.ChallengePasswordlessPolicy == "" { - inputs.ChallengePasswordlessPolicy = string(bd.GetChallengePasswordlessPolicy()) + inputs.ChallengePasswordlessPolicy = string(current.GetChallengePasswordlessPolicy()) } challengePasswordlessPolicy, err := managementv2.NewBotDetectionChallengePolicyPasswordlessFlowEnumFromString(inputs.ChallengePasswordlessPolicy) if err != nil { @@ -218,11 +218,11 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co bdUpdate.SetChallengePasswordlessPolicy(&challengePasswordlessPolicy) // Set challenge password reset policy. - if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, stringPtr(bd.ChallengePasswordResetPolicy.Ptr())); err != nil { + if err := bdFlags.ChallengePasswordResetPolicy.AskU(cmd, &inputs.ChallengePasswordResetPolicy, stringPtr(current.ChallengePasswordResetPolicy.Ptr())); err != nil { return err } if inputs.ChallengePasswordResetPolicy == "" { - inputs.ChallengePasswordResetPolicy = string(bd.GetChallengePasswordResetPolicy()) + inputs.ChallengePasswordResetPolicy = string(current.GetChallengePasswordResetPolicy()) } challengePasswordResetPolicy, err := managementv2.NewBotDetectionChallengePolicyPasswordResetFlowEnumFromString(inputs.ChallengePasswordResetPolicy) if err != nil { @@ -231,22 +231,23 @@ func updateBotDetectionCmdRun(cli *cli, inputs *botDetectionInputs) func(cmd *co bdUpdate.SetChallengePasswordResetPolicy(&challengePasswordResetPolicy) // Set allowlist. - allowListString := strings.Join(bd.GetAllowlist(), ",") + allowListString := strings.Join(current.GetAllowlist(), ",") if err := bdFlags.AllowList.AskManyU(cmd, &inputs.AllowList, &allowListString); err != nil { return err } if len(inputs.AllowList) == 0 { - inputs.AllowList = bd.GetAllowlist() + inputs.AllowList = current.GetAllowlist() } bdUpdate.SetAllowlist(&inputs.AllowList) // Set monitoring mode enabled. - if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, &bd.MonitoringModeEnabled); err != nil { - return err + if !bdFlags.MonitoringModeEnabled.IsSet(cmd) { + inputs.MonitoringModeEnabled = current.GetMonitoringModeEnabled() } - if bdFlags.MonitoringModeEnabled.IsSet(cmd) || noInputValueFlagSet(cmd) { - bdUpdate.SetMonitoringModeEnabled(&inputs.MonitoringModeEnabled) + if err := bdFlags.MonitoringModeEnabled.AskBoolU(cmd, &inputs.MonitoringModeEnabled, ¤t.MonitoringModeEnabled); err != nil { + return err } + bdUpdate.SetMonitoringModeEnabled(&inputs.MonitoringModeEnabled) var updatedBD *managementv2.UpdateBotDetectionSettingsResponseContent if err := ansi.Waiting(func() error { diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 9a87947c6..9c4f56106 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -179,23 +179,6 @@ func shouldPromptWhenNoLocalFlagsSet(cmd *cobra.Command) bool { return canPrompt(cmd) && !localFlagIsSet } -// nonInputValueFlags is a set of flags that do not take any data input values but only control the command’s output or behavior. -var nonInputValueFlags = map[string]struct{}{ - "json": {}, "json-compact": {}, "csv": {}, "force": {}, "no-input": {}, "no-color": {}, "debug": {}, "tenant": {}, -} - -// noInputValueFlagSet returns true if no data input value is passed as flag in the command. -func noInputValueFlagSet(cmd *cobra.Command) bool { - inputValueFlagSet := false - cmd.Flags().VisitAll(func(f *pflag.Flag) { - if _, ok := nonInputValueFlags[f.Name]; !ok && f.Changed { - inputValueFlagSet = true - return - } - }) - return !inputValueFlagSet -} - func prepareInteractivity(cmd *cobra.Command) { if canPrompt(cmd) || !iostream.IsInputTerminal() { cmd.Flags().VisitAll(func(flag *pflag.Flag) {