port-ocean 0.18.9__tar.gz → 0.19.2__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (188) hide show
  1. {port_ocean-0.18.9 → port_ocean-0.19.2}/PKG-INFO +1 -1
  2. port_ocean-0.19.2/port_ocean/clients/auth/auth_client.py +10 -0
  3. port_ocean-0.19.2/port_ocean/clients/auth/oauth_client.py +22 -0
  4. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/mixins/integrations.py +45 -4
  5. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/config/settings.py +4 -3
  6. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/defaults/initialize.py +16 -4
  7. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/helpers/retry.py +15 -1
  8. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/ocean.py +19 -7
  9. port_ocean-0.19.2/port_ocean/tests/clients/__init__.py +0 -0
  10. port_ocean-0.19.2/port_ocean/tests/clients/oauth/__init__.py +0 -0
  11. port_ocean-0.19.2/port_ocean/tests/clients/oauth/test_oauth_client.py +96 -0
  12. port_ocean-0.19.2/port_ocean/tests/helpers/__init__.py +0 -0
  13. port_ocean-0.19.2/port_ocean/tests/test_ocean.py +49 -0
  14. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/async_http.py +1 -1
  15. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/repeat.py +0 -2
  16. {port_ocean-0.18.9 → port_ocean-0.19.2}/pyproject.toml +1 -1
  17. {port_ocean-0.18.9 → port_ocean-0.19.2}/LICENSE.md +0 -0
  18. {port_ocean-0.18.9 → port_ocean-0.19.2}/README.md +0 -0
  19. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/Dockerfile.Deb +0 -0
  20. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/Dockerfile.alpine +0 -0
  21. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/Dockerfile.base.builder +0 -0
  22. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/Dockerfile.base.runner +0 -0
  23. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/Dockerfile.dockerignore +0 -0
  24. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/Makefile +0 -0
  25. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/grpcio.sh +0 -0
  26. {port_ocean-0.18.9 → port_ocean-0.19.2}/integrations/_infra/init.sh +0 -0
  27. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/__init__.py +0 -0
  28. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/bootstrap.py +0 -0
  29. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/__init__.py +0 -0
  30. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cli.py +0 -0
  31. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/__init__.py +0 -0
  32. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  33. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/defaults/clean.py +0 -0
  34. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/defaults/dock.py +0 -0
  35. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/defaults/group.py +0 -0
  36. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/list_integrations.py +0 -0
  37. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/main.py +0 -0
  38. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/new.py +0 -0
  39. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/pull.py +0 -0
  40. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/sail.py +0 -0
  41. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/commands/version.py +0 -0
  42. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  43. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  44. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  45. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  46. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  47. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  48. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  49. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  50. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  51. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  52. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  53. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  54. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  55. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  56. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  57. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  58. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  59. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  60. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  61. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  62. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  63. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/cli/utils.py +0 -0
  64. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/__init__.py +0 -0
  65. {port_ocean-0.18.9/port_ocean/clients/port → port_ocean-0.19.2/port_ocean/clients/auth}/__init__.py +0 -0
  66. {port_ocean-0.18.9/port_ocean/clients/port/mixins → port_ocean-0.19.2/port_ocean/clients/port}/__init__.py +0 -0
  67. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/authentication.py +0 -0
  68. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/client.py +0 -0
  69. {port_ocean-0.18.9/port_ocean/config → port_ocean-0.19.2/port_ocean/clients/port/mixins}/__init__.py +0 -0
  70. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/mixins/blueprints.py +0 -0
  71. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/mixins/entities.py +0 -0
  72. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/mixins/migrations.py +0 -0
  73. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/mixins/organization.py +0 -0
  74. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/retry_transport.py +0 -0
  75. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/types.py +0 -0
  76. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/clients/port/utils.py +0 -0
  77. {port_ocean-0.18.9/port_ocean/consumers → port_ocean-0.19.2/port_ocean/config}/__init__.py +0 -0
  78. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/config/base.py +0 -0
  79. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/config/dynamic.py +0 -0
  80. {port_ocean-0.18.9/port_ocean/context → port_ocean-0.19.2/port_ocean/consumers}/__init__.py +0 -0
  81. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/consumers/kafka_consumer.py +0 -0
  82. {port_ocean-0.18.9/port_ocean/core → port_ocean-0.19.2/port_ocean/context}/__init__.py +0 -0
  83. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/context/event.py +0 -0
  84. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/context/ocean.py +0 -0
  85. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/context/resource.py +0 -0
  86. {port_ocean-0.18.9/port_ocean/core/handlers/entities_state_applier/port → port_ocean-0.19.2/port_ocean/core}/__init__.py +0 -0
  87. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/defaults/__init__.py +0 -0
  88. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/defaults/clean.py +0 -0
  89. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/defaults/common.py +0 -0
  90. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/__init__.py +0 -0
  91. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/base.py +0 -0
  92. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/factory.py +0 -0
  93. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/http.py +0 -0
  94. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/kafka.py +0 -0
  95. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/once.py +0 -0
  96. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/polling.py +0 -0
  97. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/event_listener/webhooks_only.py +0 -0
  98. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/__init__.py +0 -0
  99. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/base.py +0 -0
  100. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  101. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  102. {port_ocean-0.18.9/port_ocean/core/handlers/webhook → port_ocean-0.19.2/port_ocean/core/handlers/entities_state_applier/port}/__init__.py +0 -0
  103. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entities_state_applier/port/applier.py +0 -0
  104. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  105. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  106. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  107. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  108. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  109. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  110. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  111. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  112. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  113. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/queue/__init__.py +0 -0
  114. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
  115. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/queue/local_queue.py +0 -0
  116. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  117. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  118. {port_ocean-0.18.9/port_ocean/core/integrations → port_ocean-0.19.2/port_ocean/core/handlers/webhook}/__init__.py +0 -0
  119. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +0 -0
  120. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/webhook/processor_manager.py +0 -0
  121. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
  122. {port_ocean-0.18.9/port_ocean/exceptions → port_ocean-0.19.2/port_ocean/core/integrations}/__init__.py +0 -0
  123. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/base.py +0 -0
  124. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  125. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/mixins/events.py +0 -0
  126. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/mixins/handler.py +0 -0
  127. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/mixins/sync.py +0 -0
  128. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/mixins/sync_raw.py +0 -0
  129. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/integrations/mixins/utils.py +0 -0
  130. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/models.py +0 -0
  131. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/ocean_types.py +0 -0
  132. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
  133. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/core/utils/utils.py +0 -0
  134. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/debug_cli.py +0 -0
  135. {port_ocean-0.18.9/port_ocean/helpers → port_ocean-0.19.2/port_ocean/exceptions}/__init__.py +0 -0
  136. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/api.py +0 -0
  137. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/base.py +0 -0
  138. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/clients.py +0 -0
  139. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/context.py +0 -0
  140. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/core.py +0 -0
  141. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/port_defaults.py +0 -0
  142. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/utils.py +0 -0
  143. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/exceptions/webhook_processor.py +0 -0
  144. {port_ocean-0.18.9/port_ocean/log → port_ocean-0.19.2/port_ocean/helpers}/__init__.py +0 -0
  145. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/helpers/async_client.py +0 -0
  146. {port_ocean-0.18.9/port_ocean/tests → port_ocean-0.19.2/port_ocean/log}/__init__.py +0 -0
  147. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/log/handlers.py +0 -0
  148. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/log/logger_setup.py +0 -0
  149. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/log/sensetive.py +0 -0
  150. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/middlewares.py +0 -0
  151. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/py.typed +0 -0
  152. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/run.py +0 -0
  153. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/sonar-project.properties +0 -0
  154. {port_ocean-0.18.9/port_ocean/tests/helpers → port_ocean-0.19.2/port_ocean/tests}/__init__.py +0 -0
  155. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  156. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +0 -0
  157. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/conftest.py +0 -0
  158. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/defaults/test_common.py +0 -0
  159. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
  160. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  161. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
  162. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
  163. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
  164. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
  165. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
  166. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +0 -0
  167. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
  168. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/test_utils.py +0 -0
  169. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
  170. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
  171. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/helpers/fake_port_api.py +0 -0
  172. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/helpers/fixtures.py +0 -0
  173. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/helpers/integration.py +0 -0
  174. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/helpers/ocean_app.py +0 -0
  175. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/helpers/port_client.py +0 -0
  176. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/helpers/smoke_test.py +0 -0
  177. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/log/test_handlers.py +0 -0
  178. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/test_smoke.py +0 -0
  179. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  180. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/tests/utils/test_cache.py +0 -0
  181. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/__init__.py +0 -0
  182. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/async_iterators.py +0 -0
  183. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/cache.py +0 -0
  184. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/misc.py +0 -0
  185. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/queue_utils.py +0 -0
  186. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/signal.py +0 -0
  187. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/utils/time.py +0 -0
  188. {port_ocean-0.18.9 → port_ocean-0.19.2}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.18.9
3
+ Version: 0.19.2
4
4
  Summary: Port Ocean is a CLI tool for managing your Port projects.
5
5
  Home-page: https://app.getport.io
6
6
  Keywords: ocean,port-ocean,port
@@ -0,0 +1,10 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ import httpx
4
+
5
+
6
+ class AuthClient(ABC):
7
+
8
+ @abstractmethod
9
+ def refresh_request_auth_creds(self, request: httpx.Request) -> httpx.Request:
10
+ pass
@@ -0,0 +1,22 @@
1
+ from port_ocean.clients.auth.auth_client import AuthClient
2
+ from port_ocean.context.ocean import ocean
3
+ from port_ocean.helpers.retry import register_on_retry_callback
4
+
5
+
6
+ class OAuthClient(AuthClient):
7
+ def __init__(self) -> None:
8
+ """
9
+ A client that can refresh a request using an access token.
10
+ """
11
+ if self.is_oauth_enabled():
12
+ register_on_retry_callback(self.refresh_request_auth_creds)
13
+
14
+ def is_oauth_enabled(self) -> bool:
15
+ return ocean.app.load_external_oauth_access_token() is not None
16
+
17
+ @property
18
+ def external_access_token(self) -> str:
19
+ access_token = ocean.app.load_external_oauth_access_token()
20
+ if access_token is None:
21
+ raise ValueError("No external access token found")
22
+ return access_token
@@ -1,5 +1,5 @@
1
1
  import asyncio
2
- from typing import Any, Dict, TYPE_CHECKING, Optional, TypedDict
2
+ from typing import Any, Dict, List, TYPE_CHECKING, Optional, TypedDict
3
3
  from urllib.parse import quote_plus
4
4
 
5
5
  import httpx
@@ -14,7 +14,7 @@ if TYPE_CHECKING:
14
14
 
15
15
 
16
16
  INTEGRATION_POLLING_INTERVAL_INITIAL_SECONDS = 3
17
- INTEGRATION_POLLING_INTERVAL_BACKOFF_FACTOR = 1.15
17
+ INTEGRATION_POLLING_INTERVAL_BACKOFF_FACTOR = 1.55
18
18
  INTEGRATION_POLLING_RETRY_LIMIT = 30
19
19
  CREATE_RESOURCES_PARAM_NAME = "integration_modes"
20
20
  CREATE_RESOURCES_PARAM_VALUE = ["create_resources"]
@@ -38,6 +38,27 @@ class IntegrationClientMixin:
38
38
  self.client = client
39
39
  self._log_attributes: LogAttributes | None = None
40
40
 
41
+ async def is_integration_provision_enabled(
42
+ self, integration_type: str, should_raise: bool = True, should_log: bool = True
43
+ ) -> bool:
44
+ enabled_integrations = await self.get_provision_enabled_integrations(
45
+ should_raise, should_log
46
+ )
47
+ return integration_type in enabled_integrations
48
+
49
+ async def get_provision_enabled_integrations(
50
+ self, should_raise: bool = True, should_log: bool = True
51
+ ) -> List[str]:
52
+ logger.info("Fetching provision enabled integrations")
53
+ response = await self.client.get(
54
+ f"{self.auth.api_url}/integration/provision-enabled",
55
+ headers=await self.auth.headers(),
56
+ )
57
+
58
+ handle_status_code(response, should_raise, should_log)
59
+
60
+ return response.json().get("integrations", [])
61
+
41
62
  async def _get_current_integration(self) -> httpx.Response:
42
63
  logger.info(f"Fetching integration with id: {self.integration_identifier}")
43
64
  response = await self.client.get(
@@ -51,7 +72,27 @@ class IntegrationClientMixin:
51
72
  ) -> dict[str, Any]:
52
73
  response = await self._get_current_integration()
53
74
  handle_status_code(response, should_raise, should_log)
54
- return response.json().get("integration", {})
75
+ integration = response.json().get("integration", {})
76
+ if integration.get("config", None) or not integration:
77
+ return integration
78
+ is_provision_enabled_for_integration = integration.get(
79
+ "installationAppType", None
80
+ ) and (
81
+ await self.is_integration_provision_enabled(
82
+ integration.get("installationAppType", ""),
83
+ should_raise,
84
+ should_log,
85
+ )
86
+ )
87
+
88
+ if is_provision_enabled_for_integration:
89
+ logger.info(
90
+ "integration type is enabled, polling until provisioning is complete"
91
+ )
92
+ integration = (
93
+ await self._poll_integration_until_default_provisioning_is_complete()
94
+ )
95
+ return integration
55
96
 
56
97
  async def get_log_attributes(self) -> LogAttributes:
57
98
  if self._log_attributes is None:
@@ -72,7 +113,7 @@ class IntegrationClientMixin:
72
113
  )
73
114
  response = await self._get_current_integration()
74
115
  integration_json = response.json()
75
- if integration_json.get("integration", {}).get("config", {}):
116
+ if integration_json.get("integration", {}).get("config", {}) != {}:
76
117
  return integration_json
77
118
 
78
119
  logger.info(
@@ -1,12 +1,12 @@
1
1
  from typing import Any, Literal, Type, cast
2
2
 
3
- from pydantic import Extra, AnyHttpUrl, parse_obj_as, parse_raw_as
3
+ from pydantic import AnyHttpUrl, Extra, parse_obj_as, parse_raw_as
4
4
  from pydantic.class_validators import root_validator, validator
5
- from pydantic.env_settings import InitSettingsSource, EnvSettingsSource, BaseSettings
5
+ from pydantic.env_settings import BaseSettings, EnvSettingsSource, InitSettingsSource
6
6
  from pydantic.fields import Field
7
7
  from pydantic.main import BaseModel
8
8
 
9
- from port_ocean.config.base import BaseOceanSettings, BaseOceanModel
9
+ from port_ocean.config.base import BaseOceanModel, BaseOceanSettings
10
10
  from port_ocean.core.event_listener import EventListenerSettingsType
11
11
  from port_ocean.core.models import CreatePortResourcesOrigin, Runtime
12
12
  from port_ocean.utils.misc import get_integration_name, get_spec_file
@@ -71,6 +71,7 @@ class IntegrationConfiguration(BaseOceanSettings, extra=Extra.allow):
71
71
  # Determines if Port should generate resources such as blueprints and pages instead of ocean
72
72
  create_port_resources_origin: CreatePortResourcesOrigin | None = None
73
73
  send_raw_data_examples: bool = True
74
+ oauth_access_token_file_path: str | None = None
74
75
  port: PortSettings
75
76
  event_listener: EventListenerSettingsType = Field(
76
77
  default=cast(EventListenerSettingsType, {"type": "POLLING"})
@@ -75,7 +75,7 @@ async def _initialize_required_integration_settings(
75
75
  create_port_resources_origin_in_port=integration_config.create_port_resources_origin
76
76
  == CreatePortResourcesOrigin.Port,
77
77
  )
78
- elif not integration.get("config"):
78
+ elif not integration.get("config", None):
79
79
  logger.info(
80
80
  "Encountered that the integration's mapping is empty, Initializing to default mapping"
81
81
  )
@@ -213,11 +213,20 @@ async def _initialize_defaults(
213
213
  config_class, integration_config.resources_path
214
214
  )
215
215
 
216
+ is_integration_provision_enabled = (
217
+ await port_client.is_integration_provision_enabled(
218
+ integration_config.integration.type
219
+ )
220
+ )
221
+
216
222
  if (
217
223
  not integration_config.create_port_resources_origin
218
- and integration_config.runtime.is_saas_runtime
224
+ and is_integration_provision_enabled
219
225
  ):
220
- logger.info("Setting resources origin to be Port")
226
+ # Need to set default since spec is missing
227
+ logger.info(
228
+ f"Setting resources origin to be Port (integration {integration_config.integration.type} is supported)"
229
+ )
221
230
  integration_config.create_port_resources_origin = CreatePortResourcesOrigin.Port
222
231
 
223
232
  if (
@@ -228,7 +237,10 @@ async def _initialize_defaults(
228
237
  "Resources origin is set to be Port, verifying integration is supported"
229
238
  )
230
239
  org_feature_flags = await port_client.get_organization_feature_flags()
231
- if ORG_USE_PROVISIONED_DEFAULTS_FEATURE_FLAG not in org_feature_flags:
240
+ if (
241
+ not is_integration_provision_enabled
242
+ or ORG_USE_PROVISIONED_DEFAULTS_FEATURE_FLAG not in org_feature_flags
243
+ ):
232
244
  logger.info(
233
245
  "Port origin for Integration is not supported, changing resources origin to use Ocean"
234
246
  )
@@ -9,6 +9,15 @@ from typing import Any, Callable, Coroutine, Iterable, Mapping, Union
9
9
  import httpx
10
10
  from dateutil.parser import isoparse
11
11
 
12
+ _ON_RETRY_CALLBACK: Callable[[httpx.Request], httpx.Request] | None = None
13
+
14
+
15
+ def register_on_retry_callback(
16
+ _on_retry_callback: Callable[[httpx.Request], httpx.Request]
17
+ ) -> None:
18
+ global _ON_RETRY_CALLBACK
19
+ _ON_RETRY_CALLBACK = _on_retry_callback
20
+
12
21
 
13
22
  # Adapted from https://github.com/encode/httpx/issues/108#issuecomment-1434439481
14
23
  class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
@@ -43,7 +52,6 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
43
52
  _retry_status_codes (frozenset): The HTTP status codes that can be retried.
44
53
  _jitter_ratio (float): The amount of jitter to add to the backoff time.
45
54
  _max_backoff_wait (float): The maximum time to wait between retries in seconds.
46
-
47
55
  """
48
56
 
49
57
  RETRYABLE_METHODS = frozenset(["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"])
@@ -53,6 +61,8 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
53
61
  HTTPStatus.BAD_GATEWAY,
54
62
  HTTPStatus.SERVICE_UNAVAILABLE,
55
63
  HTTPStatus.GATEWAY_TIMEOUT,
64
+ HTTPStatus.UNAUTHORIZED,
65
+ HTTPStatus.BAD_REQUEST,
56
66
  ]
57
67
  )
58
68
  MAX_BACKOFF_WAIT_IN_SECONDS = 60
@@ -316,6 +326,8 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
316
326
  if remaining_attempts < 1:
317
327
  self._log_error(request, error)
318
328
  raise
329
+ if _ON_RETRY_CALLBACK:
330
+ request = _ON_RETRY_CALLBACK(request)
319
331
  attempts_made += 1
320
332
  remaining_attempts -= 1
321
333
 
@@ -357,5 +369,7 @@ class RetryTransport(httpx.AsyncBaseTransport, httpx.BaseTransport):
357
369
  if remaining_attempts < 1:
358
370
  self._log_error(request, error)
359
371
  raise
372
+ if _ON_RETRY_CALLBACK:
373
+ request = _ON_RETRY_CALLBACK(request)
360
374
  attempts_made += 1
361
375
  remaining_attempts -= 1
@@ -1,31 +1,31 @@
1
1
  import asyncio
2
2
  import sys
3
- import threading
4
3
  from contextlib import asynccontextmanager
5
- from typing import Callable, Any, Dict, AsyncIterator, Type
4
+ import threading
5
+ from typing import Any, AsyncIterator, Callable, Dict, Type
6
6
 
7
- from fastapi import FastAPI, APIRouter
7
+ from fastapi import APIRouter, FastAPI
8
8
  from loguru import logger
9
9
  from pydantic import BaseModel
10
- from starlette.types import Scope, Receive, Send
10
+ from starlette.types import Receive, Scope, Send
11
11
 
12
- from port_ocean.core.handlers.resync_state_updater import ResyncStateUpdater
13
12
  from port_ocean.clients.port.client import PortClient
14
13
  from port_ocean.config.settings import (
15
14
  IntegrationConfiguration,
16
15
  )
17
16
  from port_ocean.context.ocean import (
18
17
  PortOceanContext,
19
- ocean,
20
18
  initialize_port_ocean_context,
19
+ ocean,
21
20
  )
21
+ from port_ocean.core.handlers.resync_state_updater import ResyncStateUpdater
22
22
  from port_ocean.core.integrations.base import BaseIntegration
23
23
  from port_ocean.log.sensetive import sensitive_log_filter
24
24
  from port_ocean.middlewares import request_handler
25
+ from port_ocean.utils.misc import IntegrationStateStatus
25
26
  from port_ocean.utils.repeat import repeat_every
26
27
  from port_ocean.utils.signal import signal_handler
27
28
  from port_ocean.version import __integration_version__
28
- from port_ocean.utils.misc import IntegrationStateStatus
29
29
  from port_ocean.core.handlers.webhook.processor_manager import WebhookProcessorManager
30
30
 
31
31
 
@@ -118,6 +118,18 @@ class Ocean:
118
118
  )
119
119
  await repeated_function()
120
120
 
121
+ def load_external_oauth_access_token(self) -> str | None:
122
+ if self.config.oauth_access_token_file_path is not None:
123
+ try:
124
+ with open(self.config.oauth_access_token_file_path, "r") as f:
125
+ return f.read()
126
+ except Exception:
127
+ logger.exception(
128
+ "Failed to load external oauth access token from file",
129
+ file_path=self.config.oauth_access_token_file_path,
130
+ )
131
+ return None
132
+
121
133
  def initialize_app(self) -> None:
122
134
  self.fast_api_app.include_router(self.integration_router, prefix="/integration")
123
135
 
File without changes
@@ -0,0 +1,96 @@
1
+ import pytest
2
+ import httpx
3
+ from unittest.mock import MagicMock, patch
4
+ from port_ocean.ocean import Ocean
5
+
6
+ from port_ocean.clients.auth.oauth_client import OAuthClient
7
+ from port_ocean.config.settings import IntegrationConfiguration
8
+
9
+
10
+ @pytest.fixture
11
+ def mock_ocean() -> Ocean:
12
+ with patch("port_ocean.ocean.Ocean.__init__", return_value=None):
13
+ ocean_mock = Ocean()
14
+ ocean_mock.config = MagicMock(spec=IntegrationConfiguration)
15
+ return ocean_mock
16
+
17
+
18
+ class MockOAuthClient(OAuthClient):
19
+ def __init__(self, is_oauth_enabled_value: bool = True):
20
+ self._is_oauth_enabled = is_oauth_enabled_value
21
+ self._access_token = "mock_access_token"
22
+ super().__init__()
23
+
24
+ def is_oauth_enabled(self) -> bool:
25
+ return self._is_oauth_enabled
26
+
27
+ def refresh_request_auth_creds(self, request: httpx.Request) -> httpx.Request:
28
+ headers = dict(request.headers)
29
+ headers["Authorization"] = f"Bearer {self.access_token}"
30
+ return httpx.Request(
31
+ method=request.method,
32
+ url=request.url,
33
+ headers=headers,
34
+ content=request.content,
35
+ )
36
+
37
+ @property
38
+ def access_token(self) -> str:
39
+ return self._access_token
40
+
41
+
42
+ @pytest.fixture
43
+ def mock_oauth_client() -> MockOAuthClient:
44
+ return MockOAuthClient()
45
+
46
+
47
+ @pytest.fixture
48
+ def disabled_oauth_client() -> MockOAuthClient:
49
+ return MockOAuthClient(is_oauth_enabled_value=False)
50
+
51
+
52
+ def test_oauth_client_initialization(mock_oauth_client: MockOAuthClient) -> None:
53
+ assert isinstance(mock_oauth_client, OAuthClient)
54
+ assert mock_oauth_client.is_oauth_enabled() is True
55
+
56
+
57
+ def test_oauth_client_disabled_initialization(
58
+ disabled_oauth_client: MockOAuthClient,
59
+ ) -> None:
60
+ assert isinstance(disabled_oauth_client, OAuthClient)
61
+ assert disabled_oauth_client.is_oauth_enabled() is False
62
+
63
+
64
+ def test_refresh_request_auth_creds(mock_oauth_client: MockOAuthClient) -> None:
65
+ # Create request with some content and existing headers
66
+ original_headers = {"Accept": "application/json", "X-Custom": "value"}
67
+ original_content = b'{"key": "value"}'
68
+ original_request = httpx.Request(
69
+ "GET",
70
+ "https://api.example.com",
71
+ headers=original_headers,
72
+ content=original_content,
73
+ )
74
+
75
+ refreshed_request = mock_oauth_client.refresh_request_auth_creds(original_request)
76
+
77
+ # Verify all attributes are identical except headers
78
+ assert refreshed_request.method == original_request.method
79
+ assert refreshed_request.url == original_request.url
80
+ assert refreshed_request.content == original_request.content
81
+
82
+ # Verify headers: should contain all original headers plus the new Authorization
83
+ for key, value in original_headers.items():
84
+ assert refreshed_request.headers[key] == value
85
+ assert refreshed_request.headers["Authorization"] == "Bearer mock_access_token"
86
+ # New headers should be:
87
+ # {'host': 'api.example.com',
88
+ # 'accept': 'application/json',
89
+ # 'x-custom': 'value',
90
+ # 'content-length': '16',
91
+ # 'authorization': '[secure]'}
92
+ assert len(refreshed_request.headers) == 5
93
+
94
+
95
+ def test_access_token_property(mock_oauth_client: MockOAuthClient) -> None:
96
+ assert mock_oauth_client.access_token == "mock_access_token"
File without changes
@@ -0,0 +1,49 @@
1
+ import pytest
2
+ from unittest.mock import MagicMock, mock_open, patch
3
+ from port_ocean.ocean import Ocean
4
+ from port_ocean.config.settings import IntegrationConfiguration
5
+
6
+
7
+ @pytest.fixture
8
+ def mock_ocean() -> Ocean:
9
+ with patch("port_ocean.ocean.Ocean.__init__", return_value=None):
10
+ ocean_mock = Ocean()
11
+ ocean_mock.config = MagicMock(spec=IntegrationConfiguration)
12
+ return ocean_mock
13
+
14
+
15
+ def test_load_external_oauth_access_token_no_file(mock_ocean: Ocean) -> None:
16
+ # Setup
17
+ mock_ocean.config.oauth_access_token_file_path = None
18
+
19
+ # Execute
20
+ result = mock_ocean.load_external_oauth_access_token()
21
+
22
+ # Assert
23
+ assert result is None
24
+
25
+
26
+ def test_load_external_oauth_access_token_with_file(mock_ocean: Ocean) -> None:
27
+ # Setup
28
+ mock_ocean.config.oauth_access_token_file_path = "/path/to/token.txt"
29
+ mock_file_content = "test_access_token"
30
+
31
+ with patch("builtins.open", mock_open(read_data=mock_file_content)):
32
+ # Execute
33
+ result = mock_ocean.load_external_oauth_access_token()
34
+
35
+ # Assert
36
+ assert result == "test_access_token"
37
+
38
+
39
+ def test_load_external_oauth_access_token_with_empty_file(mock_ocean: Ocean) -> None:
40
+ # Setup
41
+ mock_ocean.config.oauth_access_token_file_path = "/path/to/token.txt"
42
+ mock_file_content = ""
43
+
44
+ with patch("builtins.open", mock_open(read_data=mock_file_content)):
45
+ # Execute
46
+ result = mock_ocean.load_external_oauth_access_token()
47
+
48
+ # Assert
49
+ assert result == ""
@@ -18,7 +18,7 @@ def _get_http_client_context() -> httpx.AsyncClient:
18
18
 
19
19
 
20
20
  """
21
- Utilize this client for all outbound integration requests to the third-party application. It functions as a wrapper
21
+ Utilize this client for all outbound integration requests to the third-party application. It functions as a wrapper
22
22
  around the httpx.AsyncClient, incorporating retry logic at the transport layer for handling retries on 5xx errors and
23
23
  connection errors.
24
24
 
@@ -22,10 +22,8 @@ def repeat_every(
22
22
  ) -> NoArgsNoReturnDecorator:
23
23
  """
24
24
  This function returns a decorator that modifies a function so it is periodically re-executed after its first call.
25
-
26
25
  The function it decorates should accept no arguments and return nothing. If necessary, this can be accomplished
27
26
  by using `functools.partial` or otherwise wrapping the target function prior to decoration.
28
-
29
27
  Parameters
30
28
  ----------
31
29
  seconds: float
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "port-ocean"
3
- version = "0.18.9"
3
+ version = "0.19.2"
4
4
  description = "Port Ocean is a CLI tool for managing your Port projects."
5
5
  readme = "README.md"
6
6
  homepage = "https://app.getport.io"
File without changes
File without changes