otdf-python 0.4.0__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.pre-commit-config.yaml +1 -1
- otdf_python-0.4.1/.release-please-manifest.json +3 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.vscode/extensions.json +1 -1
- {otdf_python-0.4.0 → otdf_python-0.4.1}/CHANGELOG.md +7 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/PKG-INFO +1 -1
- {otdf_python-0.4.0 → otdf_python-0.4.1}/conftest.py +4 -6
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/pyproject.toml +1 -1
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/scripts/generate_connect_proto.py +2 -4
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/uv.lock +1 -1
- {otdf_python-0.4.0 → otdf_python-0.4.1}/pyproject.toml +29 -23
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/__init__.py +1 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/__main__.py +1 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/address_normalizer.py +8 -10
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/aesgcm.py +8 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/assertion_config.py +21 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/asym_crypto.py +18 -22
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/auth_headers.py +7 -6
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/autoconfigure_utils.py +22 -6
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/cli.py +5 -5
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/collection_store.py +13 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/collection_store_impl.py +5 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/config.py +13 -0
- otdf_python-0.4.1/src/otdf_python/connect_client.py +1 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/constants.py +2 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/crypto_utils.py +4 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/dpop.py +3 -5
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/ecc_constants.py +12 -14
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/ecc_mode.py +7 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/ecdh.py +24 -25
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/eckeypair.py +5 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/header.py +5 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/invalid_zip_exception.py +6 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/kas_client.py +48 -55
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/kas_connect_rpc_client.py +16 -19
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/kas_info.py +4 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/kas_key_cache.py +10 -9
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/key_type.py +4 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/key_type_constants.py +4 -11
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/manifest.py +24 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/nanotdf.py +34 -24
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/nanotdf_ecdsa_struct.py +5 -9
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/nanotdf_type.py +12 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/policy_binding_serializer.py +6 -4
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/policy_info.py +6 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/policy_object.py +8 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/policy_stub.py +2 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/resource_locator.py +22 -13
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/sdk.py +49 -57
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/sdk_builder.py +58 -41
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/sdk_exceptions.py +11 -1
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/symmetric_and_payload_config.py +6 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/tdf.py +47 -10
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/tdf_reader.py +10 -13
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/tdf_writer.py +5 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/token_source.py +4 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/version.py +5 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/zip_reader.py +10 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/src/otdf_python/zip_writer.py +11 -0
- otdf_python-0.4.1/tests/__init__.py +1 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/config_pydantic.py +2 -5
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/conftest.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_only/test_otdfctl_generated_fixtures.py +0 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_to_python/test_cli_comparison.py +1 -5
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_to_python/test_cli_decrypt.py +4 -13
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_to_python/test_cli_inspect.py +3 -10
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_to_python/test_nanotdf_cli_comparison.py +3 -8
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_to_python/test_python_nanotdf_only.py +2 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/otdfctl_to_python/test_tdf_reader_integration.py +1 -6
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/python_only/test_kas_client_integration.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/support_sdk.py +1 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_cli_integration.py +4 -16
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_cli_tdf_validation.py +4 -11
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_pe_interaction.py +2 -4
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/server_logs.py +6 -8
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/support_cli_args.py +3 -9
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/support_common.py +1 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/support_otdfctl.py +3 -5
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/support_otdfctl_args.py +5 -9
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_address_normalizer.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_cli.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_ecdh.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_kas_client.py +17 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_kas_key_cache.py +6 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_kas_key_management.py +2 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_key_type.py +8 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_log_collection.py +1 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_manifest.py +2 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_manifest_format.py +1 -4
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_nanotdf.py +6 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_nanotdf_ecdh.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_nanotdf_ecdsa_struct.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_nanotdf_integration.py +3 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_nanotdf_type.py +9 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_policy_object.py +7 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_sdk.py +16 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_sdk_builder.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_sdk_exceptions.py +6 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_sdk_mock.py +13 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_sdk_tdf_integration.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_tdf.py +4 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_tdf_key_management.py +2 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_tdf_reader.py +1 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_tdf_writer.py +8 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_token_source.py +3 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_url_normalization.py +2 -2
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_use_plaintext_flow.py +1 -6
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_validate_otdf_python.py +6 -3
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_version.py +8 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_zip_reader.py +7 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_zip_writer.py +6 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/uv.lock +1 -1
- otdf_python-0.4.0/.release-please-manifest.json +0 -3
- otdf_python-0.4.0/src/otdf_python/connect_client.py +0 -0
- otdf_python-0.4.0/tests/__init__.py +0 -1
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.github/check_entitlements.sh +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.github/start_opentdf_docker.sh +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.github/workflows/build-python.yaml +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.github/workflows/platform-integration-test.yaml +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.github/workflows/release-please.yaml +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.github/workflows/test-suite.yaml +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.gitignore +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.release-please-config-develop.json +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.release-please-config.json +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.release-please-manifest-develop.json +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/.vscode/settings.json +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/LICENSE +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/README.md +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/docs/CONNECT_RPC.md +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/docs/DEVELOPING.md +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/docs/LEGACY_VERSION.md +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/docs/RELEASES.md +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/README.md +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/buf.gen.yaml +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/buf.lock +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/buf.yaml +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/authorization/authorization.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/authorization/v2/authorization.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/common/common.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/entity/entity.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/entityresolution/entity_resolution.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/entityresolution/v2/entity_resolution.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/kas/kas.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/logger/audit/test.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/actions/actions.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/attributes/attributes.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/kasregistry/key_access_server_registry.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/keymanagement/key_management.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/namespaces/namespaces.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/objects.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/registeredresources/registered_resources.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/resourcemapping/resource_mapping.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/selectors.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/subjectmapping/subject_mapping.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/policy/unsafe/unsafe.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/proto-files/wellknownconfiguration/wellknown_configuration.proto +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/scripts/build_connect_proto.sh +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/scripts/setup_connect_rpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/common/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/common/common_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/common/common_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entity/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entity/entity_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entity/entity_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/kas/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/authorization/authorization_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/authorization/v2/authorization_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/common/common_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entity/entity_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entityresolution/entity_resolution_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entityresolution/v2/entity_resolution_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/kas/kas_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/logger/audit/test_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/actions/actions_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/attributes/attributes_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/kasregistry/key_access_server_registry_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/keymanagement/key_management_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/namespaces/namespaces_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/objects_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/registeredresources/registered_resources_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/resourcemapping/resource_mapping_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/selectors_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/subjectmapping/subject_mapping_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/unsafe/unsafe_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/wellknownconfiguration/wellknown_configuration_pb2_grpc.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/logger/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/logger/audit/test_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/logger/audit/test_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/objects_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/objects_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/selectors_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/selectors_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/__init__.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.pyi +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2_connect.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_data/empty_file.txt +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_data/sample_binary.png +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_data/sample_text.txt +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/integration/test_data/sample_with_attributes.txt +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/mock_crypto.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_aesgcm.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_assertion_config.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_asym_encryption.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_autoconfigure_utils.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_collection_store.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_config.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_crypto_utils.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_eckeypair.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_header.py +0 -0
- {otdf_python-0.4.0 → otdf_python-0.4.1}/tests/test_inner_classes.py +0 -0
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.1](https://github.com/b-long/opentdf-python-sdk/compare/otdf-python-v0.4.0...otdf-python-v0.4.1) (2025-12-09)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* preserve exception chain ([#119](https://github.com/b-long/opentdf-python-sdk/issues/119)) ([09984b8](https://github.com/b-long/opentdf-python-sdk/commit/09984b843b369a6d2c76dc8a81d6315f195ea773))
|
|
9
|
+
|
|
3
10
|
## [0.4.0](https://github.com/b-long/opentdf-python-sdk/compare/otdf-python-v0.3.5...otdf-python-v0.4.0) (2025-11-20)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Pytest configuration and fixtures for the OpenTDF Python SDK tests.
|
|
1
|
+
"""Pytest configuration and fixtures for the OpenTDF Python SDK tests.
|
|
3
2
|
|
|
4
3
|
This module contains pytest hooks and fixtures that will be automatically
|
|
5
4
|
loaded by pytest when running tests.
|
|
@@ -14,13 +13,13 @@ from tests.server_logs import log_server_logs_on_failure
|
|
|
14
13
|
|
|
15
14
|
@pytest.fixture(scope="session")
|
|
16
15
|
def project_root(request) -> Path:
|
|
16
|
+
"""Get project root directory."""
|
|
17
17
|
return request.config.rootpath # Project root
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
|
|
21
21
|
def pytest_runtest_makereport(item, call):
|
|
22
|
-
"""
|
|
23
|
-
Hook that runs after each test phase (setup, call, teardown).
|
|
22
|
+
"""Collect server logs when test fails after each test phase.
|
|
24
23
|
|
|
25
24
|
This hook automatically collects server logs when a test fails.
|
|
26
25
|
"""
|
|
@@ -53,8 +52,7 @@ def pytest_runtest_makereport(item, call):
|
|
|
53
52
|
|
|
54
53
|
@pytest.fixture
|
|
55
54
|
def collect_server_logs():
|
|
56
|
-
"""
|
|
57
|
-
Fixture that provides a function to manually collect server logs.
|
|
55
|
+
"""Fixture that provides a function to manually collect server logs.
|
|
58
56
|
|
|
59
57
|
Usage:
|
|
60
58
|
def test_something(collect_server_logs):
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Enhanced script to generate Python Connect RPC clients from .proto definitions.
|
|
2
|
+
"""Enhanced script to generate Python Connect RPC clients from .proto definitions.
|
|
4
3
|
|
|
5
4
|
This script:
|
|
6
5
|
1. Downloads the latest proto files from OpenTDF platform
|
|
@@ -200,8 +199,7 @@ def create_init_files(generated_dir: Path) -> None:
|
|
|
200
199
|
|
|
201
200
|
|
|
202
201
|
def _fix_ignore_if_default_value(proto_files_dir):
|
|
203
|
-
"""
|
|
204
|
-
TODO: Fix buf validation: Updated the proto files to use the correct enum value:
|
|
202
|
+
"""TODO: Fix buf validation: Updated the proto files to use the correct enum value:
|
|
205
203
|
|
|
206
204
|
Changed IGNORE_IF_DEFAULT_VALUE → IGNORE_IF_ZERO_VALUE in:
|
|
207
205
|
attributes.proto
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "otdf-python"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
description = "Unofficial OpenTDF SDK for Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -72,6 +72,7 @@ norecursedirs = ["otdf-python-proto"]
|
|
|
72
72
|
|
|
73
73
|
[tool.ruff]
|
|
74
74
|
line-length = 88
|
|
75
|
+
target-version = "py310"
|
|
75
76
|
|
|
76
77
|
# See https://docs.astral.sh/ruff/rules/
|
|
77
78
|
# for rule information.
|
|
@@ -80,28 +81,33 @@ lint.ignore = [
|
|
|
80
81
|
"E501",
|
|
81
82
|
]
|
|
82
83
|
lint.select = [
|
|
83
|
-
#
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
#
|
|
87
|
-
"
|
|
88
|
-
#
|
|
89
|
-
"
|
|
90
|
-
#
|
|
91
|
-
"
|
|
92
|
-
#
|
|
93
|
-
"
|
|
94
|
-
#
|
|
95
|
-
"
|
|
96
|
-
#
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
#
|
|
100
|
-
"UP", # pyupgrade (modern Python features)
|
|
101
|
-
"SIM", # flake8-simplify (simplifications)
|
|
102
|
-
"RUF", # Ruff-specific rules
|
|
103
|
-
"FURB", # refurb (FURB)
|
|
104
|
-
"PT018", # flake8-pytest-style (pytest style)
|
|
84
|
+
"B", # flake8-bugbear
|
|
85
|
+
"C4", # flake8-comprehensions
|
|
86
|
+
"C90", # McCabe complexity
|
|
87
|
+
"D", # pydocstyle
|
|
88
|
+
"DOC", # pydoclint
|
|
89
|
+
"E", # pycodestyle errors
|
|
90
|
+
"F", # pyflakes
|
|
91
|
+
"FURB", # refurb
|
|
92
|
+
"I", # isort
|
|
93
|
+
"PERF", # performance
|
|
94
|
+
"PT018", # pytest style
|
|
95
|
+
"PTH", # pathlib
|
|
96
|
+
"Q", # flake8-quotes
|
|
97
|
+
"RUF", # ruff-specific
|
|
98
|
+
"SIM", # flake8-simplify
|
|
99
|
+
"UP", # pyupgrade
|
|
100
|
+
"W", # pycodestyle warnings
|
|
105
101
|
]
|
|
106
102
|
# Ignore generated files
|
|
107
103
|
extend-exclude = ["otdf-python-proto/src/"]
|
|
104
|
+
|
|
105
|
+
[tool.ruff.lint.per-file-ignores]
|
|
106
|
+
"tests/**" = ["D100", "D101", "D102", "D103", "D107", "D400", "D401", "D415"]
|
|
107
|
+
"otdf-python-proto/**" = ["D"] # Ignore all D (docstring) rules for generated proto files
|
|
108
|
+
|
|
109
|
+
# TODO: Remaining work - 4 buckets to fix (140 errors remaining):
|
|
110
|
+
# Bucket #1: D102 (missing method docstrings) - 98 errors
|
|
111
|
+
# Bucket #2: D105 (missing magic method docstrings) - 23 errors
|
|
112
|
+
# Bucket #3: D205 (blank line formatting), D103, D417, D104 - 19 errors
|
|
113
|
+
"src/**" = ["D102", "D105", "D205"]
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Main entry point for running otdf_python as a module.
|
|
2
|
+
"""Main entry point for running otdf_python as a module.
|
|
4
3
|
|
|
5
4
|
This allows the package to be run with `python -m otdf_python` and properly
|
|
6
5
|
handles the CLI interface without import conflicts.
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Address normalization utilities for OpenTDF.
|
|
3
|
-
"""
|
|
1
|
+
"""Address normalization utilities for OpenTDF."""
|
|
4
2
|
|
|
5
3
|
import logging
|
|
6
4
|
import re
|
|
@@ -12,8 +10,7 @@ logger = logging.getLogger(__name__)
|
|
|
12
10
|
|
|
13
11
|
|
|
14
12
|
def normalize_address(url_string: str, use_plaintext: bool) -> str:
|
|
15
|
-
"""
|
|
16
|
-
Normalize a URL address to ensure it has the correct scheme and port.
|
|
13
|
+
"""Normalize a URL address to ensure it has the correct scheme and port.
|
|
17
14
|
|
|
18
15
|
Args:
|
|
19
16
|
url_string: The URL string to normalize
|
|
@@ -24,6 +21,7 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
|
|
|
24
21
|
|
|
25
22
|
Raises:
|
|
26
23
|
SDKException: If there's an error parsing or creating the URL
|
|
24
|
+
|
|
27
25
|
"""
|
|
28
26
|
scheme = "http" if use_plaintext else "https"
|
|
29
27
|
|
|
@@ -34,8 +32,8 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
|
|
|
34
32
|
port_str = host_port_pattern.group(2)
|
|
35
33
|
try:
|
|
36
34
|
port = int(port_str)
|
|
37
|
-
except ValueError:
|
|
38
|
-
raise SDKException(f"Invalid port in URL [{url_string}]")
|
|
35
|
+
except ValueError as err:
|
|
36
|
+
raise SDKException(f"Invalid port in URL [{url_string}]") from err
|
|
39
37
|
|
|
40
38
|
normalized_url = f"{scheme}://{host}:{port}"
|
|
41
39
|
logger.debug(f"normalized url [{url_string}] to [{normalized_url}]")
|
|
@@ -66,8 +64,8 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
|
|
|
66
64
|
_, port_str = parsed_url.netloc.split(":", 1)
|
|
67
65
|
try:
|
|
68
66
|
port = int(port_str)
|
|
69
|
-
except ValueError:
|
|
70
|
-
raise SDKException(f"Invalid port in URL [{url_string}]")
|
|
67
|
+
except ValueError as err:
|
|
68
|
+
raise SDKException(f"Invalid port in URL [{url_string}]") from err
|
|
71
69
|
|
|
72
70
|
# If no port was found or extracted, use the default
|
|
73
71
|
if port is None:
|
|
@@ -81,4 +79,4 @@ def normalize_address(url_string: str, use_plaintext: bool) -> str:
|
|
|
81
79
|
except Exception as e:
|
|
82
80
|
if isinstance(e, SDKException):
|
|
83
81
|
raise e
|
|
84
|
-
raise SDKException(f"Error normalizing URL [{url_string}]"
|
|
82
|
+
raise SDKException(f"Error normalizing URL [{url_string}]: {e}") from e
|
|
@@ -1,13 +1,18 @@
|
|
|
1
|
+
"""AES-GCM encryption and decryption functionality."""
|
|
2
|
+
|
|
1
3
|
import os
|
|
2
4
|
|
|
3
5
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class AesGcm:
|
|
9
|
+
"""AES-GCM encryption and decryption operations."""
|
|
10
|
+
|
|
7
11
|
GCM_NONCE_LENGTH = 12
|
|
8
12
|
GCM_TAG_LENGTH = 16
|
|
9
13
|
|
|
10
14
|
def __init__(self, key: bytes):
|
|
15
|
+
"""Initialize AES-GCM cipher with key."""
|
|
11
16
|
if not key or len(key) not in (16, 24, 32):
|
|
12
17
|
raise ValueError("Invalid key size for GCM encryption")
|
|
13
18
|
self.key = key
|
|
@@ -17,7 +22,10 @@ class AesGcm:
|
|
|
17
22
|
return self.key
|
|
18
23
|
|
|
19
24
|
class Encrypted:
|
|
25
|
+
"""Encrypted data with initialization vector and ciphertext."""
|
|
26
|
+
|
|
20
27
|
def __init__(self, iv: bytes, ciphertext: bytes):
|
|
28
|
+
"""Initialize encrypted data."""
|
|
21
29
|
self.iv = iv
|
|
22
30
|
self.ciphertext = ciphertext
|
|
23
31
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
"""Assertion configuration for TDF."""
|
|
2
|
+
|
|
1
3
|
from enum import Enum, auto
|
|
2
4
|
from typing import Any
|
|
3
5
|
|
|
4
6
|
|
|
5
7
|
class Type(Enum):
|
|
8
|
+
"""Assertion type enumeration."""
|
|
9
|
+
|
|
6
10
|
HANDLING_ASSERTION = "handling"
|
|
7
11
|
BASE_ASSERTION = "base"
|
|
8
12
|
|
|
@@ -11,6 +15,8 @@ class Type(Enum):
|
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
class Scope(Enum):
|
|
18
|
+
"""Assertion scope enumeration."""
|
|
19
|
+
|
|
14
20
|
TRUSTED_DATA_OBJ = "tdo"
|
|
15
21
|
PAYLOAD = "payload"
|
|
16
22
|
|
|
@@ -19,12 +25,16 @@ class Scope(Enum):
|
|
|
19
25
|
|
|
20
26
|
|
|
21
27
|
class AssertionKeyAlg(Enum):
|
|
28
|
+
"""Assertion key algorithm enumeration."""
|
|
29
|
+
|
|
22
30
|
RS256 = auto()
|
|
23
31
|
HS256 = auto()
|
|
24
32
|
NOT_DEFINED = auto()
|
|
25
33
|
|
|
26
34
|
|
|
27
35
|
class AppliesToState(Enum):
|
|
36
|
+
"""Assertion applies-to state enumeration."""
|
|
37
|
+
|
|
28
38
|
ENCRYPTED = "encrypted"
|
|
29
39
|
UNENCRYPTED = "unencrypted"
|
|
30
40
|
|
|
@@ -33,6 +43,8 @@ class AppliesToState(Enum):
|
|
|
33
43
|
|
|
34
44
|
|
|
35
45
|
class BindingMethod(Enum):
|
|
46
|
+
"""Assertion binding method enumeration."""
|
|
47
|
+
|
|
36
48
|
JWS = "jws"
|
|
37
49
|
|
|
38
50
|
def __str__(self):
|
|
@@ -40,7 +52,10 @@ class BindingMethod(Enum):
|
|
|
40
52
|
|
|
41
53
|
|
|
42
54
|
class AssertionKey:
|
|
55
|
+
"""Assertion signing key configuration."""
|
|
56
|
+
|
|
43
57
|
def __init__(self, alg: AssertionKeyAlg, key: Any):
|
|
58
|
+
"""Initialize assertion key."""
|
|
44
59
|
self.alg = alg
|
|
45
60
|
self.key = key
|
|
46
61
|
|
|
@@ -49,7 +64,10 @@ class AssertionKey:
|
|
|
49
64
|
|
|
50
65
|
|
|
51
66
|
class Statement:
|
|
67
|
+
"""Assertion statement with format, schema, and value."""
|
|
68
|
+
|
|
52
69
|
def __init__(self, format: str, schema: str, value: str):
|
|
70
|
+
"""Initialize assertion statement."""
|
|
53
71
|
self.format = format
|
|
54
72
|
self.schema = schema
|
|
55
73
|
self.value = value
|
|
@@ -67,6 +85,8 @@ class Statement:
|
|
|
67
85
|
|
|
68
86
|
|
|
69
87
|
class AssertionConfig:
|
|
88
|
+
"""TDF assertion configuration."""
|
|
89
|
+
|
|
70
90
|
def __init__(
|
|
71
91
|
self,
|
|
72
92
|
id: str,
|
|
@@ -76,6 +96,7 @@ class AssertionConfig:
|
|
|
76
96
|
statement: Statement,
|
|
77
97
|
signing_key: AssertionKey | None = None,
|
|
78
98
|
):
|
|
99
|
+
"""Initialize assertion configuration."""
|
|
79
100
|
self.id = id
|
|
80
101
|
self.type = type
|
|
81
102
|
self.scope = scope
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Asymmetric encryption and decryption utilities for RSA keys in PEM format.
|
|
3
|
-
"""
|
|
1
|
+
"""Asymmetric encryption and decryption utilities for RSA keys in PEM format."""
|
|
4
2
|
|
|
5
3
|
import base64
|
|
6
4
|
import re
|
|
@@ -14,8 +12,7 @@ from .sdk_exceptions import SDKException
|
|
|
14
12
|
|
|
15
13
|
|
|
16
14
|
class AsymDecryption:
|
|
17
|
-
"""
|
|
18
|
-
Provides functionality for asymmetric decryption using an RSA private key.
|
|
15
|
+
"""Provides functionality for asymmetric decryption using an RSA private key.
|
|
19
16
|
|
|
20
17
|
Supports both PEM string and key object initialization for flexibility.
|
|
21
18
|
"""
|
|
@@ -25,8 +22,7 @@ class AsymDecryption:
|
|
|
25
22
|
PRIVATE_KEY_FOOTER = "-----END PRIVATE KEY-----"
|
|
26
23
|
|
|
27
24
|
def __init__(self, private_key_pem: str | None = None, private_key_obj=None):
|
|
28
|
-
"""
|
|
29
|
-
Initialize with either a PEM string or a key object.
|
|
25
|
+
"""Initialize with either a PEM string or a key object.
|
|
30
26
|
|
|
31
27
|
Args:
|
|
32
28
|
private_key_pem: Private key in PEM format (with or without headers)
|
|
@@ -34,6 +30,7 @@ class AsymDecryption:
|
|
|
34
30
|
|
|
35
31
|
Raises:
|
|
36
32
|
SDKException: If key loading fails
|
|
33
|
+
|
|
37
34
|
"""
|
|
38
35
|
if private_key_obj is not None:
|
|
39
36
|
self.private_key = private_key_obj
|
|
@@ -60,13 +57,12 @@ class AsymDecryption:
|
|
|
60
57
|
decoded, password=None, backend=default_backend()
|
|
61
58
|
)
|
|
62
59
|
except Exception as e:
|
|
63
|
-
raise SDKException(f"Failed to load private key: {e}")
|
|
60
|
+
raise SDKException(f"Failed to load private key: {e}") from e
|
|
64
61
|
else:
|
|
65
62
|
self.private_key = None
|
|
66
63
|
|
|
67
64
|
def decrypt(self, data: bytes) -> bytes:
|
|
68
|
-
"""
|
|
69
|
-
Decrypt data using RSA OAEP with SHA-1.
|
|
65
|
+
"""Decrypt data using RSA OAEP with SHA-1.
|
|
70
66
|
|
|
71
67
|
Args:
|
|
72
68
|
data: Encrypted bytes to decrypt
|
|
@@ -76,6 +72,7 @@ class AsymDecryption:
|
|
|
76
72
|
|
|
77
73
|
Raises:
|
|
78
74
|
SDKException: If decryption fails or key is not set
|
|
75
|
+
|
|
79
76
|
"""
|
|
80
77
|
if self.private_key is None:
|
|
81
78
|
raise SDKException("Failed to decrypt, private key is empty")
|
|
@@ -89,12 +86,11 @@ class AsymDecryption:
|
|
|
89
86
|
),
|
|
90
87
|
)
|
|
91
88
|
except Exception as e:
|
|
92
|
-
raise SDKException(f"Error performing decryption: {e}")
|
|
89
|
+
raise SDKException(f"Error performing decryption: {e}") from e
|
|
93
90
|
|
|
94
91
|
|
|
95
92
|
class AsymEncryption:
|
|
96
|
-
"""
|
|
97
|
-
Provides functionality for asymmetric encryption using an RSA public key or certificate in PEM format.
|
|
93
|
+
"""Provides functionality for asymmetric encryption using an RSA public key or certificate in PEM format.
|
|
98
94
|
|
|
99
95
|
Supports PEM public keys, X.509 certificates, and pre-loaded key objects.
|
|
100
96
|
Also handles base64-encoded keys without PEM headers.
|
|
@@ -105,8 +101,7 @@ class AsymEncryption:
|
|
|
105
101
|
CIPHER_TRANSFORM = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding"
|
|
106
102
|
|
|
107
103
|
def __init__(self, public_key_pem: str | None = None, public_key_obj=None):
|
|
108
|
-
"""
|
|
109
|
-
Initialize with either a PEM string or a key object.
|
|
104
|
+
"""Initialize with either a PEM string or a key object.
|
|
110
105
|
|
|
111
106
|
Args:
|
|
112
107
|
public_key_pem: Public key in PEM format, X.509 certificate, or base64 string
|
|
@@ -114,6 +109,7 @@ class AsymEncryption:
|
|
|
114
109
|
|
|
115
110
|
Raises:
|
|
116
111
|
SDKException: If key loading fails or key is not RSA
|
|
112
|
+
|
|
117
113
|
"""
|
|
118
114
|
if public_key_obj is not None:
|
|
119
115
|
self.public_key = public_key_obj
|
|
@@ -141,7 +137,7 @@ class AsymEncryption:
|
|
|
141
137
|
decoded, backend=default_backend()
|
|
142
138
|
)
|
|
143
139
|
except Exception as e:
|
|
144
|
-
raise SDKException(f"Failed to load public key: {e}")
|
|
140
|
+
raise SDKException(f"Failed to load public key: {e}") from e
|
|
145
141
|
else:
|
|
146
142
|
self.public_key = None
|
|
147
143
|
|
|
@@ -152,8 +148,7 @@ class AsymEncryption:
|
|
|
152
148
|
raise SDKException("Not an RSA PEM formatted public key")
|
|
153
149
|
|
|
154
150
|
def encrypt(self, data: bytes) -> bytes:
|
|
155
|
-
"""
|
|
156
|
-
Encrypt data using RSA OAEP with SHA-1.
|
|
151
|
+
"""Encrypt data using RSA OAEP with SHA-1.
|
|
157
152
|
|
|
158
153
|
Args:
|
|
159
154
|
data: Plaintext bytes to encrypt
|
|
@@ -163,6 +158,7 @@ class AsymEncryption:
|
|
|
163
158
|
|
|
164
159
|
Raises:
|
|
165
160
|
SDKException: If encryption fails or key is not set
|
|
161
|
+
|
|
166
162
|
"""
|
|
167
163
|
if self.public_key is None:
|
|
168
164
|
raise SDKException("Failed to encrypt, public key is empty")
|
|
@@ -176,17 +172,17 @@ class AsymEncryption:
|
|
|
176
172
|
),
|
|
177
173
|
)
|
|
178
174
|
except Exception as e:
|
|
179
|
-
raise SDKException(f"Error performing encryption: {e}")
|
|
175
|
+
raise SDKException(f"Error performing encryption: {e}") from e
|
|
180
176
|
|
|
181
177
|
def public_key_in_pem_format(self) -> str:
|
|
182
|
-
"""
|
|
183
|
-
Export the public key to PEM format.
|
|
178
|
+
"""Export the public key to PEM format.
|
|
184
179
|
|
|
185
180
|
Returns:
|
|
186
181
|
Public key as PEM-encoded string
|
|
187
182
|
|
|
188
183
|
Raises:
|
|
189
184
|
SDKException: If export fails
|
|
185
|
+
|
|
190
186
|
"""
|
|
191
187
|
try:
|
|
192
188
|
pem = self.public_key.public_bytes(
|
|
@@ -195,4 +191,4 @@ class AsymEncryption:
|
|
|
195
191
|
)
|
|
196
192
|
return pem.decode()
|
|
197
193
|
except Exception as e:
|
|
198
|
-
raise SDKException(f"Error exporting public key to PEM: {e}")
|
|
194
|
+
raise SDKException(f"Error exporting public key to PEM: {e}") from e
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
"""Authentication header management."""
|
|
2
|
+
|
|
1
3
|
from dataclasses import dataclass
|
|
2
4
|
|
|
3
5
|
|
|
4
6
|
@dataclass
|
|
5
7
|
class AuthHeaders:
|
|
6
|
-
"""
|
|
7
|
-
Represents authentication headers used in token-based authorization.
|
|
8
|
+
"""Represents authentication headers used in token-based authorization.
|
|
8
9
|
This class holds authorization and DPoP (Demonstrating Proof of Possession) headers
|
|
9
10
|
that are used in token-based API requests.
|
|
10
11
|
"""
|
|
@@ -13,19 +14,19 @@ class AuthHeaders:
|
|
|
13
14
|
dpop_header: str = ""
|
|
14
15
|
|
|
15
16
|
def get_auth_header(self) -> str:
|
|
16
|
-
"""
|
|
17
|
+
"""Get the authorization header."""
|
|
17
18
|
return self.auth_header
|
|
18
19
|
|
|
19
20
|
def get_dpop_header(self) -> str:
|
|
20
|
-
"""
|
|
21
|
+
"""Get the DPoP header."""
|
|
21
22
|
return self.dpop_header
|
|
22
23
|
|
|
23
24
|
def to_dict(self) -> dict[str, str]:
|
|
24
|
-
"""
|
|
25
|
-
Convert authentication headers to a dictionary for use with HTTP clients.
|
|
25
|
+
"""Convert authentication headers to a dictionary for use with HTTP clients.
|
|
26
26
|
|
|
27
27
|
Returns:
|
|
28
28
|
Dictionary with 'Authorization' header and optionally 'DPoP' header
|
|
29
|
+
|
|
29
30
|
"""
|
|
30
31
|
headers = {"Authorization": self.auth_header}
|
|
31
32
|
if self.dpop_header:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"""Utilities for automatic SDK configuration."""
|
|
2
|
+
|
|
1
3
|
import re
|
|
2
4
|
import urllib.parse
|
|
3
5
|
from dataclasses import dataclass
|
|
@@ -6,6 +8,8 @@ from typing import Any
|
|
|
6
8
|
|
|
7
9
|
# RuleType constants
|
|
8
10
|
class RuleType:
|
|
11
|
+
"""Rule type constants for attribute hierarchy."""
|
|
12
|
+
|
|
9
13
|
HIERARCHY = "hierarchy"
|
|
10
14
|
ALL_OF = "allOf"
|
|
11
15
|
ANY_OF = "anyOf"
|
|
@@ -15,6 +19,8 @@ class RuleType:
|
|
|
15
19
|
|
|
16
20
|
@dataclass(frozen=True)
|
|
17
21
|
class KeySplitStep:
|
|
22
|
+
"""Key split step information."""
|
|
23
|
+
|
|
18
24
|
kas: str
|
|
19
25
|
splitID: str
|
|
20
26
|
|
|
@@ -31,21 +37,26 @@ class KeySplitStep:
|
|
|
31
37
|
|
|
32
38
|
|
|
33
39
|
class AutoConfigureException(Exception):
|
|
40
|
+
"""Exception for auto-configuration errors."""
|
|
41
|
+
|
|
34
42
|
pass
|
|
35
43
|
|
|
36
44
|
|
|
37
45
|
class AttributeNameFQN:
|
|
46
|
+
"""Fully qualified attribute name."""
|
|
47
|
+
|
|
38
48
|
def __init__(self, url: str):
|
|
49
|
+
"""Initialize attribute name from URL."""
|
|
39
50
|
pattern = re.compile(r"^(https?://[\w./-]+)/attr/([^/\s]*)$")
|
|
40
51
|
matcher = pattern.match(url)
|
|
41
52
|
if not matcher or not matcher.group(1) or not matcher.group(2):
|
|
42
53
|
raise AutoConfigureException("invalid type: attribute regex fail")
|
|
43
54
|
try:
|
|
44
55
|
urllib.parse.unquote(matcher.group(2))
|
|
45
|
-
except Exception:
|
|
56
|
+
except Exception as err:
|
|
46
57
|
raise AutoConfigureException(
|
|
47
58
|
f"invalid type: error in attribute name [{matcher.group(2)}]"
|
|
48
|
-
)
|
|
59
|
+
) from err
|
|
49
60
|
self.url = url
|
|
50
61
|
self.key = url.lower()
|
|
51
62
|
|
|
@@ -76,12 +87,15 @@ class AttributeNameFQN:
|
|
|
76
87
|
raise AutoConfigureException("invalid attribute")
|
|
77
88
|
try:
|
|
78
89
|
return urllib.parse.unquote(matcher.group(1))
|
|
79
|
-
except Exception:
|
|
80
|
-
raise AutoConfigureException("invalid type")
|
|
90
|
+
except Exception as err:
|
|
91
|
+
raise AutoConfigureException("invalid type") from err
|
|
81
92
|
|
|
82
93
|
|
|
83
94
|
class AttributeValueFQN:
|
|
95
|
+
"""Fully qualified attribute value."""
|
|
96
|
+
|
|
84
97
|
def __init__(self, url: str):
|
|
98
|
+
"""Initialize attribute value from URL."""
|
|
85
99
|
pattern = re.compile(r"^(https?://[\w./-]+)/attr/(\S*)/value/(\S*)$")
|
|
86
100
|
matcher = pattern.match(url)
|
|
87
101
|
if (
|
|
@@ -96,8 +110,10 @@ class AttributeValueFQN:
|
|
|
96
110
|
try:
|
|
97
111
|
urllib.parse.unquote(matcher.group(2))
|
|
98
112
|
urllib.parse.unquote(matcher.group(3))
|
|
99
|
-
except Exception:
|
|
100
|
-
raise AutoConfigureException(
|
|
113
|
+
except Exception as err:
|
|
114
|
+
raise AutoConfigureException(
|
|
115
|
+
"invalid type: error in attribute or value"
|
|
116
|
+
) from err
|
|
101
117
|
self.url = url
|
|
102
118
|
self.key = url.lower()
|
|
103
119
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
OpenTDF Python CLI
|
|
2
|
+
"""OpenTDF Python CLI.
|
|
4
3
|
|
|
5
4
|
A command-line interface for encrypting and decrypting files using OpenTDF.
|
|
6
5
|
Provides encrypt, decrypt, and inspect commands similar to the otdfctl CLI.
|
|
@@ -36,6 +35,7 @@ class CLIError(Exception):
|
|
|
36
35
|
"""Custom exception for CLI errors."""
|
|
37
36
|
|
|
38
37
|
def __init__(self, level: str, message: str, cause: Exception | None = None):
|
|
38
|
+
"""Initialize CLI error."""
|
|
39
39
|
self.level = level
|
|
40
40
|
self.message = message
|
|
41
41
|
self.cause = cause
|
|
@@ -105,11 +105,11 @@ def load_client_credentials(creds_file_path: str) -> tuple[str, str]:
|
|
|
105
105
|
except json.JSONDecodeError as e:
|
|
106
106
|
raise CLIError(
|
|
107
107
|
"CRITICAL", f"Invalid JSON in credentials file {creds_file_path}: {e}"
|
|
108
|
-
)
|
|
108
|
+
) from e
|
|
109
109
|
except Exception as e:
|
|
110
110
|
raise CLIError(
|
|
111
111
|
"CRITICAL", f"Error reading credentials file {creds_file_path}: {e}"
|
|
112
|
-
)
|
|
112
|
+
) from e
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def build_sdk(args) -> SDK:
|
|
@@ -525,7 +525,7 @@ Where creds.json contains:
|
|
|
525
525
|
|
|
526
526
|
|
|
527
527
|
def main():
|
|
528
|
-
"""
|
|
528
|
+
"""Execute the CLI entry point."""
|
|
529
529
|
parser = create_parser()
|
|
530
530
|
args = parser.parse_args()
|
|
531
531
|
|