Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3534,6 +3534,7 @@ def validate_custom_fields(fields_to_validate: dict, client: Client) -> tuple[di
f["CUSTOM_FIELD_CLI_NAME"]: {
"pretty_name": f.get("CUSTOM_FIELD_PRETTY_NAME", f["CUSTOM_FIELD_CLI_NAME"]),
"field_type": f.get("CUSTOM_FIELD_TYPE", ""),
"select_values": (f.get("CUSTOM_FIELD_FIELD_DATA") or {}).get("selectValues") or [],
}
for f in fields_data
if f.get("CUSTOM_FIELD_CLI_NAME") and not f.get("CUSTOM_FIELD_IS_SYSTEM")
Expand All @@ -3552,15 +3553,31 @@ def validate_custom_fields(fields_to_validate: dict, client: Client) -> tuple[di
)
elif field_name in custom_fields:
field_type = custom_fields[field_name]["field_type"]
if field_type == "multiSelect" and not isinstance(field_value, list):
error_messages.append(
f"Field '{field_name}' is of type multiSelect and requires a list value (e.g., [\"value\"])."
f" Received: {field_value!r}"
)
select_values = custom_fields[field_name]["select_values"]

if field_type == "multiSelect":
# Auto-coerce plain string → single-element list for multiSelect fields
if not isinstance(field_value, list):
demisto.debug(
f"Field '{field_name}' is of type multiSelect but received a string value {field_value!r}. "
f"Auto-converting to list: [{field_value!r}]"
)
field_value = [field_value]
if select_values:
invalid_values = [v for v in field_value if v not in select_values]
if invalid_values:
error_messages.append(
f"Field '{field_name}' contains invalid value(s): {invalid_values}."
f" Allowed values are: {select_values}"
)
else:
valid_fields[field_name] = field_value
else:
valid_fields[field_name] = field_value
elif field_type == "shortText" and isinstance(field_value, list):
error_messages.append(
f"Field '{field_name}' is of type shortText and does not accept a list value."
f" Provide a single value instead."
f" Provide a single string value instead."
)
else:
valid_fields[field_name] = field_value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9103,14 +9103,15 @@ def test_validate_custom_fields_cli_name_lookup(mocker):
assert not error_messages


def test_validate_custom_fields_multiselect_with_string_value_returns_error(mocker):
def test_validate_custom_fields_multiselect_with_string_value_auto_converts(mocker):
"""
GIVEN:
A multiSelect custom field provided with a string value instead of a list.
A multiSelect custom field provided with a plain string value instead of a list.
WHEN:
validate_custom_fields is called.
THEN:
The field is excluded and a clear error message instructs the user to provide a list value.
The string is auto-converted to a single-element list and the field is accepted.
No error messages are returned.
"""
from CortexPlatformCore import validate_custom_fields, Client

Expand All @@ -9134,9 +9135,8 @@ def test_validate_custom_fields_multiselect_with_string_value_returns_error(mock
fields_to_validate = {"multi_field": "single_value"}
valid_fields, error_messages = validate_custom_fields(fields_to_validate, client)

assert "multi_field" not in valid_fields
assert "multiSelect" in error_messages
assert "list" in error_messages
assert valid_fields == {"multi_field": ["single_value"]}
assert error_messages == ""


def test_validate_custom_fields_multiselect_with_list_value_succeeds(mocker):
Expand Down Expand Up @@ -9265,6 +9265,123 @@ def test_validate_custom_fields_non_enum_types_accept_string_value(mocker, field
assert not error_messages


def test_validate_custom_fields_multiselect_all_values_allowed(mocker):
"""
GIVEN:
A multiSelect custom field with selectValues defined, and all provided values are in the allowed set.
WHEN:
validate_custom_fields is called.
THEN:
The field is accepted as valid and no error messages are returned.
"""
from CortexPlatformCore import validate_custom_fields, Client

client = Client(base_url="", headers={})

metadata_response = {
"reply": {
"DATA": [
{
"CUSTOM_FIELD_NAME": "testmulti",
"CUSTOM_FIELD_CLI_NAME": "testmulti",
"CUSTOM_FIELD_PRETTY_NAME": "testmulti",
"CUSTOM_FIELD_IS_SYSTEM": False,
"CUSTOM_FIELD_TYPE": "multiSelect",
"CUSTOM_FIELD_FIELD_DATA": {
"selectValues": ["aa", "bb", "cc", "dd"],
},
},
]
}
}
mocker.patch.object(client, "get_custom_fields_metadata", return_value=metadata_response)

fields_to_validate = {"testmulti": ["aa", "cc"]}
valid_fields, error_messages = validate_custom_fields(fields_to_validate, client)

assert valid_fields == {"testmulti": ["aa", "cc"]}
assert not error_messages


def test_validate_custom_fields_multiselect_invalid_values_returns_error(mocker):
"""
GIVEN:
A multiSelect custom field with selectValues defined, and some provided values are NOT in the allowed set.
WHEN:
validate_custom_fields is called.
THEN:
The field is excluded and an error message listing the invalid values and allowed values is returned.
"""
from CortexPlatformCore import validate_custom_fields, Client

client = Client(base_url="", headers={})

metadata_response = {
"reply": {
"DATA": [
{
"CUSTOM_FIELD_NAME": "testmulti",
"CUSTOM_FIELD_CLI_NAME": "testmulti",
"CUSTOM_FIELD_PRETTY_NAME": "testmulti",
"CUSTOM_FIELD_IS_SYSTEM": False,
"CUSTOM_FIELD_TYPE": "multiSelect",
"CUSTOM_FIELD_FIELD_DATA": {
"selectValues": ["aa", "bb", "cc", "dd"],
},
},
]
}
}
mocker.patch.object(client, "get_custom_fields_metadata", return_value=metadata_response)

fields_to_validate = {"testmulti": ["aa", "zz", "xx"]}
valid_fields, error_messages = validate_custom_fields(fields_to_validate, client)

assert "testmulti" not in valid_fields
assert "zz" in error_messages
assert "xx" in error_messages
assert "aa" in error_messages # allowed values list is shown
assert "Allowed values are" in error_messages


def test_validate_custom_fields_multiselect_no_select_values_defined_passes(mocker):
"""
GIVEN:
A multiSelect custom field with no selectValues defined in CUSTOM_FIELD_FIELD_DATA (open-ended field).
WHEN:
validate_custom_fields is called with a list value.
THEN:
The field is accepted as valid — no allowed-value enforcement when selectValues is absent.
"""
from CortexPlatformCore import validate_custom_fields, Client

client = Client(base_url="", headers={})

metadata_response = {
"reply": {
"DATA": [
{
"CUSTOM_FIELD_NAME": "testmulti",
"CUSTOM_FIELD_CLI_NAME": "testmulti",
"CUSTOM_FIELD_PRETTY_NAME": "testmulti",
"CUSTOM_FIELD_IS_SYSTEM": False,
"CUSTOM_FIELD_TYPE": "multiSelect",
"CUSTOM_FIELD_FIELD_DATA": {
"selectValues": [],
},
},
]
}
}
mocker.patch.object(client, "get_custom_fields_metadata", return_value=metadata_response)

fields_to_validate = {"testmulti": ["any_value", "another_value"]}
valid_fields, error_messages = validate_custom_fields(fields_to_validate, client)

assert valid_fields == {"testmulti": ["any_value", "another_value"]}
assert not error_messages


# =========================================== TEST platform_http_request Method ===========================================#
def test_platform_http_request_success(mocker):
"""
Expand Down
Loading