splunk-soar-sdk 2.1.1__tar.gz → 2.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/PKG-INFO +1 -1
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/pyproject.toml +1 -1
- splunk_soar_sdk-2.3.0/release_notes.txt +31 -0
- splunk_soar_sdk-2.3.0/release_version.txt +1 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/action_results.py +25 -4
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app.py +4 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/serializers.py +17 -3
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/action.py +11 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/actions.py +10 -4
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/params.py +5 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_deserializers.py +5 -1
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_serializers.py +91 -2
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/app.json +143 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/app.py +23 -2
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_actions.py +3 -2
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_action_results.py +15 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_action.py +43 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/uv.lock +1 -1
- splunk_soar_sdk-2.1.1/release_notes.txt +0 -21
- splunk_soar_sdk-2.1.1/release_version.txt +0 -1
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/pull_request_template.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/utils/github.js +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/utils/update_version.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/code_quality.yml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/commit_hygiene.yml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/generate_docs.yml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/semantic_release.yml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.gitignore +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.releaserc +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/LICENSE +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/README.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/commitlint.config.js +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/api_reference.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/index.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/pre-commit-config.yaml.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/pyproject.toml.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/src_app.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/changelog.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/cli_reference.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/conf.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/index.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/reusable_components.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/templates.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/view_handlers.md +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/defining_asset.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/first_action.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/index.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/init_app.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/installation.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/testing_and_building.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/index.rst +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/abstract.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/actions_manager.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/artifact.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/container.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/vault.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_cli_runner.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_client.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/.gitignore +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/logo.svg +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/src/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/uv.lock +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/asset.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/async_utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/init/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/init/cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/deserializers.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/processors.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/package/cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/package/utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/path_utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/action_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/app_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/asset_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/templates/pyproject.toml.jinja +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/toml_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/colors.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/compat.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/crypto.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/make_request.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/on_poll.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/test_connectivity.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/view_handler.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/webhook.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/exceptions.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/input_spec.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/logging.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/adapters.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/app.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/datatypes.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/dependencies.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/webhooks.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/artifact.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/container.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/vault_attachment.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/view.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/paths.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/py.typed +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/action_result.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/app.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/base_connector.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/connector_result.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/consts.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/encryption_helper.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/install_info.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/json_keys.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/ph_ipc.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/vault.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom_common/app_interface/app_interface.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom_common/encryption/encryption_manager_factory.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/base_template.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/error.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/header.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/logo_header.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/components/pie_chart.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/widgets/widget_resize_snippet.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/widgets/widget_template.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/types.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/component_registry.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/components/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/components/pie_chart.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/template_filters.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/template_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/view_parser.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/webhooks/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/webhooks/models.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/webhooks/routing.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/test.png +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/test.txt +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/datapath_parse.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/manifests/test_processors.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_assets/converted_app/actions.py.txt +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_convert_cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_init_cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_manifests_cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_package_cli.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/code_renderers/test_action_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/conftest.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/example_asset.json +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/logo.svg +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/pyproject.toml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/async_action.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/generate_category.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/reverse_string.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/ignoreme.txt +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/templates/reverse_string.html +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/uv.lock +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/app.json +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/logo.svg +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/logo_dark.svg +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/pyproject.toml +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/src/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/src/app.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/uv.lock +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/test_artifact_interface.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/test_container_interface.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/test_vault_interface.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_adapters.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_datatypes.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_dependencies.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_webhooks.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/mocks/__init__.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/mocks/dynamic_mocks.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/mocks/importable_action.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/stubs.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_actions_manager.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_action_params.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_action_results.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_client.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_runner.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_asset.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_assets/splunk-sdk-2.1.0.tar.gz +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_async_integration.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_async_utils.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_code_renderers.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_compat.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_container.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_custom_views.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_encryption.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_logging.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_make_request_action.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_on_poll.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_params.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_template_filters.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_template_renderer.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_test_connectivity.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_view_parser.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/webhooks/test_models.py +0 -0
- {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.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: 2.
|
|
3
|
+
Version: 2.3.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
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# [2.3.0](https://github.com/phantomcyber/splunk-soar-sdk/compare/2.2.0...2.3.0) (2025-10-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* get rid of column_order and maintain counter instead ([c9b011d](https://github.com/phantomcyber/splunk-soar-sdk/commit/c9b011d84688f22b5ac2aa7f32a29468762ebe0d))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* adding column name and column order to params as well ([69a752e](https://github.com/phantomcyber/splunk-soar-sdk/commit/69a752e19d9c730ef319277480aa0a24fca03c2e))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [2.3.0](https://github.com/phantomcyber/splunk-soar-sdk/compare/2.2.0...2.3.0) (2025-10-02)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* get rid of column_order and maintain counter instead ([c9b011d](https://github.com/phantomcyber/splunk-soar-sdk/commit/c9b011d84688f22b5ac2aa7f32a29468762ebe0d))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* adding column name and column order to params as well ([69a752e](https://github.com/phantomcyber/splunk-soar-sdk/commit/69a752e19d9c730ef319277480aa0a24fca03c2e))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.3.0
|
|
@@ -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(
|
|
@@ -83,12 +83,15 @@ class OutputFieldSpecification(TypedDict):
|
|
|
83
83
|
data_type: str
|
|
84
84
|
contains: NotRequired[list[str]]
|
|
85
85
|
example_values: NotRequired[list[Union[str, float, bool]]]
|
|
86
|
+
column_name: NotRequired[str]
|
|
87
|
+
column_order: NotRequired[int]
|
|
86
88
|
|
|
87
89
|
|
|
88
90
|
def OutputField(
|
|
89
91
|
cef_types: Optional[list[str]] = None,
|
|
90
92
|
example_values: Optional[list[Union[str, float, bool]]] = None,
|
|
91
93
|
alias: Optional[str] = None,
|
|
94
|
+
column_name: Optional[str] = None,
|
|
92
95
|
) -> Any: # noqa: ANN401
|
|
93
96
|
"""Define metadata for an action output field.
|
|
94
97
|
|
|
@@ -102,6 +105,10 @@ def OutputField(
|
|
|
102
105
|
example_values: Optional list of example values for this field, used
|
|
103
106
|
in documentation and for testing/validation purposes.
|
|
104
107
|
alias: Optional alternative name for the field when serialized.
|
|
108
|
+
column_name: Optional name for the field when displayed in a table.
|
|
109
|
+
|
|
110
|
+
Note:
|
|
111
|
+
Column name and order must be set together, if one is set but the other is not, an error will be raised.
|
|
105
112
|
|
|
106
113
|
Returns:
|
|
107
114
|
A Pydantic Field object with the specified metadata.
|
|
@@ -116,8 +123,9 @@ def OutputField(
|
|
|
116
123
|
"""
|
|
117
124
|
return Field(
|
|
118
125
|
examples=example_values,
|
|
119
|
-
cef_types=cef_types,
|
|
120
126
|
alias=alias,
|
|
127
|
+
cef_types=cef_types,
|
|
128
|
+
column_name=column_name,
|
|
121
129
|
)
|
|
122
130
|
|
|
123
131
|
|
|
@@ -152,7 +160,9 @@ class ActionOutput(BaseModel):
|
|
|
152
160
|
|
|
153
161
|
@classmethod
|
|
154
162
|
def _to_json_schema(
|
|
155
|
-
cls,
|
|
163
|
+
cls,
|
|
164
|
+
parent_datapath: str = "action_result.data.*",
|
|
165
|
+
column_order_counter: Optional[itertools.count] = None,
|
|
156
166
|
) -> Iterator[OutputFieldSpecification]:
|
|
157
167
|
"""Convert the ActionOutput class to SOAR-compatible JSON schema.
|
|
158
168
|
|
|
@@ -163,6 +173,8 @@ class ActionOutput(BaseModel):
|
|
|
163
173
|
Args:
|
|
164
174
|
parent_datapath: The base datapath for fields in this output.
|
|
165
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().
|
|
166
178
|
|
|
167
179
|
Yields:
|
|
168
180
|
OutputFieldSpecification objects describing each field in the schema.
|
|
@@ -176,6 +188,9 @@ class ActionOutput(BaseModel):
|
|
|
176
188
|
Nested ActionOutput classes are recursively processed.
|
|
177
189
|
Boolean fields automatically get [True, False] example values.
|
|
178
190
|
"""
|
|
191
|
+
if column_order_counter is None:
|
|
192
|
+
column_order_counter = itertools.count()
|
|
193
|
+
|
|
179
194
|
for _field_name, field in cls.__fields__.items():
|
|
180
195
|
field_name = alias if (alias := field.alias) else _field_name
|
|
181
196
|
|
|
@@ -208,7 +223,7 @@ class ActionOutput(BaseModel):
|
|
|
208
223
|
|
|
209
224
|
if issubclass(field_type, ActionOutput):
|
|
210
225
|
# If the field is another ActionOutput, recursively call _to_json_schema
|
|
211
|
-
yield from field_type._to_json_schema(datapath)
|
|
226
|
+
yield from field_type._to_json_schema(datapath, column_order_counter)
|
|
212
227
|
continue
|
|
213
228
|
else:
|
|
214
229
|
try:
|
|
@@ -230,6 +245,12 @@ class ActionOutput(BaseModel):
|
|
|
230
245
|
if field_type is bool:
|
|
231
246
|
schema_field["example_values"] = [True, False]
|
|
232
247
|
|
|
248
|
+
column_name = field.field_info.extra.get("column_name")
|
|
249
|
+
|
|
250
|
+
if column_name is not None:
|
|
251
|
+
schema_field["column_name"] = column_name
|
|
252
|
+
schema_field["column_order"] = next(column_order_counter)
|
|
253
|
+
|
|
233
254
|
yield schema_field
|
|
234
255
|
|
|
235
256
|
|
|
@@ -237,6 +237,7 @@ class App:
|
|
|
237
237
|
read_only: bool = True,
|
|
238
238
|
params_class: Optional[type[Params]] = None,
|
|
239
239
|
output_class: Optional[type[ActionOutput]] = None,
|
|
240
|
+
render_as: Optional[str] = None,
|
|
240
241
|
view_handler: Union[str, Callable, None] = None,
|
|
241
242
|
view_template: Optional[str] = None,
|
|
242
243
|
versions: str = "EQ(*)",
|
|
@@ -355,6 +356,7 @@ class App:
|
|
|
355
356
|
read_only=read_only,
|
|
356
357
|
params_class=params_class,
|
|
357
358
|
output_class=output_class,
|
|
359
|
+
render_as=render_as,
|
|
358
360
|
view_handler=view_handler,
|
|
359
361
|
versions=versions,
|
|
360
362
|
summary_type=summary_type,
|
|
@@ -421,6 +423,7 @@ class App:
|
|
|
421
423
|
read_only: bool = True,
|
|
422
424
|
params_class: Optional[type[Params]] = None,
|
|
423
425
|
output_class: Optional[type[ActionOutput]] = None,
|
|
426
|
+
render_as: Optional[str] = None,
|
|
424
427
|
view_handler: Optional[Callable] = None,
|
|
425
428
|
versions: str = "EQ(*)",
|
|
426
429
|
summary_type: Optional[type[ActionOutput]] = None,
|
|
@@ -440,6 +443,7 @@ class App:
|
|
|
440
443
|
read_only=read_only,
|
|
441
444
|
params_class=params_class,
|
|
442
445
|
output_class=output_class,
|
|
446
|
+
render_as=render_as,
|
|
443
447
|
view_handler=view_handler,
|
|
444
448
|
versions=versions,
|
|
445
449
|
summary_type=summary_type,
|
|
@@ -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
|
)
|
|
@@ -39,6 +39,7 @@ class ActionDecorator:
|
|
|
39
39
|
AsyncGenerator[type[ActionOutput]],
|
|
40
40
|
list[type[ActionOutput]],
|
|
41
41
|
] = None,
|
|
42
|
+
render_as: Optional[str] = None,
|
|
42
43
|
view_handler: Optional[Callable] = None,
|
|
43
44
|
versions: str = "EQ(*)",
|
|
44
45
|
summary_type: Optional[type[ActionOutput]] = None,
|
|
@@ -53,6 +54,7 @@ class ActionDecorator:
|
|
|
53
54
|
self.read_only = read_only
|
|
54
55
|
self.params_class = params_class
|
|
55
56
|
self.output_class = output_class
|
|
57
|
+
self.render_as = render_as
|
|
56
58
|
self.view_handler = view_handler
|
|
57
59
|
self.versions = versions
|
|
58
60
|
self.summary_type = summary_type
|
|
@@ -100,6 +102,14 @@ class ActionDecorator:
|
|
|
100
102
|
"Return type for action function must be derived from ActionOutput class."
|
|
101
103
|
)
|
|
102
104
|
|
|
105
|
+
if self.view_handler:
|
|
106
|
+
self.render_as = "custom"
|
|
107
|
+
|
|
108
|
+
if self.render_as and self.render_as not in ("table", "json", "custom"):
|
|
109
|
+
raise ValueError(
|
|
110
|
+
"Please only specify render_as as 'table' or 'json' or 'custom'."
|
|
111
|
+
)
|
|
112
|
+
|
|
103
113
|
@action_protocol
|
|
104
114
|
@wraps(function)
|
|
105
115
|
def inner(
|
|
@@ -152,6 +162,7 @@ class ActionDecorator:
|
|
|
152
162
|
parameters=validated_params_class,
|
|
153
163
|
output=validated_output_class,
|
|
154
164
|
versions=self.versions,
|
|
165
|
+
render_as=self.render_as,
|
|
155
166
|
view_handler=self.view_handler,
|
|
156
167
|
summary_type=self.summary_type,
|
|
157
168
|
enable_concurrency_lock=self.enable_concurrency_lock,
|
|
@@ -20,6 +20,7 @@ class ActionMeta(BaseModel):
|
|
|
20
20
|
verbose: str = ""
|
|
21
21
|
parameters: Type[Params] = Field(default=Params) # noqa: UP006
|
|
22
22
|
output: Type[ActionOutput] = Field(default=ActionOutput) # noqa: UP006
|
|
23
|
+
render_as: Optional[str] = None
|
|
23
24
|
view_handler: Optional[Callable] = None
|
|
24
25
|
summary_type: Optional[Type[ActionOutput]] = Field(default=None, exclude=True) # noqa: UP006
|
|
25
26
|
enable_concurrency_lock: bool = False
|
|
@@ -31,6 +32,13 @@ class ActionMeta(BaseModel):
|
|
|
31
32
|
data["output"] = OutputsSerializer.serialize_datapaths(
|
|
32
33
|
self.parameters, self.output, summary_class=self.summary_type
|
|
33
34
|
)
|
|
35
|
+
if self.view_handler:
|
|
36
|
+
self.render_as = "custom"
|
|
37
|
+
|
|
38
|
+
if self.render_as:
|
|
39
|
+
data["render"] = {
|
|
40
|
+
"type": self.render_as,
|
|
41
|
+
}
|
|
34
42
|
|
|
35
43
|
if self.view_handler:
|
|
36
44
|
remove_when_soar_newer_than("6.4.1")
|
|
@@ -45,13 +53,11 @@ class ActionMeta(BaseModel):
|
|
|
45
53
|
else:
|
|
46
54
|
relative_module = module
|
|
47
55
|
|
|
48
|
-
data["render"] = {
|
|
49
|
-
"type": "custom",
|
|
50
|
-
"view": f"{relative_module}.{self.view_handler.__name__}",
|
|
51
|
-
}
|
|
56
|
+
data["render"]["view"] = f"{relative_module}.{self.view_handler.__name__}"
|
|
52
57
|
|
|
53
58
|
# Remove view_handler from the output since in render
|
|
54
59
|
data.pop("view_handler", None)
|
|
60
|
+
data.pop("render_as", None)
|
|
55
61
|
|
|
56
62
|
if self.enable_concurrency_lock:
|
|
57
63
|
data["lock"] = {"enabled": True}
|
|
@@ -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):
|
|
@@ -438,7 +438,11 @@ def test_from_action_json_with_parameters_and_output(mock_action_deserializer):
|
|
|
438
438
|
},
|
|
439
439
|
},
|
|
440
440
|
"output": [
|
|
441
|
-
{
|
|
441
|
+
{
|
|
442
|
+
"data_path": "action_result.data.*.result",
|
|
443
|
+
"column_name": "Result",
|
|
444
|
+
"column_order": 0,
|
|
445
|
+
},
|
|
442
446
|
{"data_path": "action_result.summary.total_items"},
|
|
443
447
|
],
|
|
444
448
|
}
|
|
@@ -153,13 +153,17 @@ 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
|
|
156
|
+
bool_value: bool = OutputField(column_name="Nested Value")
|
|
157
157
|
|
|
158
158
|
class SampleOutput(ActionOutput):
|
|
159
159
|
string_value: str
|
|
160
160
|
int_value: int
|
|
161
161
|
list_value: list[str]
|
|
162
|
-
cef_value: str = OutputField(
|
|
162
|
+
cef_value: str = OutputField(
|
|
163
|
+
cef_types=["ip"],
|
|
164
|
+
example_values=["1.1.1.1"],
|
|
165
|
+
column_name="CEF Value",
|
|
166
|
+
)
|
|
163
167
|
nested_value: SampleNestedOutput
|
|
164
168
|
underscored_value: str = OutputField(alias="_underscored_value")
|
|
165
169
|
|
|
@@ -192,11 +196,15 @@ def test_outputs_serialize_output_class():
|
|
|
192
196
|
"data_type": "string",
|
|
193
197
|
"contains": ["ip"],
|
|
194
198
|
"example_values": ["1.1.1.1"],
|
|
199
|
+
"column_name": "CEF Value",
|
|
200
|
+
"column_order": 0,
|
|
195
201
|
},
|
|
196
202
|
{
|
|
197
203
|
"data_path": "action_result.data.*.nested_value.bool_value",
|
|
198
204
|
"data_type": "boolean",
|
|
199
205
|
"example_values": [True, False],
|
|
206
|
+
"column_name": "Nested Value",
|
|
207
|
+
"column_order": 1,
|
|
200
208
|
},
|
|
201
209
|
{
|
|
202
210
|
"data_path": "action_result.data.*._underscored_value",
|
|
@@ -297,3 +305,84 @@ def test_outputs_serialize_with_parameters_class():
|
|
|
297
305
|
"example_values": [1],
|
|
298
306
|
},
|
|
299
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
|
+
]
|
|
@@ -175,6 +175,149 @@
|
|
|
175
175
|
"verbose": "",
|
|
176
176
|
"versions": "EQ(*)"
|
|
177
177
|
},
|
|
178
|
+
{
|
|
179
|
+
"action": "test json output",
|
|
180
|
+
"identifier": "test_json_output",
|
|
181
|
+
"description": "test json output",
|
|
182
|
+
"type": "generic",
|
|
183
|
+
"read_only": true,
|
|
184
|
+
"versions": "EQ(*)",
|
|
185
|
+
"verbose": "",
|
|
186
|
+
"parameters": {},
|
|
187
|
+
"output": [
|
|
188
|
+
{
|
|
189
|
+
"data_path": "action_result.status",
|
|
190
|
+
"data_type": "string",
|
|
191
|
+
"example_values": [
|
|
192
|
+
"success",
|
|
193
|
+
"failure"
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"data_path": "action_result.message",
|
|
198
|
+
"data_type": "string"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
"data_path": "action_result.data.*.name",
|
|
202
|
+
"data_type": "string",
|
|
203
|
+
"example_values": [
|
|
204
|
+
"John",
|
|
205
|
+
"Jane",
|
|
206
|
+
"Jim"
|
|
207
|
+
],
|
|
208
|
+
"column_name": "Name",
|
|
209
|
+
"column_order": 0
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"data_path": "action_result.data.*.age",
|
|
213
|
+
"data_type": "numeric",
|
|
214
|
+
"example_values": [
|
|
215
|
+
25,
|
|
216
|
+
30,
|
|
217
|
+
35
|
|
218
|
+
],
|
|
219
|
+
"column_name": "Age",
|
|
220
|
+
"column_order": 1
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"data_path": "summary.total_objects",
|
|
224
|
+
"data_type": "numeric",
|
|
225
|
+
"example_values": [
|
|
226
|
+
1
|
|
227
|
+
]
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
"data_path": "summary.total_objects_successful",
|
|
231
|
+
"data_type": "numeric",
|
|
232
|
+
"example_values": [
|
|
233
|
+
1
|
|
234
|
+
]
|
|
235
|
+
}
|
|
236
|
+
],
|
|
237
|
+
"render": {
|
|
238
|
+
"type": "json"
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
"action": "test table output",
|
|
243
|
+
"identifier": "test_table_output",
|
|
244
|
+
"description": "test table output",
|
|
245
|
+
"type": "generic",
|
|
246
|
+
"read_only": true,
|
|
247
|
+
"versions": "EQ(*)",
|
|
248
|
+
"verbose": "",
|
|
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
|
+
},
|
|
261
|
+
"output": [
|
|
262
|
+
{
|
|
263
|
+
"data_path": "action_result.status",
|
|
264
|
+
"data_type": "string",
|
|
265
|
+
"example_values": [
|
|
266
|
+
"success",
|
|
267
|
+
"failure"
|
|
268
|
+
]
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"data_path": "action_result.message",
|
|
272
|
+
"data_type": "string"
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
"data_path": "action_result.parameter.company_name",
|
|
276
|
+
"data_type": "string",
|
|
277
|
+
"column_name": "Company Name",
|
|
278
|
+
"column_order": 0
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
"data_path": "action_result.data.*.name",
|
|
282
|
+
"data_type": "string",
|
|
283
|
+
"example_values": [
|
|
284
|
+
"John",
|
|
285
|
+
"Jane",
|
|
286
|
+
"Jim"
|
|
287
|
+
],
|
|
288
|
+
"column_name": "Name",
|
|
289
|
+
"column_order": 1
|
|
290
|
+
},
|
|
291
|
+
{
|
|
292
|
+
"data_path": "action_result.data.*.age",
|
|
293
|
+
"data_type": "numeric",
|
|
294
|
+
"example_values": [
|
|
295
|
+
25,
|
|
296
|
+
30,
|
|
297
|
+
35
|
|
298
|
+
],
|
|
299
|
+
"column_name": "Age",
|
|
300
|
+
"column_order": 2
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"data_path": "summary.total_objects",
|
|
304
|
+
"data_type": "numeric",
|
|
305
|
+
"example_values": [
|
|
306
|
+
1
|
|
307
|
+
]
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
"data_path": "summary.total_objects_successful",
|
|
311
|
+
"data_type": "numeric",
|
|
312
|
+
"example_values": [
|
|
313
|
+
1
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
],
|
|
317
|
+
"render": {
|
|
318
|
+
"type": "table"
|
|
319
|
+
}
|
|
320
|
+
},
|
|
178
321
|
{
|
|
179
322
|
"action": "reverse string",
|
|
180
323
|
"identifier": "reverse_string",
|
|
@@ -5,10 +5,10 @@ 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
|
-
from soar_sdk.action_results import ActionOutput, MakeRequestOutput
|
|
11
|
+
from soar_sdk.action_results import ActionOutput, MakeRequestOutput, OutputField
|
|
12
12
|
from soar_sdk.logging import getLogger
|
|
13
13
|
|
|
14
14
|
logger = getLogger()
|
|
@@ -72,6 +72,27 @@ def test_empty_list_output(
|
|
|
72
72
|
return []
|
|
73
73
|
|
|
74
74
|
|
|
75
|
+
class JsonOutput(ActionOutput):
|
|
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
|
+
|
|
83
|
+
|
|
84
|
+
@app.action(render_as="json")
|
|
85
|
+
def test_json_output(params: Params, asset: Asset, soar: SOARClient) -> JsonOutput:
|
|
86
|
+
return JsonOutput(name="John", age=25)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@app.action(render_as="table")
|
|
90
|
+
def test_table_output(
|
|
91
|
+
params: TableParams, asset: Asset, soar: SOARClient
|
|
92
|
+
) -> JsonOutput:
|
|
93
|
+
return JsonOutput(name="John", age=25)
|
|
94
|
+
|
|
95
|
+
|
|
75
96
|
app.register_action(
|
|
76
97
|
"actions.reverse_string:reverse_string",
|
|
77
98
|
action_type="investigate",
|