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 +1 -4
- soar_sdk/actions_manager.py +1 -1
- soar_sdk/app.py +96 -13
- soar_sdk/asset.py +3 -1
- soar_sdk/cli/init/cli.py +16 -3
- soar_sdk/cli/manifests/deserializers.py +22 -3
- soar_sdk/cli/manifests/processors.py +2 -2
- soar_sdk/cli/utils.py +6 -1
- soar_sdk/code_renderers/asset_renderer.py +7 -1
- soar_sdk/compat.py +2 -0
- soar_sdk/meta/app.py +1 -1
- soar_sdk/params.py +4 -2
- {splunk_soar_sdk-1.4.0.dist-info → splunk_soar_sdk-1.5.0.dist-info}/METADATA +1 -1
- {splunk_soar_sdk-1.4.0.dist-info → splunk_soar_sdk-1.5.0.dist-info}/RECORD +17 -17
- {splunk_soar_sdk-1.4.0.dist-info → splunk_soar_sdk-1.5.0.dist-info}/WHEEL +0 -0
- {splunk_soar_sdk-1.4.0.dist-info → splunk_soar_sdk-1.5.0.dist-info}/entry_points.txt +0 -0
- {splunk_soar_sdk-1.4.0.dist-info → splunk_soar_sdk-1.5.0.dist-info}/licenses/LICENSE +0 -0
soar_sdk/abstract.py
CHANGED
|
@@ -34,10 +34,7 @@ class SOARClientAuth:
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
class SOARClient(Generic[SummaryType]):
|
|
37
|
-
"""
|
|
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
|
soar_sdk/actions_manager.py
CHANGED
|
@@ -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
|
|
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:
|
|
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:
|
|
252
|
-
|
|
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
|
|
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
|
-
|
|
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[
|
|
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=
|
|
46
|
+
default_factory=PythonVersion.all,
|
|
46
47
|
),
|
|
47
48
|
],
|
|
48
49
|
dependencies: Annotated[list[str], typer.Option(default_factory=list)],
|
|
@@ -268,11 +269,21 @@ def convert_connector_to_sdk(
|
|
|
268
269
|
# Convert the main module path to the SDK format, but save a reference to the original
|
|
269
270
|
app_meta.main_module = "src.app:app"
|
|
270
271
|
|
|
272
|
+
app_python_versions = app_meta.python_version
|
|
273
|
+
enforced_python_versions = PythonVersion.all()
|
|
274
|
+
if set(app_python_versions) != set(enforced_python_versions):
|
|
275
|
+
rprint(
|
|
276
|
+
f"[yellow]The provided app declares support for Python versions {[str(v) for v in app_python_versions]}.[/]"
|
|
277
|
+
)
|
|
278
|
+
rprint(
|
|
279
|
+
f"[yellow]The converted app will support the default versions {[str(v) for v in enforced_python_versions]}.[/]"
|
|
280
|
+
)
|
|
281
|
+
|
|
271
282
|
init_sdk_app(
|
|
272
283
|
name=app_meta.project_name,
|
|
273
284
|
description=app_meta.description,
|
|
274
285
|
authors=[author.name for author in app_meta.contributors],
|
|
275
|
-
python_versions=
|
|
286
|
+
python_versions=enforced_python_versions,
|
|
276
287
|
dependencies=[],
|
|
277
288
|
app_dir=output_dir,
|
|
278
289
|
copyright=app_meta.license,
|
|
@@ -385,18 +396,20 @@ def generate_asset_definition_ast(app_meta: AppMeta) -> ast.ClassDef:
|
|
|
385
396
|
"""
|
|
386
397
|
asset_context: list[AssetContext] = []
|
|
387
398
|
for name, config_spec in app_meta.configuration.items():
|
|
399
|
+
normalized = normalize_field_name(name)
|
|
388
400
|
if config_spec["data_type"].startswith("ph"):
|
|
389
401
|
# Skip the cosmetic placeholder fields
|
|
390
402
|
continue
|
|
391
403
|
|
|
392
404
|
asset_context.append(
|
|
393
405
|
AssetContext(
|
|
394
|
-
name=
|
|
406
|
+
name=normalized.normalized,
|
|
395
407
|
description=config_spec.get("description"),
|
|
396
408
|
required=config_spec.get("required", False),
|
|
397
409
|
default=config_spec.get("default"),
|
|
398
410
|
data_type=config_spec["data_type"],
|
|
399
411
|
value_list=config_spec.get("value_list"),
|
|
412
|
+
alias=normalized.original if normalized.modified else None,
|
|
400
413
|
)
|
|
401
414
|
)
|
|
402
415
|
|
|
@@ -6,7 +6,7 @@ import pydantic
|
|
|
6
6
|
|
|
7
7
|
from soar_sdk.action_results import ActionOutput, OutputFieldSpecification, OutputField
|
|
8
8
|
from soar_sdk.cli.utils import normalize_field_name, NormalizationResult
|
|
9
|
-
from soar_sdk.compat import PythonVersion
|
|
9
|
+
from soar_sdk.compat import PythonVersion, remove_when_soar_newer_than
|
|
10
10
|
from soar_sdk.meta.actions import ActionMeta
|
|
11
11
|
from soar_sdk.meta.app import AppMeta
|
|
12
12
|
from soar_sdk.params import Params, Param
|
|
@@ -64,6 +64,21 @@ class AppMetaDeserializer:
|
|
|
64
64
|
]
|
|
65
65
|
app_meta = AppMeta(project_name=json_path.parent.name, **manifest)
|
|
66
66
|
|
|
67
|
+
remove_when_soar_newer_than(
|
|
68
|
+
"7.1.0",
|
|
69
|
+
"Revisit this after upgrading to Pydantic 2.x. If the issue is still present, we might need to consider making `AssetFieldSpecification` a Pydantic model instead of a TypedDict, but that's a pretty big change.",
|
|
70
|
+
)
|
|
71
|
+
# Pydantic converts the default value into a string for some reason, even for non-string types.
|
|
72
|
+
# We will go through and convert it back.
|
|
73
|
+
# This has the side effect of implicitly validating that the default value matches the type.
|
|
74
|
+
for _, spec in app_meta.configuration.items():
|
|
75
|
+
if "default" not in spec:
|
|
76
|
+
continue
|
|
77
|
+
if spec["data_type"] == "numeric":
|
|
78
|
+
spec["default"] = float(spec["default"])
|
|
79
|
+
if spec["data_type"] == "boolean":
|
|
80
|
+
spec["default"] = bool(spec["default"])
|
|
81
|
+
|
|
67
82
|
has_rest_handlers = isinstance(manifest.get("rest_handler"), str)
|
|
68
83
|
has_webhooks = isinstance(manifest.get("webhooks"), dict)
|
|
69
84
|
|
|
@@ -142,7 +157,10 @@ class ActionDeserializer:
|
|
|
142
157
|
if param_spec["data_type"].startswith("ph"):
|
|
143
158
|
# Skip parameters that are placeholders
|
|
144
159
|
continue
|
|
145
|
-
|
|
160
|
+
normalized = normalize_field_name(param_name)
|
|
161
|
+
if normalized.modified:
|
|
162
|
+
param_spec["alias"] = normalized.original
|
|
163
|
+
fields[normalized.normalized] = cls._create_param_field(param_spec)
|
|
146
164
|
|
|
147
165
|
# Dynamically create a subclass of Params
|
|
148
166
|
action_name = cls._clean_action_name(action_name).normalized
|
|
@@ -164,13 +182,14 @@ class ActionDeserializer:
|
|
|
164
182
|
# Create Param field with all the metadata
|
|
165
183
|
param_field = Param(
|
|
166
184
|
description=param_spec.get("description"),
|
|
167
|
-
required=param_spec.get("required",
|
|
185
|
+
required=param_spec.get("required", False),
|
|
168
186
|
primary=param_spec.get("primary", False),
|
|
169
187
|
default=param_spec.get("default"),
|
|
170
188
|
value_list=param_spec.get("value_list"),
|
|
171
189
|
cef_types=param_spec.get("contains"), # 'contains' maps to 'cef_types'
|
|
172
190
|
allow_list=param_spec.get("allow_list", False),
|
|
173
191
|
sensitive=(data_type == "password"),
|
|
192
|
+
alias=param_spec.get("alias"),
|
|
174
193
|
)
|
|
175
194
|
|
|
176
195
|
return FieldSpec(python_type, param_field)
|
|
@@ -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
|
-
|
|
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"
|
|
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
|
|
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
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
|
|
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[
|
|
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.
|
|
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=
|
|
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=
|
|
5
|
-
soar_sdk/app.py,sha256=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
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=
|
|
40
|
-
soar_sdk/cli/manifests/processors.py,sha256=
|
|
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=
|
|
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=
|
|
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.
|
|
100
|
-
splunk_soar_sdk-1.
|
|
101
|
-
splunk_soar_sdk-1.
|
|
102
|
-
splunk_soar_sdk-1.
|
|
103
|
-
splunk_soar_sdk-1.
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|