diff --git a/.gitignore b/.gitignore index 22fa40a7c..f8e9fbf45 100644 --- a/.gitignore +++ b/.gitignore @@ -38,9 +38,8 @@ site/ assets/ Splunk_TA_Dynatrace/* Splunk_TA_Dynatrace_ucc/* -demo_addon_for_splunk_already_exists/ -demo_addon_for_splunk_license/ -addon_name +demo_addon_for_splunk*/ +addon_name/ init_addon_for_ucc_package/ demo_addon_for_splunk/ diff --git a/docs/configurations/index.md b/docs/configurations/index.md index 4f78f4524..3e889e971 100644 --- a/docs/configurations/index.md +++ b/docs/configurations/index.md @@ -41,6 +41,7 @@ tab. Currently available tab components: - [Logging tab](./logging.md) +- [Proxy tab](./proxy.md) ### Usage @@ -56,12 +57,16 @@ Currently available tab components: "entity": [] }, { - "name": "proxy", - "title": "Proxy", - "entity": [], - "options": { - "saveValidator": "" - } + "type": "proxyTab", + "warning": { + "config": { + "message": "Some warning message" + } + }, + "proxy_type": true, + "username": true, + "password": true, + "dns_resolution": true }, { "type": "loggingTab" @@ -70,7 +75,7 @@ Currently available tab components: } ``` -Note: The example above creates a Configuration page with two **empty** tabs: Account and Proxy. +Note: The example above creates a Configuration page with an **empty** Account tab. Specify your properties in `"table"` and `"entity"`. ### Output @@ -79,8 +84,8 @@ This is how table looks in the UI: ![image](../images/configuration/configuration_with_table_output.png) -This is how form looks in the UI: +This is how Proxy tab looks in the UI: -![image](../images/configuration/configuration_without_table_output.png) +![image](../images/configuration/proxy_tab_with_warning.png) More information about how to set Proxy tab, can be found [here](./proxy.md). diff --git a/docs/configurations/proxy.md b/docs/configurations/proxy.md index 55dddd22a..75ef469c7 100644 --- a/docs/configurations/proxy.md +++ b/docs/configurations/proxy.md @@ -1,120 +1,231 @@ # Proxy -There are fields that need to be specified in order to enable proxy. +The Proxy tab is a predefined component that allows to create a proxy tab with default configurations. It is added in the `pages.configuration.tabs` array -### Fields +![image](../images/configuration/proxy_tab.png) -| Field Name | Description | -|----------------|--------------------------------------------------------------------| -| proxy_enabled | Whether proxy should be enabled. | -| proxy_type | Proxy type. Available values: http, http_no_tunnel, socks4, socks5 | -| proxy_url | Host | -| proxy_port | Port | -| proxy_username | Username used to access the proxy server | -| proxy_password | Password assigned for that username | -| proxy_rdns | Whether reverse DNS resolution should be used | -### Example Tab +### Minimal definition ```json { - "name": "proxy", - "title": "Proxy", - "entity": [ - { - "type": "checkbox", - "label": "Enable", - "field": "proxy_enabled" - }, - { - "type": "singleSelect", - "label": "Proxy Type", - "options": { - "disableSearch": true, - "autoCompleteFields": [ - { - "value": "http", - "label": "http" - }, - { - "value": "socks4", - "label": "socks4" - }, - { - "value": "socks5", - "label": "socks5" - } - ] - }, - "defaultValue": "http", - "field": "proxy_type" - }, - { - "type": "text", - "label": "Host", - "validators": [ - { - "type": "string", - "errorMsg": "Max host length is 4096", - "minLength": 0, - "maxLength": 4096 - } - ], - "field": "proxy_url" - }, + "type": "proxyTab" +} +``` + +This creates the tab seen in the image above with 3 default entities that are `Enable` (checkbox for enabling proxy), `Host` (proxy host) and `Port` (proxy port). + +### Available configurations + +Below are the available properties that can be used while configuring `proxy`. Properties like `name`, `title`, `enable proxy`, `host` and `port` are auto generated (if [minimal defination](#minimal-definition) of proxy is provided). + +- Name (auto generated): + +``` +proxy +``` + +- Title (auto generated): + +``` +Proxy +``` + +- Enable proxy (auto generated) : + +```json +{ + "type": "checkbox", + "label": "Enable", + "field": "proxy_enabled" +} +``` + +- Proxy type : + +```json +{ + "type": "singleSelect", + "label": "Proxy Type", + "required": false, + "options": { + "disableSearch": true, + "autoCompleteFields": [ + {"value": "http", "label": "http"}, + {"value": "socks4", "label": "socks4"}, + {"value": "socks5", "label": "socks5"}, + ], + }, + "defaultValue": "http", + "field": "proxy_type", +} +``` + +- Host (auto generated) : + +```json +{ + "type": "text", + "label": "Host", + "validators": [ { - "type": "text", - "label": "Port", - "validators": [ - { - "type": "number", - "range": [ - 1, - 65535 - ] - } - ], - "field": "proxy_port" + "type": "string", + "errorMsg": "Max host length is 4096", + "minLength": 0, + "maxLength": 4096, }, { - "type": "text", - "label": "Username", - "validators": [ - { - "type": "string", - "errorMsg": "Max length of username is 50", - "minLength": 0, - "maxLength": 50 - } - ], - "field": "proxy_username" + "type": "regex", + "errorMsg": "Proxy Host should not have special characters", + "pattern": "^[a-zA-Z]\\w*$", }, + ], + "field": "proxy_url", +} +``` + +- Port (auto generated) : + +```json +{ + "type": "text", + "label": "Port", + "validators": [{"type": "number", "range": [1, 65535], "isInteger": true}], + "field": "proxy_port", +} +``` + +- Username : + +```json +{ + "type": "text", + "label": "Username", + "validators": [ { - "type": "text", - "label": "Password", - "validators": [ - { - "type": "string", - "errorMsg": "Max length of password is 8192", - "minLength": 0, - "maxLength": 8192 - } - ], - "encrypted": true, - "field": "proxy_password" - }, + "type": "string", + "errorMsg": "Max length of username is 50", + "minLength": 0, + "maxLength": 50, + } + ], + "field": "proxy_username", +} +``` + +- Password : + +```json +{ + "type": "text", + "label": "Password", + "validators": [ { - "type": "checkbox", - "label": "Reverse DNS resolution", - "field": "proxy_rdns" + "type": "string", + "errorMsg": "Max length of password is 8192", + "minLength": 0, + "maxLength": 8192, } ], - "options": { - "saveValidator": "function(formData) { if(!formData.proxy_enabled || formData.proxy_enabled === '0') {return true; } if(!formData.proxy_url) { return 'Proxy Host can not be empty'; } if(!formData.proxy_port) { return 'Proxy Port can not be empty'; } return true; }" + "encrypted": true, + "field": "proxy_password", +} +``` + +- DNS Resolution checkbox : + +```json +{ + "type": "checkbox", + "label": "DNS resolution", + "field": "proxy_rdns", +} +``` + + +When only `"type": "proxyTab"` is specified in the globalConfig file, the following entities will be generated by default `host`, `port`, `enable proxy`. + +Entities such as `proxy_type`, `username`, `password`, and `dns_resolution` will not be included by default. +To include these optional entities in your add-on, you must explicitly set them to `True` in your configuration. For details on available configurations, refer to the [available configurations](#available-configurations) section. + +### Usage + +It is placed just like every other configuration tab. + +```json +{ + "pages": { + "configuration": { + "tabs": [ + { + "type": "proxyTab" + } + ], + "title": "Configuration", + "description": "..." + } } } ``` -The example above creates the following form: +To customize these default configurations, you can define them in JSON format by specifying certain keys unique to each entity (refer the [keys section](#keys) for details on the required keys for each entity). When creating the JSON, you only need to include the values you want to customize. For example, if you don’t need to modify fields like `lable` or `field`, you can skip including them in your globalConfig. For better understanding, refer to the provided [Example](#example) which demonstrates how to apply customizations effectively. + +> **_NOTE:_** + There are 2 ways to exclude optional entities in your add-on, either omit them from the proxy tab, or set the entities to false. + +### Keys + +| Key Name | Description | +|----------------|--------------------------------------------------------------------| +| name | Name of the proxy | +| title | Title of proxy tab | +| enable_proxy | Whether proxy should be enabled | +| proxy_type | Type of Proxy communication protocols supported. Default: `SOCKS4`, `SOCKS5`, `HTTP` | +| host | Hostname (FQDN, IPv6 or IPv4) of the Proxy server | +| port | Port of the Proxy server that accepts the connection | +| username | Username used to authenticate the access to Proxy Server | +| password | Password for the provided username to authenticate access to Proxy Server | +| dns_resolution | Whether DNS resolution should be done by Proxy server or not | + + +### Example -![image](../images/configuration/configuration_without_table_output.png) +```json +{ + "type": "proxyTab", + "name": "custom_proxy", + "warning": { + "config": { + "message": "Some warning message" + } + }, + "port": { + "label": "Proxy port", + "validator": [ + { + "type": "number", + "range": [ + 1025, + 65535 + ], + "isInteger": true + } + ] + }, + "username": true, + "password": { + "label": "Password for Proxy" + }, + "dns_resolution": false, +} +``` + +The above will get converted to the older definition (mentioned below) in your output directory. + +![image](../images/configuration/proxy_tab_custom.png) + +```json +{ +--8<-- "tests/unit/tabs/test_proxy_tab.py:9:69" +} +``` diff --git a/docs/images/configuration/proxy_tab.png b/docs/images/configuration/proxy_tab.png new file mode 100644 index 000000000..b2fe8935c Binary files /dev/null and b/docs/images/configuration/proxy_tab.png differ diff --git a/docs/images/configuration/proxy_tab_custom.png b/docs/images/configuration/proxy_tab_custom.png new file mode 100644 index 000000000..d37d4fe6b Binary files /dev/null and b/docs/images/configuration/proxy_tab_custom.png differ diff --git a/docs/images/configuration/proxy_tab_with_warning.png b/docs/images/configuration/proxy_tab_with_warning.png new file mode 100644 index 000000000..33bb73ce3 Binary files /dev/null and b/docs/images/configuration/proxy_tab_with_warning.png differ diff --git a/splunk_add_on_ucc_framework/commands/build.py b/splunk_add_on_ucc_framework/commands/build.py index 9633aa225..9423075e4 100644 --- a/splunk_add_on_ucc_framework/commands/build.py +++ b/splunk_add_on_ucc_framework/commands/build.py @@ -502,6 +502,7 @@ def generate( pip_version=pip_version, pip_legacy_resolver=pip_legacy_resolver, pip_custom_flag=pip_custom_flag, + includes_oauth=global_config.has_oauth(), ) except SplunktaucclibNotFound as e: logger.error(str(e)) diff --git a/splunk_add_on_ucc_framework/commands/init.py b/splunk_add_on_ucc_framework/commands/init.py index 19e104518..60017af9b 100644 --- a/splunk_add_on_ucc_framework/commands/init.py +++ b/splunk_add_on_ucc_framework/commands/init.py @@ -67,6 +67,7 @@ def _generate_addon( addon_version: str, addon_rest_root: str | None = None, overwrite: bool = False, + need_proxy: bool = False, add_license: str | None = None, include_author: str | None = None, ) -> str: @@ -99,6 +100,7 @@ def _generate_addon( addon_version=addon_version, addon_display_name=addon_display_name, addon_input_name=addon_input_name, + need_proxy=need_proxy, ) ) with open(global_config_path, "w") as _f: @@ -188,6 +190,7 @@ def init( addon_version: str, addon_rest_root: str | None = None, overwrite: bool = False, + need_proxy: bool = False, add_license: str | None = None, include_author: str | None = None, ) -> str: @@ -234,6 +237,7 @@ def init( addon_version, addon_rest_root, overwrite, + need_proxy, add_license, include_author, ) diff --git a/splunk_add_on_ucc_framework/global_config_update.py b/splunk_add_on_ucc_framework/global_config_update.py index 9c59c6243..193db9e9f 100644 --- a/splunk_add_on_ucc_framework/global_config_update.py +++ b/splunk_add_on_ucc_framework/global_config_update.py @@ -142,7 +142,7 @@ def handle_global_config_update(global_config: global_config_lib.GlobalConfig) - if _version_tuple(version) < _version_tuple("0.0.2"): for tab in global_config.tabs: - if tab.get("type") in ["loggingTab"]: + if tab.get("type") in ["loggingTab", "proxyTab"]: continue if tab["name"] == "account": conf_entities = tab.get("entity") @@ -248,6 +248,10 @@ def _dump_with_migrated_tabs(global_config: GlobalConfig, path: str) -> None: for i, tab in enumerate( global_config.content.get("pages", {}).get("configuration", {}).get("tabs", []) ): + if tab.get("type") == "proxyTab": + # Collapsing the tab is not required for ProxyTab because we can't be certain + # that a particular tab is a Proxy tab, as we can with a Logging tab. + continue global_config.content["pages"]["configuration"]["tabs"][i] = _collapse_tab(tab) _dump(global_config.content, path, global_config._is_global_config_yaml) diff --git a/splunk_add_on_ucc_framework/install_python_libraries.py b/splunk_add_on_ucc_framework/install_python_libraries.py index e82ab4056..d62d74ee4 100644 --- a/splunk_add_on_ucc_framework/install_python_libraries.py +++ b/splunk_add_on_ucc_framework/install_python_libraries.py @@ -29,6 +29,7 @@ LIBS_REQUIRED_FOR_UI = {"splunktaucclib": "6.4.0"} +LIBS_REQUIRED_FOR_OAUTH = {"solnlib": "5.5.0"} class SplunktaucclibNotFound(Exception): @@ -39,6 +40,10 @@ class WrongSplunktaucclibVersion(Exception): pass +class WrongSolnlibVersion(Exception): + pass + + class CouldNotInstallRequirements(Exception): pass @@ -120,6 +125,23 @@ def _pip_is_lib_installed( raise CouldNotInstallRequirements from e +def _check_libraries_required_for_oauth( + python_binary_name: str, ucc_lib_target: str, path_to_requirements_file: str +) -> None: + for lib, version in LIBS_REQUIRED_FOR_OAUTH.items(): + if not _pip_is_lib_installed( + installer=python_binary_name, + target=ucc_lib_target, + libname=lib, + version=version, + allow_higher_version=True, + ): + raise WrongSolnlibVersion( + f"{lib} found at {path_to_requirements_file}, but is not of latest version." + f" Please make sure {lib} is of version greater than or equal to {version}." + ) + + def _check_libraries_required_for_ui( python_binary_name: str, ucc_lib_target: str, path_to_requirements_file: str ) -> None: @@ -154,6 +176,7 @@ def install_python_libraries( pip_version: str = "latest", pip_legacy_resolver: bool = False, pip_custom_flag: Optional[str] = None, + includes_oauth: bool = False, ) -> None: path_to_requirements_file = os.path.join(source_path, "lib", "requirements.txt") if os.path.isfile(path_to_requirements_file): @@ -172,6 +195,10 @@ def install_python_libraries( _check_libraries_required_for_ui( python_binary_name, ucc_lib_target, path_to_requirements_file ) + if includes_oauth: + _check_libraries_required_for_oauth( + python_binary_name, ucc_lib_target, path_to_requirements_file + ) cleanup_libraries = install_os_dependent_libraries( ucc_lib_target=ucc_lib_target, diff --git a/splunk_add_on_ucc_framework/main.py b/splunk_add_on_ucc_framework/main.py index 048f0f380..b8f70b8b4 100644 --- a/splunk_add_on_ucc_framework/main.py +++ b/splunk_add_on_ucc_framework/main.py @@ -200,6 +200,12 @@ def main(argv: Optional[Sequence[str]] = None) -> int: default=False, help="overwrite already generated add-on folder", ) + init_parser.add_argument( + "--need-proxy", + action="store_true", + required=False, + help="Specifies if proxy is needed or not", + ) init_parser.add_argument( "--add-license", type=str, @@ -257,6 +263,7 @@ def main(argv: Optional[Sequence[str]] = None) -> int: addon_input_name=args.addon_input_name, addon_version=args.addon_version, overwrite=args.overwrite, + need_proxy=args.need_proxy, add_license=args.add_license, include_author=args.include_author, ) diff --git a/splunk_add_on_ucc_framework/schema/schema.json b/splunk_add_on_ucc_framework/schema/schema.json index f25973bf8..e4569898c 100644 --- a/splunk_add_on_ucc_framework/schema/schema.json +++ b/splunk_add_on_ucc_framework/schema/schema.json @@ -453,6 +453,9 @@ }, { "$ref": "#/definitions/PredefinedLoggingTab" + }, + { + "$ref": "#/definitions/PredefinedProxyTab" } ] }, @@ -3161,6 +3164,197 @@ ], "additionalProperties": false }, + "PredefinedProxyTab": { + "type": "object", + "description": "Predefined Proxy tab configuration, can be used to reduce length of config", + "properties": { + "type": { + "type": "string", + "const": "proxyTab", + "description": "Exactly: proxyTab" + }, + "name": { + "type": "string", + "pattern": "^[\\/\\w]+$", + "default": "Proxy", + "description": "Tab name.", + "maxLength": 250 + }, + "title": { + "type": "string", + "default": "Proxy", + "description": "Tab title.", + "maxLength": 50 + }, + "enable_proxy": { + "type": "object", + "default": { + "type": "checkbox", + "label": "Enable", + "field": "proxy_enabled" + }, + "description": "Checkbox for enabling proxy" + }, + "proxy_type": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "default": { + "type": "singleSelect", + "label": "Proxy Type", + "required": false, + "options": { + "disableSearch": true, + "autoCompleteFields": [ + { + "value": "http", + "label": "http" + }, + { + "value": "socks4", + "label": "socks4" + }, + { + "value": "socks5", + "label": "socks5" + } + ] + }, + "defaultValue": "http", + "field": "proxy_type" + } + } + ], + "description": "Proxy type. Available values: http, socks4, socks5" + }, + "host": { + "type": "object", + "default": { + "type": "text", + "label": "Host", + "validators": [ + { + "type": "string", + "errorMsg": "Max host length is 4096", + "minLength": 0, + "maxLength": 4096 + }, + { + "type": "regex", + "errorMsg": "Proxy Host should not have special characters", + "pattern": "^[a-zA-Z]\\w*$" + } + ], + "field": "proxy_url" + }, + "description": "Host of the proxy" + }, + "port": { + "type": "object", + "default": { + "type": "text", + "label": "Port", + "validators": [ + { + "type": "number", + "range": [ + 1, + 65535 + ], + "isInteger": true + } + ], + "field": "proxy_port" + }, + "description": "Port of the proxy" + }, + "username": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "default": { + "type": "text", + "label": "Username", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of username is 50", + "minLength": 0, + "maxLength": 50 + } + ], + "field": "proxy_username" + } + } + ], + "description": "Username used to access the proxy server." + }, + "password": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "default": { + "type": "text", + "label": "Password", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of password is 8192", + "minLength": 0, + "maxLength": 8192 + } + ], + "encrypted": true, + "field": "proxy_password" + } + } + ], + "description": "Password assigned for the username" + }, + "dns_resolution": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "default": { + "type": "checkbox", + "label": "DNS resolution", + "field": "proxy_rdns" + } + } + ], + "description": "Specifies whether DNS resolution should be used or not." + }, + "options": { + "$ref": "#/definitions/SaveValidatorHook" + }, + "hook": { + "type": "object", + "description": "It is used to add custom behaviour to forms. Visit the Custom Hook page to learn more." + }, + "warning": { + "$ref": "#/definitions/WarningMessage" + }, + "help": { + "$ref": "#/definitions/help" + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, "InputPageSingleTable": { "type": "object", "properties": { diff --git a/splunk_add_on_ucc_framework/tabs/__init__.py b/splunk_add_on_ucc_framework/tabs/__init__.py index f8fac69ab..54c445f44 100644 --- a/splunk_add_on_ucc_framework/tabs/__init__.py +++ b/splunk_add_on_ucc_framework/tabs/__init__.py @@ -13,15 +13,15 @@ # See the License for the specific language governing permissions and # limitations under the License. # -from typing import Dict, Any +from typing import Dict, Any, List, Type + +from splunk_add_on_ucc_framework.tabs.proxy_tab import ProxyTab from splunk_add_on_ucc_framework.tabs.logging_tab import LoggingTab from splunk_add_on_ucc_framework.tabs.tab import Tab -TAB_TYPES = [ - LoggingTab, -] +TAB_TYPES: List[Type[Tab]] = [LoggingTab, ProxyTab] def resolve_tab(tab_definition: Dict[Any, Any]) -> Tab: diff --git a/splunk_add_on_ucc_framework/tabs/proxy_tab.py b/splunk_add_on_ucc_framework/tabs/proxy_tab.py new file mode 100644 index 000000000..3eefa7833 --- /dev/null +++ b/splunk_add_on_ucc_framework/tabs/proxy_tab.py @@ -0,0 +1,205 @@ +# +# Copyright 2025 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import logging +import sys +from typing import Dict, Any, Optional +from splunk_add_on_ucc_framework.tabs.tab import Tab + + +logger = logging.getLogger("ucc_gen") + +# defaults +NAME = "proxy" +TITLE = "Proxy" + +DEFAULT_PROXY_ENABLE = {"type": "checkbox", "label": "Enable", "field": "proxy_enabled"} + +DEFAULT_PROXY_TYPE = { + "type": "singleSelect", + "label": "Proxy Type", + "required": False, + "options": { + "disableSearch": True, + "autoCompleteFields": [ + {"value": "http", "label": "http"}, + {"value": "socks4", "label": "socks4"}, + {"value": "socks5", "label": "socks5"}, + ], + }, + "defaultValue": "http", + "field": "proxy_type", +} + +DEFAULT_HOST = { + "type": "text", + "label": "Host", + "validators": [ + { + "type": "string", + "errorMsg": "Max host length is 4096", + "minLength": 0, + "maxLength": 4096, + }, + { + "type": "regex", + "errorMsg": "Proxy Host should not have special characters", + "pattern": "^[a-zA-Z]\\w*$", + }, + ], + "field": "proxy_url", +} + +DEFAULT_PORT = { + "type": "text", + "label": "Port", + "validators": [{"type": "number", "range": [1, 65535], "isInteger": True}], + "field": "proxy_port", +} + +DEFAULT_USERNAME = { + "type": "text", + "label": "Username", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of username is 50", + "minLength": 0, + "maxLength": 50, + } + ], + "field": "proxy_username", +} + +DEFAULT_PASSWORD = { + "type": "text", + "label": "Password", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of password is 8192", + "minLength": 0, + "maxLength": 8192, + } + ], + "encrypted": True, + "field": "proxy_password", +} + +DEFAULT_DNS_RESOLUTION = { + "type": "checkbox", + "label": "DNS resolution", + "field": "proxy_rdns", +} + + +class ProxyTab(Tab): + @property + def tab_type(self) -> Optional[str]: + return "proxyTab" + + @classmethod + def from_definition(cls, definition: Dict[str, Any]) -> Optional["Tab"]: + """ + This function checks if the definition has type == ProxyTab; if it does, it gets converted; + otherwise, it returns None. + """ + if definition.get("type") == "proxyTab": + entity = [] + entity_key_const_dict: Dict[str, Dict[str, Any]] = { + "enable_proxy": DEFAULT_PROXY_ENABLE, + "proxy_type": DEFAULT_PROXY_TYPE, + "host": DEFAULT_HOST, + "port": DEFAULT_PORT, + "username": DEFAULT_USERNAME, + "password": DEFAULT_PASSWORD, + "dns_resolution": DEFAULT_DNS_RESOLUTION, + } + + if ("username" not in definition) ^ ("password" not in definition): + logger.error("Either of username or password is not mentioned.") + sys.exit(1) + + elif definition.get("username") != definition.get("password"): + if ( + isinstance(definition.get("username"), dict) + and definition.get("password") is False + ): + logger.error( + "You have updated the username but set the password to 'false' which is not allowed " + "set `password = True` for default configuration." + ) + sys.exit(1) + elif ( + isinstance(definition.get("password"), dict) + and definition.get("username") is False + ): + logger.error( + "You have updated the password but set username to `false` which is not allowed " + "set `username = True` for default configuration." + ) + sys.exit(1) + elif ( + type(definition.get("username")) is bool + and type(definition.get("password")) is bool + ): + logger.error( + f"You have set different values for username ({definition.get('username')})" + f" and password ({definition.get('password')}). They should be same." + ) + sys.exit(1) + for key_name, value in entity_key_const_dict.items(): + if definition.get(key_name) is True: + entity.append(value) + elif (not definition.get(key_name)) and key_name in [ + "proxy_type", + "username", + "password", + "dns_resolution", + ]: + continue + elif definition.get(key_name): + for key, i_value in value.items(): + if key not in definition.get(key_name, {}): + definition[key_name][key] = i_value + entity.append(definition[key_name]) + else: + entity.append(value) + + new_definition = { + "name": definition.get("name", NAME), + "title": definition.get("title", TITLE), + "entity": entity, + } + + for key, value in definition.items(): + if key not in [ + "name", + "title", + "enable_proxy", + "proxy_type", + "port", + "host", + "username", + "password", + "dns_resolution", + "type", + ]: + new_definition[key] = value + + return ProxyTab(new_definition) + + return None diff --git a/splunk_add_on_ucc_framework/templates/globalConfig.json.init-template b/splunk_add_on_ucc_framework/templates/globalConfig.json.init-template index ff92348b9..dd9ac7446 100644 --- a/splunk_add_on_ucc_framework/templates/globalConfig.json.init-template +++ b/splunk_add_on_ucc_framework/templates/globalConfig.json.init-template @@ -59,7 +59,11 @@ }, { "type": "loggingTab" + }{%- if need_proxy %}, + { + "type": "proxyTab" } + {%- endif %} ], "title": "Configuration", "description": "Set up your add-on" diff --git a/splunk_add_on_ucc_framework/templates/oauth.template b/splunk_add_on_ucc_framework/templates/oauth.template index 2d5449606..3f1f1adc9 100644 --- a/splunk_add_on_ucc_framework/templates/oauth.template +++ b/splunk_add_on_ucc_framework/templates/oauth.template @@ -12,6 +12,7 @@ from httplib2 import Http, ProxyInfo, socks import splunk.admin as admin from solnlib import log from solnlib import conf_manager +from solnlib.conf_manager import InvalidHostnameError, InvalidPortError from solnlib.utils import is_true import json @@ -113,13 +114,24 @@ class {{app_name | lower}}_rh_oauth2_token(admin.MConfigHandler): """ def getProxyDetails(self): - # Create confmanger object for the app with realm - cfm = conf_manager.ConfManager(self.getSessionKey( - ), "{{app_name}}", realm="__REST_CREDENTIAL__#{{app_name}}#configs/conf-{{app_name|lower}}_settings") - # Get Conf object of apps settings - conf = cfm.get_conf('{{app_name|lower}}_settings') - # Get proxy stanza from the settings - proxy_config = conf.get("proxy", True) + try: + proxy_config = conf_manager.get_proxy_dict(logger=logger, + session_key=self.getSessionKey(), + app_name="{{app_name}}", + conf_name="{{app_name | lower}}_settings", + proxy_port="proxy_port", # Field name of port + proxy_host="proxy_url" # Field name of hostname + ) + + # Handle invalid port case + except InvalidPortError as e: + logger.error(f"Proxy configuration error: {e}") + + # Handle invalid hostname case + except InvalidHostnameError as e: + logger.error(f"Proxy configuration error: {e}") + + if not proxy_config or not is_true(proxy_config.get('proxy_enabled')): logger.info('Proxy is not enabled') return None @@ -127,14 +139,6 @@ class {{app_name | lower}}_rh_oauth2_token(admin.MConfigHandler): url = proxy_config.get('proxy_url') port = proxy_config.get('proxy_port') - if url or port: - if not url: - raise ValueError('Proxy "url" must not be empty') - if not self.is_valid_port(port): - raise ValueError( - 'Proxy "port" must be in range [1,65535]: %s' % port - ) - user = proxy_config.get('proxy_username') password = proxy_config.get('proxy_password') @@ -171,11 +175,5 @@ class {{app_name | lower}}_rh_oauth2_token(admin.MConfigHandler): :type port: ``int`` """ - def is_valid_port(self, port): - try: - return 0 < int(port) <= 65535 - except ValueError: - return False - if __name__ == "__main__": admin.init({{app_name | lower}}_rh_oauth2_token, admin.CONTEXT_APP_AND_USER) diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json index df795dab8..1d6532a4e 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json @@ -280,7 +280,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py index 6b4110de2..80084c5a5 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py @@ -12,6 +12,7 @@ import splunk.admin as admin from solnlib import log from solnlib import conf_manager +from solnlib.conf_manager import InvalidHostnameError, InvalidPortError from solnlib.utils import is_true import json @@ -113,13 +114,24 @@ def handleEdit(self, confInfo): """ def getProxyDetails(self): - # Create confmanger object for the app with realm - cfm = conf_manager.ConfManager(self.getSessionKey( - ), "Splunk_TA_UCCExample", realm="__REST_CREDENTIAL__#Splunk_TA_UCCExample#configs/conf-splunk_ta_uccexample_settings") - # Get Conf object of apps settings - conf = cfm.get_conf('splunk_ta_uccexample_settings') - # Get proxy stanza from the settings - proxy_config = conf.get("proxy", True) + try: + proxy_config = conf_manager.get_proxy_dict(logger=logger, + session_key=self.getSessionKey(), + app_name="Splunk_TA_UCCExample", + conf_name="splunk_ta_uccexample_settings", + proxy_port="proxy_port", # Field name of port + proxy_host="proxy_url" # Field name of hostname + ) + + # Handle invalid port case + except InvalidPortError as e: + logger.error(f"Proxy configuration error: {e}") + + # Handle invalid hostname case + except InvalidHostnameError as e: + logger.error(f"Proxy configuration error: {e}") + + if not proxy_config or not is_true(proxy_config.get('proxy_enabled')): logger.info('Proxy is not enabled') return None @@ -127,14 +139,6 @@ def getProxyDetails(self): url = proxy_config.get('proxy_url') port = proxy_config.get('proxy_port') - if url or port: - if not url: - raise ValueError('Proxy "url" must not be empty') - if not self.is_valid_port(port): - raise ValueError( - 'Proxy "port" must be in range [1,65535]: %s' % port - ) - user = proxy_config.get('proxy_username') password = proxy_config.get('proxy_password') @@ -171,11 +175,5 @@ def getProxyDetails(self): :type port: ``int`` """ - def is_valid_port(self, port): - try: - return 0 < int(port) <= 65535 - except ValueError: - return False - if __name__ == "__main__": admin.init(splunk_ta_uccexample_rh_oauth2_token, admin.CONTEXT_APP_AND_USER) \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json index 513c07009..9971c405e 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/appserver/static/js/build/globalConfig.json @@ -292,7 +292,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py index 6b4110de2..80084c5a5 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_oauth.py @@ -12,6 +12,7 @@ import splunk.admin as admin from solnlib import log from solnlib import conf_manager +from solnlib.conf_manager import InvalidHostnameError, InvalidPortError from solnlib.utils import is_true import json @@ -113,13 +114,24 @@ def handleEdit(self, confInfo): """ def getProxyDetails(self): - # Create confmanger object for the app with realm - cfm = conf_manager.ConfManager(self.getSessionKey( - ), "Splunk_TA_UCCExample", realm="__REST_CREDENTIAL__#Splunk_TA_UCCExample#configs/conf-splunk_ta_uccexample_settings") - # Get Conf object of apps settings - conf = cfm.get_conf('splunk_ta_uccexample_settings') - # Get proxy stanza from the settings - proxy_config = conf.get("proxy", True) + try: + proxy_config = conf_manager.get_proxy_dict(logger=logger, + session_key=self.getSessionKey(), + app_name="Splunk_TA_UCCExample", + conf_name="splunk_ta_uccexample_settings", + proxy_port="proxy_port", # Field name of port + proxy_host="proxy_url" # Field name of hostname + ) + + # Handle invalid port case + except InvalidPortError as e: + logger.error(f"Proxy configuration error: {e}") + + # Handle invalid hostname case + except InvalidHostnameError as e: + logger.error(f"Proxy configuration error: {e}") + + if not proxy_config or not is_true(proxy_config.get('proxy_enabled')): logger.info('Proxy is not enabled') return None @@ -127,14 +139,6 @@ def getProxyDetails(self): url = proxy_config.get('proxy_url') port = proxy_config.get('proxy_port') - if url or port: - if not url: - raise ValueError('Proxy "url" must not be empty') - if not self.is_valid_port(port): - raise ValueError( - 'Proxy "port" must be in range [1,65535]: %s' % port - ) - user = proxy_config.get('proxy_username') password = proxy_config.get('proxy_password') @@ -171,11 +175,5 @@ def getProxyDetails(self): :type port: ``int`` """ - def is_valid_port(self, port): - try: - return 0 < int(port) <= 65535 - except ValueError: - return False - if __name__ == "__main__": admin.init(splunk_ta_uccexample_rh_oauth2_token, admin.CONTEXT_APP_AND_USER) \ No newline at end of file diff --git a/tests/testdata/test_addons/package_global_config_configuration/globalConfig.json b/tests/testdata/test_addons/package_global_config_configuration/globalConfig.json index 71f224258..b8b7591f7 100644 --- a/tests/testdata/test_addons/package_global_config_configuration/globalConfig.json +++ b/tests/testdata/test_addons/package_global_config_configuration/globalConfig.json @@ -281,7 +281,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/testdata/test_addons/package_global_config_everything/globalConfig.json b/tests/testdata/test_addons/package_global_config_everything/globalConfig.json index 5cf04d258..0a1a50cdd 100644 --- a/tests/testdata/test_addons/package_global_config_everything/globalConfig.json +++ b/tests/testdata/test_addons/package_global_config_everything/globalConfig.json @@ -494,111 +494,26 @@ "restHandlerClass": "CustomAccountValidator" }, { - "name": "proxy", - "warning": { - "config": { - "message": "Some warning for account text config" - } + "type": "proxyTab", + "proxy_type": true, + "username": { + "type": "text", + "label": "Username", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of username is 50", + "minLength": 0, + "maxLength": 50 + } + ], + "field": "proxy_username" }, - "entity": [ - { - "type": "checkbox", - "label": "Enable", - "field": "proxy_enabled" - }, - { - "type": "singleSelect", - "label": "Proxy Type", - "options": { - "disableSearch": true, - "autoCompleteFields": [ - { - "value": "http", - "label": "http" - }, - { - "value": "socks4", - "label": "socks4" - }, - { - "value": "socks5", - "label": "socks5" - } - ] - }, - "defaultValue": "http", - "field": "proxy_type" - }, - { - "type": "text", - "label": "Host", - "validators": [ - { - "type": "string", - "errorMsg": "Max host length is 4096", - "minLength": 0, - "maxLength": 4096 - }, - { - "type": "regex", - "errorMsg": "Proxy Host should not have special characters", - "pattern": "^[a-zA-Z]\\w*$" - } - ], - "field": "proxy_url" - }, - { - "type": "text", - "label": "Port", - "validators": [ - { - "type": "number", - "range": [ - 1, - 65535 - ], - "isInteger": true - } - ], - "field": "proxy_port" - }, - { - "type": "text", - "label": "Username", - "validators": [ - { - "type": "string", - "errorMsg": "Max length of username is 50", - "minLength": 0, - "maxLength": 50 - } - ], - "field": "proxy_username" - }, - { - "type": "text", - "label": "Password", - "validators": [ - { - "type": "string", - "errorMsg": "Max length of password is 8192", - "minLength": 0, - "maxLength": 8192 - } - ], - "encrypted": true, - "field": "proxy_password" - }, - { - "type": "checkbox", - "label": "Reverse DNS resolution", - "field": "proxy_rdns" - } - ], + "password": true, + "dns_resolution": true, "options": { "saveValidator": "function(formData) { if(!formData.proxy_enabled || formData.proxy_enabled === '0') {return true; } if(!formData.proxy_url) { return 'Proxy Host can not be empty'; } if(!formData.proxy_port) { return 'Proxy Port can not be empty'; } return true; }" - }, - "title": "Proxy" + } }, { "type": "loggingTab" diff --git a/tests/testdata/test_addons/package_global_config_everything_uccignore/globalConfig.json b/tests/testdata/test_addons/package_global_config_everything_uccignore/globalConfig.json index 739032266..d202924d4 100644 --- a/tests/testdata/test_addons/package_global_config_everything_uccignore/globalConfig.json +++ b/tests/testdata/test_addons/package_global_config_everything_uccignore/globalConfig.json @@ -368,7 +368,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json b/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json index 1893806f1..07669c70f 100644 --- a/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json +++ b/tests/testdata/test_addons/package_global_config_multi_input/globalConfig.json @@ -280,7 +280,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/ui/test_configuration_page_proxy_tab.py b/tests/ui/test_configuration_page_proxy_tab.py index 54f4dc753..ccc7b811b 100644 --- a/tests/ui/test_configuration_page_proxy_tab.py +++ b/tests/ui/test_configuration_page_proxy_tab.py @@ -26,7 +26,7 @@ def test_proxy_misc(self, ucc_smartx_selenium_helper, ucc_smartx_rest_helper): self.assert_util(proxy.port.get_input_label, "Port") self.assert_util(proxy.username.get_input_label, "Username") self.assert_util(proxy.password.get_input_label, "Password") - self.assert_util(proxy.dns_enable.get_input_label, "Reverse DNS resolution") + self.assert_util(proxy.dns_enable.get_input_label, "DNS resolution") # Default values self.assert_util(proxy.proxy_enable.is_checked(), False) diff --git a/tests/unit/commands/test_init.py b/tests/unit/commands/test_init.py index 37d0f10b3..b436eba39 100644 --- a/tests/unit/commands/test_init.py +++ b/tests/unit/commands/test_init.py @@ -85,6 +85,7 @@ def test__is_valid_input_name(input_name, expected): "addon_display_name": "Addon For Demo", "addon_input_name": "input_name", "addon_version": "0.0.1", + "need_proxy": True, }, ( "addon_name", @@ -93,6 +94,7 @@ def test__is_valid_input_name(input_name, expected): "0.0.1", "addon_name", False, + True, None, None, ), @@ -104,6 +106,7 @@ def test__is_valid_input_name(input_name, expected): "addon_display_name": "Addon For Demo", "addon_input_name": "input_name", "addon_version": "0.0.1", + "overwrite": True, }, ( "addon_name", @@ -111,6 +114,7 @@ def test__is_valid_input_name(input_name, expected): "input_name", "0.0.1", "addon_name", + True, False, None, None, @@ -132,6 +136,7 @@ def test__is_valid_input_name(input_name, expected): "0.0.1", "addon_rest_root", False, + False, "Apache License 2.0", None, ), @@ -154,6 +159,7 @@ def test__is_valid_input_name(input_name, expected): "0.0.1", "addon_rest_root", True, + False, "Apache License 2.0", "test_author", ), @@ -176,10 +182,32 @@ def test__is_valid_input_name(input_name, expected): "0.0.1", "addon_rest_root", True, + False, "Apache License 2.0", "test author", ), ), + ( + { + "addon_name": "addon_name", + "addon_display_name": "Addon For Demo", + "addon_input_name": "input_name", + "addon_version": "0.0.1", + "overwrite": True, + "need_proxy": True, + }, + ( + "addon_name", + "Addon For Demo", + "input_name", + "0.0.1", + "addon_name", + True, + True, + None, + None, + ), + ), ], ) def test_init(mock_generate_addon, init_kwargs, expected_args_to_generate_addon): diff --git a/tests/unit/tabs/test_proxy_tab.py b/tests/unit/tabs/test_proxy_tab.py new file mode 100644 index 000000000..faf45686b --- /dev/null +++ b/tests/unit/tabs/test_proxy_tab.py @@ -0,0 +1,147 @@ +import pytest + +from splunk_add_on_ucc_framework.tabs import ProxyTab + + +@pytest.fixture +def expected_generation(): + return { + "name": "custom_proxy", + "title": "Proxy", + "entity": [ + {"type": "checkbox", "label": "Enable", "field": "proxy_enabled"}, + { + "type": "text", + "label": "Host", + "validators": [ + { + "type": "string", + "errorMsg": "Max host length is 4096", + "minLength": 0, + "maxLength": 4096, + }, + { + "type": "regex", + "errorMsg": "Proxy Host should not have special characters", + "pattern": "^[a-zA-Z]\\w*$", + }, + ], + "field": "proxy_url", + }, + { + "label": "Proxy port", + "validators": [ + {"type": "number", "range": [1025, 65535], "isInteger": True} + ], + "type": "text", + "field": "proxy_port", + }, + { + "type": "text", + "label": "Username", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of username is 50", + "minLength": 0, + "maxLength": 50, + } + ], + "field": "proxy_username", + }, + { + "label": "Password for Proxy", + "type": "text", + "validators": [ + { + "type": "string", + "errorMsg": "Max length of password is 8192", + "minLength": 0, + "maxLength": 8192, + } + ], + "encrypted": True, + "field": "proxy_password", + }, + ], + "warning": {"config": {"message": "Some warning message"}}, + } + + +def test_proxy_tab(expected_generation): + proxy_input = { + "type": "proxyTab", + "name": "custom_proxy", + "port": { + "label": "Proxy port", + "validators": [ + {"type": "number", "range": [1025, 65535], "isInteger": True} + ], + }, + "username": True, + "password": {"label": "Password for Proxy"}, + "warning": {"config": {"message": "Some warning message"}}, + } + new_definition = ProxyTab.from_definition(proxy_input) + assert new_definition == expected_generation + + +def test_proxy_short_tab_has_default_parameters(): + new_definition = ProxyTab.from_definition({"type": "proxyTab"}) + assert new_definition is not None + assert new_definition["name"] == "proxy" + assert new_definition["title"] == "Proxy" + assert len(new_definition["entity"]) == 3 + + +@pytest.mark.parametrize( + "invalid_input, expected_failure_message", + [ + ( + { + "type": "proxyTab", + "name": "custom_name", + "password": {"label": "Password for Proxy"}, + }, + "Either of username or password is not mentioned.", + ), + ( + { + "type": "proxyTab", + "name": "custom_name", + "password": {"label": "Password for Proxy"}, + "username": False, + }, + "You have updated the password but set username to `false` which is not allowed " + "set `username = True` for default configuration.", + ), + ( + { + "type": "proxyTab", + "name": "custom_name", + "username": {"label": "Username for Proxy"}, + "password": False, + }, + "You have updated the username but set the password to 'false' which is not allowed " + "set `password = True` for default configuration.", + ), + ( + { + "type": "proxyTab", + "name": "custom_name", + "username": True, + "password": False, + }, + "You have set different values for username (True) and password (False). They should be same.", + ), + ], +) +def test_parametrize(caplog, invalid_input, expected_failure_message): + with pytest.raises(SystemExit): + ProxyTab.from_definition(invalid_input) + assert expected_failure_message in caplog.text + + +def test_proxy_wrong_type(): + # only valid type is proxyTab + assert ProxyTab.from_definition({"type": "otherTab"}) is None diff --git a/tests/unit/test_install_python_libraries.py b/tests/unit/test_install_python_libraries.py index d6740fbf0..f16e60135 100644 --- a/tests/unit/test_install_python_libraries.py +++ b/tests/unit/test_install_python_libraries.py @@ -21,6 +21,7 @@ remove_packages, validate_conflicting_paths, WrongSplunktaucclibVersion, + WrongSolnlibVersion, InvalidArguments, _pip_is_lib_installed, ) @@ -191,6 +192,28 @@ def test_install_libraries_when_wrong_splunktaucclib_is_present_but_has_ui(tmp_p assert expected_msg in str(exc.value) +def test_install_libraries_when_wrong_solnlib_is_present_but_has_oauth(tmp_path): + tmp_ucc_lib_target = tmp_path / "ucc-lib-target" + tmp_lib_path = tmp_path / "lib" + tmp_lib_path.mkdir() + tmp_lib_reqs_file = tmp_lib_path / "requirements.txt" + tmp_lib_reqs_file.write_text("solnlib==5.4.0\n") + + expected_msg = ( + f"solnlib found at {tmp_lib_reqs_file}, but is not of latest version. " + "Please make sure solnlib is of version greater than or equal to 5.5.0" + ) + + with pytest.raises(WrongSolnlibVersion) as exc: + install_python_libraries( + str(tmp_path), + str(tmp_ucc_lib_target), + python_binary_name="python3", + includes_oauth=True, + ) + assert expected_msg in str(exc.value) + + def test_remove_package_from_installed_path(tmp_path): tmp_lib_path = tmp_path / "lib" tmp_lib_path.mkdir() diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 9951a6162..cc0948f39 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -340,6 +340,7 @@ def test_build_command(mock_ucc_gen_generate, args, expected_parameters): "Splunk Add-on for Demo", "--addon-input-name", "demo_input", + "--need-proxy", ], { "addon_name": "splunk_add_on_for_demo", @@ -348,6 +349,33 @@ def test_build_command(mock_ucc_gen_generate, args, expected_parameters): "addon_version": "0.0.1", "addon_rest_root": None, "overwrite": False, + "need_proxy": True, + "add_license": None, + "include_author": None, + }, + ), + ( + [ + "init", + "--addon-name", + "splunk_add_on_for_demo", + "--addon-rest-root", + "splunk_add_on_for_demo", + "--addon-display-name", + "Splunk Add-on for Demo", + "--addon-input-name", + "demo_input", + "--overwrite", + "--need-proxy", + ], + { + "addon_name": "splunk_add_on_for_demo", + "addon_display_name": "Splunk Add-on for Demo", + "addon_input_name": "demo_input", + "addon_version": "0.0.1", + "addon_rest_root": "splunk_add_on_for_demo", + "overwrite": True, + "need_proxy": True, "add_license": None, "include_author": None, }, @@ -373,6 +401,7 @@ def test_build_command(mock_ucc_gen_generate, args, expected_parameters): "addon_version": "0.0.1", "addon_rest_root": "splunk_add_on_for_demo", "overwrite": False, + "need_proxy": False, "add_license": "MIT License", "include_author": None, }, @@ -401,6 +430,7 @@ def test_build_command(mock_ucc_gen_generate, args, expected_parameters): "addon_version": "0.0.1", "addon_rest_root": "splunk_add_on_for_demo", "overwrite": True, + "need_proxy": False, "add_license": "MIT License", "include_author": "test_author", }, diff --git a/tests/unit/testdata/valid_config.json b/tests/unit/testdata/valid_config.json index e98ed556a..1ebb30b21 100644 --- a/tests/unit/testdata/valid_config.json +++ b/tests/unit/testdata/valid_config.json @@ -316,7 +316,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/unit/testdata/valid_config.yaml b/tests/unit/testdata/valid_config.yaml index 20ac7917c..c8ebc345d 100644 --- a/tests/unit/testdata/valid_config.yaml +++ b/tests/unit/testdata/valid_config.yaml @@ -201,7 +201,7 @@ pages: encrypted: true field: proxy_password - type: checkbox - label: Reverse DNS resolution + label: DNS resolution field: proxy_rdns options: saveValidator: function(formData) { if(!formData.proxy_enabled || formData.proxy_enabled diff --git a/tests/unit/testdata/valid_config_logging_tab_not_migrated.json b/tests/unit/testdata/valid_config_logging_tab_not_migrated.json index 023c6ac8d..e7413b4de 100644 --- a/tests/unit/testdata/valid_config_logging_tab_not_migrated.json +++ b/tests/unit/testdata/valid_config_logging_tab_not_migrated.json @@ -316,7 +316,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/unit/testdata/valid_config_multiple_account.json b/tests/unit/testdata/valid_config_multiple_account.json index 82607fe95..bdba2c9c6 100644 --- a/tests/unit/testdata/valid_config_multiple_account.json +++ b/tests/unit/testdata/valid_config_multiple_account.json @@ -700,7 +700,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/unit/testdata/valid_config_only_configuration.json b/tests/unit/testdata/valid_config_only_configuration.json index a149b25e7..38c7d6403 100644 --- a/tests/unit/testdata/valid_config_only_configuration.json +++ b/tests/unit/testdata/valid_config_only_configuration.json @@ -89,7 +89,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/tests/unit/testdata/valid_single_authentication_config.json b/tests/unit/testdata/valid_single_authentication_config.json index b072ef921..d5a98d512 100644 --- a/tests/unit/testdata/valid_single_authentication_config.json +++ b/tests/unit/testdata/valid_single_authentication_config.json @@ -438,7 +438,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/ui/src/pages/Configuration/stories/globalConfig.json b/ui/src/pages/Configuration/stories/globalConfig.json index c18835402..05c04c011 100644 --- a/ui/src/pages/Configuration/stories/globalConfig.json +++ b/ui/src/pages/Configuration/stories/globalConfig.json @@ -550,7 +550,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ], diff --git a/ui/src/pages/stories/globalConfig/globalConfig.json b/ui/src/pages/stories/globalConfig/globalConfig.json index e4dc2dc03..91a4edea4 100644 --- a/ui/src/pages/stories/globalConfig/globalConfig.json +++ b/ui/src/pages/stories/globalConfig/globalConfig.json @@ -548,7 +548,7 @@ }, { "type": "checkbox", - "label": "Reverse DNS resolution", + "label": "DNS resolution", "field": "proxy_rdns" } ],