def test_is_valid_deprecated_playbook(self, current, answer): """ Given 1. A deprecated playbook with a valid description according to 'deprecated regex' (including the replacement playbook name). 2. A deprecated playbook with a valid description according to the 'deprecated no replacement regex'. 3. A deprecated playbook with a valid description according to 'deprecated regex' (including the replacement playbook name, and the reason for deprecation.). 4. A deprecated playbook with an invalid description that isn't according to the 'deprecated regex' (doesn't include a replacement playbook name, or declare there isn't a replacement). 5. A deprecated playbook with an invalid description that isn't according to the 'deprecated regex' (doesn't start with the phrase: 'Deprecated.'). 6. A deprecated playbook with an invalid description that isn't according to the 'deprecated regex' (Includes the reason for deprecation, but doesn't include a replacement playbook name, or declare there isn't a replacement). When - running is_valid_as_deprecated. Then - a playbook with an invalid description will be errored. """ structure = mock_structure("", current) validator = PlaybookValidator(structure) validator.current_file = current assert validator.is_valid_as_deprecated() is answer
def test_is_condition_branches_handled(self, source, answer): # type: (str, str, Any) -> None try: copyfile(source, PLAYBOOK_TARGET) structure = StructureValidator(source) validator = PlaybookValidator(structure) assert validator.is_condition_branches_handled() is answer finally: os.remove(PLAYBOOK_TARGET)
def test_is_root_connected_to_all_tasks(self, source, answer): # type: (str, str, Any) -> None try: copyfile(source, PLAYBOOK_TARGET) structure = StructureValidator(source) validator = PlaybookValidator(structure) assert validator.is_root_connected_to_all_tasks() is answer finally: os.remove(PLAYBOOK_TARGET)
def test_verify_all_conditional_tasks_has_else_path(self, playbook_json, expected_result): """ Given - A playbook with a condition without a default task When - Running Validate playbook Then - Function returns true as this is an ignored error. """ structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.verify_condition_tasks_has_else_path() is expected_result
def test_is_delete_context_all_in_playbook(self, playbook_json, expected_result): """ Given - A playbook When - The playbook have deleteContext script use with all=yes Then - Ensure that the validation fails when all=yes arg exists. """ structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_delete_context_all_in_playbook() is expected_result
def test_verify_else_for_conditions_task(self, playbook_task_json, expected_result): """ Given - A playbook condition task with a default task - A playbook condition task without a default task When - Running Validate playbook Then - Return True if the condition task has default path , else false """ structure = mock_structure("", playbook_task_json) validator = PlaybookValidator(structure) assert validator._is_else_path_in_condition_task(task=playbook_task_json) is expected_result
def test_skipping_test_playbooks(self, playbook_path, expected_result): """ Given - A playbook When - The playbook has unhandled condition in it Then - Ensure the unhandled condition is ignored if it's a test playbook - Ensure validation fails if it's a not test playbook """ structure = StructureValidator(file_path=playbook_path) validator = PlaybookValidator(structure) assert validator.is_valid_playbook() is expected_result
def test_is_id_uuid(self, playbook_json, expected_result): """ Given - A playbook When - The playbook include taskid and inside task field an id that are both from uuid type. - The playbook include taskid and inside task field an id that are not both from uuid type. Then - Ensure validation passes if the taskid field and the id inside task field are both from uuid type - Ensure validation fails if the taskid field and the id inside task field are one of them not from uuid type """ structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) validator._is_id_uuid() is expected_result
def test_is_taskid_equals_id(self, playbook_json, expected_result): """ Given - A playbook When - The playbook include taskid and inside task field an id that are both have the same value. - The playbook include taskid and inside task field an id that are different values. Then - Ensure validation passes if the taskid field and the id inside task field have the same value - Ensure validation fails if the taskid field and the id inside task field are have different value """ structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) validator._is_taskid_equals_id() is expected_result
def test_is_using_instance(self, playbook_json, expected_result): """ Given - A playbook When - The playbook has a using specific instance. - The playbook doestnt have using in it. Then - Ensure validation fails if it's a not test playbook - Ensure that the validataion passes if no using usage. """ structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_using_instance() is expected_result
def test_name_does_not_contains_the_type(self, pack): """ Given - An playbook with a name that does not contains the "playbook" string. When - running name_not_contain_the_type. Then - Ensure the validate passes. """ playbook = pack.create_playbook(yml={"name": "test"}) with ChangeCWD(pack.repo_path): structure_validator = StructureValidator(playbook.yml.path) validator = PlaybookValidator(structure_validator) assert validator.name_not_contain_the_type()
def test_skipping_test_playbooks(self, mocker, playbook_path, expected_result): """ Given - A playbook When - The playbook has unhandled condition in it Then - Ensure the unhandled condition is ignored if it's a test playbook - Ensure validation fails if it's a not test playbook """ structure = StructureValidator(file_path=playbook_path) validator = PlaybookValidator(structure) mocker.patch.object(validator, 'is_script_id_valid', return_value=True) assert validator.is_valid_playbook() is expected_result
def test_playbook_script_id(self, mocker, playbook, repo, playbook_json, id_set_json, expected_result): """ Given - A playbook with scrips ids or script names - An id_set file. When - validating playbook Then - In case script id or script name don't exist in id_set , prints a warning. """ playbook.yml.write_dict(playbook_json) repo.id_set.write_json(id_set_json) structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_script_id_valid(id_set_json) == expected_result
def test_validation_of_beta_playbooks(self, mocker): """ Given - A beta playbook with 'beta: true in it's root When - Running validation on it with PlaybookValidator Then - Ensure it accepts the 'beta' key as valid """ try: copyfile(VALID_BETA_PLAYBOOK_PATH, PLAYBOOK_TARGET) structure = StructureValidator(VALID_BETA_PLAYBOOK_PATH, predefined_scheme='playbook') validator = PlaybookValidator(structure) assert validator.is_valid_playbook(validate_rn=False) finally: os.remove(PLAYBOOK_TARGET)
def test_is_valid_with_indicators_input(self, playbook_json, expected_result): """ Given - A playbook When - The playbook with input from indicators, includes all valid fields. - The playbook with input from indicators, is not set on quietmode. - The playbook with input from indicators, one of the tasks does not have quiet mode on. - The playbook with input from indicators, one of the tasks continues on error Then - Ensure validation passes. - Ensure validation fails. - Ensure validation fails. - Ensure validation fails. """ structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_valid_with_indicators_input() is expected_result
def test_validate_readme_exists(self, repo, remove_readme, validate_all, expected_result): """ Given: - An integration yml that was added or modified to validate When: - The integration is missing a readme.md file in the same folder - The integration has a readme.md file in the same folder - The integration is missing a readme.md file in the same folder but has not been changed or added (This check is for backward compatibility) Then: - Ensure readme exists and validation fails - Ensure readme exists and validation passes - Ensure readme exists and validation passes """ read_me_pack = repo.create_pack('README_test') playbook = read_me_pack.create_playbook('playbook1') structure_validator = StructureValidator(playbook.yml.path) playbook_validator = PlaybookValidator(structure_validator, validate_all=validate_all) if remove_readme: os.remove(playbook.readme.path) assert playbook_validator.validate_readme_exists(playbook_validator.validate_all) is expected_result
def run_all_validations_on_file(self, file_path: str, file_type: str = None) -> None: """ Runs all validations on file specified in 'file_path' Args: file_path: A relative content path to a file to be validated file_type: The output of 'find_type' method """ file_extension = os.path.splitext(file_path)[-1] # We validate only yml json and .md files if file_extension not in ['.yml', '.json', '.md']: return # Ignoring changelog and description files since these are checked on the integration validation if 'changelog' in file_path.lower( ) or 'description' in file_path.lower(): return # unified files should not be validated if file_path.endswith('_unified.yml'): return print(f'Validating {file_path}') if 'README' in file_path: readme_validator = ReadMeValidator(file_path) if not readme_validator.is_valid_file(): self._is_valid = False return structure_validator = StructureValidator(file_path, predefined_scheme=file_type) if not structure_validator.is_valid_file(): self._is_valid = False elif re.match(TEST_PLAYBOOK_REGEX, file_path, re.IGNORECASE): playbook_validator = PlaybookValidator(structure_validator) if not playbook_validator.is_valid_playbook(): self._is_valid = False elif re.match(PLAYBOOK_REGEX, file_path, re.IGNORECASE) or file_type == 'playbook': playbook_validator = PlaybookValidator(structure_validator) if not playbook_validator.is_valid_playbook(validate_rn=False): self._is_valid = False elif checked_type(file_path, INTEGRATION_REGXES) or file_type == 'integration': integration_validator = IntegrationValidator(structure_validator) if not integration_validator.is_valid_file(validate_rn=False): self._is_valid = False elif checked_type(file_path, YML_ALL_SCRIPTS_REGEXES) or file_type == 'script': # Set file path to the yml file structure_validator.file_path = file_path script_validator = ScriptValidator(structure_validator) if not script_validator.is_valid_file(validate_rn=False): self._is_valid = False elif checked_type(file_path, YML_BETA_INTEGRATIONS_REGEXES ) or file_type == 'betaintegration': integration_validator = IntegrationValidator(structure_validator) if not integration_validator.is_valid_beta_integration(): self._is_valid = False # incident fields and indicator fields are using the same scheme. elif checked_type(file_path, JSON_INDICATOR_AND_INCIDENT_FIELDS) or \ file_type in ('incidentfield', 'indicatorfield'): incident_field_validator = IncidentFieldValidator( structure_validator) if not incident_field_validator.is_valid_file(validate_rn=False): self._is_valid = False elif checked_type( file_path, JSON_ALL_INDICATOR_TYPES_REGEXES) or file_type == 'reputation': reputation_validator = ReputationValidator(structure_validator) if not reputation_validator.is_valid_file(validate_rn=False): self._is_valid = False elif checked_type(file_path, JSON_ALL_LAYOUT_REGEXES) or file_type == 'layout': layout_validator = LayoutValidator(structure_validator) if not layout_validator.is_valid_layout(validate_rn=False): self._is_valid = False elif checked_type( file_path, JSON_ALL_DASHBOARDS_REGEXES) or file_type == 'dashboard': dashboard_validator = DashboardValidator(structure_validator) if not dashboard_validator.is_valid_dashboard(validate_rn=False): self._is_valid = False elif checked_type(file_path, JSON_ALL_INCIDENT_TYPES_REGEXES ) or file_type == 'incidenttype': incident_type_validator = IncidentTypeValidator( structure_validator) if not incident_type_validator.is_valid_incident_type( validate_rn=False): self._is_valid = False elif checked_type(file_path, CHECKED_TYPES_REGEXES): print(f'Could not find validations for file {file_path}') else: print_error( 'The file type of {} is not supported in validate command'. format(file_path)) print_error( 'validate command supports: Integrations, Scripts, Playbooks, dashboards, incident types, ' 'reputations, Incident fields, Indicator fields, Images, Release notes, ' 'Layouts and Descriptions') self._is_valid = False
def test_is_added_required_fields(self, playbook_json, expected_result): structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_no_rolename() is expected_result
def test_is_root_connected_to_all_tasks(self, playbook_json, expected_result): structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_root_connected_to_all_tasks() is expected_result
def validate_added_files(self, added_files): # noqa: C901 """Validate the added files from your branch. In case we encounter an invalid file we set the self._is_valid param to False. Args: added_files (set): A set of the modified files in the current branch. """ for file_path in added_files: print('Validating {}'.format(file_path)) if re.match(TEST_PLAYBOOK_REGEX, file_path, re.IGNORECASE): continue structure_validator = StructureValidator(file_path, is_new_file=True) if not structure_validator.is_valid_file(): self._is_valid = False if self.validate_id_set: if not self.id_set_validator.is_file_valid_in_set(file_path): self._is_valid = False if self.id_set_validator.is_file_has_used_id(file_path): self._is_valid = False elif re.match(PLAYBOOK_REGEX, file_path, re.IGNORECASE): playbook_validator = PlaybookValidator(structure_validator) if not playbook_validator.is_valid_playbook(): self._is_valid = False elif checked_type(file_path, YML_INTEGRATION_REGEXES): image_validator = ImageValidator(file_path) if not image_validator.is_valid(): self._is_valid = False description_validator = DescriptionValidator(file_path) if not description_validator.is_valid(): self._is_valid = False integration_validator = IntegrationValidator(structure_validator) if not integration_validator.is_valid_file(validate_rn=False): self._is_valid = False elif checked_type(file_path, PACKAGE_SCRIPTS_REGEXES): unifier = Unifier(os.path.dirname(file_path)) yml_path, _ = unifier.get_script_package_data() # Set file path to the yml file structure_validator.file_path = yml_path script_validator = ScriptValidator(structure_validator) if not script_validator.is_valid_file(validate_rn=False): self._is_valid = False elif re.match(BETA_INTEGRATION_REGEX, file_path, re.IGNORECASE) or \ re.match(BETA_INTEGRATION_YML_REGEX, file_path, re.IGNORECASE): description_validator = DescriptionValidator(file_path) if not description_validator.is_valid_beta_description(): self._is_valid = False integration_validator = IntegrationValidator(structure_validator) if not integration_validator.is_valid_beta_integration(): self._is_valid = False elif re.match(IMAGE_REGEX, file_path, re.IGNORECASE): image_validator = ImageValidator(file_path) if not image_validator.is_valid(): self._is_valid = False # incident fields and indicator fields are using the same scheme. elif checked_type(file_path, JSON_INDICATOR_AND_INCIDENT_FIELDS): incident_field_validator = IncidentFieldValidator(structure_validator) if not incident_field_validator.is_valid_file(): self._is_valid = False elif checked_type(file_path, JSON_ALL_LAYOUT_REGEXES): layout_validator = LayoutValidator(structure_validator) if not layout_validator.is_valid_layout(): self._is_valid = False elif 'CHANGELOG' in file_path: self.is_valid_release_notes(file_path) elif checked_type(file_path, [REPUTATION_REGEX]): print_color( F'Skipping validation for file {file_path} since no validation is currently defined.', LOG_COLORS.YELLOW) elif checked_type(file_path, CHECKED_TYPES_REGEXES): pass else: print_error("The file type of {} is not supported in validate command".format(file_path)) print_error("validate command supports: Integrations, Scripts, Playbooks, " "Incident fields, Indicator fields, Images, Release notes, Layouts and Descriptions") self._is_valid = False
def test_is_condition_branches_handled(self, playbook_json, expected_result): structure = mock_structure("", playbook_json) validator = PlaybookValidator(structure) assert validator.is_condition_branches_handled() is expected_result
def validate_modified_files(self, modified_files): # noqa: C901 """Validate the modified files from your branch. In case we encounter an invalid file we set the self._is_valid param to False. Args: modified_files (set): A set of the modified files in the current branch. """ for file_path in modified_files: old_file_path = None if isinstance(file_path, tuple): old_file_path, file_path = file_path print('Validating {}'.format(file_path)) if not checked_type(file_path): print_warning( '- Skipping validation of non-content entity file.') continue if re.match(TEST_PLAYBOOK_REGEX, file_path, re.IGNORECASE): continue elif 'README' in file_path: readme_validator = ReadMeValidator(file_path) if not readme_validator.is_valid_file(): self._is_valid = False continue structure_validator = StructureValidator( file_path, old_file_path=old_file_path) if not structure_validator.is_valid_file(): self._is_valid = False if self.validate_id_set: if not self.id_set_validator.is_file_valid_in_set(file_path): self._is_valid = False elif checked_type(file_path, YML_INTEGRATION_REGEXES): image_validator = ImageValidator(file_path) if not image_validator.is_valid(): self._is_valid = False description_validator = DescriptionValidator(file_path) if not description_validator.is_valid(): self._is_valid = False integration_validator = IntegrationValidator( structure_validator) if self.is_backward_check and not integration_validator.is_backward_compatible( ): self._is_valid = False if not integration_validator.is_valid_file(): self._is_valid = False elif checked_type(file_path, YML_BETA_INTEGRATIONS_REGEXES): image_validator = ImageValidator(file_path) if not image_validator.is_valid(): self._is_valid = False description_validator = DescriptionValidator(file_path) if not description_validator.is_valid_beta_description(): self._is_valid = False integration_validator = IntegrationValidator( structure_validator) if not integration_validator.is_valid_beta_integration(): self._is_valid = False elif checked_type(file_path, [SCRIPT_REGEX]): script_validator = ScriptValidator(structure_validator) if self.is_backward_check and not script_validator.is_backward_compatible( ): self._is_valid = False if not script_validator.is_valid_file(): self._is_valid = False elif checked_type(file_path, PLAYBOOKS_REGEXES_LIST): playbook_validator = PlaybookValidator(structure_validator) if not playbook_validator.is_valid_playbook( is_new_playbook=False): self._is_valid = False elif checked_type(file_path, PACKAGE_SCRIPTS_REGEXES): unifier = Unifier(os.path.dirname(file_path)) yml_path, _ = unifier.get_script_package_data() # Set file path to the yml file structure_validator.file_path = yml_path script_validator = ScriptValidator(structure_validator) if self.is_backward_check and not script_validator.is_backward_compatible( ): self._is_valid = False if not script_validator.is_valid_file(): self._is_valid = False elif re.match(IMAGE_REGEX, file_path, re.IGNORECASE): image_validator = ImageValidator(file_path) if not image_validator.is_valid(): self._is_valid = False # incident fields and indicator fields are using the same scheme. elif checked_type(file_path, JSON_INDICATOR_AND_INCIDENT_FIELDS): incident_field_validator = IncidentFieldValidator( structure_validator) if not incident_field_validator.is_valid_file( validate_rn=True): self._is_valid = False if self.is_backward_check and not incident_field_validator.is_backward_compatible( ): self._is_valid = False elif checked_type(file_path, [REPUTATION_REGEX]): reputation_validator = ReputationValidator(structure_validator) if not reputation_validator.is_valid_file(validate_rn=True): self._is_valid = False elif checked_type(file_path, JSON_ALL_LAYOUT_REGEXES): layout_validator = LayoutValidator(structure_validator) if not layout_validator.is_valid_layout(validate_rn=True): self._is_valid = False elif checked_type(file_path, JSON_ALL_DASHBOARDS_REGEXES): dashboard_validator = DashboardValidator(structure_validator) if not dashboard_validator.is_valid_dashboard( validate_rn=True): self._is_valid = False elif checked_type(file_path, JSON_ALL_INCIDENT_TYPES_REGEXES): incident_type_validator = IncidentTypeValidator( structure_validator) if not incident_type_validator.is_valid_incident_type( validate_rn=True): self._is_valid = False if self.is_backward_check and not incident_type_validator.is_backward_compatible( ): self._is_valid = False elif 'CHANGELOG' in file_path: self.is_valid_release_notes(file_path) elif checked_type(file_path, CHECKED_TYPES_REGEXES): pass else: print_error( "The file type of {} is not supported in validate command". format(file_path)) print_error( "'validate' command supports: Integrations, Scripts, Playbooks, " "Incident fields, Indicator fields, Images, Release notes, Layouts and Descriptions" ) self._is_valid = False
def validate_added_files(self, added_files, file_type: str = None): # noqa: C901 """Validate the added files from your branch. In case we encounter an invalid file we set the self._is_valid param to False. Args: added_files (set): A set of the modified files in the current branch. file_type (str): Used only with -p flag (the type of the file). """ for file_path in added_files: print('Validating {}'.format(file_path)) if re.match(TEST_PLAYBOOK_REGEX, file_path, re.IGNORECASE) and not file_type: continue elif 'README' in file_path: readme_validator = ReadMeValidator(file_path) if not readme_validator.is_valid_file(): self._is_valid = False continue structure_validator = StructureValidator( file_path, is_new_file=True, predefined_scheme=file_type) if not structure_validator.is_valid_file(): self._is_valid = False if self.validate_id_set: if not self.id_set_validator.is_file_valid_in_set(file_path): self._is_valid = False if self.id_set_validator.is_file_has_used_id(file_path): self._is_valid = False elif re.match(PLAYBOOK_REGEX, file_path, re.IGNORECASE) or file_type == 'playbook': playbook_validator = PlaybookValidator(structure_validator) if not playbook_validator.is_valid_playbook(): self._is_valid = False elif checked_type( file_path, YML_INTEGRATION_REGEXES) or file_type == 'integration': image_validator = ImageValidator(file_path) # if file_type(non git path) the image is not in a separate path image_validator.file_path = file_path if file_type else image_validator.file_path if not image_validator.is_valid(): self._is_valid = False description_validator = DescriptionValidator(file_path) if not description_validator.is_valid(): self._is_valid = False integration_validator = IntegrationValidator( structure_validator) if not integration_validator.is_valid_file( validate_rn=not file_type): self._is_valid = False elif checked_type( file_path, PACKAGE_SCRIPTS_REGEXES) or file_type == 'script': unifier = Unifier(os.path.dirname(file_path)) yml_path, _ = unifier.get_script_package_data() # Set file path to the yml file structure_validator.file_path = yml_path script_validator = ScriptValidator(structure_validator) if not script_validator.is_valid_file( validate_rn=not file_type): self._is_valid = False elif re.match(BETA_INTEGRATION_REGEX, file_path, re.IGNORECASE) or \ re.match(BETA_INTEGRATION_YML_REGEX, file_path, re.IGNORECASE): description_validator = DescriptionValidator(file_path) if not description_validator.is_valid_beta_description(): self._is_valid = False integration_validator = IntegrationValidator( structure_validator) if not integration_validator.is_valid_beta_integration(): self._is_valid = False elif re.match(IMAGE_REGEX, file_path, re.IGNORECASE): image_validator = ImageValidator(file_path) if not image_validator.is_valid(): self._is_valid = False # incident fields and indicator fields are using the same scheme. elif checked_type(file_path, JSON_INDICATOR_AND_INCIDENT_FIELDS) or \ file_type in ('incidentfield', 'indicatorfield'): incident_field_validator = IncidentFieldValidator( structure_validator) if not incident_field_validator.is_valid_file( validate_rn=not file_type): self._is_valid = False elif checked_type(file_path, [REPUTATION_REGEX]) or file_type == 'reputation': reputation_validator = ReputationValidator(structure_validator) if not reputation_validator.is_valid_file( validate_rn=not file_type): self._is_valid = False elif checked_type( file_path, JSON_ALL_LAYOUT_REGEXES) or file_type == 'layout': layout_validator = LayoutValidator(structure_validator) if not layout_validator.is_valid_layout( validate_rn=not file_type): self._is_valid = False elif checked_type( file_path, JSON_ALL_DASHBOARDS_REGEXES) or file_type == 'dashboard': dashboard_validator = DashboardValidator(structure_validator) if not dashboard_validator.is_valid_dashboard( validate_rn=not file_type): self._is_valid = False elif checked_type(file_path, JSON_ALL_INCIDENT_TYPES_REGEXES): incident_type_validator = IncidentTypeValidator( structure_validator) if not incident_type_validator.is_valid_incident_type( validate_rn=not file_type): self._is_valid = False elif 'CHANGELOG' in file_path: self.is_valid_release_notes(file_path) elif checked_type(file_path, CHECKED_TYPES_REGEXES): pass else: print_error( "The file type of {} is not supported in validate command". format(file_path)) print_error( "validate command supports: Integrations, Scripts, Playbooks, " "Incident fields, Indicator fields, Images, Release notes, Layouts and Descriptions" ) self._is_valid = False
def validate_playbook(self, structure_validator, pack_error_ignore_list): playbook_validator = PlaybookValidator(structure_validator, ignored_errors=pack_error_ignore_list, print_as_warnings=self.print_ignored_errors) return playbook_validator.is_valid_playbook(validate_rn=False)