splunk-soar-sdk 3.2.3__tar.gz → 3.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (257) hide show
  1. splunk_soar_sdk-3.3.1/.github/scripts/generate_test_summary.py +173 -0
  2. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/workflows/code_quality.yml +1 -1
  3. splunk_soar_sdk-3.3.1/.github/workflows/integration_tests.yml +195 -0
  4. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/PKG-INFO +1 -1
  5. splunk_soar_sdk-3.3.1/mcp_server/README.md +135 -0
  6. splunk_soar_sdk-3.3.1/mcp_server/install.sh +58 -0
  7. splunk_soar_sdk-3.3.1/mcp_server/mcp_config.json +12 -0
  8. splunk_soar_sdk-3.3.1/mcp_server/pyproject.toml +24 -0
  9. splunk_soar_sdk-3.3.1/mcp_server/pytest.ini +2 -0
  10. splunk_soar_sdk-3.3.1/mcp_server/src/soar_test_assistant/__init__.py +3 -0
  11. splunk_soar_sdk-3.3.1/mcp_server/src/soar_test_assistant/server.py +372 -0
  12. splunk_soar_sdk-3.3.1/mcp_server/tests/test_analyzer.py +23 -0
  13. splunk_soar_sdk-3.3.1/mcp_server/uv.lock +1009 -0
  14. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/pyproject.toml +10 -3
  15. splunk_soar_sdk-3.3.1/release_notes.txt +21 -0
  16. splunk_soar_sdk-3.3.1/release_version.txt +1 -0
  17. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/abstract.py +4 -4
  18. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/actions_manager.py +13 -37
  19. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app.py +15 -0
  20. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_client.py +2 -1
  21. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/asset.py +27 -0
  22. splunk_soar_sdk-3.3.1/src/soar_sdk/asset_state.py +54 -0
  23. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/cli.py +2 -0
  24. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/manifests/processors.py +5 -0
  25. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/package/cli.py +10 -4
  26. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/package/utils.py +16 -15
  27. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/path_utils.py +0 -5
  28. splunk_soar_sdk-3.3.1/src/soar_sdk/cli/test/cli.py +296 -0
  29. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/webhook.py +3 -2
  30. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/exceptions.py +9 -0
  31. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/meta/actions.py +9 -0
  32. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/base_connector.py +7 -2
  33. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/encryption_helper.py +6 -4
  34. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_package_cli.py +24 -5
  35. splunk_soar_sdk-3.3.1/tests/cli/test_test_cli.py +208 -0
  36. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/conftest.py +12 -0
  37. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/app.json +120 -32
  38. splunk_soar_sdk-3.3.1/tests/example_app/example_asset.json +9 -0
  39. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/pyproject.toml +4 -1
  40. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/src/app.py +20 -2
  41. splunk_soar_sdk-3.3.1/tests/example_app/uv.lock +1201 -0
  42. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app_with_webhook/app.json +77 -76
  43. splunk_soar_sdk-3.3.1/tests/example_app_with_webhook/example_asset.json +7 -0
  44. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app_with_webhook/pyproject.toml +2 -2
  45. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app_with_webhook/src/app.py +5 -3
  46. {splunk_soar_sdk-3.2.3/tests/example_app → splunk_soar_sdk-3.3.1/tests/example_app_with_webhook}/uv.lock +118 -113
  47. splunk_soar_sdk-3.3.1/tests/integration/conftest.py +115 -0
  48. splunk_soar_sdk-3.3.1/tests/integration/phantom_constants.py +29 -0
  49. splunk_soar_sdk-3.3.1/tests/integration/phantom_instance.py +421 -0
  50. splunk_soar_sdk-3.3.1/tests/integration/soar_client.py +250 -0
  51. splunk_soar_sdk-3.3.1/tests/integration/test_example_app.py +60 -0
  52. splunk_soar_sdk-3.3.1/tests/integration/test_example_app_with_webhook.py +19 -0
  53. splunk_soar_sdk-3.3.1/tests/interfaces/__init__.py +0 -0
  54. splunk_soar_sdk-3.3.1/tests/meta/__init__.py +0 -0
  55. splunk_soar_sdk-3.3.1/tests/mocks/__init__.py +0 -0
  56. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_actions_manager.py +7 -90
  57. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_app.py +47 -0
  58. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_asset.py +10 -0
  59. splunk_soar_sdk-3.3.1/tests/test_asset_state.py +68 -0
  60. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/uv.lock +18 -1
  61. splunk_soar_sdk-3.2.3/release_notes.txt +0 -21
  62. splunk_soar_sdk-3.2.3/release_version.txt +0 -1
  63. splunk_soar_sdk-3.2.3/tests/example_app/example_asset.json +0 -4
  64. splunk_soar_sdk-3.2.3/tests/example_app_with_webhook/uv.lock +0 -1022
  65. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/ISSUE_TEMPLATE/bug.md +0 -0
  66. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  67. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/pull_request_template.md +0 -0
  68. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/utils/github.js +0 -0
  69. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/utils/update_version.py +0 -0
  70. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/workflows/commit_hygiene.yml +0 -0
  71. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/workflows/generate_docs.yml +0 -0
  72. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.github/workflows/semantic_release.yml +0 -0
  73. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.gitignore +0 -0
  74. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.pre-commit-config.yaml +0 -0
  75. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/.releaserc +0 -0
  76. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/LICENSE +0 -0
  77. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/README.md +0 -0
  78. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/commitlint.config.js +0 -0
  79. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/api_reference.rst +0 -0
  80. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/app_structure/index.rst +0 -0
  81. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/app_structure/pre-commit-config.yaml.rst +0 -0
  82. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/app_structure/pyproject.toml.rst +0 -0
  83. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/app_structure/src_app.rst +0 -0
  84. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/changelog.rst +0 -0
  85. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/cli_reference.rst +0 -0
  86. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/conf.py +0 -0
  87. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/custom_views/index.rst +0 -0
  88. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/custom_views/reusable_components.md +0 -0
  89. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/custom_views/templates.md +0 -0
  90. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/custom_views/view_handlers.md +0 -0
  91. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/getting_started/defining_asset.rst +0 -0
  92. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/getting_started/first_action.rst +0 -0
  93. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/getting_started/index.rst +0 -0
  94. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/getting_started/init_app.rst +0 -0
  95. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/getting_started/installation.rst +0 -0
  96. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/getting_started/testing_and_building.rst +0 -0
  97. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/docs/index.rst +0 -0
  98. {splunk_soar_sdk-3.2.3/src/soar_sdk/apis → splunk_soar_sdk-3.3.1/mcp_server/tests}/__init__.py +0 -0
  99. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/__init__.py +0 -0
  100. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/action_results.py +0 -0
  101. {splunk_soar_sdk-3.2.3/src/soar_sdk/app_templates/basic_app/src → splunk_soar_sdk-3.3.1/src/soar_sdk/apis}/__init__.py +0 -0
  102. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/apis/artifact.py +0 -0
  103. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/apis/container.py +0 -0
  104. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/apis/utils.py +0 -0
  105. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/apis/vault.py +0 -0
  106. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_cli_runner.py +0 -0
  107. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_templates/basic_app/.gitignore +0 -0
  108. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_templates/basic_app/.pre-commit-config.yaml +0 -0
  109. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_templates/basic_app/logo.svg +0 -0
  110. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_templates/basic_app/logo_dark.svg +0 -0
  111. {splunk_soar_sdk-3.2.3/src/soar_sdk/cli → splunk_soar_sdk-3.3.1/src/soar_sdk/app_templates/basic_app/src}/__init__.py +0 -0
  112. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/app_templates/basic_app/uv.lock +0 -0
  113. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/async_utils.py +0 -0
  114. {splunk_soar_sdk-3.2.3/src/soar_sdk/cli/init → splunk_soar_sdk-3.3.1/src/soar_sdk/cli}/__init__.py +0 -0
  115. {splunk_soar_sdk-3.2.3/src/soar_sdk/cli/manifests → splunk_soar_sdk-3.3.1/src/soar_sdk/cli/init}/__init__.py +0 -0
  116. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/init/cli.py +0 -0
  117. {splunk_soar_sdk-3.2.3/src/soar_sdk/code_renderers → splunk_soar_sdk-3.3.1/src/soar_sdk/cli/manifests}/__init__.py +0 -0
  118. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/manifests/cli.py +0 -0
  119. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/manifests/deserializers.py +0 -0
  120. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/manifests/serializers.py +0 -0
  121. {splunk_soar_sdk-3.2.3/src/soar_sdk/meta → splunk_soar_sdk-3.3.1/src/soar_sdk/cli/test}/__init__.py +0 -0
  122. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/cli/utils.py +0 -0
  123. {splunk_soar_sdk-3.2.3/src/soar_sdk/views → splunk_soar_sdk-3.3.1/src/soar_sdk/code_renderers}/__init__.py +0 -0
  124. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/code_renderers/action_renderer.py +0 -0
  125. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/code_renderers/app_renderer.py +0 -0
  126. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/code_renderers/asset_renderer.py +0 -0
  127. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/code_renderers/renderer.py +0 -0
  128. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/code_renderers/templates/pyproject.toml.jinja +0 -0
  129. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/code_renderers/toml_renderer.py +0 -0
  130. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/colors.py +0 -0
  131. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/compat.py +0 -0
  132. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/crypto.py +0 -0
  133. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/__init__.py +0 -0
  134. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/action.py +0 -0
  135. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/make_request.py +0 -0
  136. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/on_es_poll.py +0 -0
  137. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/on_poll.py +0 -0
  138. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/test_connectivity.py +0 -0
  139. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/decorators/view_handler.py +0 -0
  140. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/field_utils.py +0 -0
  141. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/input_spec.py +0 -0
  142. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/logging.py +0 -0
  143. {splunk_soar_sdk-3.2.3/src/soar_sdk/views/components → splunk_soar_sdk-3.3.1/src/soar_sdk/meta}/__init__.py +0 -0
  144. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/meta/adapters.py +0 -0
  145. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/meta/app.py +0 -0
  146. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/meta/datatypes.py +0 -0
  147. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/meta/dependencies.py +0 -0
  148. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/meta/webhooks.py +0 -0
  149. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/__init__.py +0 -0
  150. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/artifact.py +0 -0
  151. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/attachment_input.py +0 -0
  152. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/container.py +0 -0
  153. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/finding.py +0 -0
  154. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/vault_attachment.py +0 -0
  155. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/models/view.py +0 -0
  156. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/params.py +0 -0
  157. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/paths.py +0 -0
  158. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/py.typed +0 -0
  159. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/action_result.py +0 -0
  160. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/app.py +0 -0
  161. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/connector_result.py +0 -0
  162. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/consts.py +0 -0
  163. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/install_info.py +0 -0
  164. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/json_keys.py +0 -0
  165. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/ph_ipc.py +0 -0
  166. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom/vault.py +0 -0
  167. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom_common/app_interface/app_interface.py +0 -0
  168. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/shims/phantom_common/encryption/encryption_manager_factory.py +0 -0
  169. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/base/base_template.html +0 -0
  170. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/base/error.html +0 -0
  171. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/base/header.html +0 -0
  172. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/base/logo_header.html +0 -0
  173. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/components/pie_chart.html +0 -0
  174. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/widgets/widget_resize_snippet.html +0 -0
  175. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/templates/widgets/widget_template.html +0 -0
  176. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/types.py +0 -0
  177. {splunk_soar_sdk-3.2.3/src/soar_sdk/webhooks → splunk_soar_sdk-3.3.1/src/soar_sdk/views}/__init__.py +0 -0
  178. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/views/component_registry.py +0 -0
  179. {splunk_soar_sdk-3.2.3/tests → splunk_soar_sdk-3.3.1/src/soar_sdk/views/components}/__init__.py +0 -0
  180. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/views/components/pie_chart.py +0 -0
  181. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/views/template_filters.py +0 -0
  182. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/views/template_renderer.py +0 -0
  183. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/views/view_parser.py +0 -0
  184. {splunk_soar_sdk-3.2.3/tests/cli → splunk_soar_sdk-3.3.1/src/soar_sdk/webhooks}/__init__.py +0 -0
  185. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/webhooks/models.py +0 -0
  186. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/src/soar_sdk/webhooks/routing.py +0 -0
  187. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/test.png +0 -0
  188. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/test.txt +0 -0
  189. {splunk_soar_sdk-3.2.3/tests/cli/manifests → splunk_soar_sdk-3.3.1/tests}/__init__.py +0 -0
  190. {splunk_soar_sdk-3.2.3/tests/example_app/src/actions → splunk_soar_sdk-3.3.1/tests/cli}/__init__.py +0 -0
  191. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/datapath_parse.py +0 -0
  192. {splunk_soar_sdk-3.2.3/tests/interfaces → splunk_soar_sdk-3.3.1/tests/cli/manifests}/__init__.py +0 -0
  193. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/manifests/test_processors.py +0 -0
  194. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/manifests/test_python_version_resolution.py +0 -0
  195. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_assets/converted_app/actions.py.txt +0 -0
  196. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_cli.py +0 -0
  197. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_convert_cli.py +0 -0
  198. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_deserializers.py +0 -0
  199. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_init_cli.py +0 -0
  200. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_manifests_cli.py +0 -0
  201. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_serializers.py +0 -0
  202. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/cli/test_utils.py +0 -0
  203. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/code_renderers/test_action_renderer.py +0 -0
  204. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/logo.svg +0 -0
  205. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/logo_dark.svg +0 -0
  206. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/release_notes/v1.md +0 -0
  207. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/src/__init__.py +0 -0
  208. {splunk_soar_sdk-3.2.3/tests/meta → splunk_soar_sdk-3.3.1/tests/example_app/src/actions}/__init__.py +0 -0
  209. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/src/actions/async_action.py +0 -0
  210. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/src/actions/generate_category.py +0 -0
  211. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/src/actions/reverse_string.py +0 -0
  212. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/src/ignoreme.txt +0 -0
  213. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app/templates/reverse_string.html +0 -0
  214. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app_with_webhook/logo.svg +0 -0
  215. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app_with_webhook/logo_dark.svg +0 -0
  216. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/example_app_with_webhook/src/__init__.py +0 -0
  217. {splunk_soar_sdk-3.2.3/tests/mocks → splunk_soar_sdk-3.3.1/tests/integration}/__init__.py +0 -0
  218. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/interfaces/test_artifact_interface.py +0 -0
  219. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/interfaces/test_container_interface.py +0 -0
  220. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/interfaces/test_vault_interface.py +0 -0
  221. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/meta/test_actions.py +0 -0
  222. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/meta/test_adapters.py +0 -0
  223. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/meta/test_datatypes.py +0 -0
  224. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/meta/test_dependencies.py +0 -0
  225. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/meta/test_webhooks.py +0 -0
  226. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/mocks/dynamic_mocks.py +0 -0
  227. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/mocks/importable_action.py +0 -0
  228. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/stubs.py +0 -0
  229. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_action_results.py +0 -0
  230. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_app_action.py +0 -0
  231. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_app_action_params.py +0 -0
  232. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_app_action_results.py +0 -0
  233. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_app_client.py +0 -0
  234. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_app_runner.py +0 -0
  235. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_assets/splunk-sdk-2.1.0.tar.gz +0 -0
  236. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_async_integration.py +0 -0
  237. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_async_utils.py +0 -0
  238. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_attachment_input.py +0 -0
  239. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_code_renderers.py +0 -0
  240. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_compat.py +0 -0
  241. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_container.py +0 -0
  242. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_custom_views.py +0 -0
  243. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_encryption.py +0 -0
  244. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_es_on_poll.py +0 -0
  245. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_field_utils.py +0 -0
  246. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_finding.py +0 -0
  247. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_input_spec.py +0 -0
  248. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_logging.py +0 -0
  249. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_make_request_action.py +0 -0
  250. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_on_poll.py +0 -0
  251. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_params.py +0 -0
  252. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_template_filters.py +0 -0
  253. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_template_renderer.py +0 -0
  254. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_test_connectivity.py +0 -0
  255. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/test_view_parser.py +0 -0
  256. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/webhooks/test_models.py +0 -0
  257. {splunk_soar_sdk-3.2.3 → splunk_soar_sdk-3.3.1}/tests/webhooks/test_routing.py +0 -0
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env python3
2
+ """Generate integration test summary from JUnit XML reports."""
3
+
4
+ import sys
5
+ import xml.etree.ElementTree as ET
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+
9
+
10
+ @dataclass
11
+ class TestResult:
12
+ """Test result summary for a single version."""
13
+
14
+ version: str
15
+ passed: int
16
+ failed: int
17
+ skipped: int
18
+ errors: int
19
+ duration: float
20
+ failures: list[dict[str, str]]
21
+
22
+
23
+ def parse_junit_xml(xml_path: Path) -> TestResult:
24
+ """Parse JUnit XML file and extract test results."""
25
+ tree = ET.parse(xml_path) # noqa: S314
26
+ root = tree.getroot()
27
+
28
+ version = xml_path.stem.replace("junit-", "")
29
+ passed = 0
30
+ failed = 0
31
+ skipped = 0
32
+ errors = 0
33
+ duration = 0.0
34
+ failures = []
35
+
36
+ for testsuite in root.findall(".//testsuite"):
37
+ duration += float(testsuite.get("time", 0))
38
+ passed += (
39
+ int(testsuite.get("tests", 0))
40
+ - int(testsuite.get("failures", 0))
41
+ - int(testsuite.get("skipped", 0))
42
+ - int(testsuite.get("errors", 0))
43
+ )
44
+ failed += int(testsuite.get("failures", 0))
45
+ skipped += int(testsuite.get("skipped", 0))
46
+ errors += int(testsuite.get("errors", 0))
47
+
48
+ for testcase in root.findall(".//testcase"):
49
+ failure = testcase.find("failure")
50
+ error = testcase.find("error")
51
+
52
+ if failure is not None:
53
+ failures.append(
54
+ {
55
+ "name": f"{testcase.get('classname')}.{testcase.get('name')}",
56
+ "message": failure.get("message", "No message"),
57
+ "type": failure.get("type", "AssertionError"),
58
+ "output": (failure.text or "")[:500],
59
+ }
60
+ )
61
+ elif error is not None:
62
+ failures.append(
63
+ {
64
+ "name": f"{testcase.get('classname')}.{testcase.get('name')}",
65
+ "message": error.get("message", "No message"),
66
+ "type": error.get("type", "Error"),
67
+ "output": (error.text or "")[:500],
68
+ }
69
+ )
70
+
71
+ return TestResult(
72
+ version=version,
73
+ passed=passed,
74
+ failed=failed,
75
+ skipped=skipped,
76
+ errors=errors,
77
+ duration=duration,
78
+ failures=failures,
79
+ )
80
+
81
+
82
+ def format_duration(seconds: float) -> str:
83
+ """Format duration in human-readable format."""
84
+ minutes = int(seconds // 60)
85
+ secs = int(seconds % 60)
86
+ return f"{minutes}m {secs}s"
87
+
88
+
89
+ def generate_markdown_summary(
90
+ results: list[TestResult], run_url: str | None = None
91
+ ) -> str:
92
+ """Generate markdown summary from test results."""
93
+ total_passed = sum(r.passed for r in results)
94
+ total_failed = sum(r.failed for r in results)
95
+ total_errors = sum(r.errors for r in results)
96
+
97
+ md = "# Integration Test Results\n"
98
+
99
+ if total_failed + total_errors == 0:
100
+ md += f"## ✅ {total_passed} tests passed!\n"
101
+ else:
102
+ md += "## ⚠️ Some tests failed.\n"
103
+
104
+ md += "| Version | ✅ Passed | ❌ Failed | ⏭️ Skipped | Duration |\n"
105
+ md += "| ------- | --------- | --------- | ---------- | -------- |\n"
106
+
107
+ for result in sorted(results, key=lambda r: r.version):
108
+ md += f"| {result.version} | {result.passed} | {result.failed + result.errors} | {result.skipped} | {format_duration(result.duration)} |\n"
109
+
110
+ has_failures = any(r.failures for r in results)
111
+ if has_failures:
112
+ md += "## Failed Tests\n"
113
+ md += "| Version | Name | Message | Type |\n"
114
+ md += "| ------- | ---- | ------- | ---- |\n"
115
+ for result in results:
116
+ if result.failures:
117
+ for failure in result.failures:
118
+ message = failure["message"]
119
+ if len(message) > 200:
120
+ message = message[:200].strip() + "…"
121
+ md += f"| {result.version} | {failure['name']} | {message} | {failure['type']} |\n"
122
+
123
+ if run_url:
124
+ md += "---\n[View full logs and artifacts](" + run_url + ")\n"
125
+
126
+ return md
127
+
128
+
129
+ def main() -> int:
130
+ """Main entry point."""
131
+ if len(sys.argv) < 2:
132
+ print(
133
+ "Usage: generate_test_summary.py <test-results-dir> [output-file] [run-url]"
134
+ )
135
+ return 1
136
+
137
+ test_results_dir = Path(sys.argv[1])
138
+ if not test_results_dir.exists():
139
+ print(f"Error: Directory {test_results_dir} does not exist")
140
+ return 1
141
+
142
+ junit_files = list(test_results_dir.glob("**/junit-*.xml"))
143
+ if not junit_files:
144
+ print(f"Error: No JUnit XML files found in {test_results_dir}")
145
+ return 1
146
+
147
+ results = []
148
+ for junit_file in junit_files:
149
+ try:
150
+ result = parse_junit_xml(junit_file)
151
+ results.append(result)
152
+ except Exception as e:
153
+ print(f"Error parsing {junit_file}: {e}")
154
+ continue
155
+
156
+ if not results:
157
+ print("Error: No test results could be parsed")
158
+ return 1
159
+
160
+ run_url = sys.argv[3] if len(sys.argv) > 3 else None
161
+ summary = generate_markdown_summary(results, run_url)
162
+ print(summary)
163
+
164
+ summary_file = Path(sys.argv[2]) if len(sys.argv) > 2 else Path("test-summary.md")
165
+ summary_file.write_text(summary)
166
+ print(f"\nSummary written to {summary_file}", file=sys.stderr)
167
+
168
+ has_failures = any(r.failed + r.errors > 0 for r in results)
169
+ return 1 if has_failures else 0
170
+
171
+
172
+ if __name__ == "__main__":
173
+ sys.exit(main())
@@ -56,7 +56,7 @@ jobs:
56
56
  enable-cache: true
57
57
  python-version: ${{ matrix.python-version }}
58
58
  - name: Pytest + Coverage - ${{ matrix.python-version }}
59
- run: uv run --locked pytest -n auto
59
+ run: uv run --locked pytest -n auto -m "not integration"
60
60
 
61
61
  generate_docs:
62
62
  runs-on: ubuntu-latest
@@ -0,0 +1,195 @@
1
+ name: Integration Tests
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ - next
8
+ - beta
9
+ pull_request:
10
+
11
+ jobs:
12
+ build-example-apps:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ app:
17
+ - example_app
18
+ - example_app_with_webhook
19
+ steps:
20
+ - name: Checkout SDK repository
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v5
25
+ with:
26
+ enable-cache: true
27
+ python-version: 3.13
28
+
29
+ - name: Build ${{ matrix.app }}
30
+ run: |
31
+ echo "Building SOAR SDK from branch"
32
+ uv build
33
+ echo "Building ${{ matrix.app }} using soarapps CLI"
34
+ uv run soarapps package build tests/${{ matrix.app }} --output-file /tmp/${{ matrix.app }}.tgz --with-sdk-wheel-from $(ls -t dist/splunk_soar_sdk-*.whl | head -n 1)
35
+ echo "App build completed successfully"
36
+
37
+ - name: Upload app tar file as artifact
38
+ uses: actions/upload-artifact@v4
39
+ with:
40
+ name: ${{ matrix.app }}-tar
41
+ path: /tmp/${{ matrix.app }}.tgz
42
+ retention-days: 1
43
+
44
+ integration-test:
45
+ runs-on:
46
+ - codebuild-github-splunk-soar-sdk-integration-tests-${{ github.run_id }}-${{ github.run_attempt }}
47
+ - image:custom-linux-875003031410.dkr.ecr.us-west-1.amazonaws.com/soar-connectors/pytest:3ea28df603962918dc8e72ead393c40b3ce6e20e
48
+ needs: build-example-apps
49
+ strategy:
50
+ fail-fast: false
51
+ matrix:
52
+ include:
53
+ - version: "previous"
54
+ ip: ${{ vars.PHANTOM_INSTANCE_PREVIOUS_VERSION_IP }}
55
+ - version: "current"
56
+ ip: ${{ vars.PHANTOM_INSTANCE_CURRENT_VERSION_IP }}
57
+ - version: "next"
58
+ ip: ${{ vars.PHANTOM_INSTANCE_NEXT_VERSION_IP }}
59
+ env:
60
+ PHANTOM_USERNAME: ${{ vars.PHANTOM_USERNAME }}
61
+ PHANTOM_PASSWORD: ${{ secrets.PHANTOM_PASSWORD }}
62
+ NUM_TEST_RETRIES: ${{ vars.NUM_TEST_RETRIES || '2' }}
63
+ PHANTOM_VERSION: ${{ matrix.version }}
64
+ AUTOMATION_BROKER_NAME: ${{ vars.AUTOMATION_BROKER_NAME }}
65
+ FORCE_AUTOMATION_BROKER: ${{ vars.FORCE_AUTOMATION_BROKER }}
66
+ UV_LOCKED: 1
67
+ steps:
68
+ - name: Checkout SDK repository
69
+ uses: actions/checkout@v4
70
+
71
+ - name: Install uv
72
+ uses: astral-sh/setup-uv@v5
73
+ with:
74
+ enable-cache: true
75
+ python-version: 3.13
76
+
77
+ - name: Download example_app tar file
78
+ uses: actions/download-artifact@v4
79
+ with:
80
+ name: example_app-tar
81
+ path: /tmp/
82
+
83
+ - name: Download example_app_with_webhook tar file
84
+ uses: actions/download-artifact@v4
85
+ with:
86
+ name: example_app_with_webhook-tar
87
+ path: /tmp/
88
+
89
+ - name: Clear uv cache and sync SDK
90
+ run: |
91
+ uv cache clean
92
+ uv sync
93
+
94
+ - name: Check connectivity to SOAR host
95
+ run: |
96
+ apt update -y
97
+ apt install -y netcat-openbsd
98
+ phantom_ip=${{ matrix.ip }}
99
+ nc -zv "$phantom_ip" 443
100
+ nc -zv "$phantom_ip" 3500
101
+
102
+ - name: Install example_app on Phantom instance
103
+ env:
104
+ PHANTOM_PASSWORD: ${{ secrets.PHANTOM_PASSWORD }}
105
+ run: |
106
+ phantom_ip=${{ matrix.ip }}
107
+ echo "Installing example_app on https://$phantom_ip"
108
+
109
+ uv run soarapps package install \
110
+ /tmp/example_app.tgz \
111
+ "$phantom_ip" \
112
+ --username "${{ vars.PHANTOM_USERNAME }}"
113
+
114
+ - name: Install example_app_with_webhook on Phantom instance
115
+ env:
116
+ PHANTOM_PASSWORD: ${{ secrets.PHANTOM_PASSWORD }}
117
+ run: |
118
+ phantom_ip=${{ matrix.ip }}
119
+ echo "Installing example_app_with_webhook on https://$phantom_ip"
120
+
121
+ uv run soarapps package install \
122
+ /tmp/example_app_with_webhook.tgz \
123
+ "$phantom_ip" \
124
+ --username "${{ vars.PHANTOM_USERNAME }}" \
125
+ --force
126
+
127
+ - name: Run integration tests
128
+ env:
129
+ PHANTOM_URL: "https://${{ matrix.ip }}"
130
+ run: |
131
+ echo "Running integration tests against $PHANTOM_URL"
132
+
133
+ uv sync --group dev
134
+
135
+ # Run pytest with integration tests only (no coverage)
136
+ uv run pytest tests/integration/ \
137
+ -v \
138
+ --reruns=$NUM_TEST_RETRIES \
139
+ --tb=short \
140
+ --color=yes \
141
+ --no-cov \
142
+ -m "integration" \
143
+ --junitxml=test-results/junit-${{ matrix.version }}.xml \
144
+ || exit_code=$?
145
+
146
+ echo "Integration tests completed"
147
+ exit ${exit_code:-0}
148
+
149
+ - name: Upload test results
150
+ uses: actions/upload-artifact@v4
151
+ if: always()
152
+ with:
153
+ name: integration-test-results-${{ matrix.version }}
154
+ path: |
155
+ pytest-logs/
156
+ test-results/
157
+ retention-days: 1
158
+
159
+ test-summary:
160
+ runs-on: ubuntu-latest
161
+ needs: integration-test
162
+ if: always()
163
+ steps:
164
+ - name: Checkout repository
165
+ uses: actions/checkout@v4
166
+
167
+ - name: Download all test results
168
+ uses: actions/download-artifact@v4
169
+ with:
170
+ pattern: integration-test-results-*
171
+ path: all-test-results/
172
+ merge-multiple: true
173
+
174
+ - name: Generate test summary
175
+ run: |
176
+ RUN_URL="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}"
177
+ python3 .github/scripts/generate_test_summary.py all-test-results/ test-summary.md "$RUN_URL"
178
+
179
+ - name: Post summary to job
180
+ run: |
181
+ cat test-summary.md >> $GITHUB_STEP_SUMMARY
182
+
183
+ - name: Upload summary as artifact
184
+ uses: actions/upload-artifact@v4
185
+ with:
186
+ name: test-summary
187
+ path: test-summary.md
188
+ retention-days: 7
189
+
190
+ - name: Fail if tests failed
191
+ run: |
192
+ if grep -q "FAILED" test-summary.md; then
193
+ echo "Integration tests failed - check summary above"
194
+ exit 1
195
+ fi
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splunk-soar-sdk
3
- Version: 3.2.3
3
+ Version: 3.3.1
4
4
  Summary: The official framework for developing and testing Splunk SOAR Apps
5
5
  Project-URL: Homepage, https://github.com/phantomcyber/splunk-soar-sdk
6
6
  Project-URL: Documentation, https://github.com/phantomcyber/splunk-soar-sdk
@@ -0,0 +1,135 @@
1
+ # SOAR Test Assistant MCP Server
2
+
3
+ An MCP server that provides automated test analysis and remediation capabilities for the SOAR SDK. This server orchestrates test execution, applies targeted fixes, and validates changes through an iterative workflow.
4
+
5
+ ## Workflow
6
+
7
+ The server implements a two-phase analysis and remediation cycle:
8
+
9
+ ### 1. analyze_tests - Test Execution and Failure Analysis
10
+ Executes the test suite and captures comprehensive diagnostic output including stack traces, assertion failures, and error context.
11
+
12
+ ### 2. fix_and_run_tests - Automated Remediation and Validation
13
+ Applies proposed changes to source files, test fixtures, or dependencies, then re-executes the test suite to verify the fix.
14
+
15
+ The cycle repeats until all tests pass or unresolvable failures are identified.
16
+
17
+ ## Tools
18
+
19
+ ### `analyze_tests`
20
+
21
+ Executes the SDK test suite and returns detailed diagnostic output for failure analysis.
22
+
23
+ **Parameters:**
24
+ - `test_type`: `"unit"` or `"integration"` (default: `"unit"`)
25
+ - `test_path`: Optional specific test file/directory
26
+ - `soar_instance`: Required for integration tests: `{"ip": "...", "username": "...", "password": "..."}`
27
+
28
+ **Returns:**
29
+ - `status`: `"success"` or `"failed"`
30
+ - `test_output`: Complete pytest output with stack traces and context
31
+ - `message`: Diagnostic guidance for common failure patterns
32
+
33
+ **Example:**
34
+ ```json
35
+ {
36
+ "test_type": "unit",
37
+ "test_path": "tests/cli/manifests/test_processors.py"
38
+ }
39
+ ```
40
+
41
+ ### `fix_and_run_tests`
42
+
43
+ Applies a set of proposed changes (file edits, command executions) and re-runs the test suite to validate the remediation.
44
+
45
+ **Parameters:**
46
+ - `test_type`: `"unit"` or `"integration"` (default: `"unit"`)
47
+ - `test_path`: Optional specific test file/directory
48
+ - `soar_instance`: Required for integration tests
49
+ - `changes`: Array of changes to apply
50
+
51
+ **Change Types:**
52
+
53
+ #### edit_file
54
+ Replace exact content in a file:
55
+ ```json
56
+ {
57
+ "type": "edit_file",
58
+ "file": "tests/example_app/app.json",
59
+ "old_content": "\"version\": \"1.0\"",
60
+ "new_content": "\"version\": \"1.1\"",
61
+ "reasoning": "Update version to match new release"
62
+ }
63
+ ```
64
+
65
+ #### run_command
66
+ Execute a bash command:
67
+ ```json
68
+ {
69
+ "type": "run_command",
70
+ "command": "cd tests/example_app && uv run python -c \"<regenerate fixture code>\"",
71
+ "reasoning": "Regenerate outdated test fixture"
72
+ }
73
+ ```
74
+
75
+ **Returns:**
76
+ - `status`: `"success"`, `"still_failing"`, or `"error"`
77
+ - `applied_changes`: List of changes that were applied
78
+ - `test_output`: New test results
79
+ - `errors`: Any errors encountered
80
+
81
+ ## Example Session
82
+
83
+ Automated remediation workflow for a failing manifest processor test:
84
+
85
+ 1. **Initial Analysis**: `analyze_tests` executes test suite
86
+ - Detects assertion failure: `app_meta != expected_meta`
87
+ - Identifies drift in test fixture `tests/example_app/app.json`
88
+
89
+ 2. **Remediation Strategy**: Regenerate test fixture to match current processor output
90
+ - Command: Invoke `ManifestProcessor` to generate updated manifest
91
+ - Preserve existing `utctime_updated` field to maintain test stability
92
+
93
+ 3. **Apply and Validate**: `fix_and_run_tests` executes regeneration command
94
+ - Fixture updated with current expected values
95
+ - Test suite re-executed
96
+ - Returns `status: "success"`
97
+
98
+ ## Installation
99
+
100
+ Run the installation script from the repository root:
101
+
102
+ ```bash
103
+ ./install
104
+ ```
105
+
106
+ Or configure manually by adding to your MCP settings (`~/.config/claude-code/mcp_settings.json`):
107
+
108
+ ```json
109
+ {
110
+ "mcpServers": {
111
+ "soar-test-assistant": {
112
+ "command": "uv",
113
+ "args": ["run", "soar-test-assistant"],
114
+ "cwd": "/path/to/your/splunk-soar-sdk/mcp_server"
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ Then restart Claude Code.
121
+
122
+ ## SDK-Only Focus
123
+
124
+ This MCP server is **exclusively for SOAR SDK tests**:
125
+ - **Unit tests**: `tests/` (excluding integration)
126
+ - **Integration tests**: `tests/integration/`
127
+
128
+ All tests run from the SDK root directory, which is auto-detected.
129
+
130
+ ## Development
131
+
132
+ ```bash
133
+ # Test the MCP server
134
+ uv run pytest
135
+ ```
@@ -0,0 +1,58 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ echo "Installing SOAR Test Assistant MCP Server..."
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ MCP_CONFIG_DIR="$HOME/.config/claude-code"
8
+ MCP_CONFIG_FILE="$MCP_CONFIG_DIR/mcp_settings.json"
9
+
10
+ echo "1. Installing dependencies..."
11
+ cd "$SCRIPT_DIR"
12
+ uv sync
13
+
14
+ echo "2. Setting up MCP configuration..."
15
+ mkdir -p "$MCP_CONFIG_DIR"
16
+
17
+ SERVER_NAME="soar-test-assistant"
18
+ SERVER_CONFIG=$(cat <<EOF
19
+ {
20
+ "command": "uv",
21
+ "args": [
22
+ "run",
23
+ "--directory",
24
+ "$SCRIPT_DIR",
25
+ "soar_test_assistant"
26
+ ]
27
+ }
28
+ EOF
29
+ )
30
+
31
+ if [ -f "$MCP_CONFIG_FILE" ]; then
32
+ echo " MCP config file exists, backing up..."
33
+ cp "$MCP_CONFIG_FILE" "$MCP_CONFIG_FILE.backup.$(date +%s)"
34
+
35
+ if command -v jq &> /dev/null; then
36
+ echo " Adding server to existing config..."
37
+ jq ".mcpServers[\"$SERVER_NAME\"] = $SERVER_CONFIG" "$MCP_CONFIG_FILE" > "$MCP_CONFIG_FILE.tmp"
38
+ mv "$MCP_CONFIG_FILE.tmp" "$MCP_CONFIG_FILE"
39
+ else
40
+ echo " WARNING: jq not found. Please manually add the server to $MCP_CONFIG_FILE"
41
+ echo " Server configuration:"
42
+ echo "$SERVER_CONFIG"
43
+ fi
44
+ else
45
+ echo " Creating new MCP config file..."
46
+ cat > "$MCP_CONFIG_FILE" <<EOF
47
+ {
48
+ "mcpServers": {
49
+ "$SERVER_NAME": $SERVER_CONFIG
50
+ }
51
+ }
52
+ EOF
53
+ fi
54
+
55
+ echo ""
56
+ echo "Installation complete!"
57
+ echo ""
58
+ echo "Restart Claude Code to load the new MCP server."
@@ -0,0 +1,12 @@
1
+ {
2
+ "mcpServers": {
3
+ "soar-test-assistant": {
4
+ "command": "uv",
5
+ "args": [
6
+ "run",
7
+ "soar-test-assistant"
8
+ ],
9
+ "cwd": "/path/to/splunk-soar-sdk/mcp_server"
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,24 @@
1
+ [project]
2
+ name = "soar-test-assistant"
3
+ version = "0.1.0"
4
+ requires-python = ">=3.13"
5
+
6
+ dependencies = [
7
+ "mcp>=1.1.0,<2.0.0",
8
+ "splunk-soar-sdk>=3.0.0",
9
+ ]
10
+
11
+ [tool.uv.sources]
12
+ splunk-soar-sdk = { path = "..", editable = true }
13
+
14
+ [project.scripts]
15
+ soar_test_assistant = "soar_test_assistant.server:cli"
16
+
17
+ [build-system]
18
+ requires = ["hatchling"]
19
+ build-backend = "hatchling.build"
20
+
21
+ [dependency-groups]
22
+ dev = [
23
+ "pytest>=7.4.2",
24
+ ]
@@ -0,0 +1,2 @@
1
+ [pytest]
2
+ testpaths = tests
@@ -0,0 +1,3 @@
1
+ from .server import app, cli
2
+
3
+ __all__ = ["app", "cli"]