Skip to content

Commit

Permalink
feat: server side validation of name field based on globalConfig (#1362)
Browse files Browse the repository at this point in the history
**Issue
number:[ADDON-74237](https://splunk.atlassian.net/browse/ADDON-74237)**

## Summary

Extended rh_templates to pass user validators to resthandler
this pr requires changes from splunktauuclib:
splunk/addonfactory-ucc-library#316

### Changes

* rh_templates now has an additional list "special_fields"
* rh_templates now adds "special_fields" to RestModel object
* GlobalConfigBuilderSchema now calculates "special_fields" for
rh_templates

### User experience

Name field will be validated with users validators, provided in the
globalconfig, on the server side.

## Checklist

If your change doesn't seem to apply, please leave them unchecked.

* [x] I have performed a self-review of this change
* [x] Changes have been tested
* [ ] Changes are documented
* [x] PR title follows [conventional commit
semantics](https://www.conventionalcommits.org/en/v1.0.0/)

---------

Co-authored-by: Artem Rys <[email protected]>
  • Loading branch information
sgoral-splunk and artemrys authored Oct 16, 2024
1 parent 8246870 commit 4e43c27
Show file tree
Hide file tree
Showing 12 changed files with 222 additions and 28 deletions.
36 changes: 30 additions & 6 deletions splunk_add_on_ucc_framework/commands/rest_builder/endpoint/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,34 @@ class RestEntityBuilder:
fields{name_rh} = [
{fields}
]
model{name_rh} = RestModel(fields{name_rh}, name={name})
model{name_rh} = RestModel(fields{name_rh}, name={name}{special_fields_arg})
"""
_disabled_field_template = """
field.RestField(
'disabled',
required=False,
validator=None
)
"""
_rh_special_fields_template = """
special_fields = [
{special_fields}
]
"""

def __init__(
self, name: Optional[str], fields: List["RestFieldBuilder"], **kwargs: Any
self,
name: Optional[str],
fields: List["RestFieldBuilder"],
special_fields: Optional[List["RestFieldBuilder"]] = None,
**kwargs: Any,
) -> None:
self._name = name
self._fields = fields
self._special_fields = special_fields if special_fields else []
self._special_fields_arg = (
", special_fields=special_fields" if special_fields else ""
)
self._conf_name = kwargs.get("conf_name")

@property
Expand Down Expand Up @@ -78,10 +91,10 @@ def generate_conf_with_default_values(self) -> str:
return "\n".join(lines)

def generate_rh(self) -> str:
fields = []
for field in self._fields:
field_line = field.generate_rh()
fields.append(field_line)
fields = [field.generate_rh() for field in self._fields]
special_fields = [
special_field.generate_rh() for special_field in self._special_fields
]
# add disabled field for data input
entity_builder = self.__class__.__name__
if (
Expand All @@ -91,10 +104,21 @@ def generate_rh(self) -> str:
):
fields.append(self._disabled_field_template)
fields_lines = ", \n".join(fields)
if special_fields:
special_fields_lines = ", \n".join(special_fields)
template = self._rh_special_fields_template + self._rh_template
return template.format(
special_fields=indent(special_fields_lines),
fields=indent(fields_lines),
name_rh=self.name_rh,
name=quote_string(self._name),
special_fields_arg=self._special_fields_arg,
)
return self._rh_template.format(
fields=indent(fields_lines),
name_rh=self.name_rh,
name=quote_string(self._name),
special_fields_arg=self._special_fields_arg,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# limitations under the License.
#
import json
from typing import Dict, List, Any
from typing import Dict, List, Any, Tuple

from splunk_add_on_ucc_framework import global_config as global_config_lib

Expand Down Expand Up @@ -105,10 +105,11 @@ def _builder_configs(self) -> None:
)
self._endpoints[name] = endpoint
content = self._get_oauth_enitities(config["entity"])
fields = self._parse_fields(content)
fields, special_fields = self._parse_fields(content)
entity = SingleModelEntityBuilder(
None,
fields,
special_fields=special_fields,
conf_name=config.get("conf"),
)
endpoint.add_entity(entity)
Expand Down Expand Up @@ -143,10 +144,11 @@ def _builder_settings(self) -> None:
self._endpoints["settings"] = endpoint
for setting in self.global_config.settings:
content = self._get_oauth_enitities(setting["entity"])
fields = self._parse_fields(content)
fields, special_fields = self._parse_fields(content)
entity = MultipleModelEntityBuilder(
setting["name"],
fields,
special_fields=special_fields,
)
endpoint.add_entity(entity)
if endpoint.conf_name not in self._settings_conf_file_names:
Expand Down Expand Up @@ -174,10 +176,11 @@ def _builder_inputs(self) -> None:
)
self._endpoints[name] = single_model_endpoint
content = self._get_oauth_enitities(input_item["entity"])
fields = self._parse_fields(content)
fields, special_fields = self._parse_fields(content)
single_model_entity = SingleModelEntityBuilder(
None,
fields,
special_fields=special_fields,
conf_name=input_item["conf"],
)
single_model_endpoint.add_entity(single_model_entity)
Expand All @@ -193,28 +196,34 @@ def _builder_inputs(self) -> None:
)
self._endpoints[name] = data_input_endpoint
content = self._get_oauth_enitities(input_item["entity"])
fields = self._parse_fields(content)
fields, special_fields = self._parse_fields(content)
data_input_entity = DataInputEntityBuilder(
None,
fields,
special_fields=special_fields,
input_type=input_item["name"],
)
data_input_endpoint.add_entity(data_input_entity)

def _parse_fields(
self, fields_content: List[Dict[str, Any]]
) -> List[RestFieldBuilder]:
return [
RestFieldBuilder(
) -> Tuple[List[RestFieldBuilder], List[RestFieldBuilder]]:
fields = []
special_fields = []
for field in fields_content:
rest_field = RestFieldBuilder(
field["field"],
_is_true(field.get("required")),
_is_true(field.get("encrypted")),
field.get("defaultValue"),
ValidatorBuilder().build(field.get("validators")),
)
for field in fields_content
if field["field"] != "name"
]

if field["field"] != "name":
fields.append(rest_field)
else:
special_fields.append(rest_field)
return fields, special_fields

"""
If the entity contains type oauth then we need to alter the content to generate proper entities to generate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def _set_attributes(self, **kwargs: Any) -> None:
if account["name"] == "oauth":
continue
content = self._gc_schema._get_oauth_enitities(account["entity"])
fields = self._gc_schema._parse_fields(content)
fields, special_fields = self._gc_schema._parse_fields(content)
self.account_fields.append(
("<name>", [f"{f._name} = " for f in fields])
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def _set_attributes(self, **kwargs: Any) -> None:
self.conf_spec_file = f"{self.conf_file}.spec"
for setting in self._global_config.settings:
content = self._gc_schema._get_oauth_enitities(setting["entity"])
fields = self._gc_schema._parse_fields(content)
fields, special_fields = self._gc_schema._parse_fields(content)
self.settings_stanzas.append(
(setting["name"], [f"{f._name} = " for f in fields])
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
util.remove_http_proxy_env_vars()


special_fields = [
field.RestField(
'name',
required=True,
encrypted=False,
default=None,
validator=validator.AllOf(
validator.String(
max_len=50,
min_len=1,
),
validator.Pattern(
regex=r"""^[a-zA-Z]\w*$""",
)
)
)
]

fields = [
field.RestField(
'custom_endpoint',
Expand Down Expand Up @@ -128,7 +146,7 @@
validator=None
)
]
model = RestModel(fields, name=None)
model = RestModel(fields, name=None, special_fields=special_fields)


endpoint = SingleModel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
util.remove_http_proxy_env_vars()


special_fields = [
field.RestField(
'name',
required=True,
encrypted=False,
default=None,
validator=validator.AllOf(
validator.String(
max_len=50,
min_len=1,
),
validator.Pattern(
regex=r"""^[a-zA-Z]\w*$""",
)
)
)
]

fields = [
field.RestField(
'custom_endpoint',
Expand Down Expand Up @@ -201,7 +219,7 @@
validator=None
)
]
model = RestModel(fields, name=None)
model = RestModel(fields, name=None, special_fields=special_fields)


endpoint = SingleModel(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
util.remove_http_proxy_env_vars()


special_fields = [
field.RestField(
'name',
required=True,
encrypted=False,
default=None,
validator=validator.AllOf(
validator.Pattern(
regex=r"""^[a-zA-Z]\w*$""",
),
validator.String(
max_len=100,
min_len=1,
)
)
)
]

fields = [
field.RestField(
'interval',
Expand All @@ -32,7 +50,7 @@
)

]
model = RestModel(fields, name=None)
model = RestModel(fields, name=None, special_fields=special_fields)



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
util.remove_http_proxy_env_vars()


special_fields = [
field.RestField(
'name',
required=True,
encrypted=False,
default=None,
validator=validator.AllOf(
validator.Pattern(
regex=r"""^[a-zA-Z]\w*$""",
),
validator.String(
max_len=100,
min_len=1,
)
)
)
]

fields = [
field.RestField(
'input_one_checkbox',
Expand Down Expand Up @@ -161,7 +179,7 @@
)

]
model = RestModel(fields, name=None)
model = RestModel(fields, name=None, special_fields=special_fields)



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
util.remove_http_proxy_env_vars()


special_fields = [
field.RestField(
'name',
required=True,
encrypted=False,
default=None,
validator=validator.AllOf(
validator.Pattern(
regex=r"""^[a-zA-Z]\w*$""",
),
validator.String(
max_len=100,
min_len=1,
)
)
)
]

fields = [
field.RestField(
'interval',
Expand Down Expand Up @@ -133,7 +151,7 @@
)

]
model = RestModel(fields, name=None)
model = RestModel(fields, name=None, special_fields=special_fields)



Expand Down
Loading

0 comments on commit 4e43c27

Please sign in to comment.