port-ocean 0.21.2__tar.gz → 0.29.5__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.
- {port_ocean-0.21.2 → port_ocean-0.29.5}/PKG-INFO +14 -6
- {port_ocean-0.21.2 → port_ocean-0.29.5}/README.md +1 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/Dockerfile.Deb +37 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/Dockerfile.alpine +2 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/Dockerfile.base.builder +7 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/Dockerfile.base.runner +4 -3
- port_ocean-0.29.5/integrations/_infra/Dockerfile.local +65 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/Makefile +3 -1
- port_ocean-0.29.5/integrations/_infra/README.md +30 -0
- port_ocean-0.29.5/integrations/_infra/entry_local.sh +26 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/init.sh +2 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/__init__.py +6 -1
- port_ocean-0.29.5/port_ocean/cache/base.py +25 -0
- port_ocean-0.29.5/port_ocean/cache/disk.py +61 -0
- port_ocean-0.29.5/port_ocean/cache/errors.py +10 -0
- port_ocean-0.29.5/port_ocean/cache/memory.py +36 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/cookiecutter.json +2 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +1 -1
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/auth/oauth_client.py +1 -1
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/authentication.py +23 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/client.py +11 -5
- port_ocean-0.29.5/port_ocean/clients/port/mixins/actions.py +93 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/mixins/blueprints.py +9 -21
- port_ocean-0.29.5/port_ocean/clients/port/mixins/entities.py +628 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/mixins/integrations.py +81 -12
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/mixins/migrations.py +2 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/mixins/organization.py +2 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/utils.py +9 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/config/dynamic.py +28 -3
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/config/settings.py +97 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/context/event.py +1 -0
- port_ocean-0.29.5/port_ocean/context/metric_resource.py +63 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/context/ocean.py +12 -5
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/context/resource.py +3 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/defaults/common.py +1 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/defaults/initialize.py +13 -6
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/__init__.py +7 -0
- port_ocean-0.29.5/port_ocean/core/event_listener/actions_only.py +42 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/base.py +10 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/factory.py +18 -9
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/http.py +4 -3
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/kafka.py +17 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/once.py +5 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/polling.py +4 -3
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/event_listener/webhooks_only.py +3 -2
- port_ocean-0.29.5/port_ocean/core/handlers/actions/__init__.py +7 -0
- port_ocean-0.29.5/port_ocean/core/handlers/actions/abstract_executor.py +150 -0
- port_ocean-0.29.5/port_ocean/core/handlers/actions/execution_manager.py +469 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entities_state_applier/port/applier.py +39 -16
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +7 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entity_processor/base.py +0 -2
- port_ocean-0.29.5/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +819 -0
- port_ocean-0.29.5/port_ocean/core/handlers/entity_processor/jq_input_evaluator.py +137 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/port_app_config/base.py +2 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/port_app_config/models.py +18 -5
- port_ocean-0.29.5/port_ocean/core/handlers/queue/__init__.py +5 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/queue/abstract_queue.py +8 -0
- port_ocean-0.29.5/port_ocean/core/handlers/queue/group_queue.py +138 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/queue/local_queue.py +3 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/resync_state_updater/updater.py +21 -1
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +16 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/webhook/processor_manager.py +146 -89
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/webhook/webhook_event.py +2 -5
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/integrations/base.py +15 -7
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/integrations/mixins/live_events.py +4 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/integrations/mixins/sync.py +1 -1
- port_ocean-0.29.5/port_ocean/core/integrations/mixins/sync_raw.py +1081 -0
- port_ocean-0.29.5/port_ocean/core/integrations/mixins/utils.py +326 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/models.py +71 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/ocean_types.py +2 -1
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/utils/utils.py +26 -7
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/core.py +4 -0
- port_ocean-0.29.5/port_ocean/exceptions/execution_manager.py +22 -0
- port_ocean-0.29.5/port_ocean/exceptions/webhook_processor.py +17 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/helpers/async_client.py +17 -12
- port_ocean-0.29.5/port_ocean/helpers/metric/metric.py +425 -0
- port_ocean-0.29.5/port_ocean/helpers/metric/utils.py +52 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/helpers/retry.py +195 -73
- port_ocean-0.29.5/port_ocean/helpers/stream.py +71 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/log/handlers.py +3 -4
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/log/logger_setup.py +16 -2
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/ocean.py +119 -20
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/run.py +0 -1
- port_ocean-0.29.5/port_ocean/tests/cache/__init__.py +1 -0
- port_ocean-0.29.5/port_ocean/tests/cache/test_disk_cache.py +92 -0
- port_ocean-0.29.5/port_ocean/tests/cache/test_memory_cache.py +59 -0
- port_ocean-0.29.5/port_ocean/tests/clients/port/mixins/test_entities.py +281 -0
- port_ocean-0.29.5/port_ocean/tests/clients/port/mixins/test_integrations.py +205 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +1 -0
- port_ocean-0.29.5/port_ocean/tests/config/test_config.py +38 -0
- port_ocean-0.29.5/port_ocean/tests/core/conftest.py +239 -0
- port_ocean-0.29.5/port_ocean/tests/core/event_listener/test_kafka.py +77 -0
- port_ocean-0.29.5/port_ocean/tests/core/handlers/actions/test_execution_manager.py +837 -0
- port_ocean-0.29.5/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +288 -0
- port_ocean-0.29.5/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +1290 -0
- port_ocean-0.29.5/port_ocean/tests/core/handlers/entity_processor/test_jq_input_evaluator.py +932 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/mixins/test_live_events.py +25 -15
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +299 -188
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/port_app_config/test_base.py +82 -0
- port_ocean-0.29.5/port_ocean/tests/core/handlers/queue/test_group_queue.py +681 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +199 -73
- port_ocean-0.29.5/port_ocean/tests/core/utils/test_get_port_diff.py +164 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +52 -0
- port_ocean-0.29.5/port_ocean/tests/helpers/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/helpers/fixtures.py +2 -3
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/helpers/port_client.py +1 -0
- port_ocean-0.29.5/port_ocean/tests/helpers/test_retry.py +549 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/log/test_handlers.py +2 -1
- port_ocean-0.29.5/port_ocean/tests/test_metric.py +180 -0
- port_ocean-0.29.5/port_ocean/tests/utils/test_cache.py +514 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/async_http.py +4 -1
- port_ocean-0.29.5/port_ocean/utils/cache.py +156 -0
- port_ocean-0.29.5/port_ocean/utils/ipc.py +30 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/misc.py +5 -3
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/signal.py +23 -8
- {port_ocean-0.21.2 → port_ocean-0.29.5}/pyproject.toml +20 -9
- port_ocean-0.21.2/port_ocean/clients/port/mixins/entities.py +0 -288
- port_ocean-0.21.2/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -313
- port_ocean-0.21.2/port_ocean/core/handlers/queue/__init__.py +0 -4
- port_ocean-0.21.2/port_ocean/core/integrations/mixins/sync_raw.py +0 -633
- port_ocean-0.21.2/port_ocean/core/integrations/mixins/utils.py +0 -74
- port_ocean-0.21.2/port_ocean/exceptions/webhook_processor.py +0 -4
- port_ocean-0.21.2/port_ocean/tests/clients/port/mixins/test_entities.py +0 -53
- port_ocean-0.21.2/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -86
- port_ocean-0.21.2/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -350
- port_ocean-0.21.2/port_ocean/tests/utils/test_cache.py +0 -189
- port_ocean-0.21.2/port_ocean/utils/cache.py +0 -97
- {port_ocean-0.21.2 → port_ocean-0.29.5}/LICENSE.md +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/Dockerfile.dockerignore +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/integrations/_infra/grpcio.sh +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/bootstrap.py +0 -0
- {port_ocean-0.21.2/port_ocean/cli/cookiecutter → port_ocean-0.29.5/port_ocean/cache}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cli.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/defaults/__init___.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/defaults/clean.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/defaults/dock.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/defaults/group.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/list_integrations.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/main.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/new.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/pull.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/sail.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/commands/version.py +0 -0
- {port_ocean-0.21.2/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests → port_ocean-0.29.5/port_ocean/cli/cookiecutter}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/extensions.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
- {port_ocean-0.21.2/port_ocean/clients → port_ocean-0.29.5/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/cli/utils.py +0 -0
- {port_ocean-0.21.2/port_ocean/clients/auth → port_ocean-0.29.5/port_ocean/clients}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/clients/port → port_ocean-0.29.5/port_ocean/clients/auth}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/auth/auth_client.py +0 -0
- {port_ocean-0.21.2/port_ocean/clients/port/mixins → port_ocean-0.29.5/port_ocean/clients/port}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/config → port_ocean-0.29.5/port_ocean/clients/port/mixins}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/retry_transport.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/clients/port/types.py +0 -0
- {port_ocean-0.21.2/port_ocean/consumers → port_ocean-0.29.5/port_ocean/config}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/config/base.py +0 -0
- {port_ocean-0.21.2/port_ocean/context → port_ocean-0.29.5/port_ocean/consumers}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/consumers/kafka_consumer.py +0 -0
- {port_ocean-0.21.2/port_ocean/core → port_ocean-0.29.5/port_ocean/context}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/core/handlers/entities_state_applier/port → port_ocean-0.29.5/port_ocean/core}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/defaults/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/defaults/clean.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/base.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
- {port_ocean-0.21.2/port_ocean/core/handlers/webhook → port_ocean-0.29.5/port_ocean/core/handlers/entities_state_applier/port}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/port_app_config/api.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/core/integrations → port_ocean-0.29.5/port_ocean/core/handlers/webhook}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/exceptions → port_ocean-0.29.5/port_ocean/core/integrations}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/integrations/mixins/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/integrations/mixins/events.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/integrations/mixins/handler.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/debug_cli.py +0 -0
- {port_ocean-0.21.2/port_ocean/helpers → port_ocean-0.29.5/port_ocean/exceptions}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/api.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/base.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/clients.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/context.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/port_defaults.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/exceptions/utils.py +0 -0
- {port_ocean-0.21.2/port_ocean/log → port_ocean-0.29.5/port_ocean/helpers}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/tests → port_ocean-0.29.5/port_ocean/log}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/log/sensetive.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/middlewares.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/py.typed +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/sonar-project.properties +0 -0
- {port_ocean-0.21.2/port_ocean/tests/clients → port_ocean-0.29.5/port_ocean/tests}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/tests/clients/oauth → port_ocean-0.29.5/port_ocean/tests/clients}/__init__.py +0 -0
- {port_ocean-0.21.2/port_ocean/tests/helpers → port_ocean-0.29.5/port_ocean/tests/clients/oauth}/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/conftest.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/defaults/test_common.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/test_utils.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/helpers/fake_port_api.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/helpers/integration.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/helpers/ocean_app.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/helpers/smoke_test.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/test_ocean.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/test_smoke.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/tests/utils/test_async_iterators.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/__init__.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/async_iterators.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/queue_utils.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/repeat.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/utils/time.py +0 -0
- {port_ocean-0.21.2 → port_ocean-0.29.5}/port_ocean/version.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: port-ocean
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.29.5
|
|
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
|
|
@@ -22,25 +22,32 @@ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
23
|
Classifier: Topic :: Utilities
|
|
24
24
|
Provides-Extra: cli
|
|
25
|
+
Requires-Dist: aiofiles (>=24.1.0,<25.0.0)
|
|
25
26
|
Requires-Dist: aiostream (>=0.5.2,<0.7.0)
|
|
26
27
|
Requires-Dist: click (>=8.1.3,<9.0.0) ; extra == "cli"
|
|
27
|
-
Requires-Dist: confluent-kafka (>=2.
|
|
28
|
+
Requires-Dist: confluent-kafka (>=2.10.1,<3.0.0)
|
|
28
29
|
Requires-Dist: cookiecutter (>=2.1.1,<3.0.0) ; extra == "cli"
|
|
29
|
-
Requires-Dist:
|
|
30
|
-
Requires-Dist:
|
|
30
|
+
Requires-Dist: cryptography (>=44.0.1,<45.0.0)
|
|
31
|
+
Requires-Dist: fastapi (>=0.121.0,<0.122.0)
|
|
32
|
+
Requires-Dist: httpx (>=0.28.1,<0.29.0)
|
|
33
|
+
Requires-Dist: ijson (>=3.4.0,<4.0.0)
|
|
34
|
+
Requires-Dist: jinja2 (>=3.1.6)
|
|
31
35
|
Requires-Dist: jinja2-time (>=0.2.0,<0.3.0) ; extra == "cli"
|
|
32
36
|
Requires-Dist: jq (>=1.8.0,<2.0.0)
|
|
33
37
|
Requires-Dist: loguru (>=0.7.0,<0.8.0)
|
|
38
|
+
Requires-Dist: prometheus-client (>=0.21.1,<0.22.0)
|
|
34
39
|
Requires-Dist: pydantic[dotenv] (>=1.10.8,<2.0.0)
|
|
35
40
|
Requires-Dist: pydispatcher (>=2.0.7,<3.0.0)
|
|
36
41
|
Requires-Dist: pyhumps (>=3.8.0,<4.0.0)
|
|
42
|
+
Requires-Dist: pyjwt (>=2.10.1,<3.0.0)
|
|
43
|
+
Requires-Dist: pytest-cov (>=6.0.0,<7.0.0)
|
|
37
44
|
Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
|
|
38
45
|
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
39
46
|
Requires-Dist: rich (>=13.4.1,<14.0.0) ; extra == "cli"
|
|
40
47
|
Requires-Dist: six (>=1.16.0,<2.0.0)
|
|
41
48
|
Requires-Dist: tomli (>=2.0.1,<3.0.0)
|
|
42
|
-
Requires-Dist: urllib3 (>=
|
|
43
|
-
Requires-Dist: uvicorn (>=0.
|
|
49
|
+
Requires-Dist: urllib3 (>=2.5.0,<3.0.0)
|
|
50
|
+
Requires-Dist: uvicorn (>=0.34.3,<0.35.0)
|
|
44
51
|
Requires-Dist: werkzeug (>=2.3.4,<4.0.0)
|
|
45
52
|
Project-URL: Repository, https://github.com/port-labs/Port-Ocean
|
|
46
53
|
Description-Content-Type: text/markdown
|
|
@@ -50,6 +57,7 @@ Description-Content-Type: text/markdown
|
|
|
50
57
|
# Ocean <img src="./assets/OceanSymbol.svg" alt="Ocean" width="100" height="100" align="right">
|
|
51
58
|
|
|
52
59
|
[](https://github.com/port-labs/port-ocean/actions/workflows/lint.yml)
|
|
60
|
+
[](https://deepwiki.com/port-labs/ocean)
|
|
53
61
|
|
|
54
62
|
Ocean is an innovative solution developed by Port to seamlessly integrate various third-party systems with our developer portal product,
|
|
55
63
|
empowering engineers to effortlessly prioritize key features and streamline the integration process.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# Ocean <img src="./assets/OceanSymbol.svg" alt="Ocean" width="100" height="100" align="right">
|
|
4
4
|
|
|
5
5
|
[](https://github.com/port-labs/port-ocean/actions/workflows/lint.yml)
|
|
6
|
+
[](https://deepwiki.com/port-labs/ocean)
|
|
6
7
|
|
|
7
8
|
Ocean is an innovative solution developed by Port to seamlessly integrate various third-party systems with our developer portal product,
|
|
8
9
|
empowering engineers to effortlessly prioritize key features and streamline the integration process.
|
|
@@ -6,7 +6,7 @@ FROM ${BASE_BUILDER_PYTHON_IMAGE} AS base
|
|
|
6
6
|
ARG BUILD_CONTEXT
|
|
7
7
|
ARG BUILDPLATFORM
|
|
8
8
|
|
|
9
|
-
ENV LIBRDKAFKA_VERSION=
|
|
9
|
+
ENV LIBRDKAFKA_VERSION=2.8.2 \
|
|
10
10
|
PYTHONUNBUFFERED=1 \
|
|
11
11
|
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
|
12
12
|
PIP_ROOT_USER_ACTION=ignore
|
|
@@ -18,17 +18,37 @@ COPY ./${BUILD_CONTEXT}/pyproject.toml ./${BUILD_CONTEXT}/poetry.lock /app/
|
|
|
18
18
|
RUN poetry install --without dev --no-root --no-interaction --no-ansi --no-cache
|
|
19
19
|
|
|
20
20
|
FROM ${BASE_RUNNER_PYTHON_IMAGE} AS prod
|
|
21
|
+
ARG OCEAN_USER_ID=999
|
|
22
|
+
|
|
23
|
+
RUN groupadd -r appgroup && useradd -r -g appgroup -m -u ${OCEAN_USER_ID} ocean
|
|
24
|
+
|
|
25
|
+
RUN mkdir -p /tmp/ocean
|
|
21
26
|
|
|
22
27
|
ARG INTEGRATION_VERSION
|
|
23
28
|
ARG BUILD_CONTEXT
|
|
29
|
+
ARG PROMETHEUS_MULTIPROC_DIR=/tmp/ocean/prometheus/metrics
|
|
30
|
+
ARG OAUTH_CONFIG_DIR=/app/.config
|
|
31
|
+
ARG STREAMING_LOCATION=/tmp/ocean/streaming
|
|
32
|
+
|
|
33
|
+
ENV LIBRDKAFKA_VERSION=2.8.2 \
|
|
34
|
+
PROMETHEUS_MULTIPROC_DIR=${PROMETHEUS_MULTIPROC_DIR} \
|
|
35
|
+
STREAMING_LOCATION=${STREAMING_LOCATION}
|
|
24
36
|
|
|
25
|
-
|
|
37
|
+
RUN mkdir -p ${PROMETHEUS_MULTIPROC_DIR}
|
|
38
|
+
RUN mkdir -p ${STREAMING_LOCATION}
|
|
39
|
+
RUN chown -R ocean:appgroup /tmp/ocean && chmod -R 755 /tmp/ocean
|
|
40
|
+
|
|
41
|
+
RUN mkdir -p ${OAUTH_CONFIG_DIR}
|
|
42
|
+
RUN chown -R ocean:appgroup ${OAUTH_CONFIG_DIR}
|
|
26
43
|
|
|
27
44
|
RUN apt-get update \
|
|
28
45
|
&& apt-get install -y \
|
|
29
46
|
ca-certificates \
|
|
30
47
|
openssl \
|
|
31
48
|
curl \
|
|
49
|
+
acl \
|
|
50
|
+
sudo \
|
|
51
|
+
jq \
|
|
32
52
|
&& apt-get clean
|
|
33
53
|
|
|
34
54
|
LABEL INTEGRATION_VERSION=${INTEGRATION_VERSION}
|
|
@@ -39,6 +59,8 @@ ENV PIP_ROOT_USER_ACTION=ignore
|
|
|
39
59
|
|
|
40
60
|
WORKDIR /app
|
|
41
61
|
|
|
62
|
+
USER ocean
|
|
63
|
+
|
|
42
64
|
# Copy the application code
|
|
43
65
|
COPY ./${BUILD_CONTEXT} /app
|
|
44
66
|
|
|
@@ -47,10 +69,23 @@ COPY --from=base /app/.venv /app/.venv
|
|
|
47
69
|
|
|
48
70
|
COPY ./integrations/_infra/init.sh /app/init.sh
|
|
49
71
|
|
|
72
|
+
USER root
|
|
73
|
+
|
|
50
74
|
# Ensure that ocean is available for all in path
|
|
51
75
|
RUN chmod a+x /app/.venv/bin/ocean
|
|
52
76
|
|
|
53
77
|
RUN chmod a+x /app/init.sh
|
|
54
78
|
RUN ln -s /app/.venv/bin/ocean /usr/bin/ocean
|
|
79
|
+
|
|
80
|
+
# Add ocean user to ssl certs group
|
|
81
|
+
RUN setfacl -R -m u:ocean:rwX /etc/ssl/certs \
|
|
82
|
+
&& setfacl -d -m u:ocean:rwX /etc/ssl/certs
|
|
83
|
+
|
|
84
|
+
# Allow ocean user to run update-ca-certificates without password (secure, limited sudo)
|
|
85
|
+
RUN echo "ocean ALL=(root) NOPASSWD: /usr/sbin/update-ca-certificates" >> /etc/sudoers.d/ocean-certs \
|
|
86
|
+
&& chmod 440 /etc/sudoers.d/ocean-certs
|
|
87
|
+
|
|
88
|
+
USER ocean
|
|
89
|
+
|
|
55
90
|
# Run the application
|
|
56
91
|
CMD ["bash", "/app/init.sh"]
|
|
@@ -5,7 +5,7 @@ FROM ${BASE_PYTHON_IMAGE} AS base
|
|
|
5
5
|
ARG BUILD_CONTEXT
|
|
6
6
|
ARG BUILDPLATFORM
|
|
7
7
|
|
|
8
|
-
ENV LIBRDKAFKA_VERSION=
|
|
8
|
+
ENV LIBRDKAFKA_VERSION=2.8.2 \
|
|
9
9
|
PYTHONUNBUFFERED=1 \
|
|
10
10
|
PIP_DISABLE_PIP_VERSION_CHECK=on \
|
|
11
11
|
POETRY_NO_INTERACTION=1 \
|
|
@@ -66,7 +66,7 @@ FROM ${BASE_PYTHON_IMAGE} AS prod
|
|
|
66
66
|
ARG INTEGRATION_VERSION
|
|
67
67
|
ARG BUILD_CONTEXT
|
|
68
68
|
|
|
69
|
-
ENV LIBRDKAFKA_VERSION=
|
|
69
|
+
ENV LIBRDKAFKA_VERSION=2.8.2
|
|
70
70
|
|
|
71
71
|
LABEL INTEGRATION_VERSION=${INTEGRATION_VERSION}
|
|
72
72
|
# Used to ensure that new integrations will be public, see https://docs.github.com/en/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
ARG
|
|
2
|
-
|
|
1
|
+
ARG ACCOUNT_ID=1
|
|
2
|
+
ARG BASE_PYTHON_IMAGE=${ACCOUNT_ID}.dkr.ecr.eu-west-1.amazonaws.com/echo/python:3.13
|
|
3
|
+
|
|
3
4
|
FROM ${BASE_PYTHON_IMAGE}
|
|
4
5
|
|
|
5
6
|
LABEL org.opencontainers.image.source=https://github.com/port-labs/ocean
|
|
6
7
|
|
|
7
|
-
ENV LIBRDKAFKA_VERSION=
|
|
8
|
+
ENV LIBRDKAFKA_VERSION=2.8.2 \
|
|
8
9
|
PYTHONUNBUFFERED=1 \
|
|
9
10
|
POETRY_VIRTUALENVS_IN_PROJECT=1 \
|
|
10
|
-
PIP_ROOT_USER_ACTION=ignore
|
|
11
|
+
PIP_ROOT_USER_ACTION=ignore \
|
|
12
|
+
POETRY_VIRTUALENVS_PREFER_ACTIVE_PYTHON=true \
|
|
13
|
+
POETRY_PYTHON=/usr/local/bin/python3.13
|
|
11
14
|
|
|
12
15
|
RUN apt-get update \
|
|
13
16
|
&& apt-get install -y \
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
ARG
|
|
2
|
-
|
|
1
|
+
ARG ACCOUNT_ID=1
|
|
2
|
+
ARG BASE_PYTHON_IMAGE=${ACCOUNT_ID}.dkr.ecr.eu-west-1.amazonaws.com/echo/python:3.13
|
|
3
|
+
|
|
3
4
|
FROM ${BASE_PYTHON_IMAGE}
|
|
4
5
|
|
|
5
6
|
LABEL org.opencontainers.image.source=https://github.com/port-labs/ocean
|
|
6
7
|
|
|
7
|
-
ENV LIBRDKAFKA_VERSION=
|
|
8
|
+
ENV LIBRDKAFKA_VERSION=2.8.2
|
|
8
9
|
|
|
9
10
|
ENV PIP_ROOT_USER_ACTION=ignore
|
|
10
11
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
ARG BASE_PYTHON_IMAGE=debian:trixie-slim
|
|
2
|
+
# debian:trixie-slim - Python 3.12
|
|
3
|
+
FROM ${BASE_PYTHON_IMAGE}
|
|
4
|
+
|
|
5
|
+
ARG OCEAN_USER_ID=999
|
|
6
|
+
RUN groupadd -r appgroup && useradd -r -g appgroup -m -u ${OCEAN_USER_ID} ocean
|
|
7
|
+
|
|
8
|
+
RUN mkdir -p /tmp/ocean
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
RUN apt-get update \
|
|
12
|
+
&& apt-get install -y --no-install-recommends librdkafka-dev python3 \
|
|
13
|
+
&& apt-get clean
|
|
14
|
+
RUN apt-get update \
|
|
15
|
+
&& apt-get install -y \
|
|
16
|
+
--no-install-recommends \
|
|
17
|
+
wget \
|
|
18
|
+
g++ \
|
|
19
|
+
libssl-dev \
|
|
20
|
+
autoconf \
|
|
21
|
+
automake \
|
|
22
|
+
libtool \
|
|
23
|
+
curl \
|
|
24
|
+
librdkafka-dev \
|
|
25
|
+
python3 \
|
|
26
|
+
python3-pip \
|
|
27
|
+
python3-poetry \
|
|
28
|
+
build-essential\
|
|
29
|
+
jq \
|
|
30
|
+
git \
|
|
31
|
+
python3-venv \
|
|
32
|
+
acl \
|
|
33
|
+
&& apt-get clean
|
|
34
|
+
|
|
35
|
+
ARG BUILD_CONTEXT
|
|
36
|
+
ARG PROMETHEUS_MULTIPROC_DIR=/tmp/ocean/prometheus/metrics
|
|
37
|
+
ARG STREAMING_LOCATION=/tmp/ocean/streaming
|
|
38
|
+
|
|
39
|
+
ENV PROMETHEUS_MULTIPROC_DIR=${PROMETHEUS_MULTIPROC_DIR}
|
|
40
|
+
ENV STREAMING_LOCATION=${STREAMING_LOCATION}
|
|
41
|
+
# Create /tmp/ocean directory and set permissions
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
RUN mkdir -p ${PROMETHEUS_MULTIPROC_DIR}
|
|
45
|
+
RUN mkdir -p ${STREAMING_LOCATION}
|
|
46
|
+
|
|
47
|
+
WORKDIR /app
|
|
48
|
+
|
|
49
|
+
COPY . .
|
|
50
|
+
RUN rm -rf .venv-docker ${BUILD_CONTEXT}/.venv-docker
|
|
51
|
+
RUN python3 -m venv .venv-docker
|
|
52
|
+
RUN python3 -m venv ${BUILD_CONTEXT}/.venv-docker
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
WORKDIR /app/${BUILD_CONTEXT}
|
|
56
|
+
|
|
57
|
+
WORKDIR /app
|
|
58
|
+
RUN chown -R ocean:appgroup /app && chmod -R 755 /app
|
|
59
|
+
RUN chown -R ocean:appgroup /app/${BUILD_CONTEXT} && chmod -R 755 /app/${BUILD_CONTEXT}
|
|
60
|
+
RUN chown -R ocean:appgroup /tmp/ocean && chmod -R 755 /tmp/ocean
|
|
61
|
+
# Add ocean user to ssl certs group
|
|
62
|
+
RUN setfacl -m u:ocean:rwX /etc/ssl/certs
|
|
63
|
+
USER ocean
|
|
64
|
+
|
|
65
|
+
ENTRYPOINT ["./integrations/_infra/entry_local.sh"]
|
|
@@ -11,6 +11,8 @@ define run_checks
|
|
|
11
11
|
ruff check . || exit_code=$$?; \
|
|
12
12
|
echo "Running black"; \
|
|
13
13
|
black --check . || exit_code=$$?; \
|
|
14
|
+
echo "Running yamllint"; \
|
|
15
|
+
yamllint . || exit_code=$$?; \
|
|
14
16
|
if [ $$exit_code -eq 1 ]; then \
|
|
15
17
|
echo "\033[0;31mOne or more checks failed with exit code $$exit_code\033[0m"; \
|
|
16
18
|
else \
|
|
@@ -46,7 +48,7 @@ endef
|
|
|
46
48
|
install:
|
|
47
49
|
$(call deactivate_virtualenv) && \
|
|
48
50
|
$(call install_poetry) && \
|
|
49
|
-
poetry install --with dev
|
|
51
|
+
poetry install --with dev --no-root
|
|
50
52
|
|
|
51
53
|
install/local-core: install
|
|
52
54
|
# NOTE: This is a temporary change that shouldn't be committed
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Running the Ocean image locally using vscode / Cursor
|
|
2
|
+
|
|
3
|
+
In order to run the local image of Ocean you need to follow these steps:
|
|
4
|
+
|
|
5
|
+
1. Build the image:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
docker build -f integrations/_infra/Dockerfile.local --build-arg BUILD_CONTEXT=integrations/<integration_type> --platform linux/arm64 -t <my-local-image>:<local> .
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
2. Run the image
|
|
12
|
+
1. `5678` is the debugpy port mentioned in the `entry_local.sh` file
|
|
13
|
+
2. `8000` is the port of the Ocean FastAPI server
|
|
14
|
+
3. the `-v` option mounts your local Ocean directory to the pod, allowing you not to constantly build the image.
|
|
15
|
+
1. Make sure to run the command from the root directory of the Ocean repository.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
docker run --rm -it \
|
|
19
|
+
-v $(pwd):/app \
|
|
20
|
+
-p 5678:5678 \
|
|
21
|
+
-p 8000:8000 \
|
|
22
|
+
-e BUILD_CONTEXT=integrations/<integration_type> \
|
|
23
|
+
-e OCEAN__PORT__CLIENT_ID=<MY_CLIENT_ID> \
|
|
24
|
+
-e OCEAN__PORT__CLIENT_SECRET=<MY_CLIENT_SECRET> \
|
|
25
|
+
-e OCEAN__PORT__MY_OTHER_CONFIGURATION=<MY_OTHER_CONFIGURATION> \
|
|
26
|
+
<my-local-image>:<local>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
3. In vscode/Cursor, run the `Attach to docker fake-integration integration` Running configuration from the `launch.json`.
|
|
30
|
+
4. Have fun debugging!
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
if [ -z "$BUILD_CONTEXT" ]; then
|
|
3
|
+
echo "BUILD_CONTEXT is not set"
|
|
4
|
+
exit 1
|
|
5
|
+
fi
|
|
6
|
+
|
|
7
|
+
if [ ! -d ".venv-docker" ]; then
|
|
8
|
+
/usr/bin/python3 -m venv .venv-docker
|
|
9
|
+
source .venv-docker/bin/activate
|
|
10
|
+
python -m pip install poetry
|
|
11
|
+
python -m poetry install
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
cd $BUILD_CONTEXT
|
|
15
|
+
|
|
16
|
+
if [ ! -d ".venv-docker" ]; then
|
|
17
|
+
/usr/bin/python3 -m venv .venv-docker
|
|
18
|
+
source .venv-docker/bin/activate
|
|
19
|
+
python -m pip install poetry
|
|
20
|
+
python -m poetry install
|
|
21
|
+
fi
|
|
22
|
+
source .venv-docker/bin/activate
|
|
23
|
+
python -m pip install -e ../../
|
|
24
|
+
|
|
25
|
+
python -m pip install debugpy
|
|
26
|
+
python -m debugpy --listen 0.0.0.0:5678 --wait-for-client debug.py
|
|
@@ -8,4 +8,9 @@ from .run import run # noqa: E402
|
|
|
8
8
|
from .version import __integration_version__, __version__ # noqa: E402
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
__all__ = [
|
|
11
|
+
__all__ = [
|
|
12
|
+
"Ocean",
|
|
13
|
+
"run",
|
|
14
|
+
"__version__",
|
|
15
|
+
"__integration_version__",
|
|
16
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Optional
|
|
3
|
+
|
|
4
|
+
from port_ocean.core.models import CachingStorageMode
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CacheProvider(ABC):
|
|
8
|
+
"""Base class for cache providers that defines the contract for all cache implementations."""
|
|
9
|
+
|
|
10
|
+
STORAGE_TYPE: CachingStorageMode
|
|
11
|
+
|
|
12
|
+
@abstractmethod
|
|
13
|
+
async def get(self, key: str) -> Optional[Any]:
|
|
14
|
+
"""Get a value from the cache."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
async def set(self, key: str, value: Any) -> None:
|
|
19
|
+
"""Set a value in the cache."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
async def clear(self) -> None:
|
|
24
|
+
"""Clear all values from the cache."""
|
|
25
|
+
pass
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
|
|
5
|
+
from port_ocean.cache.base import CacheProvider
|
|
6
|
+
from port_ocean.cache.errors import FailedToReadCacheError, FailedToWriteCacheError
|
|
7
|
+
from port_ocean.core.models import CachingStorageMode
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FailedToReadCacheFileError(FailedToReadCacheError):
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FailedToWriteCacheFileError(FailedToWriteCacheError):
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class DiskCacheProvider(CacheProvider):
|
|
19
|
+
STORAGE_TYPE = CachingStorageMode.disk
|
|
20
|
+
|
|
21
|
+
def __init__(self, cache_dir: str | None = None) -> None:
|
|
22
|
+
if cache_dir is None:
|
|
23
|
+
cache_dir = "/tmp/ocean/.ocean_cache"
|
|
24
|
+
self._cache_dir = Path(cache_dir)
|
|
25
|
+
self._cache_dir.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
|
|
27
|
+
def _get_cache_path(self, key: str) -> Path:
|
|
28
|
+
return self._cache_dir / f"{key}.pkl"
|
|
29
|
+
|
|
30
|
+
async def get(self, key: str) -> Optional[Any]:
|
|
31
|
+
cache_path = self._get_cache_path(key)
|
|
32
|
+
if not cache_path.exists():
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
with open(cache_path, "rb") as f:
|
|
37
|
+
return pickle.load(f)
|
|
38
|
+
except (pickle.PickleError, EOFError) as e:
|
|
39
|
+
raise FailedToReadCacheFileError(
|
|
40
|
+
f"Failed to read cache file: {cache_path}: {str(e)}"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
async def set(self, key: str, value: Any) -> None:
|
|
44
|
+
cache_path = self._get_cache_path(key)
|
|
45
|
+
try:
|
|
46
|
+
with open(cache_path, "wb") as f:
|
|
47
|
+
pickle.dump(value, f)
|
|
48
|
+
except (pickle.PickleError, IOError) as e:
|
|
49
|
+
raise FailedToWriteCacheFileError(
|
|
50
|
+
f"Failed to write cache file: {cache_path}: {str(e)}"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
async def clear(self) -> None:
|
|
54
|
+
try:
|
|
55
|
+
for cache_file in self._cache_dir.glob("*.pkl"):
|
|
56
|
+
try:
|
|
57
|
+
cache_file.unlink()
|
|
58
|
+
except OSError:
|
|
59
|
+
pass
|
|
60
|
+
except OSError:
|
|
61
|
+
pass
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from typing import Any, Optional
|
|
2
|
+
from port_ocean.cache.base import CacheProvider
|
|
3
|
+
from port_ocean.cache.errors import FailedToReadCacheError, FailedToWriteCacheError
|
|
4
|
+
from port_ocean.core.models import CachingStorageMode
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FailedToReadCacheMemoryError(FailedToReadCacheError):
|
|
8
|
+
pass
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FailedToWriteCacheMemoryError(FailedToWriteCacheError):
|
|
12
|
+
pass
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class InMemoryCacheProvider(CacheProvider):
|
|
16
|
+
CACHE_KEY = "cache"
|
|
17
|
+
STORAGE_TYPE = CachingStorageMode.memory
|
|
18
|
+
|
|
19
|
+
def __init__(self, caching_storage: dict[str, Any] | None = None) -> None:
|
|
20
|
+
self._storage = caching_storage or {}
|
|
21
|
+
self._storage[self.CACHE_KEY] = self._storage.get(self.CACHE_KEY, {})
|
|
22
|
+
|
|
23
|
+
async def get(self, key: str) -> Optional[Any]:
|
|
24
|
+
try:
|
|
25
|
+
return self._storage.get(self.CACHE_KEY, {}).get(key)
|
|
26
|
+
except KeyError as e:
|
|
27
|
+
raise FailedToReadCacheMemoryError(f"Failed to read cache: {str(e)}")
|
|
28
|
+
|
|
29
|
+
async def set(self, key: str, value: Any) -> None:
|
|
30
|
+
try:
|
|
31
|
+
self._storage[self.CACHE_KEY][key] = value
|
|
32
|
+
except KeyError as e:
|
|
33
|
+
raise FailedToWriteCacheMemoryError(f"Failed to write cache: {str(e)}")
|
|
34
|
+
|
|
35
|
+
async def clear(self) -> None:
|
|
36
|
+
self._storage[self.CACHE_KEY].clear()
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"email": "Your address email <you@example.com>",
|
|
7
7
|
"release_date": "{% now 'local' %}",
|
|
8
8
|
"is_private_integration": true,
|
|
9
|
-
"port_client_id": "you can find it using: https://docs.
|
|
10
|
-
"port_client_secret": "you can find it using: https://docs.
|
|
9
|
+
"port_client_id": "you can find it using: https://docs.port.io/build-your-software-catalog/custom-integration/api/#find-your-port-credentials",
|
|
10
|
+
"port_client_secret": "you can find it using: https://docs.port.io/build-your-software-catalog/custom-integration/api/#find-your-port-credentials",
|
|
11
11
|
"is_us_region": false,
|
|
12
12
|
"_extensions": [
|
|
13
13
|
"jinja2_time.TimeExtension",
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
An integration used to import {{cookiecutter.integration_name}} resources into Port.
|
|
4
4
|
|
|
5
|
-
#### Install & use the integration - [Integration documentation](https://docs.
|
|
5
|
+
#### Install & use the integration - [Integration documentation](https://docs.port.io/build-your-software-catalog/sync-data-to-catalog/) *Replace this link with a link to this integration's documentation*
|
|
6
6
|
|
|
7
7
|
#### Develop & improve the integration - [Ocean integration development documentation](https://ocean.getport.io/develop-an-integration/)
|
|
@@ -12,7 +12,7 @@ class OAuthClient(AuthClient):
|
|
|
12
12
|
register_on_retry_callback(self.refresh_request_auth_creds)
|
|
13
13
|
|
|
14
14
|
def is_oauth_enabled(self) -> bool:
|
|
15
|
-
return ocean.app.
|
|
15
|
+
return ocean.app.config.oauth_access_token_file_path is not None
|
|
16
16
|
|
|
17
17
|
@property
|
|
18
18
|
def external_access_token(self) -> str:
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import re
|
|
2
|
+
import jwt
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
4
5
|
import httpx
|
|
@@ -6,7 +7,7 @@ from loguru import logger
|
|
|
6
7
|
from pydantic import BaseModel, Field, PrivateAttr
|
|
7
8
|
|
|
8
9
|
from port_ocean.clients.port.types import UserAgentType
|
|
9
|
-
from port_ocean.clients.port.utils import
|
|
10
|
+
from port_ocean.clients.port.utils import handle_port_status_code
|
|
10
11
|
from port_ocean.utils.misc import get_time
|
|
11
12
|
|
|
12
13
|
|
|
@@ -35,6 +36,7 @@ class PortAuthentication:
|
|
|
35
36
|
integration_identifier: str,
|
|
36
37
|
integration_type: str,
|
|
37
38
|
integration_version: str,
|
|
39
|
+
ingest_url: str,
|
|
38
40
|
):
|
|
39
41
|
self.client = client
|
|
40
42
|
self.api_url = api_url
|
|
@@ -43,6 +45,7 @@ class PortAuthentication:
|
|
|
43
45
|
self.integration_identifier = integration_identifier
|
|
44
46
|
self.integration_type = integration_type
|
|
45
47
|
self.integration_version = integration_version
|
|
48
|
+
self.ingest_url = ingest_url
|
|
46
49
|
self.last_token_object: TokenResponse | None = None
|
|
47
50
|
|
|
48
51
|
async def _get_token(self, client_id: str, client_secret: str) -> TokenResponse:
|
|
@@ -58,7 +61,7 @@ class PortAuthentication:
|
|
|
58
61
|
json=credentials,
|
|
59
62
|
extensions={"retryable": True},
|
|
60
63
|
)
|
|
61
|
-
|
|
64
|
+
handle_port_status_code(response)
|
|
62
65
|
return TokenResponse(**response.json())
|
|
63
66
|
|
|
64
67
|
def user_agent(self, user_agent_type: UserAgentType | None = None) -> str:
|
|
@@ -88,6 +91,24 @@ class PortAuthentication:
|
|
|
88
91
|
)
|
|
89
92
|
return self.last_token_object.full_token
|
|
90
93
|
|
|
94
|
+
async def is_machine_user(self) -> bool:
|
|
95
|
+
# Ensure self.last_token_object is populated
|
|
96
|
+
await self.token
|
|
97
|
+
if not self.last_token_object:
|
|
98
|
+
raise ValueError("No token found")
|
|
99
|
+
|
|
100
|
+
payload: dict[str, Any] = jwt.decode(
|
|
101
|
+
self.last_token_object.access_token, options={"verify_signature": False}
|
|
102
|
+
)
|
|
103
|
+
is_machine_user = payload.get("isMachine")
|
|
104
|
+
if is_machine_user is None:
|
|
105
|
+
logger.warning(
|
|
106
|
+
"Can not determine if the user is a machine user directly, checking for personal token usage instead"
|
|
107
|
+
)
|
|
108
|
+
return not payload.get("personalToken", True)
|
|
109
|
+
|
|
110
|
+
return is_machine_user
|
|
111
|
+
|
|
91
112
|
@staticmethod
|
|
92
113
|
def _is_personal_token(client_id: str) -> bool:
|
|
93
114
|
email_regex = r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"
|