From f6472908a514565e22c116ae9f60ff6bf70a25f9 Mon Sep 17 00:00:00 2001 From: KIRAN KUMAR B Date: Fri, 4 Sep 2026 17:45:27 +0530 Subject: [PATCH 1/4] chore(deps): bump go-auth0 v1 to pseudo-version f5a492879bcb - Update github.com/auth0/go-auth0 from v1.48.0 to v1.48.1-0.20260904094659-f5a492879bcb to pull in unreleased changes needed for match-all network ACL support. - Sync go.sum accordingly. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4f4547e3d..2fc5b8ef6 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.48.0 + github.com/auth0/go-auth0 v1.48.1-0.20260904094659-f5a492879bcb github.com/auth0/go-auth0/v3 v3.3.0 github.com/briandowns/spinner v1.23.2 github.com/charmbracelet/glamour v1.0.0 diff --git a/go.sum b/go.sum index 4bb856a6c..4d9254ce4 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,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.48.0 h1:INqEEZbDEkXVI0xUZluS1zzoB4YbYzvCysHH2CNEGzc= -github.com/auth0/go-auth0 v1.48.0/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= +github.com/auth0/go-auth0 v1.48.1-0.20260904094659-f5a492879bcb h1:0wnPrAL2OWPu/fZgDuIUFBR0MNHbuswjbmB53rJDmIc= +github.com/auth0/go-auth0 v1.48.1-0.20260904094659-f5a492879bcb/go.mod h1:32sQB1uAn+99fJo6N819EniKq8h785p0ag0lMWhiTaE= github.com/auth0/go-auth0/v3 v3.3.0 h1:p/OxyycZNUtFekO6uXGBqrVXtnJ92gO7ikXtVDuT0ZA= github.com/auth0/go-auth0/v3 v3.3.0/go.mod h1:wb20iE6T4wCGWtMXAZTWTTxx1/T1aHfVK+dOWleQvlg= github.com/aybabtme/iocontrol v0.0.0-20150809002002-ad15bcfc95a0 h1:0NmehRCgyk5rljDQLKUO+cRJCnduDyn11+zGZIc9Z48= From 4b8dce17401580e2c5b67492bcb91644b65a6f55 Mon Sep 17 00:00:00 2001 From: KIRAN KUMAR B Date: Fri, 4 Sep 2026 19:14:24 +0530 Subject: [PATCH 2/4] feat(network-acl): support match_all unconditional deny-all rules - Add the rule.match_all field to network-acl create and update, exposed via --rule JSON and a new --match-all flag. - Confirm Match All before the match/not_match prompt in the interactive builder and short-circuit rule construction when set, reflecting that match_all is a top-level signal mutually exclusive with match/not_match. - Render a MATCH ALL row in the show/create/update output. - Extend extractCurrentRuleDefaults to pre-fill match_all on update. - Add unit tests for rule building, defaults extraction, and display, plus an integration case for a match_all deny-all rule. - Regenerate command docs for the new flag and examples. --- docs/auth0_network-acl_create.md | 2 + docs/auth0_network-acl_update.md | 2 + internal/cli/network_acl.go | 36 ++++++++ internal/cli/network_acl_test.go | 93 ++++++++++++++++++++ internal/display/network_acl.go | 5 ++ internal/display/network_acl_test.go | 20 +++++ test/integration/network-acl-test-cases.yaml | 16 +++- 7 files changed, 172 insertions(+), 2 deletions(-) diff --git a/docs/auth0_network-acl_create.md b/docs/auth0_network-acl_create.md index 234eaa583..e9d414ff7 100644 --- a/docs/auth0_network-acl_create.md +++ b/docs/auth0_network-acl_create.md @@ -24,6 +24,7 @@ auth0 network-acl create [flags] auth0 network-acl create --description "Redirect Traffic" --priority 3 --active true --rule '{"action":{"redirect":true,"redirect_uri":"https://example.com"},"scope":"management","match":{"ipv4_cidrs":["192.168.1.0/24"]}}' auth0 network-acl create -d "Block Bots" -p 4 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"user_agents":["badbot/*","malicious/*"],"ja3_fingerprints":["deadbeef","cafebabe"]}}' auth0 network-acl create --description "Complex Rule" --priority 5 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}' + auth0 network-acl create --description "Deny All" --priority 99 --active true --rule '{"action":{"block":true},"scope":"tenant","match_all":true}' # Early Access (auth0_managed match/not_match value): auth0 network-acl create -d "Curated Blocklist" -p 6 --active true --rule '{"action":{"log":true},"scope":"tenant","not_match":{"auth0_managed":["auth0.vpn","auth0.proxy"]}}' @@ -46,6 +47,7 @@ auth0 network-acl create [flags] --ja4-fingerprints strings Comma-separated list of JA4 fingerprints to match (Eg. t13d1516h2_8daaf6152771) --json Output in json format. --json-compact Output in compact json format. + --match-all Match all traffic unconditionally (Eg. block all). Cannot be combined with match/not_match criteria. -p, --priority int Priority of the network ACL (required) --redirect-uri string URI to redirect to when action is redirect --rule string Network ACL rule configuration in JSON format (required for non-interactive mode) diff --git a/docs/auth0_network-acl_update.md b/docs/auth0_network-acl_update.md index 7081a4966..c2136fa55 100644 --- a/docs/auth0_network-acl_update.md +++ b/docs/auth0_network-acl_update.md @@ -24,6 +24,7 @@ auth0 network-acl update [flags] auth0 network-acl update --description "Updated description" auth0 network-acl update --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"]}}' auth0 network-acl update --description "Complex Rule updated" --priority 1 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}' + auth0 network-acl update --rule '{"action":{"block":true},"scope":"tenant","match_all":true}' # Early Access (auth0_managed match/not_match value): auth0 network-acl update --rule '{"action":{"allow":true},"scope":"tenant","match":{"auth0_managed":["auth0.low_reputation"]}}' @@ -45,6 +46,7 @@ auth0 network-acl update [flags] --ja3-fingerprints strings Comma-separated list of JA3 fingerprints to match (Eg. deadbeef,cafebabe) --ja4-fingerprints strings Comma-separated list of JA4 fingerprints to match (Eg. t13d1516h2_8daaf6152771) --json Output in JSON format + --match-all Match all traffic unconditionally (Eg. block all). Cannot be combined with match/not_match criteria. -p, --priority int Priority of the network ACL (default 1) --redirect-uri string URI to redirect to when action is redirect --rule string Network ACL rule configuration in JSON format diff --git a/internal/cli/network_acl.go b/internal/cli/network_acl.go index d406eaabc..dc28c6f45 100644 --- a/internal/cli/network_acl.go +++ b/internal/cli/network_acl.go @@ -106,6 +106,12 @@ var ( LongForm: "auth0-managed", Help: "Comma-separated list of Auth0-curated blocklists to match (Eg. auth0.icloud_relay_proxy,auth0.low_reputation). (EA only).", } + + networkACLMatchAll = Flag{ + Name: "MatchAll", + LongForm: "match-all", + Help: "Match all traffic unconditionally (Eg. block all). Cannot be combined with match/not_match criteria.", + } ) // validateAndSetBasicFields handles the common validation and patch building logic for basic fields. @@ -130,6 +136,7 @@ func validateAndSetBasicFields(inputs *struct { Auth0Managed []string MatchRule bool NoMatchRule bool + MatchAll bool }, patch *management.NetworkACL, cmd *cobra.Command) error { if cmd.Flags().Changed("description") { if len(inputs.Description) > 255 { @@ -233,6 +240,7 @@ type ruleDefaults struct { IsMatchRule bool HasMatchRule bool HasNotMatch bool + MatchAll bool } // extractCurrentRuleDefaults extracts default values from current ACL rule for interactive prompts. @@ -267,6 +275,11 @@ func extractCurrentRuleDefaults(currentACL *management.NetworkACL) *ruleDefaults } } + // Extract match_all (unconditional rule, mutually exclusive with match/not_match). + if currentACL.Rule.MatchAll != nil && *currentACL.Rule.MatchAll { + defaults.MatchAll = true + } + // Extract match criteria from either Match or NotMatch. var match *management.NetworkACLRuleMatch if currentACL.Rule.Match != nil { @@ -329,6 +342,7 @@ type ruleInputs struct { IsMatchRule bool MatchRule bool NoMatchRule bool + MatchAll bool } // promptForRuleDetails handles interactive prompting for rule configuration. @@ -362,6 +376,16 @@ func promptForRuleDetails(cmd *cobra.Command, cli *cli, defaults *ruleDefaults, } } + // Match All is a top-level rule signal, orthogonal to match/not_match and mutually + // exclusive with them at the API. Confirm it before the match/not_match flow, and when + // it is set, skip the criteria selection entirely (there is nothing more to ask). + if err := networkACLMatchAll.AskBool(cmd, &inputs.MatchAll, &defaults.MatchAll); err != nil { + return nil, err + } + if inputs.MatchAll { + return inputs, nil + } + // Handle Match/NotMatch rule changes for updates. if isUpdate { if defaults.HasMatchRule { @@ -494,6 +518,12 @@ func buildNetworkACLRule(inputs *ruleInputs) (*management.NetworkACLRule, error) rule.Action.RedirectURI = &inputs.RedirectURI } + // A match_all rule is unconditional and mutually exclusive with match/not_match criteria. + if inputs.MatchAll { + rule.MatchAll = auth0.Bool(true) + return rule, nil + } + // Build match criteria. match := &management.NetworkACLRuleMatch{} matchProvided := false @@ -654,6 +684,7 @@ func createNetworkACLCmd(cli *cli) *cobra.Command { UserAgents []string Auth0Managed []string Scope string + MatchAll bool isMatchRule bool } @@ -671,6 +702,7 @@ The --rule parameter is required and must contain a valid JSON object with actio auth0 network-acl create --description "Redirect Traffic" --priority 3 --active true --rule '{"action":{"redirect":true,"redirect_uri":"https://example.com"},"scope":"management","match":{"ipv4_cidrs":["192.168.1.0/24"]}}' auth0 network-acl create -d "Block Bots" -p 4 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"user_agents":["badbot/*","malicious/*"],"ja3_fingerprints":["deadbeef","cafebabe"]}}' auth0 network-acl create --description "Complex Rule" --priority 5 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}' + auth0 network-acl create --description "Deny All" --priority 99 --active true --rule '{"action":{"block":true},"scope":"tenant","match_all":true}' # Early Access (auth0_managed match/not_match value): auth0 network-acl create -d "Curated Blocklist" -p 6 --active true --rule '{"action":{"log":true},"scope":"tenant","not_match":{"auth0_managed":["auth0.vpn","auth0.proxy"]}}' @@ -800,6 +832,7 @@ The --rule parameter is required and must contain a valid JSON object with actio networkACLJA4Fingerprints.RegisterStringSlice(cmd, &inputs.JA4, nil) networkACLUserAgents.RegisterStringSlice(cmd, &inputs.UserAgents, nil) networkACLAuth0Managed.RegisterStringSlice(cmd, &inputs.Auth0Managed, nil) + networkACLMatchAll.RegisterBool(cmd, &inputs.MatchAll, false) // These flags must be passed in non-interactive mode. cmd.MarkFlagRequired("description") @@ -831,6 +864,7 @@ func updateNetworkACLCmd(cli *cli) *cobra.Command { Auth0Managed []string MatchRule bool NoMatchRule bool + MatchAll bool } cmd := &cobra.Command{ @@ -847,6 +881,7 @@ To update non-interactively, supply the description, active, priority, and rule auth0 network-acl update --description "Updated description" auth0 network-acl update --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"]}}' auth0 network-acl update --description "Complex Rule updated" --priority 1 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}' + auth0 network-acl update --rule '{"action":{"block":true},"scope":"tenant","match_all":true}' # Early Access (auth0_managed match/not_match value): auth0 network-acl update --rule '{"action":{"allow":true},"scope":"tenant","match":{"auth0_managed":["auth0.low_reputation"]}}' @@ -961,6 +996,7 @@ To update non-interactively, supply the description, active, priority, and rule networkACLJA4Fingerprints.RegisterStringSlice(cmd, &inputs.JA4, nil) networkACLUserAgents.RegisterStringSlice(cmd, &inputs.UserAgents, nil) networkACLAuth0Managed.RegisterStringSlice(cmd, &inputs.Auth0Managed, nil) + networkACLMatchAll.RegisterBool(cmd, &inputs.MatchAll, false) return cmd } diff --git a/internal/cli/network_acl_test.go b/internal/cli/network_acl_test.go index b160a99e2..71ddd36c5 100644 --- a/internal/cli/network_acl_test.go +++ b/internal/cli/network_acl_test.go @@ -177,6 +177,99 @@ func TestBuildNetworkACLRule_Auth0Managed(t *testing.T) { } } +func TestBuildNetworkACLRule_MatchAll(t *testing.T) { + tests := []struct { + name string + inputs *ruleInputs + assertRule func(t testing.TB, rule *management.NetworkACLRule) + expectError bool + }{ + { + name: "match_all block rule sets match_all and skips criteria", + inputs: &ruleInputs{ + Scope: "tenant", + Action: "block", + MatchAll: true, + }, + assertRule: func(t testing.TB, rule *management.NetworkACLRule) { + assert.Nil(t, rule.Match) + assert.Nil(t, rule.NotMatch) + assert.NotNil(t, rule.MatchAll) + assert.True(t, *rule.MatchAll) + assert.NotNil(t, rule.Action.Block) + assert.True(t, *rule.Action.Block) + assert.Equal(t, "tenant", *rule.Scope) + }, + }, + { + name: "match_all ignores any match criteria provided", + inputs: &ruleInputs{ + Scope: "tenant", + Action: "block", + MatchAll: true, + IPv4CIDRs: []string{"192.168.1.0/24"}, + IsMatchRule: true, + }, + assertRule: func(t testing.TB, rule *management.NetworkACLRule) { + assert.Nil(t, rule.Match) + assert.Nil(t, rule.NotMatch) + assert.NotNil(t, rule.MatchAll) + assert.True(t, *rule.MatchAll) + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + rule, err := buildNetworkACLRule(test.inputs) + + if test.expectError { + assert.Error(t, err) + return + } + + assert.NoError(t, err) + test.assertRule(t, rule) + }) + } +} + +func TestExtractCurrentRuleDefaults_MatchAll(t *testing.T) { + tests := []struct { + name string + acl *management.NetworkACL + wantMatchAll bool + }{ + { + name: "extracts match_all when true", + acl: &management.NetworkACL{ + Rule: &management.NetworkACLRule{ + MatchAll: auth0.Bool(true), + }, + }, + wantMatchAll: true, + }, + { + name: "no match_all set", + acl: &management.NetworkACL{ + Rule: &management.NetworkACLRule{ + Match: &management.NetworkACLRuleMatch{ + IPv4Cidrs: &[]string{"192.168.1.0/24"}, + }, + }, + }, + wantMatchAll: false, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + defaults := extractCurrentRuleDefaults(test.acl) + assert.Equal(t, test.wantMatchAll, defaults.MatchAll) + }) + } +} + func TestExtractCurrentRuleDefaults_Auth0Managed(t *testing.T) { tests := []struct { name string diff --git a/internal/display/network_acl.go b/internal/display/network_acl.go index 70d238c31..a63344713 100644 --- a/internal/display/network_acl.go +++ b/internal/display/network_acl.go @@ -61,6 +61,11 @@ func (v *networkACLView) KeyValues() [][]string { keyValues = append(keyValues, []string{"REDIRECT URI", *acl.Rule.Action.RedirectURI}) } + // Add match_all if set (unconditional rule, mutually exclusive with match/not_match). + if acl.Rule.MatchAll != nil && *acl.Rule.MatchAll { + keyValues = append(keyValues, []string{"MATCH ALL", "true"}) + } + // Add match criteria if present. if acl.Rule.Match != nil { match := acl.Rule.Match diff --git a/internal/display/network_acl_test.go b/internal/display/network_acl_test.go index 561a739e3..89ac1be51 100644 --- a/internal/display/network_acl_test.go +++ b/internal/display/network_acl_test.go @@ -80,6 +80,26 @@ func TestNetworkACLView_KeyValues_Auth0Managed(t *testing.T) { } } +func TestNetworkACLView_KeyValues_MatchAll(t *testing.T) { + acl := &management.NetworkACL{ + ID: strPtr("acl-match-all"), + Description: strPtr("Deny All"), + Priority: intPtr(99), + Active: boolPtr(true), + Rule: &management.NetworkACLRule{ + Scope: strPtr("tenant"), + Action: &management.NetworkACLRuleAction{Block: boolPtr(true)}, + MatchAll: boolPtr(true), + }, + } + + kvs := makeNetworkACLView(acl).KeyValues() + + value, ok := keyValue(kvs, "MATCH ALL") + assert.True(t, ok, "expected key \"MATCH ALL\" to be present in KeyValues()") + assert.Equal(t, "true", value) +} + // TestNetworkACLView_Object_IncludesID guards against a regression where storing // a *management.NetworkACL in the view's raw field engaged that type's pointer // receiver MarshalJSON, which emits only the writable subset of fields and drops diff --git a/test/integration/network-acl-test-cases.yaml b/test/integration/network-acl-test-cases.yaml index 523a8d700..b27e18176 100644 --- a/test/integration/network-acl-test-cases.yaml +++ b/test/integration/network-acl-test-cases.yaml @@ -99,10 +99,22 @@ tests: rule.action.block: "true" rule.not_match.ipv4_cidrs: "[10.0.0.0/8]" - 010 - delete network ACL: + 010 - create network ACL with match_all deny-all rule: + command: auth0 network-acl create --description "Integration Test ACL Match All" --active false --priority 6 --rule '{"action":{"block":true},"scope":"tenant","match_all":true}' --json --no-input + exit-code: 0 + stdout: + json: + description: "Integration Test ACL Match All" + active: "false" + priority: "99" + rule.scope: "tenant" + rule.action.block: "true" + rule.match_all: "true" + + 011 - delete network ACL: command: auth0 network-acl delete $(./test/integration/scripts/get-network-acl-id.sh) --force --no-input exit-code: 0 - 011 - delete all network ACLs: + 012 - delete all network ACLs: command: auth0 network-acl delete --all --force --no-input exit-code: 0 From c51c14787de0f83ff2eaf51c5994eb7f3cf1cff6 Mon Sep 17 00:00:00 2001 From: KIRAN KUMAR B Date: Mon, 7 Sep 2026 13:53:04 +0530 Subject: [PATCH 3/4] test(network-acl): fix expected priority in match_all case - Correct the asserted priority from 99 to 6 in the match_all deny-all integration case so it matches the value the create command sends. --- test/integration/network-acl-test-cases.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/network-acl-test-cases.yaml b/test/integration/network-acl-test-cases.yaml index b27e18176..8c331a705 100644 --- a/test/integration/network-acl-test-cases.yaml +++ b/test/integration/network-acl-test-cases.yaml @@ -106,7 +106,7 @@ tests: json: description: "Integration Test ACL Match All" active: "false" - priority: "99" + priority: "6" rule.scope: "tenant" rule.action.block: "true" rule.match_all: "true" From 2b40fb57b5655e312cc6976d28158b441a196dee Mon Sep 17 00:00:00 2001 From: KIRAN KUMAR B Date: Mon, 7 Sep 2026 17:42:37 +0530 Subject: [PATCH 4/4] feat(network-acl): honor explicitly set --match-all flag in prompts - Seed ruleInputs.MatchAll from the --match-all flag before AskBool in promptForRuleDetails; AskBool suppresses its own prompt when the flag is set explicitly, which previously left MatchAll false and pushed the user into the match/not_match flow instead of building a match_all rule. - Check the flag before the match-criteria prompts so it short-circuits the rest of the rule questions, matching how the other rule sub-config flags behave. - Add TestPromptForRuleDetails_MatchAllFlag to exercise the flag-to-input wiring, closing the gap where only buildNetworkACLRule and the --rule JSON path were covered. --- internal/cli/network_acl.go | 9 +++++++++ internal/cli/network_acl_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/internal/cli/network_acl.go b/internal/cli/network_acl.go index dc28c6f45..c10c944c7 100644 --- a/internal/cli/network_acl.go +++ b/internal/cli/network_acl.go @@ -379,6 +379,15 @@ func promptForRuleDetails(cmd *cobra.Command, cli *cli, defaults *ruleDefaults, // Match All is a top-level rule signal, orthogonal to match/not_match and mutually // exclusive with them at the API. Confirm it before the match/not_match flow, and when // it is set, skip the criteria selection entirely (there is nothing more to ask). + // AskBool skips its prompt when --match-all was set explicitly, so seed the value + // from the flag first to preserve an explicitly supplied value. + if cmd.Flags().Changed("match-all") { + matchAll, err := cmd.Flags().GetBool("match-all") + if err != nil { + return nil, err + } + inputs.MatchAll = matchAll + } if err := networkACLMatchAll.AskBool(cmd, &inputs.MatchAll, &defaults.MatchAll); err != nil { return nil, err } diff --git a/internal/cli/network_acl_test.go b/internal/cli/network_acl_test.go index 71ddd36c5..d8e86ebac 100644 --- a/internal/cli/network_acl_test.go +++ b/internal/cli/network_acl_test.go @@ -7,6 +7,7 @@ import ( "github.com/auth0/go-auth0/management" "github.com/golang/mock/gomock" + "github.com/spf13/cobra" "github.com/stretchr/testify/assert" @@ -234,6 +235,30 @@ func TestBuildNetworkACLRule_MatchAll(t *testing.T) { } } +func TestPromptForRuleDetails_MatchAllFlag(t *testing.T) { + // In tests there is no TTY, so canPrompt is false and every interactive prompt is + // skipped. This lets us exercise the seeding of MatchAll from an explicitly-set + // --match-all flag and confirm it short-circuits before the match criteria prompts. + newCmd := func(setMatchAll bool) *cobra.Command { + cmd := &cobra.Command{Use: "create"} + var matchAll bool + networkACLMatchAll.RegisterBool(cmd, &matchAll, false) + if setMatchAll { + assert.NoError(t, cmd.Flags().Set("match-all", "true")) + } + return cmd + } + + cli := &cli{renderer: testRenderer()} + defaults := &ruleDefaults{Scope: "tenant", Action: "block"} + + // With --match-all set, seeding runs and the early return fires before the + // match/not_match selection and criteria prompts, so no TTY is needed. + inputs, err := promptForRuleDetails(newCmd(true), cli, defaults, false) + assert.NoError(t, err) + assert.True(t, inputs.MatchAll) +} + func TestExtractCurrentRuleDefaults_MatchAll(t *testing.T) { tests := []struct { name string