otdf-python 0.3.0__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 (251) hide show
  1. otdf_python-0.3.0/.github/check_entitlements.sh +56 -0
  2. otdf_python-0.3.0/.github/start_opentdf_docker.sh +61 -0
  3. otdf_python-0.3.0/.github/workflows/build-python.yaml +42 -0
  4. otdf_python-0.3.0/.github/workflows/platform-integration-test.yaml +213 -0
  5. otdf_python-0.3.0/.github/workflows/release-please.yaml +139 -0
  6. otdf_python-0.3.0/.github/workflows/test-suite.yaml +121 -0
  7. otdf_python-0.3.0/.gitignore +179 -0
  8. otdf_python-0.3.0/.pre-commit-config.yaml +48 -0
  9. otdf_python-0.3.0/.release-please-config-develop.json +44 -0
  10. otdf_python-0.3.0/.release-please-config.json +42 -0
  11. otdf_python-0.3.0/.release-please-manifest-develop.json +3 -0
  12. otdf_python-0.3.0/.release-please-manifest.json +3 -0
  13. otdf_python-0.3.0/.vscode/extensions.json +5 -0
  14. otdf_python-0.3.0/.vscode/settings.json +8 -0
  15. otdf_python-0.3.0/CHANGELOG.md +12 -0
  16. otdf_python-0.3.0/LICENSE +21 -0
  17. otdf_python-0.3.0/PKG-INFO +231 -0
  18. otdf_python-0.3.0/README.md +212 -0
  19. otdf_python-0.3.0/conftest.py +68 -0
  20. otdf_python-0.3.0/docs/CONNECT_RPC_MIGRATION.md +283 -0
  21. otdf_python-0.3.0/docs/DEVELOPING.md +18 -0
  22. otdf_python-0.3.0/docs/LEGACY_VERSION.md +20 -0
  23. otdf_python-0.3.0/docs/PROTOBUF_SETUP.md +135 -0
  24. otdf_python-0.3.0/docs/RELEASES.md +205 -0
  25. otdf_python-0.3.0/otdf-python-proto/README.md +186 -0
  26. otdf_python-0.3.0/otdf-python-proto/buf.gen.yaml +28 -0
  27. otdf_python-0.3.0/otdf-python-proto/buf.lock +12 -0
  28. otdf_python-0.3.0/otdf-python-proto/buf.yaml +24 -0
  29. otdf_python-0.3.0/otdf-python-proto/proto-files/authorization/authorization.proto +305 -0
  30. otdf_python-0.3.0/otdf-python-proto/proto-files/authorization/v2/authorization.proto +171 -0
  31. otdf_python-0.3.0/otdf-python-proto/proto-files/common/common.proto +41 -0
  32. otdf_python-0.3.0/otdf-python-proto/proto-files/entity/entity.proto +41 -0
  33. otdf_python-0.3.0/otdf-python-proto/proto-files/entityresolution/entity_resolution.proto +124 -0
  34. otdf_python-0.3.0/otdf-python-proto/proto-files/entityresolution/v2/entity_resolution.proto +46 -0
  35. otdf_python-0.3.0/otdf-python-proto/proto-files/kas/kas.proto +160 -0
  36. otdf_python-0.3.0/otdf-python-proto/proto-files/logger/audit/test.proto +40 -0
  37. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/actions/actions.proto +108 -0
  38. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/attributes/attributes.proto +464 -0
  39. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/kasregistry/key_access_server_registry.proto +663 -0
  40. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/keymanagement/key_management.proto +84 -0
  41. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/namespaces/namespaces.proto +200 -0
  42. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/objects.proto +556 -0
  43. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/registeredresources/registered_resources.proto +330 -0
  44. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/resourcemapping/resource_mapping.proto +276 -0
  45. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/selectors.proto +70 -0
  46. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/subjectmapping/subject_mapping.proto +215 -0
  47. otdf_python-0.3.0/otdf-python-proto/proto-files/policy/unsafe/unsafe.proto +209 -0
  48. otdf_python-0.3.0/otdf-python-proto/proto-files/wellknownconfiguration/wellknown_configuration.proto +23 -0
  49. otdf_python-0.3.0/otdf-python-proto/pyproject.toml +32 -0
  50. otdf_python-0.3.0/otdf-python-proto/scripts/build_connect_proto.sh +95 -0
  51. otdf_python-0.3.0/otdf-python-proto/scripts/generate_connect_proto.py +299 -0
  52. otdf_python-0.3.0/otdf-python-proto/scripts/setup_connect_rpc.py +0 -0
  53. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/__init__.py +37 -0
  54. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/__init__.py +1 -0
  55. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2.py +80 -0
  56. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2.pyi +161 -0
  57. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/authorization_pb2_connect.py +191 -0
  58. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2.py +105 -0
  59. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2.pyi +134 -0
  60. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/authorization/v2/authorization_pb2_connect.py +233 -0
  61. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/common/__init__.py +1 -0
  62. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/common/common_pb2.py +52 -0
  63. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/common/common_pb2.pyi +61 -0
  64. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entity/__init__.py +1 -0
  65. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entity/entity_pb2.py +47 -0
  66. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entity/entity_pb2.pyi +50 -0
  67. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/__init__.py +1 -0
  68. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2.py +57 -0
  69. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2.pyi +55 -0
  70. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/entity_resolution_pb2_connect.py +149 -0
  71. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.py +55 -0
  72. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2.pyi +55 -0
  73. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/entityresolution/v2/entity_resolution_pb2_connect.py +149 -0
  74. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/kas/__init__.py +9 -0
  75. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2.py +103 -0
  76. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2.pyi +170 -0
  77. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/kas/kas_pb2_connect.py +192 -0
  78. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/__init__.py +1 -0
  79. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/authorization/authorization_pb2_grpc.py +163 -0
  80. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/authorization/v2/authorization_pb2_grpc.py +206 -0
  81. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/common/common_pb2_grpc.py +4 -0
  82. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entity/entity_pb2_grpc.py +4 -0
  83. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entityresolution/entity_resolution_pb2_grpc.py +122 -0
  84. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/entityresolution/v2/entity_resolution_pb2_grpc.py +120 -0
  85. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/kas/kas_pb2_grpc.py +172 -0
  86. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/logger/audit/test_pb2_grpc.py +4 -0
  87. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/actions/actions_pb2_grpc.py +249 -0
  88. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/attributes/attributes_pb2_grpc.py +873 -0
  89. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/kasregistry/key_access_server_registry_pb2_grpc.py +602 -0
  90. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/keymanagement/key_management_pb2_grpc.py +251 -0
  91. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/namespaces/namespaces_pb2_grpc.py +427 -0
  92. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/objects_pb2_grpc.py +4 -0
  93. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/registeredresources/registered_resources_pb2_grpc.py +524 -0
  94. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/resourcemapping/resource_mapping_pb2_grpc.py +516 -0
  95. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/selectors_pb2_grpc.py +4 -0
  96. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/subjectmapping/subject_mapping_pb2_grpc.py +551 -0
  97. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/policy/unsafe/unsafe_pb2_grpc.py +485 -0
  98. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/legacy_grpc/wellknownconfiguration/wellknown_configuration_pb2_grpc.py +77 -0
  99. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/logger/__init__.py +1 -0
  100. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/logger/audit/test_pb2.py +43 -0
  101. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/logger/audit/test_pb2.pyi +45 -0
  102. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/__init__.py +1 -0
  103. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2.py +75 -0
  104. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2.pyi +87 -0
  105. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/actions/actions_pb2_connect.py +275 -0
  106. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2.py +234 -0
  107. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2.pyi +328 -0
  108. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/attributes/attributes_pb2_connect.py +863 -0
  109. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.py +266 -0
  110. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2.pyi +450 -0
  111. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/kasregistry/key_access_server_registry_pb2_connect.py +611 -0
  112. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2.py +79 -0
  113. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2.pyi +87 -0
  114. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/keymanagement/key_management_pb2_connect.py +275 -0
  115. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2.py +117 -0
  116. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2.pyi +147 -0
  117. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/namespaces/namespaces_pb2_connect.py +443 -0
  118. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/objects_pb2.py +150 -0
  119. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/objects_pb2.pyi +464 -0
  120. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2.py +139 -0
  121. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2.pyi +196 -0
  122. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/registeredresources/registered_resources_pb2_connect.py +527 -0
  123. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.py +139 -0
  124. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2.pyi +194 -0
  125. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/resourcemapping/resource_mapping_pb2_connect.py +527 -0
  126. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/selectors_pb2.py +57 -0
  127. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/selectors_pb2.pyi +90 -0
  128. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.py +127 -0
  129. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2.pyi +189 -0
  130. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/subjectmapping/subject_mapping_pb2_connect.py +569 -0
  131. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2.py +113 -0
  132. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2.pyi +145 -0
  133. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/policy/unsafe/unsafe_pb2_connect.py +485 -0
  134. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/__init__.py +1 -0
  135. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.py +51 -0
  136. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2.pyi +32 -0
  137. otdf_python-0.3.0/otdf-python-proto/src/otdf_python_proto/wellknownconfiguration/wellknown_configuration_pb2_connect.py +107 -0
  138. otdf_python-0.3.0/otdf-python-proto/uv.lock +759 -0
  139. otdf_python-0.3.0/pyproject.toml +84 -0
  140. otdf_python-0.3.0/src/otdf_python/__init__.py +25 -0
  141. otdf_python-0.3.0/src/otdf_python/__main__.py +12 -0
  142. otdf_python-0.3.0/src/otdf_python/address_normalizer.py +84 -0
  143. otdf_python-0.3.0/src/otdf_python/aesgcm.py +55 -0
  144. otdf_python-0.3.0/src/otdf_python/assertion_config.py +84 -0
  145. otdf_python-0.3.0/src/otdf_python/asym_crypto.py +85 -0
  146. otdf_python-0.3.0/src/otdf_python/asym_decryption.py +53 -0
  147. otdf_python-0.3.0/src/otdf_python/asym_encryption.py +75 -0
  148. otdf_python-0.3.0/src/otdf_python/auth_headers.py +21 -0
  149. otdf_python-0.3.0/src/otdf_python/autoconfigure_utils.py +113 -0
  150. otdf_python-0.3.0/src/otdf_python/cli.py +570 -0
  151. otdf_python-0.3.0/src/otdf_python/collection_store.py +41 -0
  152. otdf_python-0.3.0/src/otdf_python/collection_store_impl.py +22 -0
  153. otdf_python-0.3.0/src/otdf_python/config.py +69 -0
  154. otdf_python-0.3.0/src/otdf_python/connect_client.py +0 -0
  155. otdf_python-0.3.0/src/otdf_python/constants.py +1 -0
  156. otdf_python-0.3.0/src/otdf_python/crypto_utils.py +78 -0
  157. otdf_python-0.3.0/src/otdf_python/dpop.py +81 -0
  158. otdf_python-0.3.0/src/otdf_python/ecc_mode.py +32 -0
  159. otdf_python-0.3.0/src/otdf_python/eckeypair.py +75 -0
  160. otdf_python-0.3.0/src/otdf_python/header.py +143 -0
  161. otdf_python-0.3.0/src/otdf_python/invalid_zip_exception.py +8 -0
  162. otdf_python-0.3.0/src/otdf_python/kas_client.py +603 -0
  163. otdf_python-0.3.0/src/otdf_python/kas_connect_rpc_client.py +207 -0
  164. otdf_python-0.3.0/src/otdf_python/kas_info.py +25 -0
  165. otdf_python-0.3.0/src/otdf_python/kas_key_cache.py +52 -0
  166. otdf_python-0.3.0/src/otdf_python/key_type.py +31 -0
  167. otdf_python-0.3.0/src/otdf_python/key_type_constants.py +43 -0
  168. otdf_python-0.3.0/src/otdf_python/manifest.py +215 -0
  169. otdf_python-0.3.0/src/otdf_python/nanotdf.py +553 -0
  170. otdf_python-0.3.0/src/otdf_python/nanotdf_ecdsa_struct.py +132 -0
  171. otdf_python-0.3.0/src/otdf_python/nanotdf_type.py +43 -0
  172. otdf_python-0.3.0/src/otdf_python/policy_binding_serializer.py +39 -0
  173. otdf_python-0.3.0/src/otdf_python/policy_info.py +78 -0
  174. otdf_python-0.3.0/src/otdf_python/policy_object.py +22 -0
  175. otdf_python-0.3.0/src/otdf_python/policy_stub.py +2 -0
  176. otdf_python-0.3.0/src/otdf_python/resource_locator.py +44 -0
  177. otdf_python-0.3.0/src/otdf_python/sdk.py +528 -0
  178. otdf_python-0.3.0/src/otdf_python/sdk_builder.py +448 -0
  179. otdf_python-0.3.0/src/otdf_python/sdk_exceptions.py +16 -0
  180. otdf_python-0.3.0/src/otdf_python/symmetric_and_payload_config.py +30 -0
  181. otdf_python-0.3.0/src/otdf_python/tdf.py +479 -0
  182. otdf_python-0.3.0/src/otdf_python/tdf_reader.py +153 -0
  183. otdf_python-0.3.0/src/otdf_python/tdf_writer.py +23 -0
  184. otdf_python-0.3.0/src/otdf_python/token_source.py +34 -0
  185. otdf_python-0.3.0/src/otdf_python/version.py +57 -0
  186. otdf_python-0.3.0/src/otdf_python/zip_reader.py +47 -0
  187. otdf_python-0.3.0/src/otdf_python/zip_writer.py +70 -0
  188. otdf_python-0.3.0/tests/__init__.py +1 -0
  189. otdf_python-0.3.0/tests/config_pydantic.py +104 -0
  190. otdf_python-0.3.0/tests/integration/conftest.py +74 -0
  191. otdf_python-0.3.0/tests/integration/otdfctl_only/test_otdfctl_generated_fixtures.py +113 -0
  192. otdf_python-0.3.0/tests/integration/otdfctl_to_python/test_cli_comparison.py +178 -0
  193. otdf_python-0.3.0/tests/integration/otdfctl_to_python/test_cli_decrypt.py +191 -0
  194. otdf_python-0.3.0/tests/integration/otdfctl_to_python/test_cli_inspect.py +122 -0
  195. otdf_python-0.3.0/tests/integration/otdfctl_to_python/test_tdf_reader_integration.py +272 -0
  196. otdf_python-0.3.0/tests/integration/python_only/test_kas_client_integration.py +244 -0
  197. otdf_python-0.3.0/tests/integration/support_sdk.py +75 -0
  198. otdf_python-0.3.0/tests/integration/test_cli_integration.py +304 -0
  199. otdf_python-0.3.0/tests/integration/test_cli_tdf_validation.py +568 -0
  200. otdf_python-0.3.0/tests/integration/test_data/empty_file.txt +0 -0
  201. otdf_python-0.3.0/tests/integration/test_data/sample_binary.png +0 -0
  202. otdf_python-0.3.0/tests/integration/test_data/sample_text.txt +5 -0
  203. otdf_python-0.3.0/tests/integration/test_data/sample_with_attributes.txt +4 -0
  204. otdf_python-0.3.0/tests/integration/test_pe_interaction.py +96 -0
  205. otdf_python-0.3.0/tests/mock_crypto.py +35 -0
  206. otdf_python-0.3.0/tests/server_logs.py +97 -0
  207. otdf_python-0.3.0/tests/support_cli_args.py +183 -0
  208. otdf_python-0.3.0/tests/support_common.py +90 -0
  209. otdf_python-0.3.0/tests/support_otdfctl.py +26 -0
  210. otdf_python-0.3.0/tests/support_otdfctl_args.py +280 -0
  211. otdf_python-0.3.0/tests/test_address_normalizer.py +73 -0
  212. otdf_python-0.3.0/tests/test_aesgcm.py +35 -0
  213. otdf_python-0.3.0/tests/test_assertion_config.py +56 -0
  214. otdf_python-0.3.0/tests/test_asym_encryption.py +13 -0
  215. otdf_python-0.3.0/tests/test_autoconfigure_utils.py +50 -0
  216. otdf_python-0.3.0/tests/test_cli.py +188 -0
  217. otdf_python-0.3.0/tests/test_collection_store.py +43 -0
  218. otdf_python-0.3.0/tests/test_config.py +35 -0
  219. otdf_python-0.3.0/tests/test_crypto_utils.py +38 -0
  220. otdf_python-0.3.0/tests/test_eckeypair.py +34 -0
  221. otdf_python-0.3.0/tests/test_header.py +38 -0
  222. otdf_python-0.3.0/tests/test_inner_classes.py +67 -0
  223. otdf_python-0.3.0/tests/test_kas_client.py +526 -0
  224. otdf_python-0.3.0/tests/test_kas_key_cache.py +44 -0
  225. otdf_python-0.3.0/tests/test_kas_key_management.py +121 -0
  226. otdf_python-0.3.0/tests/test_key_type.py +30 -0
  227. otdf_python-0.3.0/tests/test_log_collection.py +39 -0
  228. otdf_python-0.3.0/tests/test_manifest.py +65 -0
  229. otdf_python-0.3.0/tests/test_manifest_format.py +103 -0
  230. otdf_python-0.3.0/tests/test_nanotdf.py +70 -0
  231. otdf_python-0.3.0/tests/test_nanotdf_ecdsa_struct.py +91 -0
  232. otdf_python-0.3.0/tests/test_nanotdf_integration.py +42 -0
  233. otdf_python-0.3.0/tests/test_nanotdf_type.py +44 -0
  234. otdf_python-0.3.0/tests/test_policy_object.py +38 -0
  235. otdf_python-0.3.0/tests/test_sdk.py +97 -0
  236. otdf_python-0.3.0/tests/test_sdk_builder.py +214 -0
  237. otdf_python-0.3.0/tests/test_sdk_exceptions.py +22 -0
  238. otdf_python-0.3.0/tests/test_sdk_mock.py +58 -0
  239. otdf_python-0.3.0/tests/test_sdk_tdf_integration.py +263 -0
  240. otdf_python-0.3.0/tests/test_tdf.py +58 -0
  241. otdf_python-0.3.0/tests/test_tdf_key_management.py +151 -0
  242. otdf_python-0.3.0/tests/test_tdf_reader.py +155 -0
  243. otdf_python-0.3.0/tests/test_tdf_writer.py +60 -0
  244. otdf_python-0.3.0/tests/test_token_source.py +42 -0
  245. otdf_python-0.3.0/tests/test_url_normalization.py +50 -0
  246. otdf_python-0.3.0/tests/test_use_plaintext_flow.py +103 -0
  247. otdf_python-0.3.0/tests/test_validate_otdf_python.py +191 -0
  248. otdf_python-0.3.0/tests/test_version.py +39 -0
  249. otdf_python-0.3.0/tests/test_zip_reader.py +70 -0
  250. otdf_python-0.3.0/tests/test_zip_writer.py +35 -0
  251. otdf_python-0.3.0/uv.lock +1274 -0
@@ -0,0 +1,56 @@
1
+ #!/bin/bash
2
+
3
+ # Derive additional environment variables
4
+ TOKEN_URL="${OIDC_OP_TOKEN_ENDPOINT}"
5
+ OTDF_HOST_AND_PORT="${OPENTDF_PLATFORM_HOST}"
6
+ OTDF_CLIENT="${OPENTDF_CLIENT_ID}"
7
+ OTDF_CLIENT_SECRET="${OPENTDF_CLIENT_SECRET}"
8
+
9
+ echo "🔧 Environment Configuration:"
10
+ echo " TOKEN_URL: ${TOKEN_URL}"
11
+ echo " OTDF_HOST_AND_PORT: ${OTDF_HOST_AND_PORT}"
12
+ echo " OTDF_CLIENT: ${OTDF_CLIENT}"
13
+ echo " OTDF_CLIENT_SECRET: ${OTDF_CLIENT_SECRET}"
14
+ echo ""
15
+
16
+ get_token() {
17
+ curl -k --location "$TOKEN_URL" \
18
+ --header "X-VirtruPubKey;" \
19
+ --header "Content-Type: application/x-www-form-urlencoded" \
20
+ --data-urlencode "grant_type=client_credentials" \
21
+ --data-urlencode "client_id=$OTDF_CLIENT" \
22
+ --data-urlencode "client_secret=$OTDF_CLIENT_SECRET"
23
+ }
24
+
25
+ echo "🔐 Getting access token..."
26
+ BEARER=$( get_token | jq -r '.access_token' )
27
+ # NOTE: It's always okay to print this token, because it will
28
+ # only be valid / available in dummy / dev scenarios
29
+ [[ "${DEBUG:-}" == "1" ]] && echo "Got Access Token: ${BEARER}"
30
+ echo ""
31
+
32
+ # Array of usernames to check
33
+ USERNAMES=("opentdf" "sample-user" "sample-user-1" "cli-client" "opentdf-sdk")
34
+
35
+ for USERNAME in "${USERNAMES[@]}"; do
36
+ echo "👤 Fetching entitlements for username: ${USERNAME}"
37
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
38
+
39
+ grpcurl -plaintext \
40
+ -H "authorization: Bearer $BEARER" \
41
+ -d "{
42
+ \"entities\": [
43
+ {
44
+ \"userName\": \"$USERNAME\"
45
+ }
46
+ ]
47
+ }" \
48
+ "$OTDF_HOST_AND_PORT" \
49
+ authorization.AuthorizationService/GetEntitlements
50
+
51
+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
52
+ echo "✅ Entitlements retrieval complete for ${USERNAME}!"
53
+ echo ""
54
+ done
55
+
56
+ echo "🎉 All entitlement checks completed!"
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -euo pipefail
4
+
5
+ if ! [ -d platform ]; then
6
+ git clone https://github.com/opentdf/platform.git
7
+ fi
8
+ cd platform
9
+ git checkout 3360befcb3e6e9791d7bfd2e89128aee0e7d2818 # Branch 'DSPX-1539-keytoolnomore'
10
+
11
+ yq -i '.realms[0].clients[0].client.directAccessGrantsEnabled = true | .realms[0].clients[0].client.serviceAccountsEnabled = true' service/cmd/keycloak_data.yaml
12
+
13
+ yq -i '.realms[0].clients[1].client.directAccessGrantsEnabled = true | .realms[0].clients[1].client.serviceAccountsEnabled = true' service/cmd/keycloak_data.yaml
14
+
15
+ yq -i '.realms[0].clients[4].client.directAccessGrantsEnabled = true | .realms[0].clients[4].client.serviceAccountsEnabled = true' service/cmd/keycloak_data.yaml
16
+
17
+
18
+ if ! [ -d ./keys ]; then
19
+ go mod download
20
+
21
+ go mod verify
22
+
23
+ .github/scripts/init-temp-keys.sh
24
+ cp opentdf-example.yaml opentdf.yaml
25
+
26
+ # Edit 'opentdf.yaml' for our use case
27
+ yq -i 'del(.db) | .services.entityresolution.url = "http://localhost:8888/auth" | .server.auth.issuer = "http://localhost:8888/auth/realms/opentdf"' opentdf.yaml
28
+ # The above expression can also be written as 3 separate commands:
29
+ # yq -i 'del(.db)' opentdf.yaml
30
+ # yq -i '.services.entityresolution.url = "http://localhost:8888/auth"' opentdf.yaml
31
+ # yq -i '.server.auth.issuer = "http://localhost:8888/auth/realms/opentdf"' opentdf.yaml
32
+
33
+ yq -i '
34
+ .server.cryptoProvider = {
35
+ "type": "standard",
36
+ "standard": {
37
+ "keys": [
38
+ {
39
+ "kid": "r1",
40
+ "alg": "rsa:2048",
41
+ "private": "kas-private.pem",
42
+ "cert": "kas-cert.pem"
43
+ },
44
+ {
45
+ "kid": "e1",
46
+ "alg": "ec:secp256r1",
47
+ "private": "kas-ec-private.pem",
48
+ "cert": "kas-ec-cert.pem"
49
+ }
50
+ ]
51
+ }
52
+ }
53
+ ' opentdf.yaml
54
+ chmod -R 700 ./keys
55
+ fi
56
+
57
+ docker compose up -d --wait --wait-timeout 360
58
+
59
+ go run ./service provision keycloak
60
+
61
+ go run ./service provision fixtures
@@ -0,0 +1,42 @@
1
+ # Build otdf-python wheel using uv and output the wheel path for downstream workflows
2
+ name: "Build Python Wheel"
3
+ on:
4
+ push:
5
+ branches:
6
+ - chore/rewrite
7
+ pull_request:
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-22.04
12
+ outputs:
13
+ wheel: ${{ steps.find_wheel.outputs.wheel_path }}
14
+ steps:
15
+ - name: Checkout this repo
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Set up uv
19
+ uses: astral-sh/setup-uv@v6
20
+ with:
21
+ enable-cache: true
22
+ cache-dependency-glob: "uv.lock"
23
+
24
+ - name: Build otdf-python wheel using uv
25
+ run: |
26
+ uv sync --frozen
27
+ uv build
28
+ shell: bash
29
+
30
+ - name: Find built wheel
31
+ id: find_wheel
32
+ run: |
33
+ wheel_path=$(ls dist/*.whl | head -n1)
34
+ echo "wheel_path=$wheel_path" >> $GITHUB_OUTPUT
35
+ shell: bash
36
+
37
+ # - name: Upload wheel as artifact
38
+ # uses: actions/upload-artifact@v4
39
+ # with:
40
+ # name: python-wheel
41
+ # path: dist/*.whl
42
+ # overwrite: true
@@ -0,0 +1,213 @@
1
+ # Based on
2
+ # https://github.com/opentdf/java-sdk/blob/v0.6.1/.github/workflows/checks.yaml
3
+ #
4
+ # Except, that this is a "Composite Action", and specifies 'shell: bash' for
5
+ # each 'run:' step.
6
+ name: "NEW: Platform Integration testing"
7
+
8
+ on:
9
+ workflow_call:
10
+ inputs:
11
+ wheel:
12
+ required: true
13
+ type: string
14
+ python_version:
15
+ required: true
16
+ type: string
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ integration_test:
23
+ runs-on: ubuntu-22.04
24
+ steps:
25
+ - name: Checkout this repo
26
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
27
+
28
+ # - uses: bufbuild/buf-setup-action@382440cdb8ec7bc25a68d7b4711163d95f7cc3aa
29
+ # with:
30
+ # github_token: ${{ secrets.GITHUB_TOKEN }}
31
+
32
+ - name: Check out platform
33
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
34
+ with:
35
+ repository: opentdf/platform
36
+ ref: main
37
+ path: platform
38
+ - name: Set up go
39
+ uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
40
+ with:
41
+ go-version: "1.24.x"
42
+ check-latest: false
43
+ cache-dependency-path: |
44
+ platform/service/go.sum
45
+ platform/examples/go.sum
46
+ platform/protocol/go/go.sum
47
+ platform/sdk/go.sum
48
+ - run: go mod download
49
+ shell: bash
50
+ working-directory: platform
51
+ - run: go mod verify
52
+ shell: bash
53
+ working-directory: platform
54
+ - name: Create keys
55
+ shell: bash
56
+ run: |
57
+ .github/scripts/init-temp-keys.sh
58
+ # Edit Keycloak sample file for our use case
59
+ yq -i '.realms[0].clients[0].client.directAccessGrantsEnabled = true | .realms[0].clients[0].client.serviceAccountsEnabled = true' service/cmd/keycloak_data.yaml
60
+ yq -i '.realms[0].clients[1].client.directAccessGrantsEnabled = true | .realms[0].clients[1].client.serviceAccountsEnabled = true' service/cmd/keycloak_data.yaml
61
+ yq -i '.realms[0].clients[4].client.directAccessGrantsEnabled = true | .realms[0].clients[4].client.serviceAccountsEnabled = true' service/cmd/keycloak_data.yaml
62
+
63
+ cp opentdf-example.yaml opentdf.yaml
64
+ # Edit 'opentdf.yaml' for our use case
65
+ yq -i 'del(.db) | .services.entityresolution.url = "http://localhost:8888/auth" | .server.auth.issuer = "http://localhost:8888/auth/realms/opentdf"' opentdf.yaml
66
+ # The above expression can also be written as 3 separate commands:
67
+ # yq -i 'del(.db)' opentdf.yaml
68
+ # yq -i '.services.entityresolution.url = "http://localhost:8888/auth"' opentdf.yaml
69
+ # yq -i '.server.auth.issuer = "http://localhost:8888/auth/realms/opentdf"' opentdf.yaml
70
+ yq -i '
71
+ .server.cryptoProvider = {
72
+ "type": "standard",
73
+ "standard": {
74
+ "keys": [
75
+ {
76
+ "kid": "r1",
77
+ "alg": "rsa:2048",
78
+ "private": "kas-private.pem",
79
+ "cert": "kas-cert.pem"
80
+ },
81
+ {
82
+ "kid": "e1",
83
+ "alg": "ec:secp256r1",
84
+ "private": "kas-ec-private.pem",
85
+ "cert": "kas-ec-cert.pem"
86
+ }
87
+ ]
88
+ }
89
+ }
90
+ ' opentdf.yaml
91
+ sudo chmod -R 777 ./keys
92
+ working-directory: platform
93
+ # - name: Trust the locally issued cert
94
+ # run: |
95
+ # keytool \
96
+ # -importcert \
97
+ # -storepass changeit \
98
+ # -noprompt \
99
+ # -file localhost.crt \
100
+ # -keystore $JAVA_HOME/lib/security/cacerts \
101
+ # -alias localhost-for-tests
102
+ # working-directory: platform/keys
103
+ - name: Bring the services up
104
+ shell: bash
105
+ run: docker compose up -d --wait --wait-timeout 240
106
+ working-directory: platform
107
+ - name: Provision keycloak
108
+ shell: bash
109
+ run: go run ./service provision keycloak
110
+ working-directory: platform
111
+ - name: Provision fixtures
112
+ shell: bash
113
+ run: go run ./service provision fixtures
114
+ working-directory: platform
115
+ - name: Start server in background
116
+ uses: JarvusInnovations/background-action@2428e7b970a846423095c79d43f759abf979a635
117
+ with:
118
+ run: |
119
+ go run ./service start
120
+ wait-on: |
121
+ tcp:localhost:8080
122
+ log-output-if: true
123
+ wait-for: 90s
124
+ working-directory: platform
125
+ - name: Get grpcurl
126
+ shell: bash
127
+ run: go install github.com/fullstorydev/grpcurl/cmd/grpcurl@v1.8.9
128
+ - name: Make sure that the platform is up
129
+ shell: bash
130
+ run: |
131
+ grpcurl -plaintext localhost:8080 list && \
132
+ grpcurl -plaintext localhost:8080 kas.AccessService/PublicKey
133
+
134
+ - name: Install otdfctl
135
+ run: go install github.com/opentdf/otdfctl@latest
136
+ shell: bash
137
+
138
+ - name: Create creds.json for otdfctl
139
+ run: echo -n '{"clientId":"opentdf-sdk","clientSecret":"secret"}' > creds.json
140
+ shell: bash
141
+
142
+ - name: Create a plaintext file
143
+ run: echo "integration test secret" > secret.txt
144
+ shell: bash
145
+
146
+ - name: Encrypt file with otdfctl (no attributes)
147
+ run: |
148
+ export PATH=$PATH:$(go env GOPATH)/bin
149
+ otdfctl encrypt -o secret.txt.tdf --host http://localhost:8080 --tls-no-verify --with-client-creds-file creds.json secret.txt
150
+ shell: bash
151
+
152
+ - name: Set up uv
153
+ uses: astral-sh/setup-uv@v6
154
+ with:
155
+ enable-cache: true
156
+ cache-dependency-glob: "uv.lock"
157
+
158
+ - name: Run all tests, minus integration tests
159
+ env:
160
+ OPENTDF_CLIENT_ID: "opentdf"
161
+ OPENTDF_CLIENT_SECRET: "secret"
162
+ OPENTDF_HOSTNAME: "localhost:8080"
163
+ OIDC_TOKEN_ENDPOINT: "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token"
164
+ OPENTDF_KAS_URL: "http://localhost:8080/kas"
165
+ INSECURE_SKIP_VERIFY: "TRUE"
166
+ TEST_OPENTDF_ATTRIBUTE_1: "https://example.net/attr/attr1/value/value1"
167
+ TEST_OPENTDF_ATTRIBUTE_2: "https://example.com/attr/attr1/value/value1"
168
+ run: |
169
+ uv sync
170
+ # Skip the tests marked "integration"
171
+ uv run pytest -m "not integration" --tb=short -vv tests
172
+ shell: bash
173
+
174
+ - name: Run integration tests
175
+ env:
176
+ OPENTDF_CLIENT_ID: "opentdf"
177
+ OPENTDF_CLIENT_SECRET: "secret"
178
+ OPENTDF_PLATFORM_HOST: "localhost:8080"
179
+ OPENTDF_PLATFORM_URL: "http://localhost:8080"
180
+ OIDC_OP_TOKEN_ENDPOINT: "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token"
181
+ OPENTDF_KAS_URL: "http://localhost:8080/kas"
182
+ INSECURE_SKIP_VERIFY: "TRUE"
183
+ TEST_OPENTDF_ATTRIBUTE_1: "https://example.net/attr/attr1/value/value1"
184
+ TEST_OPENTDF_ATTRIBUTE_2: "https://example.com/attr/attr1/value/value1"
185
+ run: |
186
+ # Run check_entitlements.sh
187
+ ./.github/check_entitlements.sh
188
+
189
+ uv sync
190
+ # Skip the tests marked "integration"
191
+ uv run pytest -m "integration" --tb=short -vv tests
192
+ shell: bash
193
+
194
+ # platform-xtest:
195
+ # permissions:
196
+ # contents: read
197
+ # packages: read
198
+ # needs: platform-integration
199
+ # uses: opentdf/tests/.github/workflows/xtest.yml@main
200
+ # with:
201
+ # java-ref: ${{ github.ref }}
202
+
203
+ # ci:
204
+ # needs:
205
+ # - platform-integration
206
+ # - platform-xtest
207
+ # - mavenverify
208
+ # - pr
209
+ # runs-on: ubuntu-22.04
210
+ # if: always()
211
+ # steps:
212
+ # - if: contains(needs.*.result, 'failure')
213
+ # run: echo "Failed due to ${{ contains(needs.*.result, 'failure') }}" && exit 1
@@ -0,0 +1,139 @@
1
+ name: Release Please
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - develop
8
+ workflow_dispatch:
9
+
10
+ permissions:
11
+ contents: write
12
+ pull-requests: write
13
+
14
+ jobs:
15
+ # Run full test suite before any release operations
16
+ test-suite:
17
+ uses: ./.github/workflows/test-suite.yaml
18
+
19
+ release-please:
20
+ runs-on: ubuntu-latest
21
+ needs: test-suite
22
+ if: needs.test-suite.outputs.tests_passed == 'true'
23
+ outputs:
24
+ releases_created: ${{ steps.release-develop.outputs.releases_created || steps.release-main.outputs.releases_created }}
25
+ paths_released: ${{ steps.release-develop.outputs.paths_released || steps.release-main.outputs.paths_released }}
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+
29
+ # Release-please for develop branch (creates alpha prereleases)
30
+ - uses: googleapis/release-please-action@v4
31
+ if: github.ref == 'refs/heads/develop'
32
+ id: release-develop
33
+ with:
34
+ config-file: .release-please-config-develop.json
35
+ manifest-file: .release-please-manifest-develop.json
36
+ target-branch: develop
37
+ token: ${{ secrets.GITHUB_TOKEN }}
38
+
39
+ # Release-please for main branch (creates stable releases)
40
+ - uses: googleapis/release-please-action@v4
41
+ if: github.ref == 'refs/heads/main'
42
+ id: release-main
43
+ with:
44
+ config-file: .release-please-config.json
45
+ manifest-file: .release-please-manifest.json
46
+ target-branch: main
47
+ token: ${{ secrets.GITHUB_TOKEN }}
48
+
49
+ # Trigger appropriate publish workflows based on release type
50
+ trigger-publish:
51
+ permissions:
52
+ contents: write
53
+ # This permission is mandatory for PyPI's trusted publishing
54
+ id-token: write
55
+ needs: release-please
56
+ if: ${{ needs.release-please.outputs.releases_created }}
57
+ runs-on: ubuntu-latest
58
+ steps:
59
+ - uses: actions/checkout@v4
60
+
61
+ - name: Install uv
62
+ uses: astral-sh/setup-uv@v6
63
+ with:
64
+ version: "latest"
65
+
66
+ - name: Build package
67
+ shell: bash
68
+ run: |
69
+ uv build
70
+
71
+ - name: Test import
72
+ shell: bash
73
+ run: |
74
+ uv run python -c 'import otdf_python; print("Package imported successfully")'
75
+
76
+ # While we improve the release process, prevent publishing to TestPyPI for versions <= 0.3.2
77
+ - name: Store version and determine if should publish to TestPyPI
78
+ id: check_version
79
+ shell: bash
80
+ run: |
81
+ PROJECT_VERSION=$(uv version --short)
82
+ echo "PROJECT_VERSION=$PROJECT_VERSION" >> $GITHUB_ENV
83
+
84
+ if [[ "$PROJECT_VERSION" =~ [0-9]+\.[0-9]+\.[0-9]+a[0-9]+ ]]; then
85
+ echo "is_alpha=true" >> $GITHUB_OUTPUT
86
+ echo "Alpha version detected: $PROJECT_VERSION"
87
+ else
88
+ echo "is_alpha=false" >> $GITHUB_OUTPUT
89
+ echo "Stable version detected: $PROJECT_VERSION"
90
+ fi
91
+
92
+ # Remove any alpha/beta/rc suffixes for comparison
93
+ CLEAN_VERSION=$(echo "$PROJECT_VERSION" | sed 's/[a-zA-Z].*//')
94
+ echo "clean_version=$CLEAN_VERSION" >> $GITHUB_OUTPUT
95
+
96
+ # Convert versions to comparable format (e.g., "0.3.2" -> "000300020000")
97
+ version_to_number() {
98
+ echo "$1" | awk -F. '{ printf("%04d%04d%04d\n", $1,$2,$3); }'
99
+ }
100
+
101
+ CURRENT_NUM=$(version_to_number "$CLEAN_VERSION")
102
+ THRESHOLD_NUM=$(version_to_number "0.3.2")
103
+
104
+ if [ "$CURRENT_NUM" -gt "$THRESHOLD_NUM" ]; then
105
+ echo "should_publish=true" >> $GITHUB_OUTPUT
106
+ echo "Version $PROJECT_VERSION (clean: $CLEAN_VERSION) is > 0.3.2, will publish to TestPyPI"
107
+ else
108
+ echo "should_publish=false" >> $GITHUB_OUTPUT
109
+ echo "Version $PROJECT_VERSION (clean: $CLEAN_VERSION) is <= 0.3.2, skipping TestPyPI publish"
110
+ fi
111
+
112
+ # For develop branch: trigger TestPyPI build (alpha prereleases go to TestPyPI from develop)
113
+
114
+ # Publish with "trusted publisher" mechanism:
115
+ # https://docs.pypi.org/trusted-publishers/
116
+ #
117
+ # Requires GHA token permission (above in YAML) and PyPI management:
118
+ # https://test.pypi.org/manage/project/otdf-python/settings/publishing/
119
+ - name: Publish package distributions to TestPyPI
120
+ if: github.ref == 'refs/heads/develop' && steps.check_version.outputs.should_publish == 'true'
121
+ uses: pypa/gh-action-pypi-publish@release/v1
122
+ with:
123
+ repository-url: https://test.pypi.org/legacy/
124
+ verbose: true
125
+ packages-dir: dist/
126
+
127
+ # For main branch: trigger PyPI build (stable releases go to PyPI from main)
128
+ # Publish with "trusted publisher" mechanism:
129
+ # https://docs.pypi.org/trusted-publishers/
130
+ #
131
+ # Requires GHA token permission (above in YAML) and PyPI management:
132
+ # https://pypi.org/manage/project/otdf-python/settings/publishing/
133
+ - name: Publish package distributions to PyPI
134
+ if: github.ref == 'refs/heads/main'
135
+ uses: pypa/gh-action-pypi-publish@release/v1
136
+ with:
137
+ # repository-url: https://pypi.org/legacy/
138
+ packages-dir: dist/
139
+ verbose: true
@@ -0,0 +1,121 @@
1
+ name: Test Suite
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - develop
8
+ pull_request:
9
+ workflow_call:
10
+ outputs:
11
+ tests_passed:
12
+ description: "Whether all tests passed"
13
+ value: ${{ jobs.report.outputs.success }}
14
+ workflow_dispatch:
15
+
16
+ jobs:
17
+ # Step 1: Fast lint and format checks (fail fast on code style)
18
+ lint-check:
19
+ runs-on: ubuntu-22.04
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Set up uv
24
+ uses: astral-sh/setup-uv@v6
25
+ with:
26
+ enable-cache: true
27
+ cache-dependency-glob: "uv.lock"
28
+
29
+ - name: Run linting (fail fast)
30
+ run: |
31
+ uv sync --frozen
32
+ uv run ruff check
33
+ uv run ruff format --check
34
+
35
+ # Step 2: Build (only after linting passes)
36
+ build:
37
+ runs-on: ubuntu-22.04
38
+ needs: lint-check
39
+ outputs:
40
+ wheel: ${{ steps.find_wheel.outputs.wheel_path }}
41
+ steps:
42
+ - name: Checkout this repo
43
+ uses: actions/checkout@v4
44
+
45
+ - name: Set up uv
46
+ uses: astral-sh/setup-uv@v6
47
+ with:
48
+ enable-cache: true
49
+ cache-dependency-glob: "uv.lock"
50
+
51
+ - name: Build otdf-python wheel using uv
52
+ run: |
53
+ uv sync --frozen
54
+ uv build
55
+ shell: bash
56
+
57
+ - name: Find built wheel
58
+ id: find_wheel
59
+ run: |
60
+ wheel_path=$(ls dist/*.whl | head -n1)
61
+ echo "wheel_path=$wheel_path" >> $GITHUB_OUTPUT
62
+ shell: bash
63
+
64
+ - name: Upload wheel as artifact
65
+ uses: actions/upload-artifact@v4
66
+ with:
67
+ name: python-wheel
68
+ path: dist/*.whl
69
+
70
+ # Step 3: Unit tests (only after build succeeds)
71
+ unit-tests:
72
+ runs-on: ubuntu-22.04
73
+ needs: build
74
+ steps:
75
+ - uses: actions/checkout@v4
76
+
77
+ - name: Set up uv
78
+ uses: astral-sh/setup-uv@v6
79
+ with:
80
+ enable-cache: true
81
+ cache-dependency-glob: "uv.lock"
82
+
83
+ - name: Run unit tests
84
+ run: |
85
+ uv sync --frozen
86
+ uv run pytest -m "not integration" --tb=short -v tests/
87
+
88
+ # Step 4: Integration tests (only after unit tests pass)
89
+ integration-tests:
90
+ strategy:
91
+ fail-fast: true
92
+ matrix:
93
+ python3_version: ["3.10", "3.11", "3.12", "3.13"]
94
+ needs: [build, unit-tests]
95
+ uses: ./.github/workflows/platform-integration-test.yaml
96
+ with:
97
+ wheel: ${{ needs.build.outputs.wheel }}
98
+ python_version: ${{ matrix.python3_version }}
99
+
100
+ report:
101
+ runs-on: ubuntu-22.04
102
+ needs: [lint-check, build, unit-tests, integration-tests]
103
+ if: always()
104
+ outputs:
105
+ success: ${{ steps.check.outputs.success }}
106
+ steps:
107
+ - name: Check all jobs succeeded
108
+ id: check
109
+ run: |
110
+ if [[ "${{ needs.lint-check.result }}" == "success" && "${{ needs.build.result }}" == "success" && "${{ needs.unit-tests.result }}" == "success" && "${{ needs.integration-tests.result }}" == "success" ]]; then
111
+ echo "success=true" >> $GITHUB_OUTPUT
112
+ echo "✅ All tests passed!"
113
+ else
114
+ echo "success=false" >> $GITHUB_OUTPUT
115
+ echo "❌ Some tests failed:"
116
+ echo " Lint Check: ${{ needs.lint-check.result }}"
117
+ echo " Build: ${{ needs.build.result }}"
118
+ echo " Unit Tests: ${{ needs.unit-tests.result }}"
119
+ echo " Integration Tests: ${{ needs.integration-tests.result }}"
120
+ exit 1
121
+ fi