otdf-python 0.9.1__tar.gz → 0.10.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.
Files changed (177) hide show
  1. {otdf_python-0.9.1 → otdf_python-0.10.1}/PKG-INFO +1 -1
  2. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/cli.py +121 -26
  3. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/kas_client.py +6 -2
  4. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/sdk_builder.py +46 -6
  5. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/tdf.py +16 -0
  6. {otdf_python-0.9.1 → otdf_python-0.10.1}/pyproject.toml +1 -1
  7. {otdf_python-0.9.1 → otdf_python-0.10.1}/.gitignore +0 -0
  8. {otdf_python-0.9.1 → otdf_python-0.10.1}/README.md +0 -0
  9. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/__init__.py +0 -0
  10. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/__init__.py +0 -0
  11. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/authorization_connect.py +0 -0
  12. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/authorization_pb2.py +0 -0
  13. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/authorization_pb2.pyi +0 -0
  14. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/v2/__init__.py +0 -0
  15. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/v2/authorization_connect.py +0 -0
  16. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/v2/authorization_pb2.py +0 -0
  17. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/authorization/v2/authorization_pb2.pyi +0 -0
  18. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/common/__init__.py +0 -0
  19. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/common/common_pb2.py +0 -0
  20. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/common/common_pb2.pyi +0 -0
  21. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entity/__init__.py +0 -0
  22. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entity/entity_pb2.py +0 -0
  23. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entity/entity_pb2.pyi +0 -0
  24. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/__init__.py +0 -0
  25. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/entity_resolution_connect.py +0 -0
  26. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/entity_resolution_pb2.py +0 -0
  27. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/entity_resolution_pb2.pyi +0 -0
  28. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/v2/__init__.py +0 -0
  29. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/v2/entity_resolution_connect.py +0 -0
  30. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.py +0 -0
  31. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.pyi +0 -0
  32. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/kas/__init__.py +0 -0
  33. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/kas/kas_connect.py +0 -0
  34. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/kas/kas_pb2.py +0 -0
  35. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/kas/kas_pb2.pyi +0 -0
  36. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/__init__.py +0 -0
  37. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/authorization/__init__.py +0 -0
  38. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/authorization/authorization_pb2_grpc.py +0 -0
  39. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/authorization/v2/__init__.py +0 -0
  40. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/authorization/v2/authorization_pb2_grpc.py +0 -0
  41. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/common/__init__.py +0 -0
  42. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/common/common_pb2_grpc.py +0 -0
  43. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/entity/__init__.py +0 -0
  44. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/entity/entity_pb2_grpc.py +0 -0
  45. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/entityresolution/__init__.py +0 -0
  46. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/entityresolution/entity_resolution_pb2_grpc.py +0 -0
  47. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/entityresolution/v2/__init__.py +0 -0
  48. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/entityresolution/v2/entity_resolution_pb2_grpc.py +0 -0
  49. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/kas/__init__.py +0 -0
  50. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/kas/kas_pb2_grpc.py +0 -0
  51. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/logger/__init__.py +0 -0
  52. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/logger/audit/__init__.py +0 -0
  53. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/logger/audit/test_pb2_grpc.py +0 -0
  54. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/__init__.py +0 -0
  55. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/actions/__init__.py +0 -0
  56. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/actions/actions_pb2_grpc.py +0 -0
  57. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/attributes/__init__.py +0 -0
  58. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/attributes/attributes_pb2_grpc.py +0 -0
  59. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/kasregistry/__init__.py +0 -0
  60. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/kasregistry/key_access_server_registry_pb2_grpc.py +0 -0
  61. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/keymanagement/__init__.py +0 -0
  62. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/keymanagement/key_management_pb2_grpc.py +0 -0
  63. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/namespaces/__init__.py +0 -0
  64. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/namespaces/namespaces_pb2_grpc.py +0 -0
  65. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/objects_pb2_grpc.py +0 -0
  66. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/obligations/__init__.py +0 -0
  67. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/obligations/obligations_pb2_grpc.py +0 -0
  68. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/registeredresources/__init__.py +0 -0
  69. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/registeredresources/registered_resources_pb2_grpc.py +0 -0
  70. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/resourcemapping/__init__.py +0 -0
  71. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/resourcemapping/resource_mapping_pb2_grpc.py +0 -0
  72. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/selectors_pb2_grpc.py +0 -0
  73. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/subjectmapping/__init__.py +0 -0
  74. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/subjectmapping/subject_mapping_pb2_grpc.py +0 -0
  75. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/unsafe/__init__.py +0 -0
  76. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/policy/unsafe/unsafe_pb2_grpc.py +0 -0
  77. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/wellknownconfiguration/__init__.py +0 -0
  78. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/legacy_grpc/wellknownconfiguration/wellknown_configuration_pb2_grpc.py +0 -0
  79. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/logger/__init__.py +0 -0
  80. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/logger/audit/__init__.py +0 -0
  81. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/logger/audit/test_pb2.py +0 -0
  82. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/logger/audit/test_pb2.pyi +0 -0
  83. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/__init__.py +0 -0
  84. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/actions/__init__.py +0 -0
  85. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/actions/actions_connect.py +0 -0
  86. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/actions/actions_pb2.py +0 -0
  87. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/actions/actions_pb2.pyi +0 -0
  88. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/attributes/__init__.py +0 -0
  89. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/attributes/attributes_connect.py +0 -0
  90. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/attributes/attributes_pb2.py +0 -0
  91. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/attributes/attributes_pb2.pyi +0 -0
  92. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/kasregistry/__init__.py +0 -0
  93. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/kasregistry/key_access_server_registry_connect.py +0 -0
  94. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.py +0 -0
  95. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.pyi +0 -0
  96. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/keymanagement/__init__.py +0 -0
  97. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/keymanagement/key_management_connect.py +0 -0
  98. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/keymanagement/key_management_pb2.py +0 -0
  99. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/keymanagement/key_management_pb2.pyi +0 -0
  100. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/namespaces/__init__.py +0 -0
  101. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/namespaces/namespaces_connect.py +0 -0
  102. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/namespaces/namespaces_pb2.py +0 -0
  103. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/namespaces/namespaces_pb2.pyi +0 -0
  104. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/objects_pb2.py +0 -0
  105. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/objects_pb2.pyi +0 -0
  106. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/obligations/__init__.py +0 -0
  107. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/obligations/obligations_connect.py +0 -0
  108. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/obligations/obligations_pb2.py +0 -0
  109. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/obligations/obligations_pb2.pyi +0 -0
  110. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/registeredresources/__init__.py +0 -0
  111. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/registeredresources/registered_resources_connect.py +0 -0
  112. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/registeredresources/registered_resources_pb2.py +0 -0
  113. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/registeredresources/registered_resources_pb2.pyi +0 -0
  114. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/resourcemapping/__init__.py +0 -0
  115. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/resourcemapping/resource_mapping_connect.py +0 -0
  116. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.py +0 -0
  117. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.pyi +0 -0
  118. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/selectors_pb2.py +0 -0
  119. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/selectors_pb2.pyi +0 -0
  120. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/subjectmapping/__init__.py +0 -0
  121. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/subjectmapping/subject_mapping_connect.py +0 -0
  122. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.py +0 -0
  123. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.pyi +0 -0
  124. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/unsafe/__init__.py +0 -0
  125. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/unsafe/unsafe_connect.py +0 -0
  126. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/unsafe/unsafe_pb2.py +0 -0
  127. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/policy/unsafe/unsafe_pb2.pyi +0 -0
  128. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/wellknownconfiguration/__init__.py +0 -0
  129. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/wellknownconfiguration/wellknown_configuration_connect.py +0 -0
  130. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.py +0 -0
  131. {otdf_python-0.9.1 → otdf_python-0.10.1}/_proto/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.pyi +0 -0
  132. {otdf_python-0.9.1 → otdf_python-0.10.1}/hatch_build.py +0 -0
  133. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/__init__.py +0 -0
  134. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/__main__.py +0 -0
  135. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/address_normalizer.py +0 -0
  136. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/aesgcm.py +0 -0
  137. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/assertion_config.py +0 -0
  138. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/asym_crypto.py +0 -0
  139. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/auth_headers.py +0 -0
  140. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/autoconfigure_utils.py +0 -0
  141. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/collection_store.py +0 -0
  142. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/collection_store_impl.py +0 -0
  143. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/config.py +0 -0
  144. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/connect_client.py +0 -0
  145. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/constants.py +0 -0
  146. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/crypto_utils.py +0 -0
  147. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/dpop.py +0 -0
  148. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/ecc_constants.py +0 -0
  149. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/ecc_mode.py +0 -0
  150. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/ecdh.py +0 -0
  151. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/eckeypair.py +0 -0
  152. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/header.py +0 -0
  153. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/invalid_zip_exception.py +0 -0
  154. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/kas_allowlist.py +0 -0
  155. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/kas_connect_rpc_client.py +0 -0
  156. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/kas_info.py +0 -0
  157. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/kas_key_cache.py +0 -0
  158. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/key_type.py +0 -0
  159. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/key_type_constants.py +0 -0
  160. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/manifest.py +0 -0
  161. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/nanotdf.py +0 -0
  162. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/nanotdf_ecdsa_struct.py +0 -0
  163. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/nanotdf_type.py +0 -0
  164. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/policy_binding_serializer.py +0 -0
  165. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/policy_info.py +0 -0
  166. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/policy_object.py +0 -0
  167. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/policy_stub.py +0 -0
  168. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/resource_locator.py +0 -0
  169. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/sdk.py +0 -0
  170. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/sdk_exceptions.py +0 -0
  171. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/symmetric_and_payload_config.py +0 -0
  172. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/tdf_reader.py +0 -0
  173. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/tdf_writer.py +0 -0
  174. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/token_source.py +0 -0
  175. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/version.py +0 -0
  176. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/zip_reader.py +0 -0
  177. {otdf_python-0.9.1 → otdf_python-0.10.1}/otdf_python/zip_writer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: otdf-python
3
- Version: 0.9.1
3
+ Version: 0.10.1
4
4
  Summary: Unofficial OpenTDF SDK for Python
5
5
  Project-URL: Homepage, https://github.com/b-long/opentdf-python-sdk
6
6
  Project-URL: Repository, https://github.com/b-long/opentdf-python-sdk
@@ -9,6 +9,7 @@ import argparse
9
9
  import contextlib
10
10
  import json
11
11
  import logging
12
+ import os
12
13
  import sys
13
14
  from dataclasses import asdict
14
15
  from importlib import metadata
@@ -113,7 +114,14 @@ def load_client_credentials(creds_file_path: str) -> tuple[str, str]:
113
114
 
114
115
 
115
116
  def _configure_auth(builder: SDKBuilder, args) -> None:
116
- """Configure authentication on the SDK builder."""
117
+ """Configure authentication on the SDK builder.
118
+
119
+ Preference order:
120
+ 1. Explicit --client-id / --client-secret flags
121
+ 2. --with-client-creds-file
122
+ 3. --auth clientId:clientSecret
123
+ 4. CLIENTID / CLIENTSECRET environment variables (xtest / local platform)
124
+ """
117
125
  if args.client_id and args.client_secret:
118
126
  builder.client_secret(args.client_id, args.client_secret)
119
127
  elif hasattr(args, "with_client_creds_file") and args.with_client_creds_file:
@@ -127,10 +135,14 @@ def _configure_auth(builder: SDKBuilder, args) -> None:
127
135
  f"Auth expects <clientId>:<clientSecret>, received {args.auth}",
128
136
  )
129
137
  builder.client_secret(auth_parts[0], auth_parts[1])
138
+ elif os.environ.get("CLIENTID") and os.environ.get("CLIENTSECRET"):
139
+ builder.client_secret(os.environ["CLIENTID"], os.environ["CLIENTSECRET"])
140
+ logger.debug("Using CLIENTID/CLIENTSECRET from environment")
130
141
  else:
131
142
  raise CLIError(
132
143
  "CRITICAL",
133
- "Authentication required: provide --with-client-creds-file OR --client-id and --client-secret",
144
+ "Authentication required: provide --with-client-creds-file, "
145
+ "--client-id/--client-secret, or set CLIENTID and CLIENTSECRET env vars",
134
146
  )
135
147
 
136
148
 
@@ -149,29 +161,41 @@ def _configure_kas_allowlist(builder: SDKBuilder, args) -> None:
149
161
 
150
162
 
151
163
  def build_sdk(args) -> SDK:
152
- """Build SDK instance from CLI arguments."""
164
+ """Build SDK instance from CLI arguments.
165
+
166
+ Falls back to PLATFORMURL / KCFULLURL / KASURL environment variables
167
+ (xtest contract) when flags are omitted, so shims need not pass secrets
168
+ on argv.
169
+ """
153
170
  builder = SDKBuilder()
154
171
 
155
- if args.platform_url:
156
- builder.set_platform_endpoint(args.platform_url)
172
+ platform_url = getattr(args, "platform_url", None) or os.environ.get("PLATFORMURL")
173
+ oidc_endpoint = getattr(args, "oidc_endpoint", None) or os.environ.get("KCFULLURL")
174
+ # kas-endpoint may be comma-separated; also accept single KASURL env.
175
+ if not getattr(args, "kas_endpoint", None) and os.environ.get("KASURL"):
176
+ args.kas_endpoint = os.environ["KASURL"]
177
+
178
+ if platform_url:
179
+ builder.set_platform_endpoint(platform_url)
157
180
  # Auto-detect HTTP URLs and enable plaintext mode
158
- if args.platform_url.startswith("http://") and (
159
- not hasattr(args, "plaintext") or not args.plaintext
160
- ):
181
+ if platform_url.startswith("http://") and not getattr(args, "plaintext", None):
161
182
  logger.debug(
162
- f"Auto-detected HTTP URL {args.platform_url}, enabling plaintext mode"
183
+ f"Auto-detected HTTP URL {platform_url}, enabling plaintext mode"
163
184
  )
164
185
  builder.use_insecure_plaintext_connection(True)
186
+ # Keep args.platform_url set for create_tdf_config / nano KAS derivation
187
+ args.platform_url = platform_url
165
188
 
166
- if args.oidc_endpoint:
167
- builder.set_issuer_endpoint(args.oidc_endpoint)
189
+ if oidc_endpoint:
190
+ builder.set_issuer_endpoint(oidc_endpoint)
191
+ args.oidc_endpoint = oidc_endpoint
168
192
 
169
193
  _configure_auth(builder, args)
170
194
 
171
- if hasattr(args, "plaintext") and args.plaintext:
195
+ if getattr(args, "plaintext", None):
172
196
  builder.use_insecure_plaintext_connection(True)
173
197
 
174
- if args.insecure:
198
+ if getattr(args, "insecure", None):
175
199
  builder.use_insecure_skip_verify(True)
176
200
 
177
201
  _configure_kas_allowlist(builder, args)
@@ -179,6 +203,61 @@ def build_sdk(args) -> SDK:
179
203
  return builder.build()
180
204
 
181
205
 
206
+ # Features the Python SDK currently exercises honestly in community xtest Stage-1.
207
+ # Keep conservative: only advertise what encrypt/decrypt paths actually honor.
208
+ _SUPPORTED_FEATURES: frozenset[str] = frozenset(
209
+ {
210
+ "autoconfigure",
211
+ "connectrpc",
212
+ "hexless",
213
+ "kasallowlist",
214
+ }
215
+ )
216
+
217
+ _KNOWN_FEATURES: frozenset[str] = frozenset(
218
+ {
219
+ "assertions",
220
+ "assertion_verification",
221
+ "attribute_traversal",
222
+ "audit_logging",
223
+ "autoconfigure",
224
+ "better-messages-2024",
225
+ "bulk_rewrap",
226
+ "connectrpc",
227
+ "dpop",
228
+ "dpop_nonce_challenge",
229
+ "ecwrap",
230
+ "hexless",
231
+ "hexaflexible",
232
+ "kasallowlist",
233
+ "key_management",
234
+ "mechanism-rsa-4096",
235
+ "mechanism-ec-curves-384-521",
236
+ "mechanism-xwing",
237
+ "mechanism-secpmlkem",
238
+ "mechanism-mlkem",
239
+ "ns_grants",
240
+ "obligations",
241
+ }
242
+ )
243
+
244
+
245
+ def cmd_supports(args) -> int:
246
+ """Check if a feature is supported (xtest CLI contract).
247
+
248
+ Returns:
249
+ 0 if supported, 1 if not supported, 2 if unknown.
250
+
251
+ """
252
+ feature = getattr(args, "feature", None)
253
+ if feature not in _KNOWN_FEATURES:
254
+ logger.error(f"Unknown feature: {feature}")
255
+ return 2
256
+ if feature in _SUPPORTED_FEATURES:
257
+ return 0
258
+ return 1
259
+
260
+
182
261
  def create_tdf_config(sdk: SDK, args) -> TDFConfig:
183
262
  """Create TDF configuration from CLI arguments."""
184
263
  attributes = (
@@ -190,10 +269,13 @@ def create_tdf_config(sdk: SDK, args) -> TDFConfig:
190
269
  config = sdk.new_tdf_config(attributes=attributes)
191
270
 
192
271
  if hasattr(args, "kas_endpoint") and args.kas_endpoint:
193
- # Add KAS endpoints
272
+ # Explicit endpoints replace the platform-derived default; extending
273
+ # would give the same KAS two key access objects in the manifest.
194
274
  kas_endpoints = parse_kas_endpoints(args.kas_endpoint)
195
- kas_info_list = [KASInfo(url=kas_url) for kas_url in kas_endpoints]
196
- config.kas_info_list.extend(kas_info_list)
275
+ config.kas_info_list = [
276
+ KASInfo(url=kas_url, default=(i == 0))
277
+ for i, kas_url in enumerate(kas_endpoints)
278
+ ]
197
279
 
198
280
  if hasattr(args, "mime_type") and args.mime_type:
199
281
  config.mime_type = args.mime_type
@@ -550,9 +632,31 @@ Where creds.json contains:
550
632
  )
551
633
  inspect_parser.add_argument("file", help="Path to encrypted file")
552
634
 
635
+ # Supports command (xtest feature probe)
636
+ supports_parser = subparsers.add_parser(
637
+ "supports",
638
+ help="Check if a feature is supported (exit 0=yes, 1=no, 2=unknown)",
639
+ )
640
+ supports_parser.add_argument("feature", help="Feature name (e.g. ecwrap, hexless)")
641
+
553
642
  return parser
554
643
 
555
644
 
645
+ def _dispatch_command(parser, args) -> None:
646
+ """Route a parsed command to its handler."""
647
+ if args.command == "encrypt":
648
+ cmd_encrypt(args)
649
+ elif args.command == "decrypt":
650
+ cmd_decrypt(args)
651
+ elif args.command == "inspect":
652
+ cmd_inspect(args)
653
+ elif args.command == "supports":
654
+ sys.exit(cmd_supports(args))
655
+ else:
656
+ parser.print_help()
657
+ sys.exit(1)
658
+
659
+
556
660
  def main():
557
661
  """Execute the CLI entry point."""
558
662
  parser = create_parser()
@@ -567,16 +671,7 @@ def main():
567
671
  sys.exit(1)
568
672
 
569
673
  try:
570
- if args.command == "encrypt":
571
- cmd_encrypt(args)
572
- elif args.command == "decrypt":
573
- cmd_decrypt(args)
574
- elif args.command == "inspect":
575
- cmd_inspect(args)
576
- else:
577
- parser.print_help()
578
- sys.exit(1)
579
-
674
+ _dispatch_command(parser, args)
580
675
  except CLIError as e:
581
676
  logger.error(f"{e.level}: {e.message}")
582
677
  if e.cause:
@@ -703,13 +703,17 @@ class KASClient:
703
703
  session_key_type: Optional session key type (RSA_KEY_TYPE or EC_KEY_TYPE)
704
704
 
705
705
  """
706
- # Get access token for authentication if token source is available
706
+ # Rewrap always requires authentication — fail fast rather than send
707
+ # an unauthenticated request KAS will reject with a misleading
708
+ # "missing authorization header".
707
709
  access_token = None
708
710
  if self.token_source:
709
711
  try:
710
712
  access_token = self.token_source()
711
713
  except Exception as e:
712
- logging.warning(f"Failed to get access token: {e}")
714
+ raise SDKException(
715
+ f"Failed to get access token for KAS rewrap: {e}"
716
+ ) from e
713
717
 
714
718
  # Normalize the URL
715
719
  normalized_kas_url = self._normalize_kas_url(key_access.url)
@@ -290,6 +290,50 @@ class SDKBuilder:
290
290
 
291
291
  self._discover_token_endpoint_from_issuer(platform_issuer)
292
292
 
293
+ def _candidate_issuer_urls(self) -> list[str]:
294
+ """Issuer URLs to try for OIDC discovery, in order.
295
+
296
+ An endpoint that already names a realm (contains ``/realms/``) is
297
+ used verbatim — appending another realm segment would double the
298
+ path (…/realms/opentdf/realms/opentdf) and 404. A bare Keycloak
299
+ base URL gets the default realm appended, with the bare URL as a
300
+ fallback for non-Keycloak issuers.
301
+ """
302
+ base = (self.issuer_endpoint or "").rstrip("/")
303
+ if not base:
304
+ return []
305
+ if "/realms/" in base:
306
+ return [base]
307
+ return [f"{base}/realms/opentdf", base]
308
+
309
+ def _discover_token_endpoint_from_issuer_endpoint(self) -> None:
310
+ """Discover the token endpoint from the configured issuer endpoint.
311
+
312
+ Raises:
313
+ AutoConfigureException: If discovery fails for every candidate
314
+
315
+ """
316
+
317
+ def try_issuer(issuer_url: str) -> Exception | None:
318
+ try:
319
+ self._discover_token_endpoint_from_issuer(issuer_url)
320
+ except Exception as e:
321
+ return e
322
+ return None
323
+
324
+ last_error: Exception | None = None
325
+ for issuer_url in self._candidate_issuer_urls():
326
+ last_error = try_issuer(issuer_url)
327
+ if last_error is None:
328
+ return
329
+ if last_error is not None:
330
+ raise AutoConfigureException(
331
+ f"Error during token endpoint discovery: {last_error!s}"
332
+ ) from last_error
333
+ raise AutoConfigureException(
334
+ "Issuer endpoint must be configured for OIDC token discovery"
335
+ )
336
+
293
337
  def _discover_token_endpoint_from_issuer(self, issuer_url: str) -> None:
294
338
  """Discover token endpoint using OIDC discovery from issuer.
295
339
 
@@ -335,9 +379,7 @@ class SDKBuilder:
335
379
  # If platform fails and we have an explicit issuer, try that
336
380
  if self.issuer_endpoint:
337
381
  try:
338
- realm_name = "opentdf" # Default realm name
339
- issuer_url = f"{self.issuer_endpoint}/realms/{realm_name}"
340
- self._discover_token_endpoint_from_issuer(issuer_url)
382
+ self._discover_token_endpoint_from_issuer_endpoint()
341
383
  return
342
384
  except Exception:
343
385
  # Re-raise the original platform error
@@ -348,9 +390,7 @@ class SDKBuilder:
348
390
 
349
391
  # Fall back to explicit issuer endpoint
350
392
  if self.issuer_endpoint:
351
- realm_name = "opentdf" # Default realm name
352
- issuer_url = f"{self.issuer_endpoint}/realms/{realm_name}"
353
- self._discover_token_endpoint_from_issuer(issuer_url)
393
+ self._discover_token_endpoint_from_issuer_endpoint()
354
394
  return
355
395
 
356
396
  raise AutoConfigureException(
@@ -77,6 +77,22 @@ class TDF:
77
77
  if not isinstance(kas_infos, list):
78
78
  kas_infos = [kas_infos]
79
79
 
80
+ # One key access object per KAS: drop entries that only repeat an
81
+ # earlier URL (e.g. a platform-derived default plus the same KAS
82
+ # passed explicitly).
83
+ seen_urls = set()
84
+ unique_kas_infos = []
85
+ for kas in kas_infos:
86
+ url = (getattr(kas, "url", "") or "").strip()
87
+ if not url:
88
+ raise ValueError("KAS info must have a valid non-empty URL")
89
+ url_key = url.rstrip("/").lower()
90
+ if url_key in seen_urls:
91
+ continue
92
+ seen_urls.add(url_key)
93
+ unique_kas_infos.append(kas)
94
+ kas_infos = unique_kas_infos
95
+
80
96
  validated_kas_infos = []
81
97
  for kas in kas_infos:
82
98
  # If public key is missing, try to fetch it from the KAS service
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "otdf-python"
3
- version = "0.9.1"
3
+ version = "0.10.1"
4
4
  description = "Unofficial OpenTDF SDK for Python"
5
5
  readme = "README.md"
6
6
  authors = [
File without changes
File without changes
File without changes