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.
Files changed (219) hide show
  1. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/PKG-INFO +1 -1
  2. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/pyproject.toml +1 -1
  3. splunk_soar_sdk-2.3.0/release_notes.txt +31 -0
  4. splunk_soar_sdk-2.3.0/release_version.txt +1 -0
  5. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/action_results.py +25 -4
  6. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app.py +4 -0
  7. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/serializers.py +17 -3
  8. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/action.py +11 -0
  9. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/actions.py +10 -4
  10. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/params.py +5 -0
  11. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_deserializers.py +5 -1
  12. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_serializers.py +91 -2
  13. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/app.json +143 -0
  14. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/app.py +23 -2
  15. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_actions.py +3 -2
  16. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_action_results.py +15 -0
  17. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_action.py +43 -0
  18. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/uv.lock +1 -1
  19. splunk_soar_sdk-2.1.1/release_notes.txt +0 -21
  20. splunk_soar_sdk-2.1.1/release_version.txt +0 -1
  21. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/ISSUE_TEMPLATE/bug.md +0 -0
  22. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  23. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/pull_request_template.md +0 -0
  24. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/utils/github.js +0 -0
  25. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/utils/update_version.py +0 -0
  26. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/code_quality.yml +0 -0
  27. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/commit_hygiene.yml +0 -0
  28. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/generate_docs.yml +0 -0
  29. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.github/workflows/semantic_release.yml +0 -0
  30. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.gitignore +0 -0
  31. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.pre-commit-config.yaml +0 -0
  32. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/.releaserc +0 -0
  33. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/LICENSE +0 -0
  34. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/README.md +0 -0
  35. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/commitlint.config.js +0 -0
  36. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/api_reference.rst +0 -0
  37. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/index.rst +0 -0
  38. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/pre-commit-config.yaml.rst +0 -0
  39. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/pyproject.toml.rst +0 -0
  40. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/app_structure/src_app.rst +0 -0
  41. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/changelog.rst +0 -0
  42. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/cli_reference.rst +0 -0
  43. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/conf.py +0 -0
  44. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/index.rst +0 -0
  45. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/reusable_components.md +0 -0
  46. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/templates.md +0 -0
  47. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/custom_views/view_handlers.md +0 -0
  48. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/defining_asset.rst +0 -0
  49. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/first_action.rst +0 -0
  50. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/index.rst +0 -0
  51. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/init_app.rst +0 -0
  52. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/installation.rst +0 -0
  53. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/getting_started/testing_and_building.rst +0 -0
  54. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/docs/index.rst +0 -0
  55. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/__init__.py +0 -0
  56. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/abstract.py +0 -0
  57. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/actions_manager.py +0 -0
  58. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/__init__.py +0 -0
  59. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/artifact.py +0 -0
  60. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/container.py +0 -0
  61. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/utils.py +0 -0
  62. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/apis/vault.py +0 -0
  63. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_cli_runner.py +0 -0
  64. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_client.py +0 -0
  65. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/.gitignore +0 -0
  66. {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
  67. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/logo.svg +0 -0
  68. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/logo_dark.svg +0 -0
  69. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/src/__init__.py +0 -0
  70. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/app_templates/basic_app/uv.lock +0 -0
  71. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/asset.py +0 -0
  72. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/async_utils.py +0 -0
  73. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/__init__.py +0 -0
  74. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/cli.py +0 -0
  75. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/init/__init__.py +0 -0
  76. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/init/cli.py +0 -0
  77. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/__init__.py +0 -0
  78. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/cli.py +0 -0
  79. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/deserializers.py +0 -0
  80. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/manifests/processors.py +0 -0
  81. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/package/cli.py +0 -0
  82. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/package/utils.py +0 -0
  83. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/path_utils.py +0 -0
  84. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/cli/utils.py +0 -0
  85. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/__init__.py +0 -0
  86. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/action_renderer.py +0 -0
  87. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/app_renderer.py +0 -0
  88. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/asset_renderer.py +0 -0
  89. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/renderer.py +0 -0
  90. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/templates/pyproject.toml.jinja +0 -0
  91. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/code_renderers/toml_renderer.py +0 -0
  92. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/colors.py +0 -0
  93. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/compat.py +0 -0
  94. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/crypto.py +0 -0
  95. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/__init__.py +0 -0
  96. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/make_request.py +0 -0
  97. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/on_poll.py +0 -0
  98. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/test_connectivity.py +0 -0
  99. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/view_handler.py +0 -0
  100. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/decorators/webhook.py +0 -0
  101. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/exceptions.py +0 -0
  102. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/input_spec.py +0 -0
  103. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/logging.py +0 -0
  104. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/__init__.py +0 -0
  105. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/adapters.py +0 -0
  106. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/app.py +0 -0
  107. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/datatypes.py +0 -0
  108. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/dependencies.py +0 -0
  109. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/meta/webhooks.py +0 -0
  110. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/__init__.py +0 -0
  111. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/artifact.py +0 -0
  112. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/container.py +0 -0
  113. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/vault_attachment.py +0 -0
  114. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/models/view.py +0 -0
  115. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/paths.py +0 -0
  116. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/py.typed +0 -0
  117. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/action_result.py +0 -0
  118. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/app.py +0 -0
  119. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/base_connector.py +0 -0
  120. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/connector_result.py +0 -0
  121. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/consts.py +0 -0
  122. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/encryption_helper.py +0 -0
  123. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/install_info.py +0 -0
  124. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/json_keys.py +0 -0
  125. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/ph_ipc.py +0 -0
  126. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/shims/phantom/vault.py +0 -0
  127. {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
  128. {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
  129. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/base_template.html +0 -0
  130. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/error.html +0 -0
  131. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/header.html +0 -0
  132. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/base/logo_header.html +0 -0
  133. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/components/pie_chart.html +0 -0
  134. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/widgets/widget_resize_snippet.html +0 -0
  135. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/templates/widgets/widget_template.html +0 -0
  136. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/types.py +0 -0
  137. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/__init__.py +0 -0
  138. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/component_registry.py +0 -0
  139. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/components/__init__.py +0 -0
  140. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/components/pie_chart.py +0 -0
  141. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/template_filters.py +0 -0
  142. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/template_renderer.py +0 -0
  143. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/views/view_parser.py +0 -0
  144. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/webhooks/__init__.py +0 -0
  145. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/webhooks/models.py +0 -0
  146. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/src/soar_sdk/webhooks/routing.py +0 -0
  147. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/test.png +0 -0
  148. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/test.txt +0 -0
  149. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/__init__.py +0 -0
  150. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/__init__.py +0 -0
  151. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/datapath_parse.py +0 -0
  152. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/manifests/__init__.py +0 -0
  153. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/manifests/test_processors.py +0 -0
  154. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_assets/converted_app/actions.py.txt +0 -0
  155. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_cli.py +0 -0
  156. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_convert_cli.py +0 -0
  157. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_init_cli.py +0 -0
  158. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_manifests_cli.py +0 -0
  159. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_package_cli.py +0 -0
  160. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/cli/test_utils.py +0 -0
  161. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/code_renderers/test_action_renderer.py +0 -0
  162. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/conftest.py +0 -0
  163. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/example_asset.json +0 -0
  164. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/logo.svg +0 -0
  165. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/logo_dark.svg +0 -0
  166. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/pyproject.toml +0 -0
  167. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/__init__.py +0 -0
  168. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/__init__.py +0 -0
  169. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/async_action.py +0 -0
  170. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/generate_category.py +0 -0
  171. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/actions/reverse_string.py +0 -0
  172. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/src/ignoreme.txt +0 -0
  173. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/templates/reverse_string.html +0 -0
  174. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app/uv.lock +0 -0
  175. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/app.json +0 -0
  176. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/logo.svg +0 -0
  177. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/logo_dark.svg +0 -0
  178. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/pyproject.toml +0 -0
  179. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/src/__init__.py +0 -0
  180. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/src/app.py +0 -0
  181. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/example_app_with_webhook/uv.lock +0 -0
  182. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/__init__.py +0 -0
  183. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/test_artifact_interface.py +0 -0
  184. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/test_container_interface.py +0 -0
  185. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/interfaces/test_vault_interface.py +0 -0
  186. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/__init__.py +0 -0
  187. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_adapters.py +0 -0
  188. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_datatypes.py +0 -0
  189. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_dependencies.py +0 -0
  190. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/meta/test_webhooks.py +0 -0
  191. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/mocks/__init__.py +0 -0
  192. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/mocks/dynamic_mocks.py +0 -0
  193. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/mocks/importable_action.py +0 -0
  194. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/stubs.py +0 -0
  195. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_actions_manager.py +0 -0
  196. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app.py +0 -0
  197. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_action_params.py +0 -0
  198. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_action_results.py +0 -0
  199. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_client.py +0 -0
  200. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_app_runner.py +0 -0
  201. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_asset.py +0 -0
  202. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_assets/splunk-sdk-2.1.0.tar.gz +0 -0
  203. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_async_integration.py +0 -0
  204. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_async_utils.py +0 -0
  205. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_code_renderers.py +0 -0
  206. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_compat.py +0 -0
  207. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_container.py +0 -0
  208. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_custom_views.py +0 -0
  209. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_encryption.py +0 -0
  210. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_logging.py +0 -0
  211. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_make_request_action.py +0 -0
  212. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_on_poll.py +0 -0
  213. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_params.py +0 -0
  214. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_template_filters.py +0 -0
  215. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_template_renderer.py +0 -0
  216. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_test_connectivity.py +0 -0
  217. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/test_view_parser.py +0 -0
  218. {splunk_soar_sdk-2.1.1 → splunk_soar_sdk-2.3.0}/tests/webhooks/test_models.py +0 -0
  219. {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.1.1
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "splunk-soar-sdk"
3
- version = "2.1.1"
3
+ version = "2.3.0"
4
4
  description = "The official framework for developing and testing Splunk SOAR Apps"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.9, <3.14"
@@ -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, parent_datapath: str = "action_result.data.*"
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
- params = cls.serialize_parameter_datapaths(params_class)
61
- outputs = outputs_class._to_json_schema()
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
- {"data_path": "action_result.data.*.result"},
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(cef_types=["ip"], example_values=["1.1.1.1"])
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",