otdf-python 0.3.3__tar.gz → 0.3.4__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.3.3 → otdf_python-0.3.4}/.github/check_entitlements.sh +0 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.pre-commit-config.yaml +1 -1
- otdf_python-0.3.4/.release-please-manifest.json +3 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/CHANGELOG.md +11 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/PKG-INFO +1 -3
- {otdf_python-0.3.3 → otdf_python-0.3.4}/README.md +0 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/README.md +5 -5
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/pyproject.toml +1 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/scripts/generate_connect_proto.py +6 -6
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/uv.lock +1 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/pyproject.toml +2 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/auth_headers.py +13 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/cli.py +9 -9
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/header.py +2 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/kas_connect_rpc_client.py +7 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/nanotdf.py +1 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/sdk.py +6 -84
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/sdk_builder.py +5 -37
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/conftest.py +1 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/otdfctl_only/test_otdfctl_generated_fixtures.py +2 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/otdfctl_to_python/test_cli_comparison.py +2 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/otdfctl_to_python/test_tdf_reader_integration.py +7 -7
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_cli_integration.py +4 -4
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_cli_tdf_validation.py +3 -3
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_pe_interaction.py +3 -3
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/support_common.py +2 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_cli.py +5 -6
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_crypto_utils.py +1 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_inner_classes.py +21 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_manifest_format.py +2 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_sdk.py +0 -3
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_sdk_builder.py +5 -5
- otdf_python-0.3.4/tests/test_sdk_mock.py +31 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_sdk_tdf_integration.py +4 -4
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_tdf.py +1 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_tdf_reader.py +2 -2
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_url_normalization.py +0 -6
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_validate_otdf_python.py +4 -4
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_zip_reader.py +2 -1
- {otdf_python-0.3.3 → otdf_python-0.3.4}/uv.lock +21 -21
- otdf_python-0.3.3/.release-please-manifest.json +0 -3
- otdf_python-0.3.3/tests/test_sdk_mock.py +0 -58
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.github/start_opentdf_docker.sh +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.github/workflows/build-python.yaml +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.github/workflows/platform-integration-test.yaml +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.github/workflows/release-please.yaml +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.github/workflows/test-suite.yaml +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.gitignore +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.release-please-config-develop.json +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.release-please-config.json +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.release-please-manifest-develop.json +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.vscode/extensions.json +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/.vscode/settings.json +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/LICENSE +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/conftest.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/docs/CONNECT_RPC.md +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/docs/DEVELOPING.md +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/docs/LEGACY_VERSION.md +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/docs/RELEASES.md +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/buf.gen.yaml +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/buf.lock +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/buf.yaml +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/authorization/authorization.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/authorization/v2/authorization.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/common/common.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/entity/entity.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/entityresolution/entity_resolution.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/entityresolution/v2/entity_resolution.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/kas/kas.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/logger/audit/test.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/actions/actions.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/attributes/attributes.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/kasregistry/key_access_server_registry.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/keymanagement/key_management.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/namespaces/namespaces.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/objects.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/registeredresources/registered_resources.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/resourcemapping/resource_mapping.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/selectors.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/subjectmapping/subject_mapping.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/policy/unsafe/unsafe.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/proto-files/wellknownconfiguration/wellknown_configuration.proto +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/scripts/build_connect_proto.sh +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/scripts/setup_connect_rpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/common/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/common/common_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/common/common_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entity/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entity/entity_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entity/entity_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/kas/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/authorization/authorization_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/authorization/v2/authorization_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/common/common_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entity/entity_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entityresolution/entity_resolution_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entityresolution/v2/entity_resolution_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/kas/kas_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/logger/audit/test_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/actions/actions_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/attributes/attributes_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/kasregistry/key_access_server_registry_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/keymanagement/key_management_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/namespaces/namespaces_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/objects_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/registeredresources/registered_resources_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/resourcemapping/resource_mapping_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/selectors_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/subjectmapping/subject_mapping_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/unsafe/unsafe_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/legacy_grpc/wellknownconfiguration/wellknown_configuration_pb2_grpc.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/logger/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/logger/audit/test_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/logger/audit/test_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/objects_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/objects_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/selectors_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/selectors_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.pyi +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2_connect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/__main__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/address_normalizer.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/aesgcm.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/assertion_config.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/asym_crypto.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/asym_decryption.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/asym_encryption.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/autoconfigure_utils.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/collection_store.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/collection_store_impl.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/config.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/connect_client.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/constants.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/crypto_utils.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/dpop.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/ecc_mode.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/eckeypair.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/invalid_zip_exception.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/kas_client.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/kas_info.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/kas_key_cache.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/key_type.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/key_type_constants.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/manifest.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/nanotdf_ecdsa_struct.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/nanotdf_type.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/policy_binding_serializer.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/policy_info.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/policy_object.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/policy_stub.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/resource_locator.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/sdk_exceptions.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/symmetric_and_payload_config.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/tdf.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/tdf_reader.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/tdf_writer.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/token_source.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/version.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/zip_reader.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/src/otdf_python/zip_writer.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/__init__.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/config_pydantic.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/otdfctl_to_python/test_cli_decrypt.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/otdfctl_to_python/test_cli_inspect.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/python_only/test_kas_client_integration.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/support_sdk.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_data/empty_file.txt +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_data/sample_binary.png +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_data/sample_text.txt +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/test_data/sample_with_attributes.txt +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/mock_crypto.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/server_logs.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/support_cli_args.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/support_otdfctl.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/support_otdfctl_args.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_address_normalizer.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_aesgcm.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_assertion_config.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_asym_encryption.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_autoconfigure_utils.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_collection_store.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_config.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_eckeypair.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_header.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_kas_client.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_kas_key_cache.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_kas_key_management.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_key_type.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_log_collection.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_manifest.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_nanotdf.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_nanotdf_ecdsa_struct.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_nanotdf_integration.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_nanotdf_type.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_policy_object.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_sdk_exceptions.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_tdf_key_management.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_tdf_writer.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_token_source.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_use_plaintext_flow.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_version.py +0 -0
- {otdf_python-0.3.3 → otdf_python-0.3.4}/tests/test_zip_writer.py +0 -0
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.4](https://github.com/b-long/opentdf-python-sdk/compare/otdf-python-v0.3.3...otdf-python-v0.3.4) (2025-10-04)
|
|
4
|
+
|
|
5
|
+
### Chores
|
|
6
|
+
|
|
7
|
+
* chore: remove placeholders ([#110](https://github.com/b-long/opentdf-python-sdk/issues/110))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Bug Fixes
|
|
11
|
+
|
|
12
|
+
* update ruff ([#108](https://github.com/b-long/opentdf-python-sdk/issues/108)) ([5e4c796](https://github.com/b-long/opentdf-python-sdk/commit/5e4c796a8c1fc10b206cd2769f7c8548903ad3c1))
|
|
13
|
+
|
|
3
14
|
## [0.3.3](https://github.com/b-long/opentdf-python-sdk/compare/otdf-python-v0.3.2...otdf-python-v0.3.3) (2025-09-17)
|
|
4
15
|
|
|
5
16
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: otdf-python
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Unofficial OpenTDF SDK for Python
|
|
5
5
|
Author-email: b-long <b-long@users.noreply.github.com>
|
|
6
6
|
License-File: LICENSE
|
|
@@ -114,8 +114,6 @@ decrypted_data = tdf_reader.payload
|
|
|
114
114
|
with open("decrypted.txt", "wb") as f:
|
|
115
115
|
f.write(decrypted_data)
|
|
116
116
|
|
|
117
|
-
# Don't forget to close the SDK when done
|
|
118
|
-
sdk.close()
|
|
119
117
|
```
|
|
120
118
|
|
|
121
119
|
## Project Structure
|
|
@@ -17,7 +17,7 @@ See [CONNECT_RPC.md](../docs/CONNECT_RPC.md) for additional information.
|
|
|
17
17
|
## Structure
|
|
18
18
|
|
|
19
19
|
- `proto-files/`: Contains the raw .proto files downloaded from the OpenTDF platform
|
|
20
|
-
- `
|
|
20
|
+
- `src/otdf_python_proto/`: Contains the generated Python protobuf and Connect RPC client files
|
|
21
21
|
- `scripts/`: Contains build scripts for generating protobuf and Connect RPC files
|
|
22
22
|
- `buf.yaml`: Buf configuration for proto validation and management
|
|
23
23
|
- `buf.gen.yaml`: Buf generation configuration for Connect RPC and protobuf
|
|
@@ -40,10 +40,10 @@ Or use the convenience script:
|
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
This generates:
|
|
43
|
-
- `
|
|
44
|
-
- `
|
|
45
|
-
- `
|
|
46
|
-
- `
|
|
43
|
+
- `src/otdf_python_proto/**/*_connect.py` - Connect RPC clients (preferred)
|
|
44
|
+
- `src/otdf_python_proto/**/*_pb2.py` - Standard protobuf classes
|
|
45
|
+
- `src/otdf_python_proto/**/*_pb2.pyi` - Type stubs for better IDE support
|
|
46
|
+
- `src/otdf_python_proto/legacy_grpc/**/*_pb2_grpc.py` - Legacy gRPC clients (backward compatibility)
|
|
47
47
|
|
|
48
48
|
### Legacy gRPC Generation
|
|
49
49
|
|
|
@@ -96,10 +96,10 @@ def copy_opentdf_proto_files(proto_gen_dir: Path) -> bool:
|
|
|
96
96
|
print(f" Copying {relative_path}...")
|
|
97
97
|
|
|
98
98
|
# Copy the file content
|
|
99
|
-
with open(
|
|
99
|
+
with proto_file.open() as src:
|
|
100
100
|
content = src.read()
|
|
101
101
|
|
|
102
|
-
with open(
|
|
102
|
+
with dest_path.open("w") as dst:
|
|
103
103
|
dst.write(content)
|
|
104
104
|
|
|
105
105
|
copied_files += 1
|
|
@@ -155,7 +155,7 @@ def run_buf_generate(proto_gen_dir: Path) -> bool:
|
|
|
155
155
|
|
|
156
156
|
# Update buf.gen.yaml with the correct path
|
|
157
157
|
buf_gen_path = proto_gen_dir / "buf.gen.yaml"
|
|
158
|
-
with open(
|
|
158
|
+
with buf_gen_path.open() as f:
|
|
159
159
|
content = f.read()
|
|
160
160
|
|
|
161
161
|
# Replace the local plugin path
|
|
@@ -163,7 +163,7 @@ def run_buf_generate(proto_gen_dir: Path) -> bool:
|
|
|
163
163
|
"- local: protoc-gen-connect_python", f"- local: {connect_plugin_path}"
|
|
164
164
|
)
|
|
165
165
|
|
|
166
|
-
with open(
|
|
166
|
+
with buf_gen_path.open("w") as f:
|
|
167
167
|
f.write(updated_content)
|
|
168
168
|
|
|
169
169
|
# Run buf generate
|
|
@@ -221,7 +221,7 @@ def _fix_ignore_if_default_value(proto_files_dir):
|
|
|
221
221
|
# Iterate all .proto files in the directory
|
|
222
222
|
for proto_file in proto_files_dir.glob("**/*.proto"):
|
|
223
223
|
try:
|
|
224
|
-
with open(
|
|
224
|
+
with proto_file.open("r") as file:
|
|
225
225
|
content = file.read()
|
|
226
226
|
|
|
227
227
|
# Replace the old enum value with the new one
|
|
@@ -230,7 +230,7 @@ def _fix_ignore_if_default_value(proto_files_dir):
|
|
|
230
230
|
)
|
|
231
231
|
|
|
232
232
|
# Write the updated content back to the file
|
|
233
|
-
with open(
|
|
233
|
+
with proto_file.open("w") as file:
|
|
234
234
|
file.write(updated_content)
|
|
235
235
|
|
|
236
236
|
print(f"Updated {proto_file.name} to use IGNORE_IF_ZERO_VALUE")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "otdf-python"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.4"
|
|
4
4
|
description = "Unofficial OpenTDF SDK for Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -73,6 +73,7 @@ lint.select = [
|
|
|
73
73
|
"I",
|
|
74
74
|
# Performance-related rules
|
|
75
75
|
"PERF", # Ruff's performance rules
|
|
76
|
+
"PTH", # pathlib (path handling)
|
|
76
77
|
# Additional useful rules
|
|
77
78
|
"UP", # pyupgrade (modern Python features)
|
|
78
79
|
"SIM", # flake8-simplify (simplifications)
|
|
@@ -10,7 +10,7 @@ class AuthHeaders:
|
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
12
|
auth_header: str
|
|
13
|
-
dpop_header: str
|
|
13
|
+
dpop_header: str = ""
|
|
14
14
|
|
|
15
15
|
def get_auth_header(self) -> str:
|
|
16
16
|
"""Returns the authorization header."""
|
|
@@ -19,3 +19,15 @@ class AuthHeaders:
|
|
|
19
19
|
def get_dpop_header(self) -> str:
|
|
20
20
|
"""Returns the DPoP header."""
|
|
21
21
|
return self.dpop_header
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> dict[str, str]:
|
|
24
|
+
"""
|
|
25
|
+
Convert authentication headers to a dictionary for use with HTTP clients.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Dictionary with 'Authorization' header and optionally 'DPoP' header
|
|
29
|
+
"""
|
|
30
|
+
headers = {"Authorization": self.auth_header}
|
|
31
|
+
if self.dpop_header:
|
|
32
|
+
headers["DPoP"] = self.dpop_header
|
|
33
|
+
return headers
|
|
@@ -88,7 +88,7 @@ def load_client_credentials(creds_file_path: str) -> tuple[str, str]:
|
|
|
88
88
|
"CRITICAL", f"Credentials file does not exist: {creds_file_path}"
|
|
89
89
|
)
|
|
90
90
|
|
|
91
|
-
with open(
|
|
91
|
+
with creds_path.open() as f:
|
|
92
92
|
creds = json.load(f)
|
|
93
93
|
|
|
94
94
|
client_id = creds.get("clientId")
|
|
@@ -223,13 +223,13 @@ def cmd_encrypt(args):
|
|
|
223
223
|
|
|
224
224
|
try:
|
|
225
225
|
# Read input file
|
|
226
|
-
with open(
|
|
226
|
+
with input_path.open("rb") as input_file:
|
|
227
227
|
payload = input_file.read()
|
|
228
228
|
|
|
229
229
|
# Determine output
|
|
230
230
|
if args.output:
|
|
231
231
|
output_path = Path(args.output)
|
|
232
|
-
with open(
|
|
232
|
+
with output_path.open("wb") as output_file:
|
|
233
233
|
try:
|
|
234
234
|
# Create appropriate config based on container type
|
|
235
235
|
container_type = getattr(args, "container_type", "tdf")
|
|
@@ -247,7 +247,7 @@ def cmd_encrypt(args):
|
|
|
247
247
|
logger.debug("Creating TDF")
|
|
248
248
|
config = create_tdf_config(sdk, args)
|
|
249
249
|
output_stream = BytesIO()
|
|
250
|
-
|
|
250
|
+
_manifest, size, _ = sdk.create_tdf(
|
|
251
251
|
BytesIO(payload), config, output_stream
|
|
252
252
|
)
|
|
253
253
|
output_file.write(output_stream.getvalue())
|
|
@@ -274,7 +274,7 @@ def cmd_encrypt(args):
|
|
|
274
274
|
logger.debug("Creating TDF")
|
|
275
275
|
config = create_tdf_config(sdk, args)
|
|
276
276
|
output_stream = BytesIO()
|
|
277
|
-
|
|
277
|
+
_manifest, size, _ = sdk.create_tdf(
|
|
278
278
|
BytesIO(payload), config, output_stream
|
|
279
279
|
)
|
|
280
280
|
output_file.write(output_stream.getvalue())
|
|
@@ -296,13 +296,13 @@ def cmd_decrypt(args):
|
|
|
296
296
|
|
|
297
297
|
try:
|
|
298
298
|
# Read encrypted file
|
|
299
|
-
with open(
|
|
299
|
+
with input_path.open("rb") as input_file:
|
|
300
300
|
encrypted_data = input_file.read()
|
|
301
301
|
|
|
302
302
|
# Determine output
|
|
303
303
|
if args.output:
|
|
304
304
|
output_path = Path(args.output)
|
|
305
|
-
with open(
|
|
305
|
+
with output_path.open("wb") as output_file:
|
|
306
306
|
try:
|
|
307
307
|
# Try to determine if it's a NanoTDF or regular TDF
|
|
308
308
|
# NanoTDFs have a specific header format, regular TDFs are ZIP files
|
|
@@ -359,7 +359,7 @@ def cmd_inspect(args):
|
|
|
359
359
|
|
|
360
360
|
try:
|
|
361
361
|
# Read encrypted file
|
|
362
|
-
with open(
|
|
362
|
+
with input_path.open("rb") as input_file:
|
|
363
363
|
encrypted_data = input_file.read()
|
|
364
364
|
|
|
365
365
|
if encrypted_data.startswith(b"PK"):
|
|
@@ -400,7 +400,7 @@ def cmd_inspect(args):
|
|
|
400
400
|
except Exception as e:
|
|
401
401
|
# If we can't inspect due to auth issues, show what we can
|
|
402
402
|
logger.warning(f"Limited inspection due to: {e}")
|
|
403
|
-
with open(
|
|
403
|
+
with input_path.open("rb") as input_file:
|
|
404
404
|
encrypted_data = input_file.read()
|
|
405
405
|
|
|
406
406
|
file_type = "TDF" if encrypted_data.startswith(b"PK") else "NanoTDF"
|
|
@@ -51,7 +51,7 @@ class Header:
|
|
|
51
51
|
# MAGIC_NUMBER_AND_VERSION (3 bytes)
|
|
52
52
|
offset += 3
|
|
53
53
|
# ResourceLocator
|
|
54
|
-
|
|
54
|
+
_kas_locator, kas_size = ResourceLocator.from_bytes_with_size(buffer[offset:])
|
|
55
55
|
offset += kas_size
|
|
56
56
|
# ECC mode (1 byte)
|
|
57
57
|
ecc_mode = ECCMode(buffer[offset])
|
|
@@ -59,7 +59,7 @@ class Header:
|
|
|
59
59
|
# Payload config (1 byte)
|
|
60
60
|
offset += 1
|
|
61
61
|
# PolicyInfo
|
|
62
|
-
|
|
62
|
+
_policy_info, policy_size = PolicyInfo.from_bytes_with_size(
|
|
63
63
|
buffer[offset:], ecc_mode
|
|
64
64
|
)
|
|
65
65
|
offset += policy_size
|
|
@@ -9,6 +9,8 @@ import urllib3
|
|
|
9
9
|
from otdf_python_proto.kas import kas_pb2
|
|
10
10
|
from otdf_python_proto.kas.kas_pb2_connect import AccessServiceClient
|
|
11
11
|
|
|
12
|
+
from otdf_python.auth_headers import AuthHeaders
|
|
13
|
+
|
|
12
14
|
from .sdk_exceptions import SDKException
|
|
13
15
|
|
|
14
16
|
|
|
@@ -69,7 +71,11 @@ class KASConnectRPCClient:
|
|
|
69
71
|
Dictionary with authentication headers or None
|
|
70
72
|
"""
|
|
71
73
|
if access_token:
|
|
72
|
-
|
|
74
|
+
auth_headers = AuthHeaders(
|
|
75
|
+
auth_header=f"Bearer {access_token}",
|
|
76
|
+
dpop_header="", # Empty for now, ready for future DPoP support
|
|
77
|
+
)
|
|
78
|
+
return auth_headers.to_dict()
|
|
73
79
|
return None
|
|
74
80
|
|
|
75
81
|
def get_public_key(self, normalized_kas_url, kas_info, access_token=None):
|
|
@@ -300,7 +300,7 @@ class NanoTDF:
|
|
|
300
300
|
iv, ciphertext = self._encrypt_payload(payload, key)
|
|
301
301
|
|
|
302
302
|
# Wrap key if needed
|
|
303
|
-
wrapped_key,
|
|
303
|
+
wrapped_key, _kas_public_key = self._wrap_key_if_needed(key, config)
|
|
304
304
|
|
|
305
305
|
# Compose the complete NanoTDF: [IV][CIPHERTEXT][WRAPPED_KEY][WRAPPED_KEY_LEN]
|
|
306
306
|
if wrapped_key:
|
|
@@ -6,42 +6,12 @@ from contextlib import AbstractContextManager
|
|
|
6
6
|
from io import BytesIO
|
|
7
7
|
from typing import Any, BinaryIO
|
|
8
8
|
|
|
9
|
-
from otdf_python.config import NanoTDFConfig, TDFConfig
|
|
9
|
+
from otdf_python.config import KASInfo, NanoTDFConfig, TDFConfig
|
|
10
10
|
from otdf_python.nanotdf import NanoTDF
|
|
11
11
|
from otdf_python.sdk_exceptions import SDKException
|
|
12
12
|
from otdf_python.tdf import TDF, TDFReader, TDFReaderConfig
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
# Stubs for service client interfaces (to be implemented)
|
|
16
|
-
class AttributesServiceClientInterface: ...
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class NamespaceServiceClientInterface: ...
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class SubjectMappingServiceClientInterface: ...
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class ResourceMappingServiceClientInterface: ...
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class AuthorizationServiceClientInterface: ...
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class KeyAccessServerRegistryServiceClientInterface: ...
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
# Placeholder for ProtocolClient and Interceptor
|
|
35
|
-
class ProtocolClient: ...
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class Interceptor: ... # Can be dict in Python implementation
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
# Placeholder for TrustManager
|
|
42
|
-
class TrustManager: ...
|
|
43
|
-
|
|
44
|
-
|
|
45
15
|
class KAS(AbstractContextManager):
|
|
46
16
|
"""
|
|
47
17
|
KAS (Key Access Service) interface to define methods related to key access and management.
|
|
@@ -71,7 +41,6 @@ class KAS(AbstractContextManager):
|
|
|
71
41
|
token_source=None,
|
|
72
42
|
sdk_ssl_verify=True,
|
|
73
43
|
use_plaintext=False,
|
|
74
|
-
auth_headers: dict | None = None,
|
|
75
44
|
):
|
|
76
45
|
"""
|
|
77
46
|
Initialize the KAS client
|
|
@@ -81,7 +50,6 @@ class KAS(AbstractContextManager):
|
|
|
81
50
|
token_source: Function that returns an authentication token
|
|
82
51
|
sdk_ssl_verify: Whether to verify SSL certificates
|
|
83
52
|
use_plaintext: Whether to use plaintext HTTP connections instead of HTTPS
|
|
84
|
-
auth_headers: Dictionary of authentication headers to include in requests
|
|
85
53
|
"""
|
|
86
54
|
from .kas_client import KASClient
|
|
87
55
|
|
|
@@ -94,7 +62,6 @@ class KAS(AbstractContextManager):
|
|
|
94
62
|
# Store the parameters for potential use
|
|
95
63
|
self._sdk_ssl_verify = sdk_ssl_verify
|
|
96
64
|
self._use_plaintext = use_plaintext
|
|
97
|
-
self._auth_headers = auth_headers
|
|
98
65
|
|
|
99
66
|
def get_ec_public_key(self, kas_info: Any, curve: Any) -> Any:
|
|
100
67
|
"""
|
|
@@ -179,12 +146,14 @@ class KAS(AbstractContextManager):
|
|
|
179
146
|
|
|
180
147
|
class SDK(AbstractContextManager):
|
|
181
148
|
def new_tdf_config(
|
|
182
|
-
self,
|
|
149
|
+
self,
|
|
150
|
+
attributes: list[str] | None = None,
|
|
151
|
+
kas_info_list: list[KASInfo] | None = None,
|
|
152
|
+
**kwargs,
|
|
183
153
|
) -> TDFConfig:
|
|
184
154
|
"""
|
|
185
155
|
Create a TDFConfig with default kas_info_list from the SDK's platform_url.
|
|
186
156
|
"""
|
|
187
|
-
from otdf_python.config import KASInfo
|
|
188
157
|
|
|
189
158
|
if self.platform_url is None:
|
|
190
159
|
raise SDKException("Cannot create TDFConfig: SDK platform_url is not set.")
|
|
@@ -232,10 +201,8 @@ class SDK(AbstractContextManager):
|
|
|
232
201
|
# Use existing port with the determined scheme
|
|
233
202
|
kas_url = f"{scheme}://{parsed_url.hostname}:{parsed_url.port}{parsed_url.path.rstrip('/')}/kas"
|
|
234
203
|
|
|
235
|
-
kas_info = KASInfo(url=kas_url, default=True)
|
|
236
|
-
# Accept user override for kas_info_list if provided
|
|
237
|
-
kas_info_list = kwargs.pop("kas_info_list", None)
|
|
238
204
|
if kas_info_list is None:
|
|
205
|
+
kas_info = KASInfo(url=kas_url, default=True)
|
|
239
206
|
kas_info_list = [kas_info]
|
|
240
207
|
return TDFConfig(
|
|
241
208
|
kas_info_list=kas_info_list, attributes=attributes or [], **kwargs
|
|
@@ -251,30 +218,6 @@ class SDK(AbstractContextManager):
|
|
|
251
218
|
The Services interface provides access to various platform service clients and KAS.
|
|
252
219
|
"""
|
|
253
220
|
|
|
254
|
-
def attributes(self) -> AttributesServiceClientInterface:
|
|
255
|
-
"""Returns the attributes service client"""
|
|
256
|
-
raise NotImplementedError
|
|
257
|
-
|
|
258
|
-
def namespaces(self) -> NamespaceServiceClientInterface:
|
|
259
|
-
"""Returns the namespaces service client"""
|
|
260
|
-
raise NotImplementedError
|
|
261
|
-
|
|
262
|
-
def subject_mappings(self) -> SubjectMappingServiceClientInterface:
|
|
263
|
-
"""Returns the subject mappings service client"""
|
|
264
|
-
raise NotImplementedError
|
|
265
|
-
|
|
266
|
-
def resource_mappings(self) -> ResourceMappingServiceClientInterface:
|
|
267
|
-
"""Returns the resource mappings service client"""
|
|
268
|
-
raise NotImplementedError
|
|
269
|
-
|
|
270
|
-
def authorization(self) -> AuthorizationServiceClientInterface:
|
|
271
|
-
"""Returns the authorization service client"""
|
|
272
|
-
raise NotImplementedError
|
|
273
|
-
|
|
274
|
-
def kas_registry(self) -> KeyAccessServerRegistryServiceClientInterface:
|
|
275
|
-
"""Returns the KAS registry service client"""
|
|
276
|
-
raise NotImplementedError
|
|
277
|
-
|
|
278
221
|
def kas(self) -> KAS:
|
|
279
222
|
"""
|
|
280
223
|
Returns the KAS client for key access operations.
|
|
@@ -292,9 +235,6 @@ class SDK(AbstractContextManager):
|
|
|
292
235
|
def __init__(
|
|
293
236
|
self,
|
|
294
237
|
services: "SDK.Services",
|
|
295
|
-
trust_manager: TrustManager | None = None,
|
|
296
|
-
auth_interceptor: Interceptor | dict[str, str] | None = None,
|
|
297
|
-
platform_services_client: ProtocolClient | None = None,
|
|
298
238
|
platform_url: str | None = None,
|
|
299
239
|
ssl_verify: bool = True,
|
|
300
240
|
use_plaintext: bool = False,
|
|
@@ -304,17 +244,11 @@ class SDK(AbstractContextManager):
|
|
|
304
244
|
|
|
305
245
|
Args:
|
|
306
246
|
services: The services interface implementation
|
|
307
|
-
trust_manager: Optional trust manager for SSL validation
|
|
308
|
-
auth_interceptor: Optional auth interceptor for API requests
|
|
309
|
-
platform_services_client: Optional client for platform services
|
|
310
247
|
platform_url: Optional platform base URL
|
|
311
248
|
ssl_verify: Whether to verify SSL certificates (default: True)
|
|
312
249
|
use_plaintext: Whether to use HTTP instead of HTTPS (default: False)
|
|
313
250
|
"""
|
|
314
251
|
self.services = services
|
|
315
|
-
self.trust_manager = trust_manager
|
|
316
|
-
self.auth_interceptor = auth_interceptor
|
|
317
|
-
self.platform_services_client = platform_services_client
|
|
318
252
|
self.platform_url = platform_url
|
|
319
253
|
self.ssl_verify = ssl_verify
|
|
320
254
|
self._use_plaintext = use_plaintext
|
|
@@ -332,18 +266,6 @@ class SDK(AbstractContextManager):
|
|
|
332
266
|
"""Returns the services interface"""
|
|
333
267
|
return self.services
|
|
334
268
|
|
|
335
|
-
def get_trust_manager(self) -> TrustManager | None:
|
|
336
|
-
"""Returns the trust manager if set"""
|
|
337
|
-
return self.trust_manager
|
|
338
|
-
|
|
339
|
-
def get_auth_interceptor(self) -> Interceptor | dict[str, str] | None:
|
|
340
|
-
"""Returns the auth interceptor if set"""
|
|
341
|
-
return self.auth_interceptor
|
|
342
|
-
|
|
343
|
-
def get_platform_services_client(self) -> ProtocolClient | None:
|
|
344
|
-
"""Returns the platform services client if set"""
|
|
345
|
-
return self.platform_services_client
|
|
346
|
-
|
|
347
269
|
def get_platform_url(self) -> str | None:
|
|
348
270
|
"""Returns the platform URL if set"""
|
|
349
271
|
return self.platform_url
|
|
@@ -4,10 +4,9 @@ Provides methods to configure and build SDK instances.
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
import logging
|
|
7
|
-
import os
|
|
8
7
|
import ssl
|
|
9
8
|
from dataclasses import dataclass
|
|
10
|
-
from
|
|
9
|
+
from pathlib import Path
|
|
11
10
|
|
|
12
11
|
import httpx
|
|
13
12
|
|
|
@@ -77,9 +76,10 @@ class SDKBuilder:
|
|
|
77
76
|
self.cert_paths = []
|
|
78
77
|
|
|
79
78
|
# Find all .pem and .crt files in the directory
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
certs_path = Path(certs_dir_path)
|
|
80
|
+
for cert_file in certs_path.iterdir():
|
|
81
|
+
if cert_file.suffix in (".pem", ".crt"):
|
|
82
|
+
self.cert_paths.append(str(cert_file))
|
|
83
83
|
|
|
84
84
|
# Create SSL context with these certificates
|
|
85
85
|
if self.cert_paths:
|
|
@@ -343,32 +343,6 @@ class SDKBuilder:
|
|
|
343
343
|
except Exception as e:
|
|
344
344
|
raise AutoConfigureException(f"Error during token acquisition: {e!s}")
|
|
345
345
|
|
|
346
|
-
def _create_auth_interceptor(self) -> Any:
|
|
347
|
-
"""
|
|
348
|
-
Creates an authentication interceptor for API requests (httpx).
|
|
349
|
-
Returns:
|
|
350
|
-
Any: An auth interceptor object
|
|
351
|
-
Raises:
|
|
352
|
-
AutoConfigureException: If auth configuration fails
|
|
353
|
-
"""
|
|
354
|
-
# For now, this is just a placeholder returning a dict with auth headers
|
|
355
|
-
# In a real implementation, this would create a proper interceptor object
|
|
356
|
-
# that injects auth headers into httpx requests
|
|
357
|
-
|
|
358
|
-
token = None
|
|
359
|
-
|
|
360
|
-
if self.auth_token:
|
|
361
|
-
# Use provided token
|
|
362
|
-
token = self.auth_token
|
|
363
|
-
elif self.oauth_config:
|
|
364
|
-
# Get token from OAuth
|
|
365
|
-
token = self._get_token_from_client_credentials()
|
|
366
|
-
|
|
367
|
-
if token:
|
|
368
|
-
return {"Authorization": f"Bearer {token}"}
|
|
369
|
-
|
|
370
|
-
return None
|
|
371
|
-
|
|
372
346
|
def _create_services(self) -> SDK.Services:
|
|
373
347
|
"""
|
|
374
348
|
Creates service client instances.
|
|
@@ -382,13 +356,11 @@ class SDKBuilder:
|
|
|
382
356
|
# connecting to the platform endpoints
|
|
383
357
|
|
|
384
358
|
ssl_verify = not self.insecure_skip_verify
|
|
385
|
-
auth_interceptor = self._create_auth_interceptor()
|
|
386
359
|
|
|
387
360
|
class ServicesImpl(SDK.Services):
|
|
388
361
|
def __init__(self, builder_instance):
|
|
389
362
|
self.closed = False
|
|
390
363
|
self._ssl_verify = ssl_verify
|
|
391
|
-
self._auth_headers = auth_interceptor if auth_interceptor else {}
|
|
392
364
|
self._builder = builder_instance
|
|
393
365
|
|
|
394
366
|
def kas(self) -> KAS:
|
|
@@ -432,16 +404,12 @@ class SDKBuilder:
|
|
|
432
404
|
if not self.platform_endpoint:
|
|
433
405
|
raise AutoConfigureException("Platform endpoint is not set")
|
|
434
406
|
|
|
435
|
-
# Create the auth interceptor
|
|
436
|
-
auth_interceptor = self._create_auth_interceptor()
|
|
437
|
-
|
|
438
407
|
# Create services
|
|
439
408
|
services = self._create_services()
|
|
440
409
|
|
|
441
410
|
# Return the SDK instance, platform_url is set for new_tdf_config
|
|
442
411
|
return SDK(
|
|
443
412
|
services=services,
|
|
444
|
-
auth_interceptor=auth_interceptor,
|
|
445
413
|
platform_url=self.platform_endpoint,
|
|
446
414
|
ssl_verify=not self.insecure_skip_verify,
|
|
447
415
|
use_plaintext=getattr(self, "use_plaintext", False),
|
|
@@ -20,7 +20,7 @@ def temp_credentials_file():
|
|
|
20
20
|
with tempfile.TemporaryDirectory() as temp_dir:
|
|
21
21
|
creds_file = Path(temp_dir) / "creds.json"
|
|
22
22
|
creds_data = {"clientId": "opentdf", "clientSecret": "secret"}
|
|
23
|
-
with open(
|
|
23
|
+
with creds_file.open("w") as f:
|
|
24
24
|
json.dump(creds_data, f)
|
|
25
25
|
yield creds_file
|
|
26
26
|
|
|
@@ -48,7 +48,7 @@ def test_sample_file_contents(sample_input_files):
|
|
|
48
48
|
# Check text file has content
|
|
49
49
|
text_file = sample_input_files["text"]
|
|
50
50
|
assert text_file.exists(), f"Text file should exist: {text_file}"
|
|
51
|
-
with open(
|
|
51
|
+
with text_file.open() as f:
|
|
52
52
|
content = f.read()
|
|
53
53
|
assert "Hello, World!" in content
|
|
54
54
|
assert len(content) > 0
|
|
@@ -66,7 +66,7 @@ def test_sample_file_contents(sample_input_files):
|
|
|
66
66
|
# Check attributes file has content
|
|
67
67
|
attr_file = sample_input_files["with_attributes"]
|
|
68
68
|
assert attr_file.exists(), f"Attributes file should exist: {attr_file}"
|
|
69
|
-
with open(
|
|
69
|
+
with attr_file.open() as f:
|
|
70
70
|
content = f.read()
|
|
71
71
|
assert "Classification: SECRET" in content
|
|
72
72
|
|
{otdf_python-0.3.3 → otdf_python-0.3.4}/tests/integration/otdfctl_to_python/test_cli_comparison.py
RENAMED
|
@@ -32,7 +32,7 @@ def test_otdfctl_encrypt_python_decrypt(
|
|
|
32
32
|
# Create input file
|
|
33
33
|
input_file = temp_path / "input.txt"
|
|
34
34
|
input_content = "Hello, World! This is a test for otdfctl decrypt comparison."
|
|
35
|
-
with open(
|
|
35
|
+
with input_file.open("w") as f:
|
|
36
36
|
f.write(input_content)
|
|
37
37
|
|
|
38
38
|
# Define TDF file created by otdfctl
|
|
@@ -115,7 +115,7 @@ def test_otdfctl_encrypt_otdfctl_decrypt(collect_server_logs, temp_credentials_f
|
|
|
115
115
|
input_content = (
|
|
116
116
|
"Hello, World! This is a test for otdfctl roundtrip encryption/decryption."
|
|
117
117
|
)
|
|
118
|
-
with open(
|
|
118
|
+
with input_file.open("w") as f:
|
|
119
119
|
f.write(input_content)
|
|
120
120
|
|
|
121
121
|
# Define TDF file and decrypted output
|