From 843f8f6297c9574667daa1449cdf47e4d38a566f Mon Sep 17 00:00:00 2001 From: Ken Ho Date: Wed, 29 Jul 2026 09:37:53 -0400 Subject: [PATCH 1/3] chore(ers): add BDD scenarios for condition operators equals, contains, regex Cover the three untested condition operators in multi-strategy ERS: - equals: exact match, negative match, case-insensitive (EqualFold) - contains: substring match, negative match, AND logic (multiple conditions) - regex: pattern match, negative match, AND logic (regex + exists) All 9 scenarios use LDAP strategies with user_name entities to avoid the claims provider bug (#3790). Each feature file is @stateless and runs independently. Part of DSPX-4100. Co-Authored-By: Claude Opus 4.6 --- .../features/ers-condition-contains.feature | 145 ++++++++++++++++++ .../features/ers-condition-equals.feature | 141 +++++++++++++++++ .../features/ers-condition-regex.feature | 143 +++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 tests-bdd/features/ers-condition-contains.feature create mode 100644 tests-bdd/features/ers-condition-equals.feature create mode 100644 tests-bdd/features/ers-condition-regex.feature diff --git a/tests-bdd/features/ers-condition-contains.feature b/tests-bdd/features/ers-condition-contains.feature new file mode 100644 index 0000000000..037ffb38b8 --- /dev/null +++ b/tests-bdd/features/ers-condition-contains.feature @@ -0,0 +1,145 @@ +@ers-condition-contains @stateless +Feature: ERS condition operator — contains + Validate that the "contains" condition operator performs case-insensitive + substring matching on JWT claims to select the correct mapping strategy. + + The contains operator checks if a string claim value contains any of the + values in condition.Values[] as a substring (case-insensitive). + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + + Scenario: Contains condition matches substring — "alice" contains "ali" gets PERMIT + And an ERS mapping strategy "contains_ali_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: contains + values: ["ali"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "ct-match.test" and reference id "ns_ct_match" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_ct_match | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_ct_match" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_ct_match" containing the condition groups "cg_ct_match" + And I send a request to create a subject condition set referenced as "scs_ct_match" containing subject sets "ss_ct_match" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_ct_match | https://ct-match.test/attr/department/value/engineering | scs_ct_match | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_ct" + When I send a decision request for entity chain "alice_ct" for "read" action on resource "https://ct-match.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: Contains condition does not match — "bob" does not contain "ali" gets DENY + And an ERS mapping strategy "contains_ali_strat2" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: contains + values: ["ali"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "ct-nomatch.test" and reference id "ns_ct_nomatch" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_ct_nomatch | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_ct_nomatch" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_ct_nomatch" containing the condition groups "cg_ct_nomatch" + And I send a request to create a subject condition set referenced as "scs_ct_nomatch" containing subject sets "ss_ct_nomatch" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_ct_nomatch | https://ct-nomatch.test/attr/department/value/engineering | scs_ct_nomatch | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "bob" and referenced as "bob_ct" + When I send a decision request for entity chain "bob_ct" for "read" action on resource "https://ct-nomatch.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "DENY" decision response + + Scenario: Multiple contains conditions (AND logic) — both must match for strategy selection + # "diana" contains "an" (di-AN-a) AND "di" (DI-ana) -> both match -> strategy selected + And an ERS mapping strategy "multi_contains_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: contains + values: ["an"] + - claim: userName + operator: contains + values: ["di"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "ct-and.test" and reference id "ns_ct_and" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_ct_and | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_ct_and" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_ct_and" containing the condition groups "cg_ct_and" + And I send a request to create a subject condition set referenced as "scs_ct_and" containing subject sets "ss_ct_and" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_ct_and | https://ct-and.test/attr/department/value/engineering | scs_ct_and | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "diana" and referenced as "diana_ct" + When I send a decision request for entity chain "diana_ct" for "read" action on resource "https://ct-and.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response diff --git a/tests-bdd/features/ers-condition-equals.feature b/tests-bdd/features/ers-condition-equals.feature new file mode 100644 index 0000000000..50175baa7a --- /dev/null +++ b/tests-bdd/features/ers-condition-equals.feature @@ -0,0 +1,141 @@ +@ers-condition-equals @stateless +Feature: ERS condition operator — equals + Validate that the "equals" condition operator performs case-insensitive + exact matching on JWT claims to select the correct mapping strategy. + + The equals operator checks if a claim value matches any of the values + in condition.Values[] using strings.EqualFold (case-insensitive). + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + + Scenario: Equals condition matches — alice routed to strategy gets PERMIT + And an ERS mapping strategy "alice_only_strategy" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: equals + values: ["alice"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "eq-match.test" and reference id "ns_eq_match" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_eq_match | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_eq_match" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_eq_match" containing the condition groups "cg_eq_match" + And I send a request to create a subject condition set referenced as "scs_eq_match" containing subject sets "ss_eq_match" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_eq_match | https://eq-match.test/attr/department/value/engineering | scs_eq_match | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_eq" + When I send a decision request for entity chain "alice_eq" for "read" action on resource "https://eq-match.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: Equals condition does not match — bob skipped by alice-only strategy gets DENY + And an ERS mapping strategy "alice_only_strat2" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: equals + values: ["alice"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "eq-nomatch.test" and reference id "ns_eq_nomatch" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_eq_nomatch | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_eq_nomatch" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_eq_nomatch" containing the condition groups "cg_eq_nomatch" + And I send a request to create a subject condition set referenced as "scs_eq_nomatch" containing subject sets "ss_eq_nomatch" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_eq_nomatch | https://eq-nomatch.test/attr/department/value/engineering | scs_eq_nomatch | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "bob" and referenced as "bob_eq" + When I send a decision request for entity chain "bob_eq" for "read" action on resource "https://eq-nomatch.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "DENY" decision response + + Scenario: Equals condition is case-insensitive — condition "ALICE" matches userName "alice" + And an ERS mapping strategy "ci_alice_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: equals + values: ["ALICE"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "eq-ci.test" and reference id "ns_eq_ci" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_eq_ci | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_eq_ci" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_eq_ci" containing the condition groups "cg_eq_ci" + And I send a request to create a subject condition set referenced as "scs_eq_ci" containing subject sets "ss_eq_ci" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_eq_ci | https://eq-ci.test/attr/department/value/engineering | scs_eq_ci | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_ci" + When I send a decision request for entity chain "alice_ci" for "read" action on resource "https://eq-ci.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response diff --git a/tests-bdd/features/ers-condition-regex.feature b/tests-bdd/features/ers-condition-regex.feature new file mode 100644 index 0000000000..35b9d48510 --- /dev/null +++ b/tests-bdd/features/ers-condition-regex.feature @@ -0,0 +1,143 @@ +@ers-condition-regex @stateless +Feature: ERS condition operator — regex + Validate that the "regex" condition operator performs pattern matching + on JWT claims to select the correct mapping strategy. + + The regex operator uses regexp.MatchString to test whether the claim + value matches any pattern in condition.Values[]. Patterns use Go RE2 syntax. + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + + Scenario: Regex condition matches — userName matching "^[a-d].*" selects strategy for alice + And an ERS mapping strategy "regex_ad_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: regex + values: ["^[a-d].*"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "rx-match.test" and reference id "ns_rx_match" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_rx_match | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_rx_match" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_rx_match" containing the condition groups "cg_rx_match" + And I send a request to create a subject condition set referenced as "scs_rx_match" containing subject sets "ss_rx_match" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_rx_match | https://rx-match.test/attr/department/value/engineering | scs_rx_match | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_rx" + When I send a decision request for entity chain "alice_rx" for "read" action on resource "https://rx-match.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: Regex condition does not match — "henry" does not match "^[a-d].*" gets DENY + And an ERS mapping strategy "regex_ad_strat2" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: regex + values: ["^[a-d].*"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "rx-nomatch.test" and reference id "ns_rx_nomatch" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_rx_nomatch | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_rx_nomatch" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_rx_nomatch" containing the condition groups "cg_rx_nomatch" + And I send a request to create a subject condition set referenced as "scs_rx_nomatch" containing subject sets "ss_rx_nomatch" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_rx_nomatch | https://rx-nomatch.test/attr/department/value/engineering | scs_rx_nomatch | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "henry" and referenced as "henry_rx" + When I send a decision request for entity chain "henry_rx" for "read" action on resource "https://rx-nomatch.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "DENY" decision response + + Scenario: Multiple conditions with regex and exists (AND logic) — both must match + And an ERS mapping strategy "regex_and_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: regex + values: ["^(alice|diana)$"] + - claim: userName + operator: exists + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + Given I submit a request to create a namespace with name "rx-and.test" and reference id "ns_rx_and" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_rx_and | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_rx_and" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_rx_and" containing the condition groups "cg_rx_and" + And I send a request to create a subject condition set referenced as "scs_rx_and" containing subject sets "ss_rx_and" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_rx_and | https://rx-and.test/attr/department/value/engineering | scs_rx_and | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_rx_and" + When I send a decision request for entity chain "alice_rx_and" for "read" action on resource "https://rx-and.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response From b36a64b5d42cee6110557fbe6643512d23996f9f Mon Sep 17 00:00:00 2001 From: Ken Ho Date: Wed, 29 Jul 2026 10:23:25 -0400 Subject: [PATCH 2/3] fix(ers): split condition operator BDD scenarios into separate features With @stateless, the platform starts once per feature file and the ERS config from the Background is fixed for all scenarios. Scenarios that need different strategy configs must be in separate feature files. Split into 5 feature files: - ers-condition-equals: match + no-match (shared strategy) - ers-condition-equals-ci: case-insensitive (values: ["ALICE"]) - ers-condition-contains: substring match + no-match - ers-condition-regex: pattern match + no-match - ers-condition-and-logic: multiple conditions AND logic + partial match Co-Authored-By: Claude Opus 4.6 --- .../features/ers-condition-and-logic.feature | 75 +++++++++++++++++++ .../features/ers-condition-contains.feature | 74 +----------------- .../features/ers-condition-equals-ci.feature | 53 +++++++++++++ .../features/ers-condition-equals.feature | 70 +---------------- .../features/ers-condition-regex.feature | 72 +----------------- 5 files changed, 134 insertions(+), 210 deletions(-) create mode 100644 tests-bdd/features/ers-condition-and-logic.feature create mode 100644 tests-bdd/features/ers-condition-equals-ci.feature diff --git a/tests-bdd/features/ers-condition-and-logic.feature b/tests-bdd/features/ers-condition-and-logic.feature new file mode 100644 index 0000000000..da5229218a --- /dev/null +++ b/tests-bdd/features/ers-condition-and-logic.feature @@ -0,0 +1,75 @@ +@ers-condition-and-logic @stateless +Feature: ERS condition — multiple conditions AND logic + Validate that when a strategy has multiple JWT claim conditions, ALL + conditions must match for the strategy to be selected (AND logic). + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + And an ERS mapping strategy "multi_condition_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: contains + values: ["an"] + - claim: userName + operator: contains + values: ["di"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + + Scenario: Both AND conditions match — diana contains "an" and "di" gets PERMIT + Given I submit a request to create a namespace with name "and-match.test" and reference id "ns_and_match" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_and_match | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_and_match" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_and_match" containing the condition groups "cg_and_match" + And I send a request to create a subject condition set referenced as "scs_and_match" containing subject sets "ss_and_match" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_and_match | https://and-match.test/attr/department/value/engineering | scs_and_match | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "diana" and referenced as "diana_and" + When I send a decision request for entity chain "diana_and" for "read" action on resource "https://and-match.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: Only one AND condition matches — alice contains "ali" but not "di" gets DENY + Given I submit a request to create a namespace with name "and-partial.test" and reference id "ns_and_partial" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_and_partial | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_and_partial" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_and_partial" containing the condition groups "cg_and_partial" + And I send a request to create a subject condition set referenced as "scs_and_partial" containing subject sets "ss_and_partial" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_and_partial | https://and-partial.test/attr/department/value/engineering | scs_and_partial | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_and" + When I send a decision request for entity chain "alice_and" for "read" action on resource "https://and-partial.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "DENY" decision response diff --git a/tests-bdd/features/ers-condition-contains.feature b/tests-bdd/features/ers-condition-contains.feature index 037ffb38b8..7da95de70c 100644 --- a/tests-bdd/features/ers-condition-contains.feature +++ b/tests-bdd/features/ers-condition-contains.feature @@ -10,8 +10,6 @@ Feature: ERS condition operator — contains Given an LDAP directory with test users And an ERS configuration with mode "multi-strategy" and failure strategy "continue" And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory - - Scenario: Contains condition matches substring — "alice" contains "ali" gets PERMIT And an ERS mapping strategy "contains_ali_strat" using provider "ldap_directory" """ entity_type: subject @@ -35,6 +33,8 @@ Feature: ERS condition operator — contains claim_name: username """ And a local platform with inline ERS configuration + + Scenario: Contains condition matches substring — "alice" contains "ali" gets PERMIT Given I submit a request to create a namespace with name "ct-match.test" and reference id "ns_ct_match" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -55,29 +55,6 @@ Feature: ERS condition operator — contains And I should get a "PERMIT" decision response Scenario: Contains condition does not match — "bob" does not contain "ali" gets DENY - And an ERS mapping strategy "contains_ali_strat2" using provider "ldap_directory" - """ - entity_type: subject - conditions: - jwt_claims: - - claim: userName - operator: contains - values: ["ali"] - ldap_search: - base_dn: "ou=users,dc=opentdf,dc=test" - filter: "(&(objectClass=inetOrgPerson)(uid={username}))" - scope: subtree - attributes: ["uid", "mail", "departmentNumber"] - input_mapping: - - jwt_claim: userName - parameter: username - output_mapping: - - source_attribute: departmentNumber - claim_name: department - - source_attribute: uid - claim_name: username - """ - And a local platform with inline ERS configuration Given I submit a request to create a namespace with name "ct-nomatch.test" and reference id "ns_ct_nomatch" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -96,50 +73,3 @@ Feature: ERS condition operator — contains When I send a decision request for entity chain "bob_ct" for "read" action on resource "https://ct-nomatch.test/attr/department/value/engineering" Then the response should be successful And I should get a "DENY" decision response - - Scenario: Multiple contains conditions (AND logic) — both must match for strategy selection - # "diana" contains "an" (di-AN-a) AND "di" (DI-ana) -> both match -> strategy selected - And an ERS mapping strategy "multi_contains_strat" using provider "ldap_directory" - """ - entity_type: subject - conditions: - jwt_claims: - - claim: userName - operator: contains - values: ["an"] - - claim: userName - operator: contains - values: ["di"] - ldap_search: - base_dn: "ou=users,dc=opentdf,dc=test" - filter: "(&(objectClass=inetOrgPerson)(uid={username}))" - scope: subtree - attributes: ["uid", "mail", "departmentNumber"] - input_mapping: - - jwt_claim: userName - parameter: username - output_mapping: - - source_attribute: departmentNumber - claim_name: department - - source_attribute: uid - claim_name: username - """ - And a local platform with inline ERS configuration - Given I submit a request to create a namespace with name "ct-and.test" and reference id "ns_ct_and" - And I send a request to create an attribute with: - | namespace_id | name | rule | values | - | ns_ct_and | department | anyOf | engineering,marketing,security | - Then the response should be successful - Given a condition group referenced as "cg_ct_and" with an "or" operator with conditions: - | selector_value | operator | values | - | .department | in | engineering | - And a subject set referenced as "ss_ct_and" containing the condition groups "cg_ct_and" - And I send a request to create a subject condition set referenced as "scs_ct_and" containing subject sets "ss_ct_and" - And I send a request to create a subject mapping with: - | reference_id | attribute_value | condition_set_name | standard actions | custom actions | - | sm_ct_and | https://ct-and.test/attr/department/value/engineering | scs_ct_and | read | | - Then the response should be successful - Given there is a "user_name" subject entity with value "diana" and referenced as "diana_ct" - When I send a decision request for entity chain "diana_ct" for "read" action on resource "https://ct-and.test/attr/department/value/engineering" - Then the response should be successful - And I should get a "PERMIT" decision response diff --git a/tests-bdd/features/ers-condition-equals-ci.feature b/tests-bdd/features/ers-condition-equals-ci.feature new file mode 100644 index 0000000000..b4bdc34970 --- /dev/null +++ b/tests-bdd/features/ers-condition-equals-ci.feature @@ -0,0 +1,53 @@ +@ers-condition-equals-ci @stateless +Feature: ERS condition operator — equals case-insensitivity + Validate that the "equals" condition operator is case-insensitive, + using strings.EqualFold so that condition value "ALICE" matches + userName "alice". + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + And an ERS mapping strategy "ci_alice_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: equals + values: ["ALICE"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + + Scenario: Equals condition is case-insensitive — condition "ALICE" matches userName "alice" + Given I submit a request to create a namespace with name "eq-ci.test" and reference id "ns_eq_ci" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_eq_ci | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_eq_ci" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_eq_ci" containing the condition groups "cg_eq_ci" + And I send a request to create a subject condition set referenced as "scs_eq_ci" containing subject sets "ss_eq_ci" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_eq_ci | https://eq-ci.test/attr/department/value/engineering | scs_eq_ci | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_ci" + When I send a decision request for entity chain "alice_ci" for "read" action on resource "https://eq-ci.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response diff --git a/tests-bdd/features/ers-condition-equals.feature b/tests-bdd/features/ers-condition-equals.feature index 50175baa7a..9638dccc48 100644 --- a/tests-bdd/features/ers-condition-equals.feature +++ b/tests-bdd/features/ers-condition-equals.feature @@ -10,8 +10,6 @@ Feature: ERS condition operator — equals Given an LDAP directory with test users And an ERS configuration with mode "multi-strategy" and failure strategy "continue" And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory - - Scenario: Equals condition matches — alice routed to strategy gets PERMIT And an ERS mapping strategy "alice_only_strategy" using provider "ldap_directory" """ entity_type: subject @@ -35,6 +33,8 @@ Feature: ERS condition operator — equals claim_name: username """ And a local platform with inline ERS configuration + + Scenario: Equals condition matches — alice routed to strategy gets PERMIT Given I submit a request to create a namespace with name "eq-match.test" and reference id "ns_eq_match" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -55,29 +55,6 @@ Feature: ERS condition operator — equals And I should get a "PERMIT" decision response Scenario: Equals condition does not match — bob skipped by alice-only strategy gets DENY - And an ERS mapping strategy "alice_only_strat2" using provider "ldap_directory" - """ - entity_type: subject - conditions: - jwt_claims: - - claim: userName - operator: equals - values: ["alice"] - ldap_search: - base_dn: "ou=users,dc=opentdf,dc=test" - filter: "(&(objectClass=inetOrgPerson)(uid={username}))" - scope: subtree - attributes: ["uid", "mail", "departmentNumber"] - input_mapping: - - jwt_claim: userName - parameter: username - output_mapping: - - source_attribute: departmentNumber - claim_name: department - - source_attribute: uid - claim_name: username - """ - And a local platform with inline ERS configuration Given I submit a request to create a namespace with name "eq-nomatch.test" and reference id "ns_eq_nomatch" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -96,46 +73,3 @@ Feature: ERS condition operator — equals When I send a decision request for entity chain "bob_eq" for "read" action on resource "https://eq-nomatch.test/attr/department/value/engineering" Then the response should be successful And I should get a "DENY" decision response - - Scenario: Equals condition is case-insensitive — condition "ALICE" matches userName "alice" - And an ERS mapping strategy "ci_alice_strat" using provider "ldap_directory" - """ - entity_type: subject - conditions: - jwt_claims: - - claim: userName - operator: equals - values: ["ALICE"] - ldap_search: - base_dn: "ou=users,dc=opentdf,dc=test" - filter: "(&(objectClass=inetOrgPerson)(uid={username}))" - scope: subtree - attributes: ["uid", "mail", "departmentNumber"] - input_mapping: - - jwt_claim: userName - parameter: username - output_mapping: - - source_attribute: departmentNumber - claim_name: department - - source_attribute: uid - claim_name: username - """ - And a local platform with inline ERS configuration - Given I submit a request to create a namespace with name "eq-ci.test" and reference id "ns_eq_ci" - And I send a request to create an attribute with: - | namespace_id | name | rule | values | - | ns_eq_ci | department | anyOf | engineering,marketing,security | - Then the response should be successful - Given a condition group referenced as "cg_eq_ci" with an "or" operator with conditions: - | selector_value | operator | values | - | .department | in | engineering | - And a subject set referenced as "ss_eq_ci" containing the condition groups "cg_eq_ci" - And I send a request to create a subject condition set referenced as "scs_eq_ci" containing subject sets "ss_eq_ci" - And I send a request to create a subject mapping with: - | reference_id | attribute_value | condition_set_name | standard actions | custom actions | - | sm_eq_ci | https://eq-ci.test/attr/department/value/engineering | scs_eq_ci | read | | - Then the response should be successful - Given there is a "user_name" subject entity with value "alice" and referenced as "alice_ci" - When I send a decision request for entity chain "alice_ci" for "read" action on resource "https://eq-ci.test/attr/department/value/engineering" - Then the response should be successful - And I should get a "PERMIT" decision response diff --git a/tests-bdd/features/ers-condition-regex.feature b/tests-bdd/features/ers-condition-regex.feature index 35b9d48510..39c339cde6 100644 --- a/tests-bdd/features/ers-condition-regex.feature +++ b/tests-bdd/features/ers-condition-regex.feature @@ -10,8 +10,6 @@ Feature: ERS condition operator — regex Given an LDAP directory with test users And an ERS configuration with mode "multi-strategy" and failure strategy "continue" And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory - - Scenario: Regex condition matches — userName matching "^[a-d].*" selects strategy for alice And an ERS mapping strategy "regex_ad_strat" using provider "ldap_directory" """ entity_type: subject @@ -35,6 +33,8 @@ Feature: ERS condition operator — regex claim_name: username """ And a local platform with inline ERS configuration + + Scenario: Regex condition matches — userName matching "^[a-d].*" selects strategy for alice Given I submit a request to create a namespace with name "rx-match.test" and reference id "ns_rx_match" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -55,29 +55,6 @@ Feature: ERS condition operator — regex And I should get a "PERMIT" decision response Scenario: Regex condition does not match — "henry" does not match "^[a-d].*" gets DENY - And an ERS mapping strategy "regex_ad_strat2" using provider "ldap_directory" - """ - entity_type: subject - conditions: - jwt_claims: - - claim: userName - operator: regex - values: ["^[a-d].*"] - ldap_search: - base_dn: "ou=users,dc=opentdf,dc=test" - filter: "(&(objectClass=inetOrgPerson)(uid={username}))" - scope: subtree - attributes: ["uid", "mail", "departmentNumber"] - input_mapping: - - jwt_claim: userName - parameter: username - output_mapping: - - source_attribute: departmentNumber - claim_name: department - - source_attribute: uid - claim_name: username - """ - And a local platform with inline ERS configuration Given I submit a request to create a namespace with name "rx-nomatch.test" and reference id "ns_rx_nomatch" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -96,48 +73,3 @@ Feature: ERS condition operator — regex When I send a decision request for entity chain "henry_rx" for "read" action on resource "https://rx-nomatch.test/attr/department/value/engineering" Then the response should be successful And I should get a "DENY" decision response - - Scenario: Multiple conditions with regex and exists (AND logic) — both must match - And an ERS mapping strategy "regex_and_strat" using provider "ldap_directory" - """ - entity_type: subject - conditions: - jwt_claims: - - claim: userName - operator: regex - values: ["^(alice|diana)$"] - - claim: userName - operator: exists - ldap_search: - base_dn: "ou=users,dc=opentdf,dc=test" - filter: "(&(objectClass=inetOrgPerson)(uid={username}))" - scope: subtree - attributes: ["uid", "mail", "departmentNumber"] - input_mapping: - - jwt_claim: userName - parameter: username - output_mapping: - - source_attribute: departmentNumber - claim_name: department - - source_attribute: uid - claim_name: username - """ - And a local platform with inline ERS configuration - Given I submit a request to create a namespace with name "rx-and.test" and reference id "ns_rx_and" - And I send a request to create an attribute with: - | namespace_id | name | rule | values | - | ns_rx_and | department | anyOf | engineering,marketing,security | - Then the response should be successful - Given a condition group referenced as "cg_rx_and" with an "or" operator with conditions: - | selector_value | operator | values | - | .department | in | engineering | - And a subject set referenced as "ss_rx_and" containing the condition groups "cg_rx_and" - And I send a request to create a subject condition set referenced as "scs_rx_and" containing subject sets "ss_rx_and" - And I send a request to create a subject mapping with: - | reference_id | attribute_value | condition_set_name | standard actions | custom actions | - | sm_rx_and | https://rx-and.test/attr/department/value/engineering | scs_rx_and | read | | - Then the response should be successful - Given there is a "user_name" subject entity with value "alice" and referenced as "alice_rx_and" - When I send a decision request for entity chain "alice_rx_and" for "read" action on resource "https://rx-and.test/attr/department/value/engineering" - Then the response should be successful - And I should get a "PERMIT" decision response From 8d038ce9d5178b5699cea9c372120d66b2928546 Mon Sep 17 00:00:00 2001 From: Ken Ho Date: Thu, 30 Jul 2026 12:01:39 -0400 Subject: [PATCH 3/3] chore(ers): address review feedback on condition operator BDD tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes and additions per Elizabeth Healy's review: 1. Fix AND partial-match: change conditions from contains "an" + "di" to contains "a" + "di" so alice matches one (not zero) — properly tests AND short-circuit 2. Fix contains case-insensitivity: change values to ["ALI"] (uppercase) so existing scenarios actually validate case-insensitive matching 3. Add mixed-operator AND: new ers-condition-and-mixed.feature with regex + contains conditions (diana matches both, alice matches only regex) 4. Add multi-value OR: new ers-condition-equals-multi.feature with values: ["alice", "diana"] testing OR-within-condition semantics 5. Array claim testing noted as blocked by #3790 (requires Entity_Claims which needs JWTClaimsContextKey fix) Co-Authored-By: Claude Opus 4.6 --- .../features/ers-condition-and-logic.feature | 6 +- .../features/ers-condition-and-mixed.feature | 76 +++++++++++++++ .../features/ers-condition-contains.feature | 6 +- .../ers-condition-equals-multi.feature | 92 +++++++++++++++++++ 4 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 tests-bdd/features/ers-condition-and-mixed.feature create mode 100644 tests-bdd/features/ers-condition-equals-multi.feature diff --git a/tests-bdd/features/ers-condition-and-logic.feature b/tests-bdd/features/ers-condition-and-logic.feature index da5229218a..777a90ee7d 100644 --- a/tests-bdd/features/ers-condition-and-logic.feature +++ b/tests-bdd/features/ers-condition-and-logic.feature @@ -14,7 +14,7 @@ Feature: ERS condition — multiple conditions AND logic jwt_claims: - claim: userName operator: contains - values: ["an"] + values: ["a"] - claim: userName operator: contains values: ["di"] @@ -34,7 +34,7 @@ Feature: ERS condition — multiple conditions AND logic """ And a local platform with inline ERS configuration - Scenario: Both AND conditions match — diana contains "an" and "di" gets PERMIT + Scenario: Both AND conditions match — diana contains "a" and "di" gets PERMIT Given I submit a request to create a namespace with name "and-match.test" and reference id "ns_and_match" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -54,7 +54,7 @@ Feature: ERS condition — multiple conditions AND logic Then the response should be successful And I should get a "PERMIT" decision response - Scenario: Only one AND condition matches — alice contains "ali" but not "di" gets DENY + Scenario: Only one AND condition matches — alice contains "a" but not "di" gets DENY Given I submit a request to create a namespace with name "and-partial.test" and reference id "ns_and_partial" And I send a request to create an attribute with: | namespace_id | name | rule | values | diff --git a/tests-bdd/features/ers-condition-and-mixed.feature b/tests-bdd/features/ers-condition-and-mixed.feature new file mode 100644 index 0000000000..621d0e856f --- /dev/null +++ b/tests-bdd/features/ers-condition-and-mixed.feature @@ -0,0 +1,76 @@ +@ers-condition-and-mixed @stateless +Feature: ERS condition — mixed operator AND logic + Validate that AND logic works across different operator types on the + same or different claims. A strategy with a regex condition plus a + contains condition requires both to match for selection. + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + And an ERS mapping strategy "mixed_ops_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: regex + values: ["^[a-d].*"] + - claim: userName + operator: contains + values: ["an"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + + Scenario: Both mixed conditions match — diana matches regex "^[a-d].*" and contains "an" gets PERMIT + Given I submit a request to create a namespace with name "mixed-match.test" and reference id "ns_mixed_match" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_mixed_match | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_mixed_match" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_mixed_match" containing the condition groups "cg_mixed_match" + And I send a request to create a subject condition set referenced as "scs_mixed_match" containing subject sets "ss_mixed_match" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_mixed_match | https://mixed-match.test/attr/department/value/engineering | scs_mixed_match | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "diana" and referenced as "diana_mixed" + When I send a decision request for entity chain "diana_mixed" for "read" action on resource "https://mixed-match.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: Regex matches but contains does not — alice matches "^[a-d].*" but not "an" gets DENY + Given I submit a request to create a namespace with name "mixed-partial.test" and reference id "ns_mixed_partial" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_mixed_partial | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_mixed_partial" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_mixed_partial" containing the condition groups "cg_mixed_partial" + And I send a request to create a subject condition set referenced as "scs_mixed_partial" containing subject sets "ss_mixed_partial" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_mixed_partial | https://mixed-partial.test/attr/department/value/engineering | scs_mixed_partial | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_mixed" + When I send a decision request for entity chain "alice_mixed" for "read" action on resource "https://mixed-partial.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "DENY" decision response diff --git a/tests-bdd/features/ers-condition-contains.feature b/tests-bdd/features/ers-condition-contains.feature index 7da95de70c..58821be701 100644 --- a/tests-bdd/features/ers-condition-contains.feature +++ b/tests-bdd/features/ers-condition-contains.feature @@ -17,7 +17,7 @@ Feature: ERS condition operator — contains jwt_claims: - claim: userName operator: contains - values: ["ali"] + values: ["ALI"] ldap_search: base_dn: "ou=users,dc=opentdf,dc=test" filter: "(&(objectClass=inetOrgPerson)(uid={username}))" @@ -34,7 +34,7 @@ Feature: ERS condition operator — contains """ And a local platform with inline ERS configuration - Scenario: Contains condition matches substring — "alice" contains "ali" gets PERMIT + Scenario: Contains condition matches substring case-insensitively — "alice" contains "ALI" gets PERMIT Given I submit a request to create a namespace with name "ct-match.test" and reference id "ns_ct_match" And I send a request to create an attribute with: | namespace_id | name | rule | values | @@ -54,7 +54,7 @@ Feature: ERS condition operator — contains Then the response should be successful And I should get a "PERMIT" decision response - Scenario: Contains condition does not match — "bob" does not contain "ali" gets DENY + Scenario: Contains condition does not match — "bob" does not contain "ALI" gets DENY Given I submit a request to create a namespace with name "ct-nomatch.test" and reference id "ns_ct_nomatch" And I send a request to create an attribute with: | namespace_id | name | rule | values | diff --git a/tests-bdd/features/ers-condition-equals-multi.feature b/tests-bdd/features/ers-condition-equals-multi.feature new file mode 100644 index 0000000000..986097500d --- /dev/null +++ b/tests-bdd/features/ers-condition-equals-multi.feature @@ -0,0 +1,92 @@ +@ers-condition-equals-multi @stateless +Feature: ERS condition operator — equals with multi-value OR + Validate that the "equals" operator matches if the claim value equals + ANY of the values in the values[] array (OR-within-condition semantics). + + Background: + Given an LDAP directory with test users + And an ERS configuration with mode "multi-strategy" and failure strategy "continue" + And an ERS provider "ldap_directory" of type "ldap" connected to the LDAP directory + And an ERS mapping strategy "multi_value_strat" using provider "ldap_directory" + """ + entity_type: subject + conditions: + jwt_claims: + - claim: userName + operator: equals + values: ["alice", "diana"] + ldap_search: + base_dn: "ou=users,dc=opentdf,dc=test" + filter: "(&(objectClass=inetOrgPerson)(uid={username}))" + scope: subtree + attributes: ["uid", "mail", "departmentNumber"] + input_mapping: + - jwt_claim: userName + parameter: username + output_mapping: + - source_attribute: departmentNumber + claim_name: department + - source_attribute: uid + claim_name: username + """ + And a local platform with inline ERS configuration + + Scenario: First value in list matches — alice equals one of ["alice", "diana"] gets PERMIT + Given I submit a request to create a namespace with name "mv-first.test" and reference id "ns_mv_first" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_mv_first | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_mv_first" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_mv_first" containing the condition groups "cg_mv_first" + And I send a request to create a subject condition set referenced as "scs_mv_first" containing subject sets "ss_mv_first" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_mv_first | https://mv-first.test/attr/department/value/engineering | scs_mv_first | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "alice" and referenced as "alice_mv" + When I send a decision request for entity chain "alice_mv" for "read" action on resource "https://mv-first.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: Second value in list matches — diana equals one of ["alice", "diana"] gets PERMIT + Given I submit a request to create a namespace with name "mv-second.test" and reference id "ns_mv_second" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_mv_second | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_mv_second" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_mv_second" containing the condition groups "cg_mv_second" + And I send a request to create a subject condition set referenced as "scs_mv_second" containing subject sets "ss_mv_second" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_mv_second | https://mv-second.test/attr/department/value/engineering | scs_mv_second | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "diana" and referenced as "diana_mv" + When I send a decision request for entity chain "diana_mv" for "read" action on resource "https://mv-second.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "PERMIT" decision response + + Scenario: No value in list matches — bob not in ["alice", "diana"] gets DENY + Given I submit a request to create a namespace with name "mv-none.test" and reference id "ns_mv_none" + And I send a request to create an attribute with: + | namespace_id | name | rule | values | + | ns_mv_none | department | anyOf | engineering,marketing,security | + Then the response should be successful + Given a condition group referenced as "cg_mv_none" with an "or" operator with conditions: + | selector_value | operator | values | + | .department | in | engineering | + And a subject set referenced as "ss_mv_none" containing the condition groups "cg_mv_none" + And I send a request to create a subject condition set referenced as "scs_mv_none" containing subject sets "ss_mv_none" + And I send a request to create a subject mapping with: + | reference_id | attribute_value | condition_set_name | standard actions | custom actions | + | sm_mv_none | https://mv-none.test/attr/department/value/engineering | scs_mv_none | read | | + Then the response should be successful + Given there is a "user_name" subject entity with value "bob" and referenced as "bob_mv" + When I send a decision request for entity chain "bob_mv" for "read" action on resource "https://mv-none.test/attr/department/value/engineering" + Then the response should be successful + And I should get a "DENY" decision response