splunk-soar-sdk 1.4.0__py3-none-any.whl → 1.4.1__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/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)
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/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
 
@@ -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.4.1
4
4
  Summary: The official framework for developing and testing Splunk SOAR Apps
5
5
  Project-URL: Homepage, https://github.com/phantomcyber/splunk-soar-sdk
6
6
  Project-URL: Documentation, https://github.com/phantomcyber/splunk-soar-sdk
@@ -5,7 +5,7 @@ soar_sdk/actions_manager.py,sha256=vYglKejmPX1MldTzafCVE2K60UiSLhNGfYcVOxD4YwU,5
5
5
  soar_sdk/app.py,sha256=lCCOLKfpUxE9WgLYn_S83riHe4vL2Kzcgda2ra4xNs4,29207
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
11
  soar_sdk/compat.py,sha256=jW3l9vJ7jLUicZ9SvfFrL4l3H84DQHUYSBy0-51VE3s,2620
@@ -13,7 +13,7 @@ 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=K16_umW_dAfvqa2QcHR2XHc93py-k7SVOHdz3GUGFGk,7615
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,12 +31,12 @@ 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
39
+ soar_sdk/cli/manifests/deserializers.py,sha256=FtXv-OywYGb_O5TptS2Hg6niWcfihRPF_RaS5zDBXRk,17045
40
40
  soar_sdk/cli/manifests/processors.py,sha256=anR_7TledkYvPWtcMakzO4JWO1iNWlj6lQBx7cD5hmE,4140
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
@@ -44,7 +44,7 @@ soar_sdk/cli/package/utils.py,sha256=JmVf_PwoXiuypE1DZ1-k4sFjZszD0c_BYTiLtwy9jDk
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
@@ -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.4.1.dist-info/METADATA,sha256=mAYVSNDk067JSRxMrKll00jaNgNZWH5tF5syV5fZxoQ,7355
100
+ splunk_soar_sdk-1.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
101
+ splunk_soar_sdk-1.4.1.dist-info/entry_points.txt,sha256=CgBjo2ZWpYNkt9TgvToL26h2Tg1yt8FbvYTb5NVgNuc,51
102
+ splunk_soar_sdk-1.4.1.dist-info/licenses/LICENSE,sha256=gNCGrGhrSQb1PUzBOByVUN1tvaliwLZfna-QU2r2hQ8,11345
103
+ splunk_soar_sdk-1.4.1.dist-info/RECORD,,