splunk-soar-sdk 1.4.0__py3-none-any.whl → 1.5.0__py3-none-any.whl

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.
soar_sdk/abstract.py CHANGED
@@ -34,10 +34,7 @@ class SOARClientAuth:
34
34
 
35
35
 
36
36
  class SOARClient(Generic[SummaryType]):
37
- """A unified API interface for performing actions on SOAR Platform.
38
-
39
- Replaces previously used BaseConnector API interface.
40
- """
37
+ """An API interface for interacting with the Splunk SOAR Platform."""
41
38
 
42
39
  @property
43
40
  @abstractmethod
@@ -71,7 +71,7 @@ class ActionsManager(BaseConnector):
71
71
  ) # TODO: replace with a valid lack of action handling
72
72
 
73
73
  def handle_action(self, param: dict[str, Any]) -> None:
74
- """The central action execution function BaseConnector expects to be overriden.
74
+ """The central action execution function BaseConnector expects to be overridden.
75
75
 
76
76
  Given the input parameter dictionary from Splunk SOAR, find the Action function
77
77
  referred to by the input, parse the parameters into the appropriate Pydantic model,
soar_sdk/app.py CHANGED
@@ -1,5 +1,7 @@
1
+ import importlib.util
1
2
  import inspect
2
3
  import json
4
+ from pathlib import Path
3
5
  import sys
4
6
  from typing import Any, Optional, Union, Callable
5
7
  from collections.abc import Iterator
@@ -226,7 +228,7 @@ class App:
226
228
  def register_action(
227
229
  self,
228
230
  /,
229
- action: Callable,
231
+ action: Union[str, Callable],
230
232
  *,
231
233
  name: Optional[str] = None,
232
234
  identifier: Optional[str] = None,
@@ -236,7 +238,7 @@ class App:
236
238
  read_only: bool = True,
237
239
  params_class: Optional[type[Params]] = None,
238
240
  output_class: Optional[type[ActionOutput]] = None,
239
- view_handler: Optional[Callable] = None,
241
+ view_handler: Union[str, Callable, None] = None,
240
242
  view_template: Optional[str] = None,
241
243
  versions: str = "EQ(*)",
242
244
  summary_type: Optional[type[ActionOutput]] = None,
@@ -248,8 +250,30 @@ class App:
248
250
  actions without using decorators directly on the action function.
249
251
 
250
252
  Args:
251
- action: Function import for the action. Must be a callable function that
252
- follows SOAR action function conventions and is imported from another module.
253
+ action: Either an import string to find the function that implements an action, or the imported function itself.
254
+
255
+ .. warning::
256
+ If you import the function directly, and provide the callable to this function, this sometimes messes with the app's CLI invocation. For example, if you import your function with a relative import, like::
257
+
258
+ from .actions.my_action import my_action_function
259
+
260
+ then executing your app directly, like::
261
+
262
+ python src/app.py action my_action_function
263
+
264
+ will fail, but running as a module, like::
265
+
266
+ python -m src.app action my_action_function
267
+
268
+ will work. By contrast, if you use an absolute import, like::
269
+
270
+ from actions.my_action import my_action_function
271
+
272
+ then the `direct CLI invocation` will work, while the `module invocation` will fail. This is a limitation with Python itself.
273
+
274
+ To avoid this confusion, it is recommended to provide the action as an import string, like ``"actions.my_action:my_action_function"``. This way, both invocation methods will work consistently.
275
+
276
+
253
277
  name: Human-readable name for the action. If not provided, defaults
254
278
  to the function name with underscores replaced by spaces.
255
279
  identifier: Unique identifier for the action. If not provided, defaults
@@ -265,12 +289,19 @@ class App:
265
289
  If not provided, uses generic parameter validation.
266
290
  output_class: Pydantic model class for structuring action output.
267
291
  If not provided, uses generic output format.
268
- view_handler: Optional raw view handler function to associate with this action.
292
+ view_handler: Optional import string to a view handler function,
293
+ or the imported function itself, to associate with this action.
269
294
  Will be automatically decorated with the view_handler decorator.
295
+
296
+ .. warning::
297
+
298
+ See the warning above about importing action functions as opposed to using import strings. The same issues apply to view handler functions as well.
299
+
270
300
  view_template: Template name to use with the view handler. Only
271
301
  relevant if view_handler is provided.
272
302
  versions: Version constraint string for when this action is available.
273
303
  Defaults to "EQ(*)" (all versions).
304
+ summary_type: Pydantic model class for structuring action summary output.
274
305
 
275
306
  Returns:
276
307
  The registered Action instance with all metadata and handlers configured.
@@ -280,17 +311,20 @@ class App:
280
311
  found in its original module for replacement.
281
312
 
282
313
  Example:
283
- >>> from my_actions_module import my_action_function
284
- >>> from my_views_module import my_view_handler
285
- >>>
286
314
  >>> action = app.register_action(
287
- ... my_action_function,
315
+ ... "action.my_action:my_action_function",
288
316
  ... name="Dynamic Action",
289
317
  ... description="Action imported from another module",
290
- ... view_handler=my_view_handler,
318
+ ... view_handler="my_views_module:my_view_handler",
291
319
  ... view_template="custom_template.html",
292
320
  ... )
293
321
  """
322
+ if isinstance(action, str):
323
+ action = self._resolve_function_import(action)
324
+
325
+ if isinstance(view_handler, str):
326
+ view_handler = self._resolve_function_import(view_handler)
327
+
294
328
  if view_handler:
295
329
  decorated_view_handler = self.view_handler(template=view_template)(
296
330
  view_handler
@@ -298,8 +332,6 @@ class App:
298
332
 
299
333
  # Replace the function in its original module with the decorated version
300
334
  if hasattr(view_handler, "__module__") and view_handler.__module__:
301
- import sys
302
-
303
335
  if (
304
336
  original_module := sys.modules.get(view_handler.__module__)
305
337
  ) and hasattr(original_module, view_handler.__name__):
@@ -327,6 +359,55 @@ class App:
327
359
  summary_type=summary_type,
328
360
  )(action)
329
361
 
362
+ def _resolve_function_import(self, action_path: str) -> Callable:
363
+ """Resolves a callable action function from a dot-separated import string.
364
+
365
+ This method takes a string representing the full import path of a function,
366
+ imports the necessary module, and retrieves the function object.
367
+
368
+ Args:
369
+ action_path: Dot-separated string representing the import path of the function.
370
+ Example: "my_module.my_submodule:my_function"
371
+
372
+ Returns:
373
+ The callable function object.
374
+
375
+ Raises:
376
+ ValueError: If the action_path is not properly formatted or if the
377
+ module/function cannot be imported.
378
+ """
379
+ # Split the action_path into module and function parts,
380
+ # handling both dot notation and file paths
381
+ module_root = Path(inspect.stack()[2].filename).parent
382
+ func_delim = ":" if ":" in action_path else "."
383
+ module_name, action_func_name = action_path.rsplit(func_delim, 1)
384
+ module_name = module_name.removesuffix(".py").replace(".", "/") + ".py"
385
+ module_path = module_root / module_name
386
+
387
+ module_name = (
388
+ # Jump up from module -> src -> package root
389
+ module_path.relative_to(module_root.parent.parent)
390
+ # Remove .py suffix, convert to dot notation
391
+ .with_suffix("")
392
+ .as_posix()
393
+ .replace("/", ".")
394
+ )
395
+ spec = importlib.util.spec_from_file_location(module_name, module_path)
396
+ # Not sure how to actually make spec None,
397
+ # but the type hint says it's technically possible
398
+ if spec is None or spec.loader is None: # pragma: no cover
399
+ raise ActionRegistrationError(action_func_name)
400
+
401
+ module = importlib.util.module_from_spec(spec)
402
+ sys.modules[module_name] = module
403
+ try:
404
+ spec.loader.exec_module(module)
405
+ action_func = getattr(module, action_func_name)
406
+ except Exception as e:
407
+ raise ActionRegistrationError(action_func_name) from e
408
+
409
+ return action_func
410
+
330
411
  def action(
331
412
  self,
332
413
  *,
@@ -415,7 +496,9 @@ class App:
415
496
  The decorated function receives parsed ActionOutput objects and can return either a dict for template rendering, HTML string, or component data model.
416
497
  If a template is provided, dict results will be rendered using the template. Component type is automatically inferred from the return type annotation.
417
498
 
418
- For more information on custom views, see the following :doc:`custom views documentation </custom_views/index>`:
499
+ .. seealso::
500
+
501
+ For more information on custom views, see the following :doc:`custom views documentation </custom_views/index>`:
419
502
 
420
503
  Example:
421
504
  >>> @app.view_handler(template="my_template.html")
soar_sdk/asset.py CHANGED
@@ -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[field_name] = params_field
244
+ params[field.alias] = params_field
243
245
 
244
246
  return params
245
247
 
soar_sdk/cli/init/cli.py CHANGED
@@ -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=lambda: [str(py) for py in PythonVersion.all()],
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=app_meta.python_version,
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=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
- fields[param_name] = cls._create_param_field(param_spec)
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", True),
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)
@@ -7,7 +7,7 @@ from pprint import pprint
7
7
 
8
8
  from soar_sdk.app import App
9
9
  from soar_sdk.cli.path_utils import context_directory
10
- from soar_sdk.compat import remove_when_soar_newer_than
10
+ from soar_sdk.compat import remove_when_soar_newer_than, UPDATE_TIME_FORMAT
11
11
  from soar_sdk.meta.adapters import TOMLDataAdapter
12
12
  from soar_sdk.meta.app import AppMeta
13
13
  from soar_sdk.meta.dependencies import UvLock
@@ -31,7 +31,7 @@ class ManifestProcessor:
31
31
  app_meta.configuration = app.asset_cls.to_json_schema()
32
32
  app_meta.actions = app.actions_manager.get_actions_meta_list()
33
33
  app_meta.utctime_updated = datetime.now(timezone.utc).strftime(
34
- "%Y-%m-%dT%H:%M:%S.%fZ"
34
+ UPDATE_TIME_FORMAT
35
35
  )
36
36
  for field, value in app.app_meta_info.items():
37
37
  setattr(app_meta, field, value)
soar_sdk/cli/utils.py CHANGED
@@ -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"_{field_name}"
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):
@@ -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 Jinja2 templates."""
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,
soar_sdk/compat.py CHANGED
@@ -4,6 +4,8 @@ from packaging.version import Version
4
4
 
5
5
  MIN_PHANTOM_VERSION = "6.4.0"
6
6
 
7
+ UPDATE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
8
+
7
9
 
8
10
  @functools.lru_cache(maxsize=32)
9
11
  def remove_when_soar_newer_than(
soar_sdk/meta/app.py CHANGED
@@ -20,7 +20,7 @@ class AppMeta(BaseModel):
20
20
 
21
21
  name: str = ""
22
22
  description: str
23
- appid: str = "1e1618e7-2f70-4fc0-916a-f96facc2d2e4" # placeholder value to pass inital validation
23
+ appid: str = "1e1618e7-2f70-4fc0-916a-f96facc2d2e4" # placeholder value to pass initial validation
24
24
  type: str = ""
25
25
  product_vendor: str = ""
26
26
  app_version: str
soar_sdk/params.py CHANGED
@@ -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
 
@@ -86,7 +88,7 @@ class Params(BaseModel):
86
88
  """Params defines the full set of inputs for an action.
87
89
 
88
90
  It can contain strings, booleans, or numbers -- no lists or dictionaries.
89
- Params fields can be optional if desired, or optionally have a default value, CEF type, and other metadata defined in soar_sdk.params.Param.
91
+ Params fields can be optional if desired, or optionally have a default value, CEF type, and other metadata defined in :func:`soar_sdk.params.Param`.
90
92
  """
91
93
 
92
94
  @staticmethod
@@ -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[field_name] = params_field
140
+ params[field.alias] = params_field
139
141
 
140
142
  return params
141
143
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: splunk-soar-sdk
3
- Version: 1.4.0
3
+ Version: 1.5.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,19 +1,19 @@
1
1
  soar_sdk/__init__.py,sha256=RzAng-ARqpK01SY82lNy4uYJFVG0yW6Q3CccEqbToJ4,726
2
- soar_sdk/abstract.py,sha256=2fYEc_xdhz635RnUn5Fn7odTuNkzqQ_YjKF25A-KjNM,7863
2
+ soar_sdk/abstract.py,sha256=ExsLCY99aoPRFHsUfw7yIVdWJeZjq1ahQCVwQmZyYh8,7798
3
3
  soar_sdk/action_results.py,sha256=gAQwHjXbkkzOJTmQnLwBjKjwbuz8mSPyqIVcirVS598,10114
4
- soar_sdk/actions_manager.py,sha256=vYglKejmPX1MldTzafCVE2K60UiSLhNGfYcVOxD4YwU,5884
5
- soar_sdk/app.py,sha256=lCCOLKfpUxE9WgLYn_S83riHe4vL2Kzcgda2ra4xNs4,29207
4
+ soar_sdk/actions_manager.py,sha256=U8OZmNCjuwtLKlC19BsVIvDyeJDS_ZiTyZIHA4SS1go,5885
5
+ soar_sdk/app.py,sha256=9zI8RM6uo4V0Bj4cgCvJzSOjIBPrvt2meXVAMaPhVrE,32882
6
6
  soar_sdk/app_cli_runner.py,sha256=uk9V-cbAHx1tzK_1gCYpfdF7IJ_ZwuWV2Ak4NMOvKGA,11873
7
7
  soar_sdk/app_client.py,sha256=UVCMFYweaYcFk7WrtoVsCoprYZ7JlzMBR108ZQRV8SE,6051
8
- soar_sdk/asset.py,sha256=_PZnbroenzfyGup7wcFsyJG_2TFcy19hf0Gi1gkBdsQ,10611
8
+ soar_sdk/asset.py,sha256=deS8_B5hr7W2fED8_6wUpVriRgiQ5r8TkGVHiasIaro,10666
9
9
  soar_sdk/async_utils.py,sha256=gND8ZiVTqDYLQ88Ua6SN1mInJaEcfa168eOaRoURt3E,1441
10
10
  soar_sdk/colors.py,sha256=--i_iXqfyITUz4O95HMjfZQGbwFZ34bLmBhtfpXXqlQ,1095
11
- soar_sdk/compat.py,sha256=jW3l9vJ7jLUicZ9SvfFrL4l3H84DQHUYSBy0-51VE3s,2620
11
+ soar_sdk/compat.py,sha256=H7At6OSsZQMtlarjyWNcPfsa4_8FC5k0JLdGrmU-O1M,2666
12
12
  soar_sdk/crypto.py,sha256=qiBMHUQqgn5lPI1DbujSj700s89FuLJrkQgCO9_eBn4,392
13
13
  soar_sdk/exceptions.py,sha256=CxJ_Q6N1jlknO_3ItDQNhHEw2pNWZr3sMLqutYmr5HA,1863
14
14
  soar_sdk/input_spec.py,sha256=BAa36l8IKDvM8SVMjgZ1XcnWZ2F7O052n2415tLeKK8,4690
15
15
  soar_sdk/logging.py,sha256=lSz8PA6hOCw2MHGE0ZSKbw-FzSr1WdbfQ7BHnXBUUY0,11440
16
- soar_sdk/params.py,sha256=BKhS71uEqWUG4Wb8vIrY3lpp6-c6H6Pv8I2U4XFyA6A,7560
16
+ soar_sdk/params.py,sha256=JKhlyBlYDdgUpQv1G6QEnJiY5G1XkiQ364_iNmyjxks,7623
17
17
  soar_sdk/paths.py,sha256=XhpanQCAiTXaulRx440oKu36mnll7P05TethHXgMpgQ,239
18
18
  soar_sdk/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
19
19
  soar_sdk/types.py,sha256=uMFnNOHpmCLrbAhQOgmXjScXiGE67sM8ySN04MhkC3U,602
@@ -31,20 +31,20 @@ soar_sdk/app_templates/basic_app/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeu
31
31
  soar_sdk/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  soar_sdk/cli/cli.py,sha256=62n6b41bjXILtkqLTpeID8JyDYMbkfXNV1LCo52YUsA,926
33
33
  soar_sdk/cli/path_utils.py,sha256=rFJDAe-sTC_6KgSiidlD3JcpygFmyHAEsn1j_6eWpIc,1263
34
- soar_sdk/cli/utils.py,sha256=9apx_uUU84pIlPa-KVTLVKTM1osmVfAF_gdn2vQlv6Q,1229
34
+ soar_sdk/cli/utils.py,sha256=GNZLFAMH_BKQo2-D5GvweWxeuR7DfR8eMZS4-sJUggU,1441
35
35
  soar_sdk/cli/init/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- soar_sdk/cli/init/cli.py,sha256=h0sqAOYl1xB039YKC1sB4bP2iA2hvZM72ywx3wvBORc,13866
36
+ soar_sdk/cli/init/cli.py,sha256=bVp8t28FYCS_wP2FhLWqmIvCkFbqmO1-7Dw8PpTFNq0,14495
37
37
  soar_sdk/cli/manifests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
38
  soar_sdk/cli/manifests/cli.py,sha256=cly5xVdj4bBIdZVMQPIWTXRgUfd1ON3qKO-76Fwql18,524
39
- soar_sdk/cli/manifests/deserializers.py,sha256=lw8tRIN1qWf9XPeb3HocFFa-QVyZEoVU3Jn9bs4qf90,15936
40
- soar_sdk/cli/manifests/processors.py,sha256=anR_7TledkYvPWtcMakzO4JWO1iNWlj6lQBx7cD5hmE,4140
39
+ soar_sdk/cli/manifests/deserializers.py,sha256=FtXv-OywYGb_O5TptS2Hg6niWcfihRPF_RaS5zDBXRk,17045
40
+ soar_sdk/cli/manifests/processors.py,sha256=6B1fQC2WGVaUP-7E9Y5g7BipaVwEomJCkUQ_7gRfSn8,4155
41
41
  soar_sdk/cli/manifests/serializers.py,sha256=HA7a3DSzB3P-v2yomAMZW0M1__wY2yCNLU_v0QZv7Vo,3245
42
42
  soar_sdk/cli/package/cli.py,sha256=oCpP9E3PtXq-zCdzQD8Z-4dowKF1YT-uKjTpbt_YT-A,9516
43
43
  soar_sdk/cli/package/utils.py,sha256=JmVf_PwoXiuypE1DZ1-k4sFjZszD0c_BYTiLtwy9jDk,1448
44
44
  soar_sdk/code_renderers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
45
45
  soar_sdk/code_renderers/action_renderer.py,sha256=Un2QwuYwa3kX0IiTdrjx_nsfszorfbGxK2stXbC5E1g,13938
46
46
  soar_sdk/code_renderers/app_renderer.py,sha256=cxXj0BwWY_1qOcmdWZ-2s6l8x1XEMRm20_LIKv5Dx5g,7408
47
- soar_sdk/code_renderers/asset_renderer.py,sha256=LNVVqVqbkgocTipwYMoJlO6z5MEyykNo4N6kHCIkWmA,3680
47
+ soar_sdk/code_renderers/asset_renderer.py,sha256=f2e2jC43nD0S_bOOfABs-e6Okcyn8znHd_H46TOaue0,3880
48
48
  soar_sdk/code_renderers/renderer.py,sha256=oDlmU-MzDqpc4Yq6zupoT4XN-vRjgL4UV5lOGTLeqkg,1242
49
49
  soar_sdk/code_renderers/toml_renderer.py,sha256=-zP8UzlYMCVVA5ex9slaNLeFTu4xLjkv88YLmRNLrTM,1505
50
50
  soar_sdk/code_renderers/templates/pyproject.toml.jinja,sha256=Ti6A5kWMb902Lbd1kmw8qPgVDPNNzlV6rd0pcVEbVUo,3917
@@ -58,7 +58,7 @@ soar_sdk/decorators/webhook.py,sha256=Pde0MjxC2kckpxoKb3m4WVfLWtiFAAzAwZe5AF5VIb
58
58
  soar_sdk/meta/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
59
59
  soar_sdk/meta/actions.py,sha256=-Py_AbQ9BOr3P-J9OrKTTdKAQvNZ5g6xvgYLCjJktlg,2215
60
60
  soar_sdk/meta/adapters.py,sha256=KjSYIUtkCz2eesA_vhsNCjfi5C-Uz71tbSuDIjhuB8U,1112
61
- soar_sdk/meta/app.py,sha256=cmbfACoFiBNvZ3IWT_f3C-Yz8hyZgqa1KURCYQV5N6k,1764
61
+ soar_sdk/meta/app.py,sha256=rwgoFfIFnLutLB9PF1kR7X1neKs175VA0Xx4KpJ6c7I,1765
62
62
  soar_sdk/meta/datatypes.py,sha256=piR-oBVAATiRciXSdVE7XaqjUZTgSaOvTEqcOcNvCS0,795
63
63
  soar_sdk/meta/dependencies.py,sha256=AQlkdm6A7JEfLI0IAXKU6WzPkUX7oPfxgDkGZ3AofHk,17927
64
64
  soar_sdk/meta/webhooks.py,sha256=1sh4-3I3_UiXFNzVEyoz2Tp6NhgTEZWpERYIzV8OYNY,1188
@@ -96,8 +96,8 @@ soar_sdk/views/components/pie_chart.py,sha256=LVTeHVJN6nf2vjUs9y7PDBhS0U1fKW750l
96
96
  soar_sdk/webhooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
97
  soar_sdk/webhooks/models.py,sha256=-rjuFA9cRX5zTLp7cHSHVTkt5eVJD6BdESGbj_qkyHI,4540
98
98
  soar_sdk/webhooks/routing.py,sha256=BKbURSrBPdOTS5UFL-mHzFEr-Fj04mJMx9KeiPrZ2VQ,6872
99
- splunk_soar_sdk-1.4.0.dist-info/METADATA,sha256=eEoL_4B-eXIvwDIamcQukIMzBWwVl6utKHZkfhDtrYE,7355
100
- splunk_soar_sdk-1.4.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
- splunk_soar_sdk-1.4.0.dist-info/entry_points.txt,sha256=CgBjo2ZWpYNkt9TgvToL26h2Tg1yt8FbvYTb5NVgNuc,51
102
- splunk_soar_sdk-1.4.0.dist-info/licenses/LICENSE,sha256=gNCGrGhrSQb1PUzBOByVUN1tvaliwLZfna-QU2r2hQ8,11345
103
- splunk_soar_sdk-1.4.0.dist-info/RECORD,,
99
+ splunk_soar_sdk-1.5.0.dist-info/METADATA,sha256=l89BBxU2lNASu9LoIr9GU9iEBItjPj3Z-RY1zhN3kX0,7355
100
+ splunk_soar_sdk-1.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
+ splunk_soar_sdk-1.5.0.dist-info/entry_points.txt,sha256=CgBjo2ZWpYNkt9TgvToL26h2Tg1yt8FbvYTb5NVgNuc,51
102
+ splunk_soar_sdk-1.5.0.dist-info/licenses/LICENSE,sha256=gNCGrGhrSQb1PUzBOByVUN1tvaliwLZfna-QU2r2hQ8,11345
103
+ splunk_soar_sdk-1.5.0.dist-info/RECORD,,