diff --git a/cmd/policy-subject_mappings.go b/cmd/policy-subjectMappings.go similarity index 95% rename from cmd/policy-subject_mappings.go rename to cmd/policy-subjectMappings.go index ea6cdea4..8bf068bd 100644 --- a/cmd/policy-subject_mappings.go +++ b/cmd/policy-subjectMappings.go @@ -132,13 +132,16 @@ func policy_createSubjectMapping(cmd *cobra.Command, args []string) { } } } + if existingSCSId == "" && newScsJSON == "" { + cli.ExitWithError("At least one Subject Condition Set flag [--subject-condition-set-id, --subject-condition-set-new] must be provided", nil) + } actions := getFullActionsList(actionsStandard, actionsCustom) - var ss []*policy.SubjectSet var scs *subjectmapping.SubjectConditionSetCreate if newScsJSON != "" { - if err := json.Unmarshal([]byte(newScsJSON), &ss); err != nil { + ss, err := unmarshalSubjectSetsProto([]byte(newScsJSON)) + if err != nil { cli.ExitWithError("Error unmarshalling subject sets", err) } scs = &subjectmapping.SubjectConditionSetCreate{ @@ -185,6 +188,7 @@ func policy_deleteSubjectMapping(cmd *cobra.Command, args []string) { defer h.Close() id := c.Flags.GetRequiredID("id") + force := c.Flags.GetOptionalBool("force") sm, err := h.GetSubjectMapping(id) if err != nil { @@ -192,7 +196,9 @@ func policy_deleteSubjectMapping(cmd *cobra.Command, args []string) { cli.ExitWithError(errMsg, err) } - cli.ConfirmAction(cli.ActionDelete, "subject mapping", sm.GetId(), false) + if !force { + cli.ConfirmAction(cli.ActionDelete, "subject mapping", sm.GetId(), false) + } deleted, err := h.DeleteSubjectMapping(id) if err != nil { @@ -366,6 +372,11 @@ func init() { deleteDoc.GetDocFlag("id").Default, deleteDoc.GetDocFlag("id").Description, ) + deleteDoc.Flags().Bool( + deleteDoc.GetDocFlag("force").Name, + false, + deleteDoc.GetDocFlag("force").Description, + ) doc := man.Docs.GetCommand("policy/subject-mappings", man.WithSubcommands( diff --git a/docs/man/policy/subject-mappings/delete.md b/docs/man/policy/subject-mappings/delete.md index 21252bd9..a6d59a0f 100644 --- a/docs/man/policy/subject-mappings/delete.md +++ b/docs/man/policy/subject-mappings/delete.md @@ -8,6 +8,8 @@ command: shorthand: i required: true default: '' + - name: force + description: Force deletion without interactive confirmation (dangerous) --- # Delete a subject mapping @@ -16,4 +18,4 @@ Delete a Subject Mapping to remove entitlement of an entity (via Subject Conditi For more information about subject mappings, see the `subject-mappings` subcommand. -For more information about subject condition sets, see the `subject-condition-sets` subcommand. \ No newline at end of file +For more information about subject condition sets, see the `subject-condition-sets` subcommand. diff --git a/e2e/setup_suite.bash b/e2e/setup_suite.bash index 871d804d..2f1f1398 100755 --- a/e2e/setup_suite.bash +++ b/e2e/setup_suite.bash @@ -8,15 +8,15 @@ setup_suite(){ bats_require_minimum_version 1.7.0 - if [[ $(which bats) == *"homebrew"* ]]; then + if [[ "$(which bats)" == *"homebrew"* ]]; then BATS_LIB_PATH=$(brew --prefix)/lib fi # Check if BATS_LIB_PATH environment variable exists if [ -z "${BATS_LIB_PATH}" ]; then # Check if bats bin has homebrew in path name - if [[ $(which bats) == *"homebrew"* ]]; then - BATS_LIB_PATH=$(dirname $(which bats))/../lib + if [[ "$(which bats)" == *"homebrew"* ]]; then + BATS_LIB_PATH=$(dirname "$(which bats)")/../lib elif [ -d "/usr/lib/bats-support" ]; then BATS_LIB_PATH="/usr/lib" elif [ -d "/usr/local/lib/bats-support" ]; then diff --git a/e2e/subject-mapping.bats b/e2e/subject-mapping.bats index 6120da6d..134aa35c 100755 --- a/e2e/subject-mapping.bats +++ b/e2e/subject-mapping.bats @@ -2,14 +2,109 @@ # Tests for subject mappings -# Create sm +setup_file() { + echo -n '{"clientId":"opentdf","clientSecret":"secret"}' > creds.json + export WITH_CREDS='--with-client-creds-file ./creds.json' + export HOST='--host http://localhost:8080' -# Get sm + # Create two namespaced values to be used in other tests + NS_NAME="subject-mappings.net" + export NS_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes namespaces create -n "$NS_NAME" --json | jq -r '.id') + ATTR_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes create --namespace "$NS_ID" --name attr1 --rule ANY_OF --json | jq -r '.id') + export VAL1_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes values create --attribute-id "$ATTR_ID" --value val1 --json | jq -r '.id') + export VAL2_ID=$(./otdfctl $HOST $WITH_CREDS policy attributes values create --attribute-id "$ATTR_ID" --value value2 --json | jq -r '.id') -# Update sm + export SCS_1='[{"condition_groups":[{"conditions":[{"operator":1,"subject_external_values":["ShinyThing"],"subject_external_selector_value":".team.name"},{"operator":2,"subject_external_values":["marketing"],"subject_external_selector_value":".org.name"}],"boolean_operator":1}]}]' + export SCS_2='[{"condition_groups":[{"conditions":[{"operator":2,"subject_external_values":["CoolTool","RadService"],"subject_external_selector_value":".team.name"},{"operator":1,"subject_external_values":["sales"],"subject_external_selector_value":".org.name"}],"boolean_operator":2}]}]' +} -# List sm +setup() { + load "${BATS_LIB_PATH}/bats-support/load.bash" + load "${BATS_LIB_PATH}/bats-assert/load.bash" -# Delete sm + # invoke binary with credentials + run_otdfctl_sm () { + run sh -c "./otdfctl $HOST $WITH_CREDS policy subject-mappings $*" + } -# Cleanup - delete everything +} + +teardown_file() { + # remove the created namespace with all underneath upon test suite completion + ./otdfctl $HOST $WITH_CREDS policy attributes namespaces unsafe delete --force --id "$NS_ID" + + unset HOST WITH_CREDS VAL1_ID VAL2_ID NS_ID SCS_1 SCS_2 +} + +@test "Create subject mapping" { + # create with simultaneous new SCS + run ./otdfctl $HOST $WITH_CREDS policy subject-mappings create -a "$VAL1_ID" -s TRANSMIT --action-standard DECRYPT --subject-condition-set-new "$SCS_2" + assert_success + assert_output --partial "Subject Condition Set: Id" + assert_output --partial '"Standard":1' + assert_output --partial '"Standard":2' + assert_output --partial ".team.name" +assert_output --regexp "Attribute Value Id.*$VAL1_ID" + + # scs is required + run_otdfctl_sm create --attribute-value-id "$VAL2_ID" -s TRANSMIT + assert_failure + assert_output --partial "At least one Subject Condition Set flag [--subject-condition-set-id, --subject-condition-set-new] must be provided" + + # action is required + run_otdfctl_sm create -a "$VAL1_ID" --subject-condition-set-new "$SCS_2" + assert_failure + assert_output --partial "At least one Standard or Custom Action [--action-standard, --action-custom] is required" +} + +@test "Get subject mapping" { + new_scs=$(./otdfctl $HOST $WITH_CREDS policy scs create -s "$SCS_2" --json | jq -r '.id') + created=$(./otdfctl $HOST $WITH_CREDS policy sm create -a "$VAL2_ID" -s TRANSMIT --subject-condition-set-id "$new_scs" --json | jq -r '.id') + # table + run_otdfctl_sm get --id "$created" + assert_success + assert_output --regexp "Id.*$created" + assert_output --regexp "Attribute Value: Id.*$VAL2_ID" + assert_output --regexp "Attribute Value: Value.*value2" + assert_output --regexp "Subject Condition Set: Id.*$created" + + # json + run_otdfctl_sm get --id "$created" --json + assert_success + [ "$(echo $output | jq -r '.id')" = "$created" ] + [ "$(echo $output | jq -r '.attribute_value.id')" = "$VAL2_ID" ] + [ "$(echo $output | jq -r '.subject_condition_set.id')" = "$new_scs" ] +} + +@test "Update a subject mapping" { + created=$(./otdfctl $HOST $WITH_CREDS policy sm create -a "$VAL1_ID" -s DECRYPT --subject-condition-set-new "$SCS_1" --json | jq -r '.id') + additional_scs=$(./otdfctl $HOST $WITH_CREDS policy scs create -s "$SCS_2" --json | jq -r '.id') + + # replace the action (always destructive replacement) + run_otdfctl_sm update --id "$created" -s TRANSMIT --json + assert_success + [ "$(echo $output | jq -r '.id')" = "$created" ] + [ "$(echo $output | jq -r '.actions[0].Value.Standard')" = 2 ] + + # reassign the SCS being mapped to + run_otdfctl_sm update --id "$created" --subject-condition-set-id "$additional_scs" --json + assert_success + [ "$(echo $output | jq -r '.id')" = "$created" ] + [ "$(echo $output | jq -r '.subject_condition_set.id')" = "$additional_scs" ] +} + +@test "List subject mappings" { + created=$(./otdfctl $HOST $WITH_CREDS policy sm create -a "$VAL1_ID" -s TRANSMIT --subject-condition-set-new "$SCS_2" --json | jq -r '.id') + + run_otdfctl_sm list + assert_success + assert_output --partial "$created" +} + +@test "Delete subject mapping" { + first_listed=$(./otdfctl $HOST $WITH_CREDS policy sm list --json | jq -r '.[0].id') + # --force to avoid indefinite hang waiting for confirmation + run_otdfctl_sm delete --id "$first_listed" --force + assert_success + assert_output --regexp "Id.*$first_listed" +} \ No newline at end of file