diff --git a/.markdownlint.yaml b/.markdownlint.yaml index 8d673078d..826fa9337 100644 --- a/.markdownlint.yaml +++ b/.markdownlint.yaml @@ -46,4 +46,4 @@ MD040: false MD041: false # MD046/code-block-style -MD046: false +MD046: false \ No newline at end of file diff --git a/splunk_add_on_ucc_framework/commands/build.py b/splunk_add_on_ucc_framework/commands/build.py index c1873b32b..aabcf555f 100644 --- a/splunk_add_on_ucc_framework/commands/build.py +++ b/splunk_add_on_ucc_framework/commands/build.py @@ -458,6 +458,12 @@ def generate( f"Updated and saved add-on version in the globalConfig file to {addon_version}" ) global_config.expand() + if ta_name != global_config.product: + logger.error( + "Add-on name mentioned in globalConfig meta tag and that app.manifest are not same," + "please unify them to build the add-on." + ) + sys.exit(1) scheme = global_config_builder_schema.GlobalConfigBuilderSchema(global_config) utils.recursive_overwrite( os.path.join(internal_root_dir, "package"), diff --git a/splunk_add_on_ucc_framework/commands/init.py b/splunk_add_on_ucc_framework/commands/init.py index 3cf4d88af..acdd4564a 100644 --- a/splunk_add_on_ucc_framework/commands/init.py +++ b/splunk_add_on_ucc_framework/commands/init.py @@ -25,9 +25,13 @@ logger = logging.getLogger("ucc_gen") -ADDON_NAME_RE_STR = r'^[^<>:"/|?*]+$' +ADDON_NAME_RE_STR = ( + r"^(?!^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$)" + r"(?!.*\.(tar(\.gz)?|tgz|spl)$)" + r"[A-Za-z_.-][A-Za-z0-9_.-]*[A-Za-z0-9_-]$" +) ADDON_NAME_RE = re.compile(ADDON_NAME_RE_STR) -ADDON_REST_ROOT_RE_STR = r"^\w+$" +ADDON_REST_ROOT_RE_STR = r"^[\w-]+$" ADDON_REST_ROOT_RE = re.compile(ADDON_REST_ROOT_RE_STR) ADDON_INPUT_NAME_RE_STR = r"^[0-9a-zA-Z][\w-]*$" ADDON_INPUT_NAME_RE = re.compile(ADDON_INPUT_NAME_RE_STR) diff --git a/splunk_add_on_ucc_framework/schema/schema.json b/splunk_add_on_ucc_framework/schema/schema.json index bf8bb10b2..37a515ab4 100644 --- a/splunk_add_on_ucc_framework/schema/schema.json +++ b/splunk_add_on_ucc_framework/schema/schema.json @@ -1848,12 +1848,12 @@ }, "name": { "type": "string", - "pattern": "^[^<>:\"\\/\\\\|\\?\\*]+$", + "pattern": "^(?!^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$)(?!.*\\.(tar(\\.gz)?|tgz|spl)$)[A-Za-z_.-][A-Za-z0-9_.-]*[A-Za-z0-9_-]$", "description": "Name used for API endpoints and all code references separating separating endpoints from any other app." }, "restRoot": { "type": "string", - "pattern": "^\\w+$", + "pattern": "^[\\w-]+$", "description": "String used to create API endpoints." }, "apiVersion": { diff --git a/splunk_add_on_ucc_framework/templates/input.helper-init-template b/splunk_add_on_ucc_framework/templates/input.helper-init-template index 4e78f3fca..41bc46a43 100644 --- a/splunk_add_on_ucc_framework/templates/input.helper-init-template +++ b/splunk_add_on_ucc_framework/templates/input.helper-init-template @@ -8,7 +8,6 @@ from splunklib import modularinput as smi ADDON_NAME = "{{addon_name}}" - def logger_for_input(input_name: str) -> logging.Logger: return log.Logs().get_logger(f"{ADDON_NAME.lower()}_{input_name}") @@ -17,9 +16,9 @@ def get_account_api_key(session_key: str, account_name: str): cfm = conf_manager.ConfManager( session_key, ADDON_NAME, - realm=f"__REST_CREDENTIAL__#{ADDON_NAME}#configs/conf-{{addon_rest_root}}_account", + realm=f"__REST_CREDENTIAL__#{ADDON_NAME}#configs/conf-{{addon_rest_root| lower}}_account", ) - account_conf_file = cfm.get_conf("{{addon_name}}_account") + account_conf_file = cfm.get_conf("{{addon_rest_root | lower}}_account") return account_conf_file.get(account_name).get("api_key") @@ -61,7 +60,7 @@ def stream_events(inputs: smi.InputDefinition, event_writer: smi.EventWriter): logger=logger, session_key=session_key, app_name=ADDON_NAME, - conf_name=f"{ADDON_NAME}_settings", + conf_name="{{addon_rest_root | lower}}_settings", ) logger.setLevel(log_level) log.modular_input_start(logger, normalized_input_name) diff --git a/tests/smoke/test_ucc_init.py b/tests/smoke/test_ucc_init.py index 4121f18c7..6f462e9bb 100644 --- a/tests/smoke/test_ucc_init.py +++ b/tests/smoke/test_ucc_init.py @@ -15,6 +15,7 @@ def test_ucc_init(): "Demo Add-on for Splunk", "demo_input", "1.0.0", + "demo-addon-for-splunk", overwrite=True, ) expected_folder = os.path.join( diff --git a/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/globalConfig.json b/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/globalConfig.json index caeb56871..b84c2f131 100644 --- a/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/globalConfig.json +++ b/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/globalConfig.json @@ -176,7 +176,7 @@ }, "meta": { "name": "demo_addon_for_splunk", - "restRoot": "demo_addon_for_splunk", + "restRoot": "demo-addon-for-splunk", "version": "1.0.0", "displayName": "Demo Add-on for Splunk", "schemaVersion": "0.0.8", diff --git a/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/package/bin/demo_input_helper.py b/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/package/bin/demo_input_helper.py index 01e036155..b39d589c3 100644 --- a/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/package/bin/demo_input_helper.py +++ b/tests/testdata/expected_addons/expected_addon_after_init/demo_addon_for_splunk/package/bin/demo_input_helper.py @@ -8,7 +8,6 @@ ADDON_NAME = "demo_addon_for_splunk" - def logger_for_input(input_name: str) -> logging.Logger: return log.Logs().get_logger(f"{ADDON_NAME.lower()}_{input_name}") @@ -17,9 +16,9 @@ def get_account_api_key(session_key: str, account_name: str): cfm = conf_manager.ConfManager( session_key, ADDON_NAME, - realm=f"__REST_CREDENTIAL__#{ADDON_NAME}#configs/conf-demo_addon_for_splunk_account", + realm=f"__REST_CREDENTIAL__#{ADDON_NAME}#configs/conf-demo-addon-for-splunk_account", ) - account_conf_file = cfm.get_conf("demo_addon_for_splunk_account") + account_conf_file = cfm.get_conf("demo-addon-for-splunk_account") return account_conf_file.get(account_name).get("api_key") @@ -61,7 +60,7 @@ def stream_events(inputs: smi.InputDefinition, event_writer: smi.EventWriter): logger=logger, session_key=session_key, app_name=ADDON_NAME, - conf_name=f"{ADDON_NAME}_settings", + conf_name="demo-addon-for-splunk_settings", ) logger.setLevel(log_level) log.modular_input_start(logger, normalized_input_name) diff --git a/tests/unit/commands/test_build.py b/tests/unit/commands/test_build.py index b17d977f5..0452a4825 100644 --- a/tests/unit/commands/test_build.py +++ b/tests/unit/commands/test_build.py @@ -1,6 +1,5 @@ import os from unittest.mock import MagicMock, patch - import pytest from splunk_add_on_ucc_framework.commands.build import ( @@ -8,6 +7,7 @@ _get_build_output_path, _get_python_version_from_executable, _get_and_check_global_config_path, + generate, ) from splunk_add_on_ucc_framework.exceptions import ( CouldNotIdentifyPythonVersionException, @@ -147,3 +147,48 @@ def test_add_modular_input(GlobalConfig, tmp_path): helper_path = tmp_path / ta_name / "bin" / "example_helper.py" assert input_path.is_file() assert helper_path.is_file() + + +@patch("splunk_add_on_ucc_framework.global_config.GlobalConfig") +@patch("splunk_add_on_ucc_framework.commands.build._get_app_manifest") +@patch("splunk_add_on_ucc_framework.commands.build._get_and_check_global_config_path") +@patch("os.path.exists") +@patch( + "splunk_add_on_ucc_framework.commands.build.global_config_update.handle_global_config_update" +) +@patch( + "splunk_add_on_ucc_framework.commands.build.global_config_validator.GlobalConfigValidator.validate" +) +def test_ta_name_mismatch( + mock_GlobalConfigValidator, + mock_global_config_update, + mock_os_path, + mock_get_and_check_global_config_path, + mock_get_app_manifest, + mock_global_config, + caplog, +): + mock_os_path.return_value = True + + mock_app_manifest = MagicMock() + mock_app_manifest.get_addon_name.return_value = "ta_name_1" + mock_get_app_manifest.return_value = mock_app_manifest + + mock_global_config_instance = MagicMock() + mock_global_config_instance.product = "ta_name_2" + mock_get_and_check_global_config_path.return_value = "mock_gc_path" + mock_global_config.return_value = mock_global_config_instance + + mock_global_config_update.return_value = None + mock_GlobalConfigValidator.return_value = True + + with pytest.raises(SystemExit): + generate( + source="source/path", + addon_version="1.0.0", + python_binary_name="python3", + verbose_file_summary_report=False, + pip_version="latest", + pip_legacy_resolver=False, + ui_source_map=False, + ) diff --git a/tests/unit/commands/test_init.py b/tests/unit/commands/test_init.py index 7b9ae8c0f..74bcf3166 100644 --- a/tests/unit/commands/test_init.py +++ b/tests/unit/commands/test_init.py @@ -1,5 +1,6 @@ from unittest import mock - +import tests.unit.helpers as helpers +import json import pytest from splunk_add_on_ucc_framework.commands import init @@ -11,6 +12,37 @@ ("test-addon", True), ("demo_addon", True), ("foo/bar/baz", False), + ("Test.", False), + ("12Test", False), + ("test-addon-123", True), + ("test.tar", False), + ("test.tgz", False), + ("test.tar.gz", False), + ("test.spl", False), + ("CON", False), + ("PRN", False), + ("AUX", False), + ("NUL", False), + ("COM1", False), + ("COM2", False), + ("COM3", False), + ("COM4", False), + ("COM5", False), + ("COM6", False), + ("COM7", False), + ("COM8", False), + ("COM9", False), + ("LPT1", False), + ("LPT2", False), + ("LPT3", False), + ("LPT4", False), + ("LPT5", False), + ("LPT6", False), + ("LPT7", False), + ("LPT8", False), + ("LPT9", False), + ("test@add-on", False), + ("test.add-on_123_", True), ], ) def test__is_valid_addon_name(addon_name, expected): @@ -20,8 +52,11 @@ def test__is_valid_addon_name(addon_name, expected): @pytest.mark.parametrize( "rest_root,expected", [ - ("test-addon", False), + ("test-addon", True), ("demo_addon", True), + ("test@addon", False), + ("Test!_addon", False), + ("test-addon_123", True), ], ) def test__is_valid_rest_root(rest_root, expected): @@ -115,7 +150,7 @@ def test_init(mock_generate_addon, init_kwargs, expected_args_to_generate_addon) ), ( { - "addon_name": "addon-name", + "addon_name": "addon-name()", "addon_display_name": "Addon For Demo", "addon_input_name": "input_name", "addon_version": "0.0.1", @@ -124,7 +159,7 @@ def test_init(mock_generate_addon, init_kwargs, expected_args_to_generate_addon) ( { "addon_name": "addon_name", - "addon_rest_root": "addon-name", + "addon_rest_root": "addon!name", "addon_display_name": "Addon For Demo", "addon_input_name": "input_name", "addon_version": "0.0.1", @@ -135,7 +170,7 @@ def test_init(mock_generate_addon, init_kwargs, expected_args_to_generate_addon) "addon_name": "addon_name", "addon_rest_root": "addon_rest_root", "addon_display_name": "Addon For Demo", - "addon_input_name": "foo" * 51, + "addon_input_name": "x" * 51, "addon_version": "0.0.1", } ), @@ -162,3 +197,18 @@ def test_init_when_folder_already_exists(mock_generate_addon, caplog): "option to overwrite the content of existing folder." ) assert expected_error_message in caplog.text + + +def test_valid_regex(): + file_path = f"{helpers.get_path_to_source_dir()}/schema/schema.json" + with open(file_path) as file: + content = file.read() + schema_json_content = json.loads(content) + restRoot_regex = schema_json_content["definitions"]["Meta"]["properties"][ + "restRoot" + ]["pattern"] + name_regex = schema_json_content["definitions"]["Meta"]["properties"]["name"][ + "pattern" + ] + assert init.ADDON_REST_ROOT_RE_STR == restRoot_regex + assert init.ADDON_NAME_RE_STR == name_regex