splunk-soar-sdk 1.4.0__tar.gz → 1.4.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-1.4.0 → splunk_soar_sdk-1.4.1}/PKG-INFO +1 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/pyproject.toml +1 -1
- splunk_soar_sdk-1.4.1/release_notes.txt +31 -0
- splunk_soar_sdk-1.4.1/release_version.txt +1 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/asset.py +3 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/init/cli.py +16 -3
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/manifests/deserializers.py +22 -3
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/utils.py +6 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/asset_renderer.py +7 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/params.py +3 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_convert_cli.py +58 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_deserializers.py +80 -2
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_serializers.py +15 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_utils.py +12 -7
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_asset.py +13 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/uv.lock +1 -1
- splunk_soar_sdk-1.4.0/release_notes.txt +0 -21
- splunk_soar_sdk-1.4.0/release_version.txt +0 -1
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/pull_request_template.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/utils/github.js +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/utils/update_version.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/workflows/code_quality.yml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/workflows/commit_hygiene.yml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/workflows/generate_docs.yml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.github/workflows/semantic_release.yml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.gitignore +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/.releaserc +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/LICENSE +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/README.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/commitlint.config.js +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/api_reference.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/app_structure/index.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/app_structure/pre-commit-config.yaml.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/app_structure/pyproject.toml.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/app_structure/src_app.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/changelog.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/cli_reference.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/conf.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/custom_views/index.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/custom_views/reusable_components.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/custom_views/templates.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/custom_views/view_handlers.md +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/getting_started/index.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/getting_started/init_app.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/getting_started/installation.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/docs/index.rst +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/abstract.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/action_results.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/actions_manager.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/apis/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/apis/artifact.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/apis/container.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/apis/utils.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/apis/vault.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_cli_runner.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_client.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_templates/basic_app/.gitignore +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_templates/basic_app/.pre-commit-config.yaml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_templates/basic_app/logo.svg +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_templates/basic_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_templates/basic_app/src/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/app_templates/basic_app/uv.lock +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/async_utils.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/init/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/manifests/cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/manifests/processors.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/manifests/serializers.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/package/cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/package/utils.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/cli/path_utils.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/action_renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/app_renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/templates/pyproject.toml.jinja +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/toml_renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/colors.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/compat.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/crypto.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/action.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/generic_action.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/on_poll.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/test_connectivity.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/view_handler.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/decorators/webhook.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/exceptions.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/input_spec.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/logging.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/actions.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/adapters.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/app.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/datatypes.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/dependencies.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/meta/webhooks.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/models/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/models/artifact.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/models/container.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/models/vault_attachment.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/models/view.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/paths.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/py.typed +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/action_result.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/app.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/base_connector.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/connector_result.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/consts.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/encryption_helper.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/install_info.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/json_keys.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/ph_ipc.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom/vault.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom_common/app_interface/app_interface.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/shims/phantom_common/encryption/encryption_manager_factory.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/base/base_template.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/base/error.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/base/header.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/base/logo_header.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/components/pie_chart.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/widgets/widget_resize_snippet.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/templates/widgets/widget_template.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/types.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/component_registry.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/components/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/components/pie_chart.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/template_filters.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/template_renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/views/view_parser.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/webhooks/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/webhooks/models.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/webhooks/routing.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/test.png +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/test.txt +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/datapath_parse.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/manifests/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/manifests/test_processors.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_assets/converted_app/actions.py.txt +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_init_cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_manifests_cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/cli/test_package_cli.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/code_renderers/test_action_renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/conftest.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/app.json +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/example_asset.json +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/logo.svg +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/logo_dark.svg +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/pyproject.toml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/actions/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/actions/async_action.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/actions/generate_category.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/actions/reverse_string.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/app.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/src/ignoreme.txt +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/templates/reverse_string.html +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app/uv.lock +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/app.json +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/logo.svg +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/logo_dark.svg +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/pyproject.toml +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/src/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/src/app.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/example_app_with_webhook/uv.lock +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/interfaces/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/interfaces/test_artifact_interface.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/interfaces/test_container_interface.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/interfaces/test_vault_interface.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/meta/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/meta/test_actions.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/meta/test_adapters.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/meta/test_datatypes.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/meta/test_dependencies.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/meta/test_webhooks.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/mocks/__init__.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/mocks/dynamic_mocks.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/mocks/importable_action.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/stubs.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_action_results.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_actions_manager.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_app.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_app_action.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_app_action_params.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_app_action_results.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_app_client.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_app_runner.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_assets/splunk-sdk-2.1.0.tar.gz +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_async_integration.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_async_utils.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_code_renderers.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_compat.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_container.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_custom_views.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_encryption.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_generic_action.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_logging.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_on_poll.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_params.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_template_renderer.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_test_connectivity.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/test_view_parser.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/tests/webhooks/test_models.py +0 -0
- {splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.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: 1.4.
|
|
3
|
+
Version: 1.4.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,31 @@
|
|
|
1
|
+
## [1.4.1](https://github.com/phantomcyber/splunk-soar-sdk/compare/1.4.0...1.4.1) (2025-09-10)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* cleanup based on pytest and pr review ([8de0911](https://github.com/phantomcyber/splunk-soar-sdk/commit/8de0911de5c1929aaed898ea81e92a38b7a03974))
|
|
7
|
+
* convert illegal field names to aliases when converting asset or action params ([9cde111](https://github.com/phantomcyber/splunk-soar-sdk/commit/9cde111dfb245fb8e2604e59a8a4fc8512768b7d))
|
|
8
|
+
* normalize_field_names removes leading underscores ([3880b09](https://github.com/phantomcyber/splunk-soar-sdk/commit/3880b09f438c8734c506c146cbe5cdd4521219cd))
|
|
9
|
+
* update converted apps to use the default python versions ([156853c](https://github.com/phantomcyber/splunk-soar-sdk/commit/156853cfe3376ab89f37692e52dc343468a314af))
|
|
10
|
+
* use correct datatypes for default asset values when converting ([c2838ff](https://github.com/phantomcyber/splunk-soar-sdk/commit/c2838ff172517d7f38650692f8e6e61176268382))
|
|
11
|
+
* when deserializing action params, treat them as optional by default ([d2d3b48](https://github.com/phantomcyber/splunk-soar-sdk/commit/d2d3b48ddd1ded8a6b432d33f6867fb394fe17ab))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## [1.4.1](https://github.com/phantomcyber/splunk-soar-sdk/compare/1.4.0...1.4.1) (2025-09-10)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* cleanup based on pytest and pr review ([8de0911](https://github.com/phantomcyber/splunk-soar-sdk/commit/8de0911de5c1929aaed898ea81e92a38b7a03974))
|
|
23
|
+
* convert illegal field names to aliases when converting asset or action params ([9cde111](https://github.com/phantomcyber/splunk-soar-sdk/commit/9cde111dfb245fb8e2604e59a8a4fc8512768b7d))
|
|
24
|
+
* normalize_field_names removes leading underscores ([3880b09](https://github.com/phantomcyber/splunk-soar-sdk/commit/3880b09f438c8734c506c146cbe5cdd4521219cd))
|
|
25
|
+
* update converted apps to use the default python versions ([156853c](https://github.com/phantomcyber/splunk-soar-sdk/commit/156853cfe3376ab89f37692e52dc343468a314af))
|
|
26
|
+
* use correct datatypes for default asset values when converting ([c2838ff](https://github.com/phantomcyber/splunk-soar-sdk/commit/c2838ff172517d7f38650692f8e6e61176268382))
|
|
27
|
+
* when deserializing action params, treat them as optional by default ([d2d3b48](https://github.com/phantomcyber/splunk-soar-sdk/commit/d2d3b48ddd1ded8a6b432d33f6867fb394fe17ab))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.4.1
|
|
@@ -21,6 +21,7 @@ def AssetField(
|
|
|
21
21
|
default: Optional[Any] = None, # noqa: ANN401
|
|
22
22
|
value_list: Optional[list] = None,
|
|
23
23
|
sensitive: bool = False,
|
|
24
|
+
alias: Optional[str] = None,
|
|
24
25
|
) -> Any: # noqa: ANN401
|
|
25
26
|
"""Representation of an asset configuration field.
|
|
26
27
|
|
|
@@ -47,6 +48,7 @@ def AssetField(
|
|
|
47
48
|
required=required,
|
|
48
49
|
value_list=value_list,
|
|
49
50
|
sensitive=sensitive,
|
|
51
|
+
alias=alias,
|
|
50
52
|
)
|
|
51
53
|
|
|
52
54
|
|
|
@@ -239,7 +241,7 @@ class BaseAsset(BaseModel):
|
|
|
239
241
|
if value_list := field.field_info.extra.get("value_list"):
|
|
240
242
|
params_field["value_list"] = value_list
|
|
241
243
|
|
|
242
|
-
params[
|
|
244
|
+
params[field.alias] = params_field
|
|
243
245
|
|
|
244
246
|
return params
|
|
245
247
|
|
|
@@ -16,6 +16,7 @@ from rich import print as rprint
|
|
|
16
16
|
from rich.markup import escape as rescape
|
|
17
17
|
|
|
18
18
|
from soar_sdk.cli.manifests.deserializers import AppMetaDeserializer
|
|
19
|
+
from soar_sdk.cli.utils import normalize_field_name
|
|
19
20
|
from soar_sdk.code_renderers.action_renderer import ActionRenderer
|
|
20
21
|
from soar_sdk.code_renderers.app_renderer import AppContext, AppRenderer
|
|
21
22
|
from soar_sdk.code_renderers.asset_renderer import AssetContext, AssetRenderer
|
|
@@ -42,7 +43,7 @@ def init_callback(
|
|
|
42
43
|
"--python-version",
|
|
43
44
|
"-p",
|
|
44
45
|
help="Supported Python versions for the app.",
|
|
45
|
-
default_factory=
|
|
46
|
+
default_factory=PythonVersion.all,
|
|
46
47
|
),
|
|
47
48
|
],
|
|
48
49
|
dependencies: Annotated[list[str], typer.Option(default_factory=list)],
|
|
@@ -268,11 +269,21 @@ def convert_connector_to_sdk(
|
|
|
268
269
|
# Convert the main module path to the SDK format, but save a reference to the original
|
|
269
270
|
app_meta.main_module = "src.app:app"
|
|
270
271
|
|
|
272
|
+
app_python_versions = app_meta.python_version
|
|
273
|
+
enforced_python_versions = PythonVersion.all()
|
|
274
|
+
if set(app_python_versions) != set(enforced_python_versions):
|
|
275
|
+
rprint(
|
|
276
|
+
f"[yellow]The provided app declares support for Python versions {[str(v) for v in app_python_versions]}.[/]"
|
|
277
|
+
)
|
|
278
|
+
rprint(
|
|
279
|
+
f"[yellow]The converted app will support the default versions {[str(v) for v in enforced_python_versions]}.[/]"
|
|
280
|
+
)
|
|
281
|
+
|
|
271
282
|
init_sdk_app(
|
|
272
283
|
name=app_meta.project_name,
|
|
273
284
|
description=app_meta.description,
|
|
274
285
|
authors=[author.name for author in app_meta.contributors],
|
|
275
|
-
python_versions=
|
|
286
|
+
python_versions=enforced_python_versions,
|
|
276
287
|
dependencies=[],
|
|
277
288
|
app_dir=output_dir,
|
|
278
289
|
copyright=app_meta.license,
|
|
@@ -385,18 +396,20 @@ def generate_asset_definition_ast(app_meta: AppMeta) -> ast.ClassDef:
|
|
|
385
396
|
"""
|
|
386
397
|
asset_context: list[AssetContext] = []
|
|
387
398
|
for name, config_spec in app_meta.configuration.items():
|
|
399
|
+
normalized = normalize_field_name(name)
|
|
388
400
|
if config_spec["data_type"].startswith("ph"):
|
|
389
401
|
# Skip the cosmetic placeholder fields
|
|
390
402
|
continue
|
|
391
403
|
|
|
392
404
|
asset_context.append(
|
|
393
405
|
AssetContext(
|
|
394
|
-
name=
|
|
406
|
+
name=normalized.normalized,
|
|
395
407
|
description=config_spec.get("description"),
|
|
396
408
|
required=config_spec.get("required", False),
|
|
397
409
|
default=config_spec.get("default"),
|
|
398
410
|
data_type=config_spec["data_type"],
|
|
399
411
|
value_list=config_spec.get("value_list"),
|
|
412
|
+
alias=normalized.original if normalized.modified else None,
|
|
400
413
|
)
|
|
401
414
|
)
|
|
402
415
|
|
|
@@ -6,7 +6,7 @@ import pydantic
|
|
|
6
6
|
|
|
7
7
|
from soar_sdk.action_results import ActionOutput, OutputFieldSpecification, OutputField
|
|
8
8
|
from soar_sdk.cli.utils import normalize_field_name, NormalizationResult
|
|
9
|
-
from soar_sdk.compat import PythonVersion
|
|
9
|
+
from soar_sdk.compat import PythonVersion, remove_when_soar_newer_than
|
|
10
10
|
from soar_sdk.meta.actions import ActionMeta
|
|
11
11
|
from soar_sdk.meta.app import AppMeta
|
|
12
12
|
from soar_sdk.params import Params, Param
|
|
@@ -64,6 +64,21 @@ class AppMetaDeserializer:
|
|
|
64
64
|
]
|
|
65
65
|
app_meta = AppMeta(project_name=json_path.parent.name, **manifest)
|
|
66
66
|
|
|
67
|
+
remove_when_soar_newer_than(
|
|
68
|
+
"7.1.0",
|
|
69
|
+
"Revisit this after upgrading to Pydantic 2.x. If the issue is still present, we might need to consider making `AssetFieldSpecification` a Pydantic model instead of a TypedDict, but that's a pretty big change.",
|
|
70
|
+
)
|
|
71
|
+
# Pydantic converts the default value into a string for some reason, even for non-string types.
|
|
72
|
+
# We will go through and convert it back.
|
|
73
|
+
# This has the side effect of implicitly validating that the default value matches the type.
|
|
74
|
+
for _, spec in app_meta.configuration.items():
|
|
75
|
+
if "default" not in spec:
|
|
76
|
+
continue
|
|
77
|
+
if spec["data_type"] == "numeric":
|
|
78
|
+
spec["default"] = float(spec["default"])
|
|
79
|
+
if spec["data_type"] == "boolean":
|
|
80
|
+
spec["default"] = bool(spec["default"])
|
|
81
|
+
|
|
67
82
|
has_rest_handlers = isinstance(manifest.get("rest_handler"), str)
|
|
68
83
|
has_webhooks = isinstance(manifest.get("webhooks"), dict)
|
|
69
84
|
|
|
@@ -142,7 +157,10 @@ class ActionDeserializer:
|
|
|
142
157
|
if param_spec["data_type"].startswith("ph"):
|
|
143
158
|
# Skip parameters that are placeholders
|
|
144
159
|
continue
|
|
145
|
-
|
|
160
|
+
normalized = normalize_field_name(param_name)
|
|
161
|
+
if normalized.modified:
|
|
162
|
+
param_spec["alias"] = normalized.original
|
|
163
|
+
fields[normalized.normalized] = cls._create_param_field(param_spec)
|
|
146
164
|
|
|
147
165
|
# Dynamically create a subclass of Params
|
|
148
166
|
action_name = cls._clean_action_name(action_name).normalized
|
|
@@ -164,13 +182,14 @@ class ActionDeserializer:
|
|
|
164
182
|
# Create Param field with all the metadata
|
|
165
183
|
param_field = Param(
|
|
166
184
|
description=param_spec.get("description"),
|
|
167
|
-
required=param_spec.get("required",
|
|
185
|
+
required=param_spec.get("required", False),
|
|
168
186
|
primary=param_spec.get("primary", False),
|
|
169
187
|
default=param_spec.get("default"),
|
|
170
188
|
value_list=param_spec.get("value_list"),
|
|
171
189
|
cef_types=param_spec.get("contains"), # 'contains' maps to 'cef_types'
|
|
172
190
|
allow_list=param_spec.get("allow_list", False),
|
|
173
191
|
sensitive=(data_type == "password"),
|
|
192
|
+
alias=param_spec.get("alias"),
|
|
174
193
|
)
|
|
175
194
|
|
|
176
195
|
return FieldSpec(python_type, param_field)
|
|
@@ -32,7 +32,12 @@ def normalize_field_name(field_name: str) -> NormalizationResult:
|
|
|
32
32
|
|
|
33
33
|
# Ensure the first character is a letter or underscore
|
|
34
34
|
if field_name[0].isdigit():
|
|
35
|
-
field_name = f"
|
|
35
|
+
field_name = f"n{field_name}"
|
|
36
|
+
|
|
37
|
+
# Drop leading underscores to avoid Pydantic marking a field as private
|
|
38
|
+
field_name = field_name.lstrip("_")
|
|
39
|
+
if not field_name:
|
|
40
|
+
raise ValueError("Field name must contain at least one letter")
|
|
36
41
|
|
|
37
42
|
# Finally, ensure the field name is not a Python keyword
|
|
38
43
|
if keyword.iskeyword(field_name):
|
{splunk_soar_sdk-1.4.0 → splunk_soar_sdk-1.4.1}/src/soar_sdk/code_renderers/asset_renderer.py
RENAMED
|
@@ -17,6 +17,7 @@ class AssetContext:
|
|
|
17
17
|
default: Union[str, int, float, bool, None]
|
|
18
18
|
data_type: str
|
|
19
19
|
value_list: Optional[list[str]]
|
|
20
|
+
alias: Optional[str] = None
|
|
20
21
|
|
|
21
22
|
@property
|
|
22
23
|
def is_str(self) -> bool:
|
|
@@ -38,7 +39,7 @@ class AssetContext:
|
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class AssetRenderer(AstRenderer[list[AssetContext]]):
|
|
41
|
-
"""A class to render an app's Asset class using
|
|
42
|
+
"""A class to render an app's Asset class using ASTs."""
|
|
42
43
|
|
|
43
44
|
def render_ast(self) -> Iterator[ast.stmt]:
|
|
44
45
|
"""Render the Asset class by building an AST.
|
|
@@ -96,6 +97,11 @@ class AssetRenderer(AstRenderer[list[AssetContext]]):
|
|
|
96
97
|
)
|
|
97
98
|
)
|
|
98
99
|
|
|
100
|
+
if field.alias is not None:
|
|
101
|
+
field_kwargs.append(
|
|
102
|
+
ast.keyword(arg="alias", value=ast.Constant(value=field.alias))
|
|
103
|
+
)
|
|
104
|
+
|
|
99
105
|
field_statement = ast.AnnAssign(
|
|
100
106
|
target=field_name,
|
|
101
107
|
annotation=field_type,
|
|
@@ -21,6 +21,7 @@ def Param(
|
|
|
21
21
|
cef_types: Optional[list] = None,
|
|
22
22
|
allow_list: bool = False,
|
|
23
23
|
sensitive: bool = False,
|
|
24
|
+
alias: Optional[str] = None,
|
|
24
25
|
) -> Any: # noqa: ANN401
|
|
25
26
|
"""Representation of a single complex action parameter.
|
|
26
27
|
|
|
@@ -64,6 +65,7 @@ def Param(
|
|
|
64
65
|
cef_types=cef_types,
|
|
65
66
|
allow_list=allow_list,
|
|
66
67
|
sensitive=sensitive,
|
|
68
|
+
alias=alias,
|
|
67
69
|
)
|
|
68
70
|
|
|
69
71
|
|
|
@@ -135,7 +137,7 @@ class Params(BaseModel):
|
|
|
135
137
|
if value_list := field.field_info.extra.get("value_list"):
|
|
136
138
|
params_field["value_list"] = value_list
|
|
137
139
|
|
|
138
|
-
params[
|
|
140
|
+
params[field.alias] = params_field
|
|
139
141
|
|
|
140
142
|
return params
|
|
141
143
|
|
|
@@ -6,6 +6,7 @@ import json
|
|
|
6
6
|
|
|
7
7
|
from typer.testing import CliRunner
|
|
8
8
|
|
|
9
|
+
from soar_sdk.compat import PythonVersion
|
|
9
10
|
from soar_sdk.meta.actions import ActionMeta
|
|
10
11
|
from soar_sdk.meta.app import AppMeta, AssetFieldSpecification
|
|
11
12
|
|
|
@@ -68,6 +69,16 @@ def test_generate_asset_definition(app_meta, tmp_path):
|
|
|
68
69
|
data_type="timezone",
|
|
69
70
|
default="UTC",
|
|
70
71
|
),
|
|
72
|
+
"number": AssetFieldSpecification(
|
|
73
|
+
label="Number",
|
|
74
|
+
required=False,
|
|
75
|
+
data_type="numeric",
|
|
76
|
+
default=42,
|
|
77
|
+
),
|
|
78
|
+
"boolean": AssetFieldSpecification(
|
|
79
|
+
label="boolean", required=False, data_type="boolean", default=True
|
|
80
|
+
),
|
|
81
|
+
"_underscore": AssetFieldSpecification(data_type="string"),
|
|
71
82
|
}
|
|
72
83
|
asset_class = cli.generate_asset_definition_ast(app_meta=app_meta)
|
|
73
84
|
|
|
@@ -78,6 +89,9 @@ def test_generate_asset_definition(app_meta, tmp_path):
|
|
|
78
89
|
" username: str = AssetField(required=True, description='The username for the application')",
|
|
79
90
|
" color: str = AssetField(required=False, default='blue', value_list=['red', 'green', 'blue'])",
|
|
80
91
|
" timezone: ZoneInfo = AssetField(required=False, default=ZoneInfo('UTC'))",
|
|
92
|
+
" number: float = AssetField(required=False, default=42)",
|
|
93
|
+
" boolean: bool = AssetField(required=False, default=True)",
|
|
94
|
+
" underscore: str = AssetField(required=False, alias='_underscore')",
|
|
81
95
|
]
|
|
82
96
|
)
|
|
83
97
|
|
|
@@ -173,6 +187,50 @@ def test_convert_cli(runner, tmp_path, app_meta):
|
|
|
173
187
|
assert (output_dir / "logo_dark.svg").exists()
|
|
174
188
|
|
|
175
189
|
|
|
190
|
+
def test_convert_cli_updates_py_versions(runner, tmp_path, app_meta):
|
|
191
|
+
"""Test that convert command generates the expected app structure."""
|
|
192
|
+
|
|
193
|
+
app_meta.configuration = {
|
|
194
|
+
"username": AssetFieldSpecification(
|
|
195
|
+
label="Username",
|
|
196
|
+
description="The username for the application",
|
|
197
|
+
required=True,
|
|
198
|
+
data_type="string",
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
app_meta.python_version = [PythonVersion.PY_3_9]
|
|
203
|
+
|
|
204
|
+
app_dir = tmp_path / "test_app"
|
|
205
|
+
app_dir.mkdir()
|
|
206
|
+
(app_dir / "app.json").write_text(app_meta.json())
|
|
207
|
+
(app_dir / app_meta.logo).touch()
|
|
208
|
+
(app_dir / app_meta.logo_dark).touch()
|
|
209
|
+
|
|
210
|
+
output_dir = tmp_path / "output"
|
|
211
|
+
|
|
212
|
+
with patch("subprocess.run"), patch("shutil.which") as mock_which:
|
|
213
|
+
mock_which.return_value = "/usr/bin/example"
|
|
214
|
+
|
|
215
|
+
result = runner.invoke(
|
|
216
|
+
cli.convert,
|
|
217
|
+
[
|
|
218
|
+
str(app_dir),
|
|
219
|
+
str(output_dir),
|
|
220
|
+
],
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
print(result.output) # For debugging purposes
|
|
224
|
+
|
|
225
|
+
assert result.exit_code == 0
|
|
226
|
+
assert "declares support for Python versions ['3.9']" in result.output
|
|
227
|
+
assert "will support the default versions ['3.9', '3.13']" in result.output
|
|
228
|
+
assert (
|
|
229
|
+
'requires-python = ">=3.9, <3.14"'
|
|
230
|
+
in (output_dir / "pyproject.toml").read_text()
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
|
|
176
234
|
def test_convert_cli_with_default_output(runner, tmp_path, app_meta):
|
|
177
235
|
"""Test that convert command uses default output directory if not specified."""
|
|
178
236
|
|
|
@@ -278,7 +278,21 @@ def test_from_app_json_complex_example(create_app_json):
|
|
|
278
278
|
"required": True,
|
|
279
279
|
"description": "Base Url",
|
|
280
280
|
"order": 0,
|
|
281
|
-
}
|
|
281
|
+
},
|
|
282
|
+
"port": {
|
|
283
|
+
"data_type": "numeric",
|
|
284
|
+
"required": False,
|
|
285
|
+
"description": "Port Number",
|
|
286
|
+
"default": 8080,
|
|
287
|
+
"order": 1,
|
|
288
|
+
},
|
|
289
|
+
"verify": {
|
|
290
|
+
"data_type": "boolean",
|
|
291
|
+
"required": False,
|
|
292
|
+
"description": "Verify",
|
|
293
|
+
"default": True,
|
|
294
|
+
"order": 2,
|
|
295
|
+
},
|
|
282
296
|
},
|
|
283
297
|
"actions": [
|
|
284
298
|
{
|
|
@@ -313,6 +327,9 @@ def test_from_app_json_complex_example(create_app_json):
|
|
|
313
327
|
assert len(result.actions) == 1
|
|
314
328
|
assert result.fips_compliant is False
|
|
315
329
|
assert result.configuration["base_url"]["data_type"] == "string"
|
|
330
|
+
assert result.configuration["port"]["default"] == 8080
|
|
331
|
+
assert type(result.configuration["verify"]["default"]) is bool
|
|
332
|
+
assert result.configuration["verify"]["default"]
|
|
316
333
|
|
|
317
334
|
|
|
318
335
|
@pytest.mark.parametrize(
|
|
@@ -406,7 +423,19 @@ def test_from_action_json_with_parameters_and_output(mock_action_deserializer):
|
|
|
406
423
|
"data_type": "string",
|
|
407
424
|
"required": True,
|
|
408
425
|
"description": "Test parameter",
|
|
409
|
-
}
|
|
426
|
+
},
|
|
427
|
+
"param2": {
|
|
428
|
+
"data_type": "numeric",
|
|
429
|
+
"required": False,
|
|
430
|
+
"description": "Another parameter",
|
|
431
|
+
"default": 42,
|
|
432
|
+
},
|
|
433
|
+
"param3": {
|
|
434
|
+
"data_type": "boolean",
|
|
435
|
+
"required": False,
|
|
436
|
+
"description": "Yet another parameter",
|
|
437
|
+
"default": True,
|
|
438
|
+
},
|
|
410
439
|
},
|
|
411
440
|
"output": [
|
|
412
441
|
{"data_path": "action_result.data.*.result"},
|
|
@@ -427,6 +456,23 @@ def test_from_action_json_with_parameters_and_output(mock_action_deserializer):
|
|
|
427
456
|
"custom action", original_parameters
|
|
428
457
|
)
|
|
429
458
|
mocks["parse_output"].assert_called_once_with("custom action", original_output)
|
|
459
|
+
assert original_parameters["param1"] == {
|
|
460
|
+
"data_type": "string",
|
|
461
|
+
"description": "Test parameter",
|
|
462
|
+
"required": True,
|
|
463
|
+
}
|
|
464
|
+
assert original_parameters["param2"] == {
|
|
465
|
+
"data_type": "numeric",
|
|
466
|
+
"description": "Another parameter",
|
|
467
|
+
"required": False,
|
|
468
|
+
"default": 42,
|
|
469
|
+
}
|
|
470
|
+
assert original_parameters["param3"] == {
|
|
471
|
+
"data_type": "boolean",
|
|
472
|
+
"description": "Yet another parameter",
|
|
473
|
+
"required": False,
|
|
474
|
+
"default": True,
|
|
475
|
+
}
|
|
430
476
|
|
|
431
477
|
|
|
432
478
|
def test_from_action_json_missing_optional_fields(mock_action_deserializer):
|
|
@@ -502,6 +548,28 @@ def test_action_deserializer_parse_parameters(input_data, expects_base_class):
|
|
|
502
548
|
assert result.__name__ == "TestActionParams"
|
|
503
549
|
|
|
504
550
|
|
|
551
|
+
def test_action_deserializer_uses_correct_default_params():
|
|
552
|
+
"""Test ActionDeserializer sets `required`, `primary`, and `allow_list` false when no defaults are provided."""
|
|
553
|
+
result = ActionDeserializer.parse_parameters(
|
|
554
|
+
"test_action", {"param1": {"data_type": "string", "description": "test param"}}
|
|
555
|
+
)
|
|
556
|
+
|
|
557
|
+
field = result.__fields__["param1"]
|
|
558
|
+
assert not field.field_info.extra.get("required")
|
|
559
|
+
assert not field.field_info.extra.get("primary")
|
|
560
|
+
assert not field.field_info.extra.get("allow_list")
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
def test_action_deserializer_with_underscored_params():
|
|
564
|
+
"""Test that the ActionDeserializer handles underscored parameters as expected"""
|
|
565
|
+
result = ActionDeserializer.parse_parameters(
|
|
566
|
+
"test_action", {"_underscore": {"data_type": "string"}}
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
field = result.__fields__["underscore"]
|
|
570
|
+
assert field.alias == "_underscore"
|
|
571
|
+
|
|
572
|
+
|
|
505
573
|
@pytest.mark.parametrize(
|
|
506
574
|
"input_data,expects_base_class",
|
|
507
575
|
[
|
|
@@ -619,6 +687,12 @@ def test_parse_parameters_with_complex_params():
|
|
|
619
687
|
"description": "Placeholder parameter",
|
|
620
688
|
"order": 3,
|
|
621
689
|
},
|
|
690
|
+
"_param5": {
|
|
691
|
+
"data_type": "string",
|
|
692
|
+
"required": False,
|
|
693
|
+
"description": "Placeholder parameter",
|
|
694
|
+
"order": 3,
|
|
695
|
+
},
|
|
622
696
|
}
|
|
623
697
|
|
|
624
698
|
result = ActionDeserializer.parse_parameters("complex_action", complex_params)
|
|
@@ -633,6 +707,10 @@ def test_parse_parameters_with_complex_params():
|
|
|
633
707
|
assert "param1" in result.__annotations__
|
|
634
708
|
assert "param2" in result.__annotations__
|
|
635
709
|
assert "param3" in result.__annotations__
|
|
710
|
+
assert "param4" not in result.__annotations__
|
|
711
|
+
|
|
712
|
+
assert "param5" in result.__fields__
|
|
713
|
+
assert result.__fields__["param5"].alias == "_param5"
|
|
636
714
|
|
|
637
715
|
|
|
638
716
|
def test_complex_output_specification():
|
|
@@ -41,6 +41,7 @@ def test_params_serialize_fields_info():
|
|
|
41
41
|
send_notifications: bool = Param(default=True)
|
|
42
42
|
platform: str = Param(value_list=["windows", "linux", "mac"])
|
|
43
43
|
api_key: str = Param(sensitive=True)
|
|
44
|
+
underscored_field: str = Param(alias="_underscored_field")
|
|
44
45
|
|
|
45
46
|
serialized_params = ParamsSerializer.serialize_fields_info(SampleParams)
|
|
46
47
|
|
|
@@ -112,6 +113,15 @@ def test_params_serialize_fields_info():
|
|
|
112
113
|
"allow_list": False,
|
|
113
114
|
"order": 6,
|
|
114
115
|
},
|
|
116
|
+
"_underscored_field": {
|
|
117
|
+
"name": "underscored_field",
|
|
118
|
+
"description": "Underscored Field",
|
|
119
|
+
"data_type": "string",
|
|
120
|
+
"required": True,
|
|
121
|
+
"primary": False,
|
|
122
|
+
"allow_list": False,
|
|
123
|
+
"order": 7,
|
|
124
|
+
},
|
|
115
125
|
}
|
|
116
126
|
|
|
117
127
|
assert serialized_params == expected_params
|
|
@@ -152,6 +162,7 @@ def test_outputs_serialize_output_class():
|
|
|
152
162
|
list_value: list[str]
|
|
153
163
|
cef_value: str = OutputField(cef_types=["ip"], example_values=["1.1.1.1"])
|
|
154
164
|
nested_value: SampleNestedOutput
|
|
165
|
+
underscored_value: str = OutputField(alias="_underscored_value")
|
|
155
166
|
|
|
156
167
|
serialized_outputs = OutputsSerializer.serialize_datapaths(Params, SampleOutput)
|
|
157
168
|
|
|
@@ -188,6 +199,10 @@ def test_outputs_serialize_output_class():
|
|
|
188
199
|
"data_type": "boolean",
|
|
189
200
|
"example_values": [True, False],
|
|
190
201
|
},
|
|
202
|
+
{
|
|
203
|
+
"data_path": "action_result.data.*._underscored_value",
|
|
204
|
+
"data_type": "string",
|
|
205
|
+
},
|
|
191
206
|
{
|
|
192
207
|
"data_path": "summary.total_objects",
|
|
193
208
|
"data_type": "numeric",
|
|
@@ -13,21 +13,21 @@ class TestNormalizeFieldName:
|
|
|
13
13
|
# Valid identifiers that shouldn't be modified
|
|
14
14
|
("valid_name", "valid_name", False),
|
|
15
15
|
("ValidName", "ValidName", False),
|
|
16
|
-
("_private", "_private", False),
|
|
17
16
|
("name123", "name123", False),
|
|
18
|
-
|
|
19
|
-
("
|
|
17
|
+
# Names starting with underscores
|
|
18
|
+
("_private", "private", True),
|
|
19
|
+
("__dunder__", "dunder__", True),
|
|
20
20
|
# Names starting with digits
|
|
21
|
-
("123invalid", "
|
|
21
|
+
("123invalid", "n123invalid", True),
|
|
22
22
|
# Names with invalid characters
|
|
23
23
|
(
|
|
24
24
|
"a-b.c d@e$f#g%h!i+j=k/l\\m|n&o*p(q)r[s]t{u}v<w>x:y;z,?'\"",
|
|
25
25
|
"a_b_c_d_e_f_g_h_i_j_k_l_m_n_o_p_q_r_s_t_u_v_w_x_y_z____",
|
|
26
26
|
True,
|
|
27
27
|
),
|
|
28
|
-
("🚀rocket-ship🚀", "
|
|
28
|
+
("🚀rocket-ship🚀", "rocket_ship_", True),
|
|
29
29
|
# Mixed issues: starting with digit and invalid characters
|
|
30
|
-
("123field@name", "
|
|
30
|
+
("123field@name", "n123field_name", True),
|
|
31
31
|
],
|
|
32
32
|
)
|
|
33
33
|
def test_basic_normalization(
|
|
@@ -41,7 +41,9 @@ class TestNormalizeFieldName:
|
|
|
41
41
|
assert result.modified == expected_modified
|
|
42
42
|
assert result.normalized.isidentifier()
|
|
43
43
|
|
|
44
|
-
@pytest.mark.parametrize(
|
|
44
|
+
@pytest.mark.parametrize(
|
|
45
|
+
"keyword", [kw for kw in keyword.kwlist if not kw.startswith("_")]
|
|
46
|
+
)
|
|
45
47
|
def test_python_keywords(self, keyword: str):
|
|
46
48
|
"""Test that Python keywords get an underscore appended."""
|
|
47
49
|
result = normalize_field_name(keyword)
|
|
@@ -55,3 +57,6 @@ class TestNormalizeFieldName:
|
|
|
55
57
|
"""Test edge cases and boundary conditions."""
|
|
56
58
|
with pytest.raises(ValueError, match="empty"):
|
|
57
59
|
normalize_field_name("")
|
|
60
|
+
|
|
61
|
+
with pytest.raises(ValueError, match="must contain at least one letter"):
|
|
62
|
+
normalize_field_name("______")
|
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
from pydantic import Field
|
|
2
2
|
import pytest
|
|
3
3
|
|
|
4
|
-
from soar_sdk.asset import AssetField, BaseAsset
|
|
4
|
+
from soar_sdk.asset import AssetField, AssetFieldSpecification, BaseAsset
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_asset_with_aliased_field():
|
|
8
|
+
"""Ensure that asset field serialization uses the field alias if available, not the name."""
|
|
9
|
+
|
|
10
|
+
class AliasedAsset(BaseAsset):
|
|
11
|
+
aliased_field: str = AssetField(alias="_aliased_field")
|
|
12
|
+
|
|
13
|
+
result = AliasedAsset.to_json_schema()
|
|
14
|
+
assert result["_aliased_field"] == AssetFieldSpecification(
|
|
15
|
+
data_type="string", required=True, description="Aliased Field", order=0
|
|
16
|
+
)
|
|
5
17
|
|
|
6
18
|
|
|
7
19
|
def test_asset_reserved_field_validation():
|
|
@@ -1291,7 +1291,7 @@ wheels = [
|
|
|
1291
1291
|
|
|
1292
1292
|
[[package]]
|
|
1293
1293
|
name = "splunk-soar-sdk"
|
|
1294
|
-
version = "1.4.
|
|
1294
|
+
version = "1.4.1"
|
|
1295
1295
|
source = { editable = "." }
|
|
1296
1296
|
dependencies = [
|
|
1297
1297
|
{ name = "beautifulsoup4", marker = "(python_full_version < '3.10' and platform_machine == 'arm64' and sys_platform == 'darwin') or (python_full_version >= '3.13' and platform_machine == 'arm64' and sys_platform == 'darwin') or (python_full_version < '3.10' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'darwin') or (python_full_version < '3.10' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.13' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.10' and platform_machine == 'x86_64' and sys_platform == 'linux') or (python_full_version >= '3.13' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# [1.4.0](https://github.com/phantomcyber/splunk-soar-sdk/compare/1.3.4...1.4.0) (2025-09-10)
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
### Features
|
|
5
|
-
|
|
6
|
-
* function to get container id on soar client ([2329956](https://github.com/phantomcyber/splunk-soar-sdk/commit/232995679cc5c568fc9ebd895c96aaf8f3f6448e))
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
# [1.4.0](https://github.com/phantomcyber/splunk-soar-sdk/compare/1.3.4...1.4.0) (2025-09-10)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
### Features
|
|
16
|
-
|
|
17
|
-
* function to get container id on soar client ([2329956](https://github.com/phantomcyber/splunk-soar-sdk/commit/232995679cc5c568fc9ebd895c96aaf8f3f6448e))
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.4.0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|