示例#1
0
    def validate_dictionary(dict_, dict_key):
        if dict_key in dict_:
            if not dict_[dict_key]:
                return

            for key, value in dict_[dict_key].items():
                if "name" in value:
                    raise ValidationException(
                        f"Deprecated 'name' key '{value}' found when 'title' should be used instead."
                    )
                if "title" in value:
                    try:
                        TitleValidator.validate_title(value["title"],
                                                      plugin_title=False)
                    except Exception as e:
                        raise ValidationException(
                            f"{dict_key} key '{key}' error.", e)
示例#2
0
 def compare_encodings(key, value):
     unicode_string = str(value)
     decoded_string = unicode_string.encode("ascii",
                                            "ignore").decode("utf-8")
     if unicode_string != decoded_string:
         raise ValidationException(
             f"A forbidden character was found in the '{key}' field of the workflow.spec.yaml file: {value}"
         )
示例#3
0
 def validate_version(version):
     if re.match("[1-9]+.[0-9]+.[0-9]+$", version) is None:
         raise ValidationException(
             "Version does not match required semver format. "
             "Version should be in form X.Y.Z with X, Y, and Z "
             "being numbers. No special characters or spaces allowed. "
             "Versions start at 1.0.0, see https://semver.org/ for more information."
         )
示例#4
0
 def validate(self, plugin_spec):
     cloud_ready = plugin_spec.spec_dictionary().get("cloud_ready")
     connection = plugin_spec.spec_dictionary().get("connection")
     if cloud_ready and connection:
         for key in connection:
             if connection[key].get("type") == "credential_token":
                 raise ValidationException(
                     "Cloud plugin connection does not support credential_token yet."
                 )
 def check_new_inputs_outputs(self, remote: dict, local: dict,
                              input_output: str):
     # remote, local are dictionaries of action or trigger inputs or outputs
     if input_output in local:
         for inner_key in local[input_output]:
             if inner_key not in remote[input_output]:
                 raise ValidationException(
                     f"New {input_output} added without incrementing minor version."
                     f"{self.MINOR_INSTRUCTIONS_STRING}")
 def validate_help_exists(spec):
     """
     Checks that 'help' is not in .yaml
     In old code help was included in the yaml. It should no longer be there
     """
     if "help" in spec:
         raise ValidationException(
             "Help section should exist in help.md and not in the workflow.spec.yaml file."
         )
示例#7
0
 def validate_version_quotes(spec):
     """Requires raw spec to see the quotes"""
     for line in spec.splitlines():
         if line.startswith("version:"):
             val = line[line.find(" ") + 1:]
             if "'" in val or '"' in val:
                 raise ValidationException(
                     "Vendor is surrounded by or contains quotes when it should not."
                 )
示例#8
0
    def check_icon_less_than_equal_70kb(plugin_spec):
        directory = plugin_spec.directory
        icon_file = directory + "/" + "icon.png"

        info = os.stat(icon_file)
        if info.st_size >= 70000:
            raise ValidationException(
                f"Included icon ({info.st_size}) file exceeds maximum size limitation of 70Kb."
            )
示例#9
0
    def _hash_python_setup(self) -> MD5:
        setup_file: str = os.path.join(self.plugin_directory, self._SETUP_PY)

        try:
            with open(file=setup_file, mode="rb") as sf:
                return md5(sf.read()).hexdigest()

        except FileNotFoundError:
            raise ValidationException(f"Fatal: No {self._SETUP_PY} found in Python plugin.")
示例#10
0
    def validate_print(section):
        print_found = False

        for f in section:
            if "print(" in f:
                print_found = True

        if print_found:
            raise ValidationException("One or more files use print statements, update to use self.logger.")
示例#11
0
    def check_extension_image_file_is_nonzero_size(plugin_spec):
        directory = plugin_spec.directory
        extension_image_file = f"{directory}/extension.png"

        image_file = os.stat(extension_image_file)
        if not image_file.st_size > 0:
            raise ValidationException(
                "Extension image file is size zero. Please include a color PNG image of a logo for this vendor or product."
            )
示例#12
0
    def _hash_python_spec(self) -> MD5:
        spec_file: str = os.path.join(self.plugin_directory, "plugin.spec.yaml")

        try:
            with open(file=spec_file, mode="rb") as sf:
                return md5(sf.read()).hexdigest()

        except FileNotFoundError:
            raise ValidationException("Fatal: No plugin spec found in Python plugin.")
示例#13
0
    def _hash_python_manifest(self) -> MD5:
        manifest_directory: str = os.path.join(self.plugin_directory, "bin")
        try:
            manifest_file: str = os.path.join(manifest_directory, os.listdir(manifest_directory)[0])
            with open(file=manifest_file, mode="rb") as mf:
                return md5(mf.read()).hexdigest()

        except (FileNotFoundError, IndexError):
            raise ValidationException("Fatal: No binfile found in Python plugin.")
示例#14
0
    def check_if_extension_image_file_exists(plugin_spec):
        directory = plugin_spec.directory
        extension_image_file = f"{directory}/extension.png"

        file_item = Path(extension_image_file)
        if not file_item.is_file():
            raise ValidationException(
                "extension.png file not included in plugin. Please include a color PNG image of a logo for this vendor or product."
            )
    def get_versions(help_content):
        raw_versions = re.findall(r"Version History\n\n.*?\n\n", help_content,
                                  re.DOTALL)
        if not raw_versions:
            raise ValidationException("Incorrect Version History in help.md.")

        versions_history = raw_versions[0].replace("Version History\n\n",
                                                   "").replace("\n\n",
                                                               "").split("\n")
        return versions_history
 def validate(self, spec):
     workflow_file = WorkflowHelpPluginUtilizationValidator.load_workflow_file(
         spec)
     workflow = WorkflowHelpPluginUtilizationValidator.extract_workflow(
         workflow_file)
     plugins_used = WorkflowHelpPluginUtilizationValidator.extract_plugins_used(
         workflow)
     plugin_in_help = WorkflowHelpPluginUtilizationValidator.extract_plugins_in_help(
         spec.raw_help())
     for plugin in plugins_used:
         if plugin not in plugin_in_help:
             raise ValidationException(
                 "The following plugin was found in the .icon file,"
                 f" but not in the help file {plugin}")
     for plugin in plugin_in_help:
         if plugin not in plugins_used:
             raise ValidationException(
                 "The following plugin was found in the help file,"
                 f" but not in the .icon file {plugin}")
 def validate(self, spec):
     """
     Checks that .icon file names do not contain spaces
     """
     d = spec.directory
     for file_name in os.listdir(d):
         if file_name.endswith(".icon"):
             if " " in file_name:
                 raise ValidationException(f"The .icon file name was '{file_name}'.\n "
                                           ".icon file may not contain spaces use a '_' instead.")
 def validate_no_input_new_or_required(self, remote: dict, local: dict):
     # operates on dictionary of individual action/trigger/task
     for input_key, input_value in local[SpecConstants.INPUT].items():
         if input_value.get(SpecConstants.REQUIRED):
             if input_key not in remote[SpecConstants.INPUT] or \
               not remote[SpecConstants.INPUT][input_key].get(SpecConstants.REQUIRED, False):
                 raise ValidationException(
                     f"Input has been added or changed to required in {input_key} without"
                     f" a major version increment."
                     f"{self.MAJOR_INSTRUCTIONS_STRING}")
示例#19
0
 def validate(self, spec):
     """
     Checks that the name key in .yaml is the same as the name of the .icon file without the .icon part
     """
     d = spec.directory
     icon_file = ""
     for file_name in listdir(d):
         if file_name.endswith(".icon"):
             icon_file = file_name[:-5]
     if "name" not in spec.spec_dictionary():
         raise ValidationException(
             "The workflow name is missing in workflow.spec.yaml.")
     if not isinstance(spec.spec_dictionary()["name"], str):
         raise ValidationException(
             "The workflow name does not contain a string.")
     name = spec.spec_dictionary()["name"]
     if not name == icon_file:
         raise ValidationException(
             f"The workflow name in workflow.spec.yaml ({name}) and the name of the "
             f".icon workflow file ({icon_file}) do not match.")
    def validate_duplicate_headings(help_raw: str):
        header_errors = []
        for header in HelpValidator.HELP_HEADERS_LIST:
            normalize_header = header.strip(" #")
            pattern = re.compile(f"#[ ]*{normalize_header}")
            if len(pattern.findall(help_raw)) > 1:
                header_errors.append(f"Please check {header} headings and remove duplicates.")

        if header_errors:
            joined_errors = "\n".join(header_errors)
            raise ValidationException(f"More than one headings in type was found. \n{joined_errors}")
示例#21
0
 def validate(self, spec):
     """
     Check that the extension.png file is the correct file
     """
     d = spec.directory
     hasher = sha256()
     try:
         with open(f"{d}/extension.png", "rb") as file:
             temp = file.read()
             hasher.update(temp)
         hash_ = hasher.hexdigest()
         if not hash_ == self._GOOD_HASH:
             raise ValidationException(
                 "The extension.png file in the workflow directory is incorrect."
                 " The file should have a SHA256 hash of"
                 f" {self._GOOD_HASH}."
                 f" The hash of the provided file was {hash_}")
     except FileNotFoundError:
         raise ValidationException(
             "Extension.png is missing from the workflow directory!")
示例#22
0
    def get_icon_steps(spec):
        icon_file = spec.directory
        for file_name in os.listdir(icon_file):
            if file_name.endswith(".icon"):
                data = dict()
                with open(f"{icon_file}/{file_name}") as json_file:
                    try:
                        data = json.load(json_file)
                    except json.JSONDecodeError:
                        raise ValidationException(
                            "ICON file is not in JSON format try exporting the .icon file again"
                        )
                workflow_versions = data.get("kom",
                                             {}).get("workflowVersions", [])
                if workflow_versions:
                    return workflow_versions[0].get("steps")

        raise ValidationException(
            "ICON file is not in JSON format try exporting the .icon file again"
        )
示例#23
0
    def validate(self, spec: KomandPluginSpec):
        ConfidentialValidator.validate_help(spec.directory)
        # ConfidentialValidator.validate_code(spec.directory)
        ConfidentialValidator.validate_tests(spec.directory)

        if len(ConfidentialValidator.violations):
            for violation in ConfidentialValidator.violations:
                print(f"violation: {violation}")
            raise ValidationException(
                f"Please use '*****@*****.**' when including emails. The above items violated this."
            )
示例#24
0
 def validate_title(title, file_type):
     if not isinstance(title, str):
         raise ValidationException(
             f"Title must not be blank in {file_type} file.")
     if title == "":
         raise ValidationException(
             f"Title must not be blank in {file_type} file.")
     if title.endswith("."):
         raise ValidationException(
             f"Title ends with period when it should not in {file_type} file."
         )
     if title[0].islower():
         # This plugin title is OK: minFraud
         # This plugin title is OK: ifconfig.co
         raise ValidationException(
             f"Title should not start with a lower case letter in {file_type} file."
         )
     if title[0].isspace():
         raise ValidationException(
             f"Title should not start with a whitespace character in {file_type} file."
         )
     for word in title.split():
         if not title.startswith(word):
             if word in title_validation_list:
                 raise ValidationException(
                     f"Title contains a capitalized '{word}' when it should not in {file_type} file."
                 )
             elif "By" == word and not title.endswith("By"):
                 # This is OK: Order By
                 # This is NOT OK: Search By String
                 raise ValidationException(
                     f"Title contains a capitalized 'By' when it should not in {file_type} file."
                 )
             elif "Of" == word and not title.endswith("Of"):
                 # This is OK: Member Of
                 # This is NOT OK: Type Of String
                 raise ValidationException(
                     f"Title contains a capitalized 'Of' when it should not in {file_type} file."
                 )
             elif not word[0].isupper() and not word.capitalize(
             ) in title_validation_list:
                 if not word.isnumeric():
                     if not word.lower() == "by" or word.lower() == "of":
                         raise ValidationException(
                             f"Title contains a lowercase '{word}' when it should not in {file_type} file."
                         )
示例#25
0
 def validate(self, spec):
     tests_dir = os.path.join(spec.directory, "tests")
     for path, _, files in os.walk(tests_dir):
         for name in files:
             if name.endswith(".json"):
                 with open(os.path.join(tests_dir, name)) as test:
                     try:
                         json.load(test)
                     except json.decoder.JSONDecodeError:
                         JSONValidator.invalid_files.append(name)
     if len(JSONValidator.invalid_files) > 0:
         raise ValidationException(f"The following test files are not in proper JSON format: {JSONValidator.invalid_files}")
示例#26
0
 def validate_support_quotes(spec):
     """
     Check for quotes around the support.
     """
     # Requires raw spec to see the quotes
     for line in spec.splitlines():
         if line.startswith("support:"):
             val = line[line.find(" ") + 1:]
             if '"' in val or "'" in val:
                 raise ValidationException(
                     "Support is surrounded by or contains quotes when it should not."
                 )
示例#27
0
 def validate_support(support):
     """
     Check that support is not komand.
     Check that support does not end with a .
     Check that support does not start with a capital letter.
     Check that support does not contain spaces.
     """
     lsupport = support.lower()
     if lsupport == "komand":
         raise ValidationException(
             "Support 'komand' not allowed. It's likely you meant 'rapid7'."
         )
     if support.endswith("."):
         raise ValidationException(
             "Support ends with period when it should not.")
     if not support[0].islower():
         raise ValidationException(
             "Support starts with a capital letter when it should not.")
     if " " in support:
         raise ValidationException(
             "Support should be separated by underscores, not spaces.")
 def validate(self, plugin_spec):
     connection = plugin_spec.spec_dictionary().get("connection")
     if connection is None:
         return
     else:
         for key in connection:
             for sub_key in connection[key]:
                 if sub_key == "type":
                     if connection[key][sub_key] == "password":
                         raise ValidationException(
                             "Remove credentials using type 'password' in plugin spec connection."
                             " Use 'credentials' types instead.")
示例#29
0
    def validate(self, spec):
        DescriptionValidator.validate_plugin_description(spec)
        DescriptionValidator.validate_actions(spec.spec_dictionary(),
                                              "actions")
        DescriptionValidator.validate_actions(spec.spec_dictionary(),
                                              "triggers")
        DescriptionValidator.validate_actions(spec.spec_dictionary(), "tasks")

        if DescriptionValidator.errors:
            errors = DescriptionValidator.errors
            DescriptionValidator.errors = []
            raise ValidationException("\n\t\t" + "\n\t\t".join(errors))
示例#30
0
    def _get_python_main_directory(self) -> str:
        """
        Parses a Python plugin and returns the main directory holding all the actions/triggers/tasks/connection/etc
        ie. 'komand_base64'. Note: This does NOT return the directory path - JUST the directory name!
        :return: Main Python plugin directory, ie. 'komand_base64'
        """

        all_ = os.listdir(self.plugin_directory)
        for a in all_:
            if os.path.isdir(a) and self.plugin_name in a:
                return a
        raise ValidationException("Fatal: Python plugin missing main directory.")