splunk-soar-sdk 2.2.0__tar.gz → 2.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/PKG-INFO +1 -1
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/pyproject.toml +1 -1
- splunk_soar_sdk-2.3.1/release_notes.txt +23 -0
- splunk_soar_sdk-2.3.1/release_version.txt +1 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/abstract.py +1 -1
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/action_results.py +12 -17
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app.py +2 -7
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_client.py +2 -2
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/manifests/serializers.py +17 -3
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/make_request.py +17 -5
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/params.py +35 -2
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_serializers.py +82 -2
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/app.json +23 -6
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/app.py +10 -8
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_action_results.py +1 -11
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_actions_manager.py +6 -18
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_make_request_action.py +17 -2
- splunk_soar_sdk-2.3.1/tests/test_params.py +43 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/uv.lock +1 -1
- splunk_soar_sdk-2.2.0/release_notes.txt +0 -21
- splunk_soar_sdk-2.2.0/release_version.txt +0 -1
- splunk_soar_sdk-2.2.0/tests/test_params.py +0 -21
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/pull_request_template.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/utils/github.js +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/utils/update_version.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/workflows/code_quality.yml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/workflows/commit_hygiene.yml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/workflows/generate_docs.yml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.github/workflows/semantic_release.yml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.gitignore +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/.releaserc +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/LICENSE +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/README.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/commitlint.config.js +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/api_reference.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/app_structure/index.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/app_structure/pre-commit-config.yaml.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/app_structure/pyproject.toml.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/app_structure/src_app.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/changelog.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/cli_reference.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/conf.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/custom_views/index.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/custom_views/reusable_components.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/custom_views/templates.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/custom_views/view_handlers.md +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/getting_started/defining_asset.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/getting_started/first_action.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/getting_started/index.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/getting_started/init_app.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/getting_started/installation.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/getting_started/testing_and_building.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/docs/index.rst +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/actions_manager.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/apis/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/apis/artifact.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/apis/container.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/apis/utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/apis/vault.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_cli_runner.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_templates/basic_app/.gitignore +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_templates/basic_app/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_templates/basic_app/logo.svg +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_templates/basic_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_templates/basic_app/src/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/app_templates/basic_app/uv.lock +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/asset.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/async_utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/init/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/init/cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/manifests/cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/manifests/deserializers.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/manifests/processors.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/package/cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/package/utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/path_utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/cli/utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/action_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/app_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/asset_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/templates/pyproject.toml.jinja +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/code_renderers/toml_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/colors.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/compat.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/crypto.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/action.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/on_poll.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/test_connectivity.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/view_handler.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/decorators/webhook.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/exceptions.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/input_spec.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/logging.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/actions.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/adapters.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/app.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/datatypes.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/dependencies.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/meta/webhooks.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/models/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/models/artifact.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/models/container.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/models/vault_attachment.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/models/view.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/paths.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/py.typed +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/action_result.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/app.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/base_connector.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/connector_result.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/consts.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/encryption_helper.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/install_info.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/json_keys.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/ph_ipc.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom/vault.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom_common/app_interface/app_interface.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/shims/phantom_common/encryption/encryption_manager_factory.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/base/base_template.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/base/error.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/base/header.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/base/logo_header.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/components/pie_chart.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/widgets/widget_resize_snippet.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/templates/widgets/widget_template.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/types.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/component_registry.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/components/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/components/pie_chart.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/template_filters.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/template_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/views/view_parser.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/webhooks/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/webhooks/models.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/src/soar_sdk/webhooks/routing.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/test.png +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/test.txt +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/datapath_parse.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/manifests/test_processors.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_assets/converted_app/actions.py.txt +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_convert_cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_deserializers.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_init_cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_manifests_cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_package_cli.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/cli/test_utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/code_renderers/test_action_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/conftest.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/example_asset.json +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/logo.svg +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/pyproject.toml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/actions/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/actions/async_action.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/actions/generate_category.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/actions/reverse_string.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/src/ignoreme.txt +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/templates/reverse_string.html +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app/uv.lock +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/app.json +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/logo.svg +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/logo_dark.svg +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/pyproject.toml +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/src/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/src/app.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/example_app_with_webhook/uv.lock +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/interfaces/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/interfaces/test_artifact_interface.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/interfaces/test_container_interface.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/interfaces/test_vault_interface.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/meta/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/meta/test_actions.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/meta/test_adapters.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/meta/test_datatypes.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/meta/test_dependencies.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/meta/test_webhooks.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/mocks/__init__.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/mocks/dynamic_mocks.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/mocks/importable_action.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/stubs.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_app.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_app_action.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_app_action_params.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_app_action_results.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_app_client.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_app_runner.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_asset.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_assets/splunk-sdk-2.1.0.tar.gz +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_async_integration.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_async_utils.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_code_renderers.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_compat.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_container.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_custom_views.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_encryption.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_logging.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_on_poll.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_template_filters.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_template_renderer.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_test_connectivity.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/test_view_parser.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/tests/webhooks/test_models.py +0 -0
- {splunk_soar_sdk-2.2.0 → splunk_soar_sdk-2.3.1}/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: 2.
|
|
3
|
+
Version: 2.3.1
|
|
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
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## [2.3.1](https://github.com/phantomcyber/splunk-soar-sdk/compare/2.3.0...2.3.1) (2025-10-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* make request changes ([ae80851](https://github.com/phantomcyber/splunk-soar-sdk/commit/ae8085161210157c9d83aa296642c4c682803805))
|
|
7
|
+
* pass empty messages to platform instead of setting dummy message ([133b7f5](https://github.com/phantomcyber/splunk-soar-sdk/commit/133b7f5ace4e782469633a40ded03f54bb605d0d))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [2.3.1](https://github.com/phantomcyber/splunk-soar-sdk/compare/2.3.0...2.3.1) (2025-10-07)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* make request changes ([ae80851](https://github.com/phantomcyber/splunk-soar-sdk/commit/ae8085161210157c9d83aa296642c4c682803805))
|
|
19
|
+
* pass empty messages to platform instead of setting dummy message ([133b7f5](https://github.com/phantomcyber/splunk-soar-sdk/commit/133b7f5ace4e782469633a40ded03f54bb605d0d))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.3.1
|
|
@@ -2,10 +2,10 @@ from typing import Optional, Union, get_origin, get_args, Any
|
|
|
2
2
|
from collections.abc import Iterator
|
|
3
3
|
from typing_extensions import NotRequired, TypedDict
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
|
+
import itertools
|
|
5
6
|
|
|
6
7
|
from soar_sdk.compat import remove_when_soar_newer_than
|
|
7
8
|
from soar_sdk.shims.phantom.action_result import ActionResult as PhantomActionResult
|
|
8
|
-
|
|
9
9
|
from soar_sdk.meta.datatypes import as_datatype
|
|
10
10
|
|
|
11
11
|
remove_when_soar_newer_than(
|
|
@@ -92,7 +92,6 @@ def OutputField(
|
|
|
92
92
|
example_values: Optional[list[Union[str, float, bool]]] = None,
|
|
93
93
|
alias: Optional[str] = None,
|
|
94
94
|
column_name: Optional[str] = None,
|
|
95
|
-
column_order: Optional[int] = None,
|
|
96
95
|
) -> Any: # noqa: ANN401
|
|
97
96
|
"""Define metadata for an action output field.
|
|
98
97
|
|
|
@@ -107,7 +106,6 @@ def OutputField(
|
|
|
107
106
|
in documentation and for testing/validation purposes.
|
|
108
107
|
alias: Optional alternative name for the field when serialized.
|
|
109
108
|
column_name: Optional name for the field when displayed in a table.
|
|
110
|
-
column_order: Optional order for the field when displayed in a table (0-indexed).
|
|
111
109
|
|
|
112
110
|
Note:
|
|
113
111
|
Column name and order must be set together, if one is set but the other is not, an error will be raised.
|
|
@@ -128,7 +126,6 @@ def OutputField(
|
|
|
128
126
|
alias=alias,
|
|
129
127
|
cef_types=cef_types,
|
|
130
128
|
column_name=column_name,
|
|
131
|
-
column_order=column_order,
|
|
132
129
|
)
|
|
133
130
|
|
|
134
131
|
|
|
@@ -163,7 +160,9 @@ class ActionOutput(BaseModel):
|
|
|
163
160
|
|
|
164
161
|
@classmethod
|
|
165
162
|
def _to_json_schema(
|
|
166
|
-
cls,
|
|
163
|
+
cls,
|
|
164
|
+
parent_datapath: str = "action_result.data.*",
|
|
165
|
+
column_order_counter: Optional[itertools.count] = None,
|
|
167
166
|
) -> Iterator[OutputFieldSpecification]:
|
|
168
167
|
"""Convert the ActionOutput class to SOAR-compatible JSON schema.
|
|
169
168
|
|
|
@@ -174,6 +173,8 @@ class ActionOutput(BaseModel):
|
|
|
174
173
|
Args:
|
|
175
174
|
parent_datapath: The base datapath for fields in this output.
|
|
176
175
|
Defaults to "action_result.data.*" for top-level outputs.
|
|
176
|
+
column_order_counter: Iterator for tracking column order across fields.
|
|
177
|
+
Used internally to maintain sequential column ordering. Defaults to itertools.count().
|
|
177
178
|
|
|
178
179
|
Yields:
|
|
179
180
|
OutputFieldSpecification objects describing each field in the schema.
|
|
@@ -187,6 +188,9 @@ class ActionOutput(BaseModel):
|
|
|
187
188
|
Nested ActionOutput classes are recursively processed.
|
|
188
189
|
Boolean fields automatically get [True, False] example values.
|
|
189
190
|
"""
|
|
191
|
+
if column_order_counter is None:
|
|
192
|
+
column_order_counter = itertools.count()
|
|
193
|
+
|
|
190
194
|
for _field_name, field in cls.__fields__.items():
|
|
191
195
|
field_name = alias if (alias := field.alias) else _field_name
|
|
192
196
|
|
|
@@ -219,7 +223,7 @@ class ActionOutput(BaseModel):
|
|
|
219
223
|
|
|
220
224
|
if issubclass(field_type, ActionOutput):
|
|
221
225
|
# If the field is another ActionOutput, recursively call _to_json_schema
|
|
222
|
-
yield from field_type._to_json_schema(datapath)
|
|
226
|
+
yield from field_type._to_json_schema(datapath, column_order_counter)
|
|
223
227
|
continue
|
|
224
228
|
else:
|
|
225
229
|
try:
|
|
@@ -241,20 +245,11 @@ class ActionOutput(BaseModel):
|
|
|
241
245
|
if field_type is bool:
|
|
242
246
|
schema_field["example_values"] = [True, False]
|
|
243
247
|
|
|
244
|
-
# Validate column metadata - both column_name and column_order must be present together
|
|
245
248
|
column_name = field.field_info.extra.get("column_name")
|
|
246
|
-
column_order = field.field_info.extra.get("column_order")
|
|
247
|
-
|
|
248
|
-
# Check if exactly one is set (XOR condition - invalid)
|
|
249
|
-
if (column_name is None) != (column_order is None):
|
|
250
|
-
raise ValueError(
|
|
251
|
-
f"Field '{field_name}' must have both 'column_name' and 'column_order' "
|
|
252
|
-
f"or neither. Found: column_name={column_name}, column_order={column_order}"
|
|
253
|
-
)
|
|
254
249
|
|
|
255
|
-
if column_name is not None
|
|
250
|
+
if column_name is not None:
|
|
256
251
|
schema_field["column_name"] = column_name
|
|
257
|
-
schema_field["column_order"] =
|
|
252
|
+
schema_field["column_order"] = next(column_order_counter)
|
|
258
253
|
|
|
259
254
|
yield schema_field
|
|
260
255
|
|
|
@@ -636,7 +636,7 @@ class App:
|
|
|
636
636
|
],
|
|
637
637
|
actions_manager: ActionsManager,
|
|
638
638
|
action_params: Optional[Params] = None,
|
|
639
|
-
message:
|
|
639
|
+
message: str = "",
|
|
640
640
|
summary: Optional[ActionOutput] = None,
|
|
641
641
|
) -> bool:
|
|
642
642
|
"""Handles multiple ways of returning response from action.
|
|
@@ -657,9 +657,7 @@ class App:
|
|
|
657
657
|
)
|
|
658
658
|
# Handle empty list/iterator case
|
|
659
659
|
if not statuses:
|
|
660
|
-
result = ActionOutput(
|
|
661
|
-
status=True, message=message or "Action completed successfully"
|
|
662
|
-
)
|
|
660
|
+
result = ActionOutput(status=True, message=message)
|
|
663
661
|
else:
|
|
664
662
|
return all(statuses)
|
|
665
663
|
|
|
@@ -667,9 +665,6 @@ class App:
|
|
|
667
665
|
output_dict = result.dict(by_alias=True)
|
|
668
666
|
param_dict = action_params.dict() if action_params else None
|
|
669
667
|
|
|
670
|
-
if not message:
|
|
671
|
-
message = "Action completed successfully"
|
|
672
|
-
|
|
673
668
|
result = ActionResult(
|
|
674
669
|
status=True,
|
|
675
670
|
message=message,
|
|
@@ -44,7 +44,7 @@ class AppClient(SOARClient[SummaryType]):
|
|
|
44
44
|
self.basic_auth: Optional[BasicAuth] = None
|
|
45
45
|
|
|
46
46
|
self._summary: Optional[SummaryType] = None
|
|
47
|
-
self._message:
|
|
47
|
+
self._message: str = ""
|
|
48
48
|
self.__container_id: int = 0
|
|
49
49
|
self.__asset_id: str = ""
|
|
50
50
|
|
|
@@ -171,6 +171,6 @@ class AppClient(SOARClient[SummaryType]):
|
|
|
171
171
|
"""Get the summary for the action result."""
|
|
172
172
|
return self._summary
|
|
173
173
|
|
|
174
|
-
def get_message(self) ->
|
|
174
|
+
def get_message(self) -> str:
|
|
175
175
|
"""Get the message for the action result."""
|
|
176
176
|
return self._message
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from typing import Any, Optional
|
|
2
2
|
from collections.abc import Iterator
|
|
3
3
|
from logging import getLogger
|
|
4
|
+
import itertools
|
|
4
5
|
|
|
5
6
|
from soar_sdk.meta.datatypes import as_datatype
|
|
6
7
|
from soar_sdk.params import Params
|
|
@@ -29,8 +30,12 @@ class OutputsSerializer:
|
|
|
29
30
|
@staticmethod
|
|
30
31
|
def serialize_parameter_datapaths(
|
|
31
32
|
params_class: type[Params],
|
|
33
|
+
column_order_counter: Optional[itertools.count] = None,
|
|
32
34
|
) -> Iterator[OutputFieldSpecification]:
|
|
33
35
|
"""Serializes the parameter data paths of a Params class to JSON schema."""
|
|
36
|
+
if column_order_counter is None:
|
|
37
|
+
column_order_counter = itertools.count()
|
|
38
|
+
|
|
34
39
|
for field_name, field in params_class.__fields__.items():
|
|
35
40
|
spec = OutputFieldSpecification(
|
|
36
41
|
data_path=f"action_result.parameter.{field_name}",
|
|
@@ -38,6 +43,12 @@ class OutputsSerializer:
|
|
|
38
43
|
)
|
|
39
44
|
if cef_types := field.field_info.extra.get("cef_types"):
|
|
40
45
|
spec["contains"] = cef_types
|
|
46
|
+
|
|
47
|
+
column_name = field.field_info.extra.get("column_name")
|
|
48
|
+
|
|
49
|
+
if column_name is not None:
|
|
50
|
+
spec["column_name"] = column_name
|
|
51
|
+
spec["column_order"] = next(column_order_counter)
|
|
41
52
|
yield spec
|
|
42
53
|
|
|
43
54
|
@classmethod
|
|
@@ -57,10 +68,13 @@ class OutputsSerializer:
|
|
|
57
68
|
data_path="action_result.message",
|
|
58
69
|
data_type="string",
|
|
59
70
|
)
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
column_order_counter = itertools.count()
|
|
72
|
+
params = cls.serialize_parameter_datapaths(params_class, column_order_counter)
|
|
73
|
+
outputs = outputs_class._to_json_schema(
|
|
74
|
+
column_order_counter=column_order_counter
|
|
75
|
+
)
|
|
62
76
|
summary = (
|
|
63
|
-
summary_class._to_json_schema("action_result.summary")
|
|
77
|
+
summary_class._to_json_schema("action_result.summary", column_order_counter)
|
|
64
78
|
if summary_class
|
|
65
79
|
else []
|
|
66
80
|
)
|
|
@@ -43,19 +43,31 @@ class MakeRequestDecorator:
|
|
|
43
43
|
"The 'make_request' decorator can only be used once per App instance."
|
|
44
44
|
)
|
|
45
45
|
|
|
46
|
-
# Validate function signature - must have
|
|
46
|
+
# Validate function signature - must have exactly one parameter of type MakeRequestParams
|
|
47
47
|
signature = inspect.signature(function)
|
|
48
48
|
params = list(signature.parameters.values())
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
make_request_params = [
|
|
51
|
+
param
|
|
52
|
+
for param in params
|
|
53
|
+
if inspect.isclass(param.annotation)
|
|
54
|
+
and issubclass(param.annotation, MakeRequestParams)
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
if len(make_request_params) == 0:
|
|
58
|
+
raise TypeError(
|
|
59
|
+
"Make request action function must have exactly one parameter of type MakeRequestParams or its subclass."
|
|
60
|
+
)
|
|
61
|
+
elif len(make_request_params) > 1:
|
|
62
|
+
param_names = [p.name for p in make_request_params]
|
|
51
63
|
raise TypeError(
|
|
52
|
-
f"Make request action function
|
|
64
|
+
f"Make request action function can only have one MakeRequestParams parameter, "
|
|
65
|
+
f"but found {len(make_request_params)}: {param_names}"
|
|
53
66
|
)
|
|
54
67
|
|
|
55
68
|
action_identifier = "make_request"
|
|
56
69
|
action_name = "make request"
|
|
57
|
-
|
|
58
|
-
validated_params_class = MakeRequestParams
|
|
70
|
+
validated_params_class = make_request_params[0].annotation
|
|
59
71
|
|
|
60
72
|
return_type = inspect.signature(function).return_annotation
|
|
61
73
|
if return_type is not inspect.Signature.empty:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import Optional, Union, Any
|
|
1
|
+
from typing import Optional, Union, Any, ClassVar
|
|
2
2
|
from typing_extensions import NotRequired, TypedDict
|
|
3
3
|
|
|
4
4
|
from pydantic.fields import Field, Undefined
|
|
@@ -22,6 +22,7 @@ def Param(
|
|
|
22
22
|
allow_list: bool = False,
|
|
23
23
|
sensitive: bool = False,
|
|
24
24
|
alias: Optional[str] = None,
|
|
25
|
+
column_name: Optional[str] = None,
|
|
25
26
|
) -> Any: # noqa: ANN401
|
|
26
27
|
"""Representation of a single complex action parameter.
|
|
27
28
|
|
|
@@ -49,6 +50,7 @@ def Param(
|
|
|
49
50
|
:param allow_list: Use this key to specify if the parameter supports specifying
|
|
50
51
|
multiple values as a comma separated string.
|
|
51
52
|
:param kwargs: additional kwargs accepted by pydantic.Field
|
|
53
|
+
:param column_name: Optional name for the parameter when displayed in an output table.
|
|
52
54
|
:return: returns the FieldInfo object as pydantic.Field
|
|
53
55
|
"""
|
|
54
56
|
if value_list is None:
|
|
@@ -64,6 +66,7 @@ def Param(
|
|
|
64
66
|
allow_list=allow_list,
|
|
65
67
|
sensitive=sensitive,
|
|
66
68
|
alias=alias,
|
|
69
|
+
column_name=column_name,
|
|
67
70
|
)
|
|
68
71
|
|
|
69
72
|
|
|
@@ -80,6 +83,8 @@ class InputFieldSpecification(TypedDict):
|
|
|
80
83
|
value_list: NotRequired[list[str]]
|
|
81
84
|
allow_list: bool
|
|
82
85
|
default: NotRequired[Union[str, int, float, bool]]
|
|
86
|
+
column_name: NotRequired[str]
|
|
87
|
+
column_order: NotRequired[int]
|
|
83
88
|
|
|
84
89
|
|
|
85
90
|
class Params(BaseModel):
|
|
@@ -173,6 +178,34 @@ class OnPollParams(Params):
|
|
|
173
178
|
class MakeRequestParams(Params):
|
|
174
179
|
"""Canonical parameters for the special make request action."""
|
|
175
180
|
|
|
181
|
+
# Define allowed field names for subclasses
|
|
182
|
+
_ALLOWED_FIELDS: ClassVar[set[str]] = {
|
|
183
|
+
"http_method",
|
|
184
|
+
"endpoint",
|
|
185
|
+
"headers",
|
|
186
|
+
"query_parameters",
|
|
187
|
+
"body",
|
|
188
|
+
"timeout",
|
|
189
|
+
"verify_ssl",
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
def __init_subclass__(cls, **kwargs: dict[str, Any]) -> None:
|
|
193
|
+
"""Validate that subclasses only define allowed fields."""
|
|
194
|
+
super().__init_subclass__(**kwargs)
|
|
195
|
+
cls._validate_make_request_fields()
|
|
196
|
+
|
|
197
|
+
@classmethod
|
|
198
|
+
def _validate_make_request_fields(cls) -> None:
|
|
199
|
+
"""Ensure subclasses only define allowed MakeRequest fields."""
|
|
200
|
+
# Check if any fields are not in the allowed set
|
|
201
|
+
invalid_fields = set(cls.__fields__.keys()) - cls._ALLOWED_FIELDS
|
|
202
|
+
|
|
203
|
+
if invalid_fields:
|
|
204
|
+
raise TypeError(
|
|
205
|
+
f"MakeRequestParams subclass '{cls.__name__}' can only define these fields: "
|
|
206
|
+
f"{sorted(cls._ALLOWED_FIELDS)}. Invalid fields: {sorted(invalid_fields)}"
|
|
207
|
+
)
|
|
208
|
+
|
|
176
209
|
http_method: str = Param(
|
|
177
210
|
description="The HTTP method to use for the request.",
|
|
178
211
|
required=True,
|
|
@@ -189,7 +222,7 @@ class MakeRequestParams(Params):
|
|
|
189
222
|
required=False,
|
|
190
223
|
)
|
|
191
224
|
|
|
192
|
-
|
|
225
|
+
query_parameters: str = Param(
|
|
193
226
|
description="The query string to send with the request.",
|
|
194
227
|
required=False,
|
|
195
228
|
)
|
|
@@ -153,7 +153,7 @@ def test_outputs_serialize_with_defaults():
|
|
|
153
153
|
|
|
154
154
|
def test_outputs_serialize_output_class():
|
|
155
155
|
class SampleNestedOutput(ActionOutput):
|
|
156
|
-
bool_value: bool = OutputField(column_name="Nested Value"
|
|
156
|
+
bool_value: bool = OutputField(column_name="Nested Value")
|
|
157
157
|
|
|
158
158
|
class SampleOutput(ActionOutput):
|
|
159
159
|
string_value: str
|
|
@@ -163,7 +163,6 @@ def test_outputs_serialize_output_class():
|
|
|
163
163
|
cef_types=["ip"],
|
|
164
164
|
example_values=["1.1.1.1"],
|
|
165
165
|
column_name="CEF Value",
|
|
166
|
-
column_order=0,
|
|
167
166
|
)
|
|
168
167
|
nested_value: SampleNestedOutput
|
|
169
168
|
underscored_value: str = OutputField(alias="_underscored_value")
|
|
@@ -306,3 +305,84 @@ def test_outputs_serialize_with_parameters_class():
|
|
|
306
305
|
"example_values": [1],
|
|
307
306
|
},
|
|
308
307
|
]
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def test_serialize_parameter_datapaths():
|
|
311
|
+
class SampleParams(Params):
|
|
312
|
+
cef_value: str = Param(cef_types=["user name"], column_name="CEF Value")
|
|
313
|
+
|
|
314
|
+
serialized_parameter_datapaths = list(
|
|
315
|
+
OutputsSerializer.serialize_parameter_datapaths(SampleParams)
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
assert serialized_parameter_datapaths == [
|
|
319
|
+
{
|
|
320
|
+
"data_path": "action_result.parameter.cef_value",
|
|
321
|
+
"data_type": "string",
|
|
322
|
+
"contains": ["user name"],
|
|
323
|
+
"column_name": "CEF Value",
|
|
324
|
+
"column_order": 0,
|
|
325
|
+
},
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def test_serilized_datapaths_params():
|
|
330
|
+
class SampleParams(Params):
|
|
331
|
+
int_value: int
|
|
332
|
+
str_value: str
|
|
333
|
+
bool_value: bool
|
|
334
|
+
cef_value: str = Param(cef_types=["user name"], column_name="CEF Value")
|
|
335
|
+
|
|
336
|
+
class SampleOutput(ActionOutput):
|
|
337
|
+
string_value: str = OutputField(column_name="String Value")
|
|
338
|
+
|
|
339
|
+
serialized_outputs = OutputsSerializer.serialize_datapaths(
|
|
340
|
+
SampleParams, SampleOutput
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
assert serialized_outputs == [
|
|
344
|
+
{
|
|
345
|
+
"data_path": "action_result.status",
|
|
346
|
+
"data_type": "string",
|
|
347
|
+
"example_values": ["success", "failure"],
|
|
348
|
+
},
|
|
349
|
+
{
|
|
350
|
+
"data_path": "action_result.message",
|
|
351
|
+
"data_type": "string",
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
"data_path": "action_result.parameter.int_value",
|
|
355
|
+
"data_type": "numeric",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
"data_path": "action_result.parameter.str_value",
|
|
359
|
+
"data_type": "string",
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
"data_path": "action_result.parameter.bool_value",
|
|
363
|
+
"data_type": "boolean",
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
"data_path": "action_result.parameter.cef_value",
|
|
367
|
+
"data_type": "string",
|
|
368
|
+
"contains": ["user name"],
|
|
369
|
+
"column_name": "CEF Value",
|
|
370
|
+
"column_order": 0,
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
"data_path": "action_result.data.*.string_value",
|
|
374
|
+
"data_type": "string",
|
|
375
|
+
"column_name": "String Value",
|
|
376
|
+
"column_order": 1,
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"data_path": "summary.total_objects",
|
|
380
|
+
"data_type": "numeric",
|
|
381
|
+
"example_values": [1],
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
"data_path": "summary.total_objects_successful",
|
|
385
|
+
"data_type": "numeric",
|
|
386
|
+
"example_values": [1],
|
|
387
|
+
},
|
|
388
|
+
]
|
|
@@ -246,7 +246,18 @@
|
|
|
246
246
|
"read_only": true,
|
|
247
247
|
"versions": "EQ(*)",
|
|
248
248
|
"verbose": "",
|
|
249
|
-
"parameters": {
|
|
249
|
+
"parameters": {
|
|
250
|
+
"company_name": {
|
|
251
|
+
"order": 0,
|
|
252
|
+
"name": "company_name",
|
|
253
|
+
"description": "Company Name",
|
|
254
|
+
"data_type": "string",
|
|
255
|
+
"required": true,
|
|
256
|
+
"primary": false,
|
|
257
|
+
"allow_list": false,
|
|
258
|
+
"default": "Splunk"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
250
261
|
"output": [
|
|
251
262
|
{
|
|
252
263
|
"data_path": "action_result.status",
|
|
@@ -260,6 +271,12 @@
|
|
|
260
271
|
"data_path": "action_result.message",
|
|
261
272
|
"data_type": "string"
|
|
262
273
|
},
|
|
274
|
+
{
|
|
275
|
+
"data_path": "action_result.parameter.company_name",
|
|
276
|
+
"data_type": "string",
|
|
277
|
+
"column_name": "Company Name",
|
|
278
|
+
"column_order": 0
|
|
279
|
+
},
|
|
263
280
|
{
|
|
264
281
|
"data_path": "action_result.data.*.name",
|
|
265
282
|
"data_type": "string",
|
|
@@ -269,7 +286,7 @@
|
|
|
269
286
|
"Jim"
|
|
270
287
|
],
|
|
271
288
|
"column_name": "Name",
|
|
272
|
-
"column_order":
|
|
289
|
+
"column_order": 1
|
|
273
290
|
},
|
|
274
291
|
{
|
|
275
292
|
"data_path": "action_result.data.*.age",
|
|
@@ -280,7 +297,7 @@
|
|
|
280
297
|
35
|
|
281
298
|
],
|
|
282
299
|
"column_name": "Age",
|
|
283
|
-
"column_order":
|
|
300
|
+
"column_order": 2
|
|
284
301
|
},
|
|
285
302
|
{
|
|
286
303
|
"data_path": "summary.total_objects",
|
|
@@ -482,9 +499,9 @@
|
|
|
482
499
|
"primary": false,
|
|
483
500
|
"allow_list": false
|
|
484
501
|
},
|
|
485
|
-
"
|
|
502
|
+
"query_parameters": {
|
|
486
503
|
"order": 3,
|
|
487
|
-
"name": "
|
|
504
|
+
"name": "query_parameters",
|
|
488
505
|
"description": "The query string to send with the request.",
|
|
489
506
|
"data_type": "string",
|
|
490
507
|
"required": false,
|
|
@@ -545,7 +562,7 @@
|
|
|
545
562
|
"data_type": "string"
|
|
546
563
|
},
|
|
547
564
|
{
|
|
548
|
-
"data_path": "action_result.parameter.
|
|
565
|
+
"data_path": "action_result.parameter.query_parameters",
|
|
549
566
|
"data_type": "string"
|
|
550
567
|
},
|
|
551
568
|
{
|
|
@@ -5,7 +5,7 @@ from zoneinfo import ZoneInfo
|
|
|
5
5
|
from soar_sdk.abstract import SOARClient
|
|
6
6
|
from soar_sdk.app import App
|
|
7
7
|
from soar_sdk.asset import AssetField, BaseAsset
|
|
8
|
-
from soar_sdk.params import OnPollParams, MakeRequestParams, Params
|
|
8
|
+
from soar_sdk.params import OnPollParams, MakeRequestParams, Params, Param
|
|
9
9
|
from soar_sdk.models.container import Container
|
|
10
10
|
from soar_sdk.models.artifact import Artifact
|
|
11
11
|
from soar_sdk.action_results import ActionOutput, MakeRequestOutput, OutputField
|
|
@@ -73,12 +73,12 @@ def test_empty_list_output(
|
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
class JsonOutput(ActionOutput):
|
|
76
|
-
name: str = OutputField(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
)
|
|
76
|
+
name: str = OutputField(example_values=["John", "Jane", "Jim"], column_name="Name")
|
|
77
|
+
age: int = OutputField(example_values=[25, 30, 35], column_name="Age")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class TableParams(Params):
|
|
81
|
+
company_name: str = Param(column_name="Company Name", default="Splunk")
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
@app.action(render_as="json")
|
|
@@ -87,7 +87,9 @@ def test_json_output(params: Params, asset: Asset, soar: SOARClient) -> JsonOutp
|
|
|
87
87
|
|
|
88
88
|
|
|
89
89
|
@app.action(render_as="table")
|
|
90
|
-
def test_table_output(
|
|
90
|
+
def test_table_output(
|
|
91
|
+
params: TableParams, asset: Asset, soar: SOARClient
|
|
92
|
+
) -> JsonOutput:
|
|
91
93
|
return JsonOutput(name="John", age=25)
|
|
92
94
|
|
|
93
95
|
|
|
@@ -157,7 +157,7 @@ def test_action_output_to_dict():
|
|
|
157
157
|
|
|
158
158
|
def test_action_output_to_json_schema_with_column_name_and_column_order():
|
|
159
159
|
class ExampleActionOutputWithColumnNames(ActionOutput):
|
|
160
|
-
stringy_field: str = OutputField(column_name="Stringy Field"
|
|
160
|
+
stringy_field: str = OutputField(column_name="Stringy Field")
|
|
161
161
|
|
|
162
162
|
schema = list(ExampleActionOutputWithColumnNames._to_json_schema())
|
|
163
163
|
assert schema == [
|
|
@@ -168,13 +168,3 @@ def test_action_output_to_json_schema_with_column_name_and_column_order():
|
|
|
168
168
|
"column_order": 0,
|
|
169
169
|
}
|
|
170
170
|
]
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def test_action_output_to_json_schema_with_column_name_and_column_order_missing():
|
|
174
|
-
class ExampleActionOutputWithColumnNames(ActionOutput):
|
|
175
|
-
stringy_field: str = OutputField(column_name="Stringy Field")
|
|
176
|
-
|
|
177
|
-
with pytest.raises(
|
|
178
|
-
ValueError, match="must have both 'column_name' and 'column_order'"
|
|
179
|
-
):
|
|
180
|
-
list(ExampleActionOutputWithColumnNames._to_json_schema())
|
|
@@ -98,10 +98,7 @@ def test_action_called_returning_iterator(
|
|
|
98
98
|
example_app.handle(simple_action_input.json())
|
|
99
99
|
|
|
100
100
|
assert len(example_app.actions_manager.get_results()) == 5
|
|
101
|
-
assert all(
|
|
102
|
-
"success" in result.message
|
|
103
|
-
for result in example_app.actions_manager.get_results()
|
|
104
|
-
)
|
|
101
|
+
assert all(result.status for result in example_app.actions_manager.get_results())
|
|
105
102
|
|
|
106
103
|
|
|
107
104
|
def test_async_action_called_returning_iterator(
|
|
@@ -120,10 +117,7 @@ def test_async_action_called_returning_iterator(
|
|
|
120
117
|
example_app.handle(simple_action_input.json())
|
|
121
118
|
|
|
122
119
|
assert len(example_app.actions_manager.get_results()) == 5
|
|
123
|
-
assert all(
|
|
124
|
-
"success" in result.message
|
|
125
|
-
for result in example_app.actions_manager.get_results()
|
|
126
|
-
)
|
|
120
|
+
assert all(result.status for result in example_app.actions_manager.get_results())
|
|
127
121
|
|
|
128
122
|
|
|
129
123
|
def test_action_called_returning_list(
|
|
@@ -139,10 +133,7 @@ def test_action_called_returning_list(
|
|
|
139
133
|
example_app.handle(simple_action_input.json())
|
|
140
134
|
|
|
141
135
|
assert len(example_app.actions_manager.get_results()) == 5
|
|
142
|
-
assert all(
|
|
143
|
-
"success" in result.message
|
|
144
|
-
for result in example_app.actions_manager.get_results()
|
|
145
|
-
)
|
|
136
|
+
assert all(result.status for result in example_app.actions_manager.get_results())
|
|
146
137
|
|
|
147
138
|
|
|
148
139
|
def test_async_action_called_returning_list(
|
|
@@ -158,10 +149,7 @@ def test_async_action_called_returning_list(
|
|
|
158
149
|
example_app.handle(simple_action_input.json())
|
|
159
150
|
|
|
160
151
|
assert len(example_app.actions_manager.get_results()) == 5
|
|
161
|
-
assert all(
|
|
162
|
-
"success" in result.message
|
|
163
|
-
for result in example_app.actions_manager.get_results()
|
|
164
|
-
)
|
|
152
|
+
assert all(result.status for result in example_app.actions_manager.get_results())
|
|
165
153
|
|
|
166
154
|
|
|
167
155
|
def test_action_called_with_default_message_set(
|
|
@@ -174,7 +162,7 @@ def test_action_called_with_default_message_set(
|
|
|
174
162
|
example_app.handle(simple_action_input.json())
|
|
175
163
|
|
|
176
164
|
assert len(example_app.actions_manager.get_results()) == 1
|
|
177
|
-
assert
|
|
165
|
+
assert example_app.actions_manager.get_results()[0].status
|
|
178
166
|
|
|
179
167
|
|
|
180
168
|
def test_action_called_with_timezone_asset(example_app: App):
|
|
@@ -204,7 +192,7 @@ def test_action_called_with_timezone_asset(example_app: App):
|
|
|
204
192
|
example_app.handle(action_input.json())
|
|
205
193
|
|
|
206
194
|
assert len(example_app.actions_manager.get_results()) == 1
|
|
207
|
-
assert
|
|
195
|
+
assert example_app.actions_manager.get_results()[0].status
|
|
208
196
|
|
|
209
197
|
|
|
210
198
|
def test_actions_provider_running_undefined_action(
|