splunk-soar-sdk 3.6.1__tar.gz → 3.7.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.
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/PKG-INFO +3 -1
- splunk_soar_sdk-3.7.0/docs/authentication/basic.rst +18 -0
- splunk_soar_sdk-3.7.0/docs/authentication/index.rst +13 -0
- splunk_soar_sdk-3.7.0/docs/authentication/oauth.rst +168 -0
- splunk_soar_sdk-3.7.0/docs/authentication/static_token.rst +46 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/index.rst +1 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/pyproject.toml +4 -1
- splunk_soar_sdk-3.7.0/release_notes.txt +41 -0
- splunk_soar_sdk-3.7.0/release_version.txt +1 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/actions_manager.py +40 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app.py +52 -4
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/asset.py +49 -69
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/asset_state.py +13 -3
- splunk_soar_sdk-3.7.0/src/soar_sdk/auth/__init__.py +41 -0
- splunk_soar_sdk-3.7.0/src/soar_sdk/auth/client.py +540 -0
- splunk_soar_sdk-3.7.0/src/soar_sdk/auth/factories.py +120 -0
- splunk_soar_sdk-3.7.0/src/soar_sdk/auth/flows.py +172 -0
- splunk_soar_sdk-3.7.0/src/soar_sdk/auth/httpx_auth.py +97 -0
- splunk_soar_sdk-3.7.0/src/soar_sdk/auth/models.py +101 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/package/cli.py +6 -4
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/base_connector.py +7 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_convert_cli.py +4 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_deserializers.py +4 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/app.json +10 -5
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/app.py +4 -2
- splunk_soar_sdk-3.7.0/tests/example_app_with_oauth/example_asset.json +11 -0
- splunk_soar_sdk-3.7.0/tests/example_app_with_oauth/logo.svg +1 -0
- splunk_soar_sdk-3.7.0/tests/example_app_with_oauth/logo_dark.svg +1 -0
- splunk_soar_sdk-3.7.0/tests/example_app_with_oauth/pyproject.toml +48 -0
- splunk_soar_sdk-3.7.0/tests/example_app_with_oauth/src/app.py +183 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/app.json +6 -3
- splunk_soar_sdk-3.7.0/tests/example_app_with_webhook/src/__init__.py +3 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_actions_manager.py +106 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_app.py +111 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_asset.py +6 -2
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_asset_state.py +19 -0
- splunk_soar_sdk-3.7.0/tests/test_oauth_certificate_client.py +304 -0
- splunk_soar_sdk-3.7.0/tests/test_oauth_client.py +784 -0
- splunk_soar_sdk-3.7.0/tests/test_oauth_factories.py +287 -0
- splunk_soar_sdk-3.7.0/tests/test_oauth_flows.py +379 -0
- splunk_soar_sdk-3.7.0/tests/test_oauth_httpx_auth.py +338 -0
- splunk_soar_sdk-3.7.0/tests/test_oauth_models.py +279 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/uv.lock +122 -1
- splunk_soar_sdk-3.6.1/release_notes.txt +0 -21
- splunk_soar_sdk-3.6.1/release_version.txt +0 -1
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/pull_request_template.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/scripts/generate_test_summary.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/utils/github.js +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/utils/update_version.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/workflows/code_quality.yml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/workflows/commit_hygiene.yml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/workflows/generate_docs.yml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/workflows/integration_tests.yml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.github/workflows/semantic_release.yml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.gitignore +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/.releaserc +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/LICENSE +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/README.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/commitlint.config.js +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/api_reference.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/app_structure/index.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/app_structure/pre-commit-config.yaml.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/app_structure/pyproject.toml.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/app_structure/src_app.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/changelog.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/cli_reference.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/conf.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/custom_views/index.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/custom_views/reusable_components.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/custom_views/templates.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/custom_views/view_handlers.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/getting_started/defining_asset.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/getting_started/first_action.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/getting_started/index.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/getting_started/init_app.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/getting_started/installation.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/docs/getting_started/testing_and_building.rst +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/README.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/install.sh +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/mcp_config.json +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/pyproject.toml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/pytest.ini +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/src/soar_test_assistant/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/src/soar_test_assistant/server.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/tests/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/tests/test_analyzer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/mcp_server/uv.lock +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/abstract.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/action_results.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/apis/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/apis/artifact.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/apis/container.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/apis/es/findings.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/apis/utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/apis/vault.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_cli_runner.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_client.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_templates/basic_app/.gitignore +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_templates/basic_app/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_templates/basic_app/logo.svg +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_templates/basic_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_templates/basic_app/src/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/app_templates/basic_app/uv.lock +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/async_utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/init/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/init/cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/manifests/cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/manifests/deserializers.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/manifests/processors.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/manifests/serializers.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/package/utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/path_utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/test/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/test/cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/cli/utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/action_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/app_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/asset_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/templates/pyproject.toml.jinja +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/code_renderers/toml_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/colors.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/compat.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/crypto.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/action.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/make_request.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/on_es_poll.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/on_poll.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/test_connectivity.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/view_handler.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/decorators/webhook.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/es_client.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/exceptions.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/extras/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/extras/email/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/extras/email/processor.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/extras/email/rfc5322.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/extras/email/utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/field_utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/input_spec.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/logging.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/actions.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/adapters.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/app.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/datatypes.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/dependencies.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/meta/webhooks.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/artifact.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/attachment_input.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/container.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/finding.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/vault_attachment.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/models/view.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/params.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/paths.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/py.typed +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/action_result.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/app.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/connector_result.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/consts.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/encryption_helper.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/install_info.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/json_keys.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/ph_ipc.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom/vault.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom_common/app_interface/app_interface.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/shims/phantom_common/encryption/encryption_manager_factory.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/base/base_template.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/base/error.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/base/header.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/base/logo_header.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/components/pie_chart.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/widgets/widget_resize_snippet.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/templates/widgets/widget_template.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/types.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/component_registry.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/components/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/components/pie_chart.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/template_filters.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/template_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/views/view_parser.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/webhooks/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/webhooks/models.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/src/soar_sdk/webhooks/routing.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/datapath_parse.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/manifests/test_processors.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/manifests/test_python_version_resolution.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_assets/converted_app/actions.py.txt +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_init_cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_manifests_cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_package_cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_serializers.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_test_cli.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/cli/test_utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/code_renderers/test_action_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/conftest.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/example_asset.json +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/logo.svg +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/pyproject.toml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/release_notes/v1.md +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/actions/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/actions/async_action.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/actions/generate_category.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/actions/reverse_string.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/src/ignoreme.txt +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/templates/reverse_string.html +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app/uv.lock +0 -0
- {splunk_soar_sdk-3.6.1/tests/example_app_with_webhook → splunk_soar_sdk-3.7.0/tests/example_app_with_oauth}/src/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/example_asset.json +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/logo.svg +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/logo_dark.svg +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/pyproject.toml +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/src/app.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/example_app_with_webhook/uv.lock +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/conftest.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/phantom_constants.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/phantom_instance.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/soar_client.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/test_example_app.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/integration/test_example_app_with_webhook.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/interfaces/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/interfaces/test_artifact_interface.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/interfaces/test_container_interface.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/interfaces/test_vault_interface.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/meta/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/meta/test_actions.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/meta/test_adapters.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/meta/test_datatypes.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/meta/test_dependencies.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/meta/test_webhooks.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/mocks/__init__.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/mocks/dynamic_mocks.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/mocks/importable_action.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/stubs.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_action_results.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_app_action.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_app_action_params.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_app_action_results.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_app_client.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_app_runner.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_assets/splunk-sdk-2.1.0.tar.gz +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_async_integration.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_async_utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_attachment_input.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_code_renderers.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_compat.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_container.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_custom_views.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_email_processor.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_encryption.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_es_client.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_es_on_poll.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_field_utils.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_finding.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_input_spec.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_logging.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_make_request_action.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_on_poll.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_params.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_rfc5322.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_template_filters.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_template_renderer.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_test_connectivity.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/test_view_parser.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/webhooks/test_models.py +0 -0
- {splunk_soar_sdk-3.6.1 → splunk_soar_sdk-3.7.0}/tests/webhooks/test_routing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splunk-soar-sdk
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.0
|
|
4
4
|
Summary: The official framework for developing and testing Splunk SOAR Apps
|
|
5
5
|
Project-URL: Homepage, https://github.com/phantomcyber/splunk-soar-sdk
|
|
6
6
|
Project-URL: Documentation, https://github.com/phantomcyber/splunk-soar-sdk
|
|
@@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
19
|
Requires-Python: <3.15,>=3.13
|
|
20
|
+
Requires-Dist: authlib>=1.3.0
|
|
20
21
|
Requires-Dist: beautifulsoup4>=4.10.0
|
|
21
22
|
Requires-Dist: bleach>=6.2.0
|
|
22
23
|
Requires-Dist: build>=1.3.0
|
|
@@ -29,6 +30,7 @@ Requires-Dist: humanize>=4.12.2
|
|
|
29
30
|
Requires-Dist: jinja2>=3.1.0
|
|
30
31
|
Requires-Dist: packaging>=25.0
|
|
31
32
|
Requires-Dist: pydantic<3,>=2
|
|
33
|
+
Requires-Dist: pyjwt[crypto]>=2.8.0
|
|
32
34
|
Requires-Dist: requests<3
|
|
33
35
|
Requires-Dist: setuptools>=80.9.0
|
|
34
36
|
Requires-Dist: toml<1,>=0.10.2
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
.. _basic_auth:
|
|
2
|
+
|
|
3
|
+
Basic Authentication
|
|
4
|
+
====================
|
|
5
|
+
|
|
6
|
+
For APIs that use HTTP Basic Authentication (username/password):
|
|
7
|
+
|
|
8
|
+
.. code-block:: python
|
|
9
|
+
|
|
10
|
+
from soar_sdk.auth import BasicAuth
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
auth = BasicAuth(asset.username, asset.password)
|
|
14
|
+
|
|
15
|
+
with httpx.Client(auth=auth) as client:
|
|
16
|
+
response = client.get("https://api.example.com/data")
|
|
17
|
+
|
|
18
|
+
This sends the ``Authorization: Basic <base64(username:password)>`` header with each request.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
.. _oauth:
|
|
2
|
+
|
|
3
|
+
OAuth 2.0 Authentication
|
|
4
|
+
========================
|
|
5
|
+
|
|
6
|
+
The SDK provides OAuth 2.0 support for SOAR connectors, with automatic token management and secure storage.
|
|
7
|
+
|
|
8
|
+
Supported Flows
|
|
9
|
+
---------------
|
|
10
|
+
|
|
11
|
+
- **Authorization Code** (with PKCE support) - For user-delegated access
|
|
12
|
+
- **Client Credentials** - For service-to-service authentication
|
|
13
|
+
- **Certificate-based** - For certificate authentication (e.g., Microsoft Entra ID)
|
|
14
|
+
|
|
15
|
+
Client Credentials Flow
|
|
16
|
+
-----------------------
|
|
17
|
+
|
|
18
|
+
The simplest flow for service accounts:
|
|
19
|
+
|
|
20
|
+
.. code-block:: python
|
|
21
|
+
|
|
22
|
+
from soar_sdk.auth import ClientCredentialsFlow
|
|
23
|
+
|
|
24
|
+
flow = ClientCredentialsFlow(
|
|
25
|
+
auth_state=asset.auth_state,
|
|
26
|
+
client_id=asset.client_id,
|
|
27
|
+
client_secret=asset.client_secret,
|
|
28
|
+
token_endpoint="https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
|
|
29
|
+
scope=["https://graph.microsoft.com/.default"],
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
token = flow.get_token()
|
|
33
|
+
|
|
34
|
+
Authorization Code Flow
|
|
35
|
+
-----------------------
|
|
36
|
+
|
|
37
|
+
For user-delegated access requiring browser authorization:
|
|
38
|
+
|
|
39
|
+
.. code-block:: python
|
|
40
|
+
|
|
41
|
+
from soar_sdk.auth import AuthorizationCodeFlow
|
|
42
|
+
|
|
43
|
+
flow = AuthorizationCodeFlow(
|
|
44
|
+
auth_state=asset.auth_state,
|
|
45
|
+
asset_id=soar.get_asset_id(),
|
|
46
|
+
client_id=asset.client_id,
|
|
47
|
+
client_secret=asset.client_secret,
|
|
48
|
+
authorization_endpoint=asset.auth_url,
|
|
49
|
+
token_endpoint=asset.token_url,
|
|
50
|
+
redirect_uri=app.get_webhook_url("oauth_callback"),
|
|
51
|
+
scope=["openid", "profile", "email"],
|
|
52
|
+
use_pkce=True,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
auth_url = flow.get_authorization_url()
|
|
56
|
+
logger.progress(f"Please authorize: {auth_url}")
|
|
57
|
+
token = flow.wait_for_authorization()
|
|
58
|
+
|
|
59
|
+
Using with HTTPX
|
|
60
|
+
----------------
|
|
61
|
+
|
|
62
|
+
For automatic token injection in HTTP requests, use ``create_oauth_client``:
|
|
63
|
+
|
|
64
|
+
.. code-block:: python
|
|
65
|
+
|
|
66
|
+
from soar_sdk.auth import create_oauth_client
|
|
67
|
+
|
|
68
|
+
with create_oauth_client(asset) as client:
|
|
69
|
+
response = client.get("https://api.example.com/resource")
|
|
70
|
+
|
|
71
|
+
The factory infers ``client_id``, ``client_secret``, and ``token_endpoint`` from common
|
|
72
|
+
asset field names and returns a fully configured ``httpx.Client``.
|
|
73
|
+
|
|
74
|
+
For more control over the client, you can pass additional httpx options:
|
|
75
|
+
|
|
76
|
+
.. code-block:: python
|
|
77
|
+
|
|
78
|
+
with create_oauth_client(asset, timeout=60.0, follow_redirects=True) as client:
|
|
79
|
+
response = client.get("https://api.example.com/resource")
|
|
80
|
+
|
|
81
|
+
If you need just the auth handler (e.g., for async clients), use ``create_oauth_auth``:
|
|
82
|
+
|
|
83
|
+
.. code-block:: python
|
|
84
|
+
|
|
85
|
+
from soar_sdk.auth import create_oauth_auth
|
|
86
|
+
import httpx
|
|
87
|
+
|
|
88
|
+
auth = create_oauth_auth(asset)
|
|
89
|
+
|
|
90
|
+
with httpx.Client(auth=auth) as client:
|
|
91
|
+
response = client.get("https://api.example.com/resource")
|
|
92
|
+
|
|
93
|
+
For custom configuration:
|
|
94
|
+
|
|
95
|
+
.. code-block:: python
|
|
96
|
+
|
|
97
|
+
from soar_sdk.auth import OAuthBearerAuth, OAuthConfig, SOARAssetOAuthClient
|
|
98
|
+
|
|
99
|
+
config = OAuthConfig(
|
|
100
|
+
client_id=asset.client_id,
|
|
101
|
+
client_secret=asset.client_secret,
|
|
102
|
+
token_endpoint=asset.token_url,
|
|
103
|
+
scope=["custom_scope"],
|
|
104
|
+
)
|
|
105
|
+
oauth_client = SOARAssetOAuthClient(config, asset.auth_state)
|
|
106
|
+
auth = OAuthBearerAuth(oauth_client)
|
|
107
|
+
|
|
108
|
+
The auth handler automatically:
|
|
109
|
+
|
|
110
|
+
- Fetches tokens on first request
|
|
111
|
+
- Refreshes expired tokens when a refresh token is available
|
|
112
|
+
- Retries on 401 responses
|
|
113
|
+
|
|
114
|
+
Token Storage
|
|
115
|
+
-------------
|
|
116
|
+
|
|
117
|
+
Tokens are automatically stored in the asset's ``auth_state`` and encrypted at rest. The SDK handles:
|
|
118
|
+
|
|
119
|
+
- Token persistence across action runs
|
|
120
|
+
- Automatic refresh when tokens expire
|
|
121
|
+
- Credential change detection (forces re-authorization if client_id changes)
|
|
122
|
+
|
|
123
|
+
Certificate-based Authentication
|
|
124
|
+
---------------------------------
|
|
125
|
+
|
|
126
|
+
For certificate-based authentication (e.g., Microsoft Entra ID):
|
|
127
|
+
|
|
128
|
+
.. code-block:: python
|
|
129
|
+
|
|
130
|
+
from soar_sdk.auth import CertificateCredentials, CertificateOAuthClient, OAuthConfig
|
|
131
|
+
|
|
132
|
+
config = OAuthConfig(
|
|
133
|
+
client_id=asset.client_id,
|
|
134
|
+
token_endpoint=f"https://login.microsoftonline.com/{asset.tenant_id}/oauth2/v2.0/token",
|
|
135
|
+
scope=["https://graph.microsoft.com/.default"],
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
certificate = CertificateCredentials(
|
|
139
|
+
certificate_thumbprint=asset.cert_thumbprint,
|
|
140
|
+
private_key=asset.private_key,
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
client = CertificateOAuthClient(config, asset.auth_state, certificate)
|
|
144
|
+
token = client.fetch_token_with_certificate()
|
|
145
|
+
|
|
146
|
+
OAuth Callback Webhook
|
|
147
|
+
----------------------
|
|
148
|
+
|
|
149
|
+
For Authorization Code flow, register a webhook to receive the OAuth callback.
|
|
150
|
+
Use ``create_oauth_callback_handler`` to reduce boilerplate:
|
|
151
|
+
|
|
152
|
+
.. code-block:: python
|
|
153
|
+
|
|
154
|
+
from soar_sdk.auth import create_oauth_callback_handler, OAuthConfig, SOARAssetOAuthClient
|
|
155
|
+
|
|
156
|
+
def get_oauth_client(asset: Asset) -> SOARAssetOAuthClient:
|
|
157
|
+
config = OAuthConfig(
|
|
158
|
+
client_id=asset.client_id,
|
|
159
|
+
client_secret=asset.client_secret,
|
|
160
|
+
token_endpoint=asset.token_url,
|
|
161
|
+
)
|
|
162
|
+
return SOARAssetOAuthClient(config, asset.auth_state)
|
|
163
|
+
|
|
164
|
+
@app.webhook("oauth_callback")
|
|
165
|
+
def oauth_callback(request: WebhookRequest[Asset]) -> WebhookResponse:
|
|
166
|
+
return create_oauth_callback_handler(get_oauth_client)(request)
|
|
167
|
+
|
|
168
|
+
The factory handles error checking, code extraction, and success responses automatically.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
.. _static_token:
|
|
2
|
+
|
|
3
|
+
Static Token Authentication
|
|
4
|
+
===========================
|
|
5
|
+
|
|
6
|
+
For APIs that use API keys or pre-obtained tokens, use ``StaticTokenAuth`` with httpx:
|
|
7
|
+
|
|
8
|
+
.. code-block:: python
|
|
9
|
+
|
|
10
|
+
from soar_sdk.auth import StaticTokenAuth
|
|
11
|
+
import httpx
|
|
12
|
+
|
|
13
|
+
auth = StaticTokenAuth(asset.api_key)
|
|
14
|
+
|
|
15
|
+
with httpx.Client(auth=auth) as client:
|
|
16
|
+
response = client.get("https://api.example.com/data")
|
|
17
|
+
|
|
18
|
+
Custom Token Types
|
|
19
|
+
------------------
|
|
20
|
+
|
|
21
|
+
By default, tokens are sent as ``Bearer`` tokens. For APIs that use different token types:
|
|
22
|
+
|
|
23
|
+
.. code-block:: python
|
|
24
|
+
|
|
25
|
+
# For APIs expecting "ApiKey" prefix
|
|
26
|
+
auth = StaticTokenAuth(asset.api_key, token_type="ApiKey")
|
|
27
|
+
|
|
28
|
+
# For APIs expecting "Token" prefix
|
|
29
|
+
auth = StaticTokenAuth(asset.api_key, token_type="Token")
|
|
30
|
+
|
|
31
|
+
This sends the header as ``Authorization: ApiKey <token>`` or ``Authorization: Token <token>``.
|
|
32
|
+
|
|
33
|
+
Custom Header Names
|
|
34
|
+
-------------------
|
|
35
|
+
|
|
36
|
+
For APIs that expect tokens in headers other than ``Authorization``:
|
|
37
|
+
|
|
38
|
+
.. code-block:: python
|
|
39
|
+
|
|
40
|
+
# For APIs using X-API-Key header
|
|
41
|
+
auth = StaticTokenAuth(asset.api_key, header_name="X-API-Key", token_type="")
|
|
42
|
+
|
|
43
|
+
# For SOAR's ph-auth-token header
|
|
44
|
+
auth = StaticTokenAuth(asset.token, header_name="ph-auth-token", token_type="")
|
|
45
|
+
|
|
46
|
+
Setting ``token_type=""`` sends the raw token without a prefix.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "splunk-soar-sdk"
|
|
3
|
-
version = "3.
|
|
3
|
+
version = "3.7.0"
|
|
4
4
|
description = "The official framework for developing and testing Splunk SOAR Apps"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.13, <3.15"
|
|
@@ -46,6 +46,9 @@ dependencies = [
|
|
|
46
46
|
"setuptools>=80.9.0",
|
|
47
47
|
"httpx-retries>=0.4.5",
|
|
48
48
|
"hatchling>=1.28.0",
|
|
49
|
+
# OAuth 2.0 support
|
|
50
|
+
"authlib>=1.3.0",
|
|
51
|
+
"pyjwt[crypto]>=2.8.0",
|
|
49
52
|
]
|
|
50
53
|
|
|
51
54
|
[project.urls]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# [3.7.0](https://github.com/phantomcyber/splunk-soar-sdk/compare/3.6.1...3.7.0) (2025-12-18)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* cleanup webhook port access and webhook state storage ([54da088](https://github.com/phantomcyber/splunk-soar-sdk/commit/54da0889cf1b5202194964f5ac1b1adb744141d3))
|
|
7
|
+
* cleanup webhook state access ([0cdf11e](https://github.com/phantomcyber/splunk-soar-sdk/commit/0cdf11e568bffffe9b80160dfd051f383c19d307))
|
|
8
|
+
* improve webhook state access ([9d3b650](https://github.com/phantomcyber/splunk-soar-sdk/commit/9d3b650dc349395937d07d1c481ed84c605f0f2d))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add a category to asset fields ([8e03fa5](https://github.com/phantomcyber/splunk-soar-sdk/commit/8e03fa5289c93213ac02286a4f9f5dd1ee00bc1a))
|
|
14
|
+
* add other auth types to standardize sdk authorization ([7a1b753](https://github.com/phantomcyber/splunk-soar-sdk/commit/7a1b7531a34c94c6a15f4d446e517fa62c06467c))
|
|
15
|
+
* implement sdk oauth flow ([31396fb](https://github.com/phantomcyber/splunk-soar-sdk/commit/31396fb14ff42145f9a56692b1817d4f9abb24a0))
|
|
16
|
+
* improve webhook redirect url generation and usage ([cfbc0f0](https://github.com/phantomcyber/splunk-soar-sdk/commit/cfbc0f02096593af7caf39866431957876a707bc))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# [3.7.0](https://github.com/phantomcyber/splunk-soar-sdk/compare/3.6.1...3.7.0) (2025-12-18)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Bug Fixes
|
|
26
|
+
|
|
27
|
+
* cleanup webhook port access and webhook state storage ([54da088](https://github.com/phantomcyber/splunk-soar-sdk/commit/54da0889cf1b5202194964f5ac1b1adb744141d3))
|
|
28
|
+
* cleanup webhook state access ([0cdf11e](https://github.com/phantomcyber/splunk-soar-sdk/commit/0cdf11e568bffffe9b80160dfd051f383c19d307))
|
|
29
|
+
* improve webhook state access ([9d3b650](https://github.com/phantomcyber/splunk-soar-sdk/commit/9d3b650dc349395937d07d1c481ed84c605f0f2d))
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Features
|
|
33
|
+
|
|
34
|
+
* add a category to asset fields ([8e03fa5](https://github.com/phantomcyber/splunk-soar-sdk/commit/8e03fa5289c93213ac02286a4f9f5dd1ee00bc1a))
|
|
35
|
+
* add other auth types to standardize sdk authorization ([7a1b753](https://github.com/phantomcyber/splunk-soar-sdk/commit/7a1b7531a34c94c6a15f4d446e517fa62c06467c))
|
|
36
|
+
* implement sdk oauth flow ([31396fb](https://github.com/phantomcyber/splunk-soar-sdk/commit/31396fb14ff42145f9a56692b1817d4f9abb24a0))
|
|
37
|
+
* improve webhook redirect url generation and usage ([cfbc0f0](https://github.com/phantomcyber/splunk-soar-sdk/commit/cfbc0f02096593af7caf39866431957876a707bc))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.7.0
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import os
|
|
3
|
+
import shutil
|
|
4
|
+
import tempfile
|
|
2
5
|
from pathlib import Path
|
|
3
6
|
from typing import Any
|
|
4
7
|
|
|
@@ -135,3 +138,40 @@ class ActionsManager(BaseConnector):
|
|
|
135
138
|
This is useful for contexts such as Webhooks, where the app dir isn't necessarily the cwd, but we still need to load the app JSON reliably.
|
|
136
139
|
"""
|
|
137
140
|
self.__app_dir = app_dir
|
|
141
|
+
|
|
142
|
+
def _get_state_file_path(self, asset_id: str) -> Path:
|
|
143
|
+
"""Get the state file path for an asset."""
|
|
144
|
+
return Path(self.get_state_dir()) / f"{asset_id}_state.json"
|
|
145
|
+
|
|
146
|
+
def load_state_from_file(self, asset_id: str) -> dict:
|
|
147
|
+
"""Load state directly from file."""
|
|
148
|
+
state_file = self._get_state_file_path(asset_id)
|
|
149
|
+
if state_file.exists():
|
|
150
|
+
return json.loads(state_file.read_text())
|
|
151
|
+
return {}
|
|
152
|
+
|
|
153
|
+
def save_state_to_file(self, asset_id: str, state: dict) -> None:
|
|
154
|
+
"""Save state directly to file using atomic write."""
|
|
155
|
+
state_file = self._get_state_file_path(asset_id)
|
|
156
|
+
state_file.parent.mkdir(parents=True, exist_ok=True)
|
|
157
|
+
|
|
158
|
+
fd, tmp_path = tempfile.mkstemp(dir=state_file.parent)
|
|
159
|
+
tmp_file = Path(tmp_path)
|
|
160
|
+
try:
|
|
161
|
+
with os.fdopen(fd, "w") as f:
|
|
162
|
+
f.write(json.dumps(state))
|
|
163
|
+
shutil.move(tmp_file, state_file)
|
|
164
|
+
except Exception:
|
|
165
|
+
if tmp_file.exists():
|
|
166
|
+
tmp_file.unlink()
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
def reload_state_from_file(self, asset_id: str) -> dict:
|
|
170
|
+
"""Reload state from file and update in-memory state.
|
|
171
|
+
|
|
172
|
+
Needed for OAuth flow where one process (webhook) updates the state file and another process (action) needs to see those changes.
|
|
173
|
+
"""
|
|
174
|
+
state = self.load_state_from_file(asset_id)
|
|
175
|
+
if state:
|
|
176
|
+
self.save_state(state)
|
|
177
|
+
return state
|
|
@@ -6,6 +6,7 @@ import uuid
|
|
|
6
6
|
from collections.abc import Callable, Iterator
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
from typing import Any
|
|
9
|
+
from urllib.parse import urlparse
|
|
9
10
|
from zoneinfo import ZoneInfo
|
|
10
11
|
|
|
11
12
|
from soar_sdk.abstract import SOARClient, SOARClientAuth
|
|
@@ -226,12 +227,16 @@ class App:
|
|
|
226
227
|
self._asset = self.asset_cls.model_validate(self._raw_asset_config)
|
|
227
228
|
|
|
228
229
|
asset_id = self.soar_client.get_asset_id()
|
|
229
|
-
|
|
230
|
+
app_id = str(self.app_meta_info["appid"])
|
|
231
|
+
|
|
232
|
+
self._asset._auth_state = AssetState(
|
|
233
|
+
self.actions_manager, "auth", asset_id, app_id=app_id
|
|
234
|
+
)
|
|
230
235
|
self._asset._cache_state = AssetState(
|
|
231
|
-
self.actions_manager, "cache", asset_id
|
|
236
|
+
self.actions_manager, "cache", asset_id, app_id=app_id
|
|
232
237
|
)
|
|
233
238
|
self._asset._ingest_state = AssetState(
|
|
234
|
-
self.actions_manager, "ingest", asset_id
|
|
239
|
+
self.actions_manager, "ingest", asset_id, app_id=app_id
|
|
235
240
|
)
|
|
236
241
|
return self._asset
|
|
237
242
|
|
|
@@ -789,6 +794,47 @@ class App:
|
|
|
789
794
|
"""Decorator for registering a webhook handler."""
|
|
790
795
|
return WebhookDecorator(self, url_pattern, allowed_methods)
|
|
791
796
|
|
|
797
|
+
def get_webhook_url(self, route: str) -> str:
|
|
798
|
+
"""Build the full URL for a webhook route (used for OAuth flow)."""
|
|
799
|
+
system_info = self.soar_client.get("rest/system_info").json()
|
|
800
|
+
base_url = system_info.get("base_url", "").rstrip("/")
|
|
801
|
+
parsed = urlparse(base_url)
|
|
802
|
+
|
|
803
|
+
webhook_port = self._get_webhook_port()
|
|
804
|
+
webhook_base = f"{parsed.scheme}://{parsed.hostname}:{webhook_port}"
|
|
805
|
+
|
|
806
|
+
config = self.actions_manager.get_config()
|
|
807
|
+
directory = config.get(
|
|
808
|
+
"directory", f"{self.app_meta_info['name']}_{self.app_meta_info['appid']}"
|
|
809
|
+
)
|
|
810
|
+
asset_id = str(self.soar_client.get_asset_id())
|
|
811
|
+
|
|
812
|
+
return f"{webhook_base}/webhook/{directory}/{asset_id}/{route}"
|
|
813
|
+
|
|
814
|
+
def _get_webhook_port(self) -> int:
|
|
815
|
+
"""Get the webhook port from the feature flag configuration."""
|
|
816
|
+
try:
|
|
817
|
+
response = self.soar_client.get("rest/feature_flag/webhooks")
|
|
818
|
+
if response.status_code == 200:
|
|
819
|
+
data = response.json()
|
|
820
|
+
config = data.get("config", {})
|
|
821
|
+
if port := config.get("webhooks_port"):
|
|
822
|
+
return int(port)
|
|
823
|
+
except Exception: # noqa: S110
|
|
824
|
+
pass
|
|
825
|
+
return 3500
|
|
826
|
+
|
|
827
|
+
def _load_webhook_state(self, asset_id: str) -> None:
|
|
828
|
+
"""Load state from file for webhooks."""
|
|
829
|
+
state = self.actions_manager.load_state_from_file(asset_id)
|
|
830
|
+
if state:
|
|
831
|
+
self.actions_manager.save_state(state)
|
|
832
|
+
|
|
833
|
+
def _save_webhook_state(self, asset_id: str) -> None:
|
|
834
|
+
"""Save state to file for webhooks."""
|
|
835
|
+
state = self.actions_manager.load_state() or {}
|
|
836
|
+
self.actions_manager.save_state_to_file(asset_id, state)
|
|
837
|
+
|
|
792
838
|
def handle_webhook(
|
|
793
839
|
self,
|
|
794
840
|
method: str,
|
|
@@ -813,7 +859,7 @@ class App:
|
|
|
813
859
|
user_session_token=soar_auth_token,
|
|
814
860
|
base_url=soar_base_url,
|
|
815
861
|
)
|
|
816
|
-
self.soar_client.update_client(soar_auth, asset_id)
|
|
862
|
+
self.soar_client.update_client(soar_auth, str(asset_id))
|
|
817
863
|
|
|
818
864
|
normalized_query = {}
|
|
819
865
|
for key, value in query.items():
|
|
@@ -829,6 +875,7 @@ class App:
|
|
|
829
875
|
|
|
830
876
|
self.actions_manager.override_app_dir(self.app_root)
|
|
831
877
|
self.actions_manager._load_app_json()
|
|
878
|
+
self._load_webhook_state(str(asset_id))
|
|
832
879
|
request = WebhookRequest(
|
|
833
880
|
method=method,
|
|
834
881
|
headers=headers,
|
|
@@ -846,4 +893,5 @@ class App:
|
|
|
846
893
|
raise TypeError(
|
|
847
894
|
f"Webhook handler must return a WebhookResponse, got {type(response)}"
|
|
848
895
|
)
|
|
896
|
+
self._save_webhook_state(str(asset_id))
|
|
849
897
|
return response.model_dump()
|