diff --git a/.github/workflows/xtest.yml b/.github/workflows/xtest.yml index 54bd4710..25e050f2 100644 --- a/.github/workflows/xtest.yml +++ b/.github/workflows/xtest.yml @@ -30,7 +30,7 @@ jobs: packages: read env: PLATFORM_REF: "${{ inputs.platform-ref || 'main' }}" - JS_REF: "${{ inputs.js-ref || 'main' }}" + JS_REF: "${{ inputs.js-ref || '8b1de243c4330b62d2c82e41cf676fb2f2e01150' }}" OTDFCTL_REF: "${{ inputs.otdfctl-ref || 'main' }}" JAVA_REF: "${{ inputs.java-ref || 'main' }}" steps: @@ -138,17 +138,17 @@ jobs: run: |- pip install -r requirements.txt working-directory: otdftests/xtest - - name: Validate xtests - if: ${{ !inputs }} - run: |- - pytest test_nano.py test_self.py - working-directory: otdftests/xtest - - name: Run xtests - run: |- - pytest -v test_tdfs.py - working-directory: otdftests/xtest - env: - PLATFORM_DIR: '../../${{ steps.run-platform.outputs.platform-working-dir }}' + # - name: Validate xtests + # if: ${{ !inputs }} + # run: |- + # pytest test_nano.py test_self.py + # working-directory: otdftests/xtest + # - name: Run xtests + # run: |- + # pytest -v test_tdfs.py + # working-directory: otdftests/xtest + # env: + # PLATFORM_DIR: '../../${{ steps.run-platform.outputs.platform-working-dir }}' ######## ATTRIBUTE BASED CONFIGURATION ############# - name: Start additional kas @@ -177,7 +177,33 @@ jobs: - name: Run attribute based configuration tests run: |- - pytest test_abac.py + pytest -s test_abac.py::test_autoconfigure_two_kas_or_first_kas_not_running --sdks-encrypt "go" --sdks-decrypt "java" working-directory: otdftests/xtest env: PLATFORM_DIR: '../../${{ steps.run-platform.outputs.platform-working-dir }}' + + - name: unzip + if: always() + run: |- + mkdir -p ./unzippedtdf + unzip tmp/test-abac-two-first-kas-non-running-go-kao_not_running_first.tdf -d ./unzippedtdf + echo $(cat unzippedtdf/0.manifest.json) + working-directory: otdftests/xtest + env: + PLATFORM_DIR: '../../${{ steps.run-platform.outputs.platform-working-dir }}' + + - name: Upload manifest as artifact + uses: actions/upload-artifact@v3 + with: + name: manifest-output + path: otdftests/xtest/unzippedtdf/0.manifest.json + + + - name: Run decrypt + if: always() + run: |- + sdk/java/cli.sh decrypt tmp/test-abac-two-first-kas-non-running-go-kao_not_running_first.tdf tmp/test-abac-or-first-kas-non-running-go-java.untdf ztdf + working-directory: otdftests/xtest + env: + PLATFORM_DIR: '../../${{ steps.run-platform.outputs.platform-working-dir }}' + diff --git a/xtest/conftest.py b/xtest/conftest.py index 43375f95..a49abe0e 100644 --- a/xtest/conftest.py +++ b/xtest/conftest.py @@ -142,6 +142,11 @@ def kas_url_ns(): return os.getenv("KASURL4", "http://localhost:8484/kas") +@pytest.fixture(scope="session") +def kas_url_not_running(): + return os.getenv("KASURL5", "http://localhost:8989/kas") + + @pytest.fixture(scope="module") def attribute_single_kas_grant( otdfctl: abac.OpentdfCommandLineTool, @@ -236,6 +241,114 @@ def attribute_two_kas_grant_or( return anyof +@pytest.fixture(scope="module") +def attribute_two_kas_grant_or_non_running_second_kas( + otdfctl: abac.OpentdfCommandLineTool, + kas_url_value1: str, + kas_url_not_running: str, + temporary_namespace: abac.Namespace, +): + anyof = otdfctl.attribute_create( + temporary_namespace, + "notrunningbeta", + abac.AttributeRule.ANY_OF, + ["alpha", "beta"], + ) + assert anyof.values + alpha, beta = anyof.values + assert alpha.value == "alpha" + assert beta.value == "beta" + + # Then assign it to all clientIds = opentdf-sdk + sc = otdfctl.scs_create( + [ + abac.SubjectSet( + condition_groups=[ + abac.ConditionGroup( + boolean_operator=abac.ConditionBooleanTypeEnum.OR, + conditions=[ + abac.Condition( + subject_external_selector_value=".clientId", + operator=abac.SubjectMappingOperatorEnum.IN, + subject_external_values=["opentdf", "opentdf-sdk"], + ) + ], + ) + ] + ) + ], + ) + sm = otdfctl.scs_map(sc, alpha) + assert sm.attribute_value.value == "alpha" + # Now assign it to the current KAS + kas_entry_alpha = otdfctl.kas_registry_create_if_not_present( + kas_url_value1, + load_cached_kas_keys(), + ) + otdfctl.grant_assign_value(kas_entry_alpha, alpha) + + kas_entry_beta = otdfctl.kas_registry_create_if_not_present( + kas_url_not_running, + load_cached_kas_keys(), + ) + otdfctl.grant_assign_value(kas_entry_beta, beta) + return anyof + + +@pytest.fixture(scope="module") +def attribute_two_kas_grant_or_non_running_first_kas( + otdfctl: abac.OpentdfCommandLineTool, + kas_url_not_running: str, + kas_url_value2: str, + temporary_namespace: abac.Namespace, +): + anyof = otdfctl.attribute_create( + temporary_namespace, + "notrunningalpha", + abac.AttributeRule.ANY_OF, + ["alpha", "beta"], + ) + assert anyof.values + alpha, beta = anyof.values + assert alpha.value == "alpha" + assert beta.value == "beta" + + # Then assign it to all clientIds = opentdf-sdk + sc = otdfctl.scs_create( + [ + abac.SubjectSet( + condition_groups=[ + abac.ConditionGroup( + boolean_operator=abac.ConditionBooleanTypeEnum.OR, + conditions=[ + abac.Condition( + subject_external_selector_value=".clientId", + operator=abac.SubjectMappingOperatorEnum.IN, + subject_external_values=["opentdf", "opentdf-sdk"], + ) + ], + ) + ] + ) + ], + ) + sm = otdfctl.scs_map(sc, alpha) + assert sm.attribute_value.value == "alpha" + # Now assign it to the current KAS + kas_entry_alpha = otdfctl.kas_registry_create_if_not_present( + kas_url_not_running, + load_cached_kas_keys(), + ) + otdfctl.grant_assign_value(kas_entry_alpha, alpha) + + kas_entry_beta = otdfctl.kas_registry_create_if_not_present( + kas_url_value2, + load_cached_kas_keys(), + ) + otdfctl.grant_assign_value(kas_entry_beta, beta) + return anyof + + @pytest.fixture(scope="module") def attribute_two_kas_grant_and( otdfctl: abac.OpentdfCommandLineTool, diff --git a/xtest/sdk/java/cli.sh b/xtest/sdk/java/cli.sh index a7e1cce0..23028b81 100755 --- a/xtest/sdk/java/cli.sh +++ b/xtest/sdk/java/cli.sh @@ -59,4 +59,4 @@ if [ -n "$6" ]; then fi echo java -jar "$SCRIPT_DIR"/cmdline.jar "${args[@]}" -f "$2" ">" "$3" -java -jar "$SCRIPT_DIR"/cmdline.jar "${args[@]}" -f "$2" >"$3" +java -Dlog4j.debug -jar "$SCRIPT_DIR"/cmdline.jar "${args[@]}" -f "$2" >"$3" diff --git a/xtest/sdk/js/cli/cli.sh b/xtest/sdk/js/cli/cli.sh index 7dfac8c6..b784cade 100755 --- a/xtest/sdk/js/cli/cli.sh +++ b/xtest/sdk/js/cli/cli.sh @@ -42,7 +42,7 @@ args=( --kasEndpoint "$KASURL" --ignoreAllowList --oidcEndpoint "$KCFULLURL" - --auth opentdf:secret + --auth $CLIENTID:$CLIENTSECRET ) # default for js cli is nano if [ "$4" == "ztdf" ]; then diff --git a/xtest/test_abac.py b/xtest/test_abac.py index 5020f2f5..170be26b 100644 --- a/xtest/test_abac.py +++ b/xtest/test_abac.py @@ -87,6 +87,137 @@ def test_autoconfigure_two_kas_or( assert filecmp.cmp(pt_file, rt_file) +def move_item(lst, current_index, desired_index): + # Validate indices + if current_index < 0 or current_index >= len(lst): + raise IndexError("Current index is out of range.") + if desired_index < 0 or desired_index >= len(lst): + raise IndexError("Desired index is out of range.") + + # Remove the item from the current index + item = lst.pop(current_index) + + # Insert the item at the desired index + lst.insert(desired_index, item) + + return lst + + +def test_autoconfigure_two_kas_or_second_kas_not_running( + attribute_two_kas_grant_or_non_running_second_kas, + encrypt_sdk, + decrypt_sdk, + tmp_dir, + pt_file, + kas_url_value1: str, + kas_url_not_running: str, +): + skip_if_unsupported(encrypt_sdk, "autoconfigure") + + sample_name = f"test-abac-two-second-kas-non-running-{encrypt_sdk}" + if sample_name in cipherTexts: + ct_file = cipherTexts[sample_name] + else: + ct_file = f"{tmp_dir}/{sample_name}.tdf" + tdfs.encrypt( + encrypt_sdk, + pt_file, + ct_file, + mime_type="text/plain", + fmt="ztdf", + attr_values=[ + attribute_two_kas_grant_or_non_running_second_kas.values[0].fqn, + attribute_two_kas_grant_or_non_running_second_kas.values[1].fqn, + ], + ) + cipherTexts[sample_name] = ct_file + manifest = tdfs.manifest(ct_file) + + if manifest.encryptionInformation.keyAccess[1].url != kas_url_not_running: + + def move_last(manifest: tdfs.Manifest) -> tdfs.Manifest: + manifest.encryptionInformation.keyAccess = move_item( + manifest.encryptionInformation.keyAccess, 0, 1 + ) + return manifest + + ct_file = tdfs.update_manifest("kao_not_running_last", ct_file, move_last) + + manifest = tdfs.manifest(ct_file) + assert manifest.encryptionInformation.keyAccess[1].url == kas_url_not_running + + assert len(manifest.encryptionInformation.keyAccess) == 2 + assert ( + manifest.encryptionInformation.keyAccess[0].sid + == manifest.encryptionInformation.keyAccess[1].sid + ) + assert set([kas_url_value1, kas_url_not_running]) == set( + [kao.url for kao in manifest.encryptionInformation.keyAccess] + ) + + rt_file = f"{tmp_dir}test-abac-or-second-kas-non-running-{encrypt_sdk}-{decrypt_sdk}.untdf" + tdfs.decrypt(decrypt_sdk, ct_file, rt_file, "ztdf") + assert filecmp.cmp(pt_file, rt_file) + + +def test_autoconfigure_two_kas_or_first_kas_not_running( + attribute_two_kas_grant_or_non_running_first_kas, + encrypt_sdk, + decrypt_sdk, + tmp_dir, + pt_file, + kas_url_not_running: str, + kas_url_value2: str, +): + skip_if_unsupported(encrypt_sdk, "autoconfigure") + + sample_name = f"test-abac-two-first-kas-non-running-{encrypt_sdk}" + if sample_name in cipherTexts: + ct_file = cipherTexts[sample_name] + else: + ct_file = f"{tmp_dir}/{sample_name}.tdf" + tdfs.encrypt( + encrypt_sdk, + pt_file, + ct_file, + mime_type="text/plain", + fmt="ztdf", + attr_values=[ + attribute_two_kas_grant_or_non_running_first_kas.values[0].fqn, + attribute_two_kas_grant_or_non_running_first_kas.values[1].fqn, + ], + ) + cipherTexts[sample_name] = ct_file + manifest = tdfs.manifest(ct_file) + if manifest.encryptionInformation.keyAccess[0].url != kas_url_not_running: + + def move_first(manifest: tdfs.Manifest) -> tdfs.Manifest: + manifest.encryptionInformation.keyAccess = move_item( + manifest.encryptionInformation.keyAccess, 1, 0 + ) + return manifest + + ct_file = tdfs.update_manifest("kao_not_running_first", ct_file, move_first) + + manifest = tdfs.manifest(ct_file) + assert manifest.encryptionInformation.keyAccess[0].url == kas_url_not_running + + assert len(manifest.encryptionInformation.keyAccess) == 2 + assert ( + manifest.encryptionInformation.keyAccess[0].sid + == manifest.encryptionInformation.keyAccess[1].sid + ) + assert set([kas_url_not_running, kas_url_value2]) == set( + [kao.url for kao in manifest.encryptionInformation.keyAccess] + ) + + rt_file = ( + f"{tmp_dir}test-abac-or-first-kas-non-running-{encrypt_sdk}-{decrypt_sdk}.untdf" + ) + tdfs.decrypt(decrypt_sdk, ct_file, rt_file, "ztdf") + assert filecmp.cmp(pt_file, rt_file) + + def skip_if_unsupported(sdk: tdfs.sdk_type, *features: tdfs.feature_type): for feature in features: if not tdfs.supports(sdk, feature):