diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py')
| -rw-r--r-- | BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py | 444 |
1 files changed, 222 insertions, 222 deletions
diff --git a/BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py b/BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py index 9734478f8b..761b964e58 100644 --- a/BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py +++ b/BaseTools/Plugin/CodeQL/CodeQlAnalyzePlugin.py @@ -1,222 +1,222 @@ -# @file CodeQAnalyzePlugin.py
-#
-# A build plugin that analyzes a CodeQL database.
-#
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-
-import json
-import logging
-import os
-import yaml
-
-from analyze import analyze_filter
-from common import codeql_plugin
-
-from edk2toolext import edk2_logging
-from edk2toolext.environment.plugintypes.uefi_build_plugin import \
- IUefiBuildPlugin
-from edk2toolext.environment.uefi_build import UefiBuilder
-from edk2toollib.uefi.edk2.path_utilities import Edk2Path
-from edk2toollib.utility_functions import RunCmd
-from pathlib import Path
-
-
-class CodeQlAnalyzePlugin(IUefiBuildPlugin):
-
- def do_post_build(self, builder: UefiBuilder) -> int:
- """CodeQL analysis post-build functionality.
-
- Args:
- builder (UefiBuilder): A UEFI builder object for this build.
-
- Returns:
- int: The number of CodeQL errors found. Zero indicates that
- AuditOnly mode is enabled or no failures were found.
- """
- self.builder = builder
- self.package = builder.edk2path.GetContainingPackage(
- builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
- builder.env.GetValue("ACTIVE_PLATFORM")
- )
- )
-
- self.package_path = Path(
- builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath(
- self.package
- )
- )
- self.target = builder.env.GetValue("TARGET")
-
- self.codeql_db_path = codeql_plugin.get_codeql_db_path(
- builder.ws, self.package, self.target,
- new_path=False)
-
- self.codeql_path = codeql_plugin.get_codeql_cli_path()
- if not self.codeql_path:
- logging.critical("CodeQL build enabled but CodeQL CLI application "
- "not found.")
- return -1
-
- codeql_sarif_dir_path = self.codeql_db_path[
- :self.codeql_db_path.rindex('-')]
- codeql_sarif_dir_path = codeql_sarif_dir_path.replace(
- "-db-", "-analysis-")
- self.codeql_sarif_path = os.path.join(
- codeql_sarif_dir_path,
- (os.path.basename(
- self.codeql_db_path) +
- ".sarif"))
-
- edk2_logging.log_progress(f"Analyzing {self.package} ({self.target}) "
- f"CodeQL database at:\n"
- f" {self.codeql_db_path}")
- edk2_logging.log_progress(f"Results will be written to:\n"
- f" {self.codeql_sarif_path}")
-
- # Packages are allowed to specify package-specific query specifiers
- # in the package CI YAML file that override the global query specifier.
- audit_only = False
- query_specifiers = None
- package_config_file = Path(os.path.join(
- self.package_path, self.package + ".ci.yaml"))
- plugin_data = None
- if package_config_file.is_file():
- with open(package_config_file, 'r') as cf:
- package_config_file_data = yaml.safe_load(cf)
- if "CodeQlAnalyze" in package_config_file_data:
- plugin_data = package_config_file_data["CodeQlAnalyze"]
- if "AuditOnly" in plugin_data:
- audit_only = plugin_data["AuditOnly"]
- if "QuerySpecifiers" in plugin_data:
- logging.debug(f"Loading CodeQL query specifiers in "
- f"{str(package_config_file)}")
- query_specifiers = plugin_data["QuerySpecifiers"]
-
- global_audit_only = builder.env.GetValue("STUART_CODEQL_AUDIT_ONLY")
- if global_audit_only:
- if global_audit_only.strip().lower() == "true":
- audit_only = True
-
- if audit_only:
- logging.info(f"CodeQL Analyze plugin is in audit only mode for "
- f"{self.package} ({self.target}).")
-
- # Builds can override the query specifiers defined in this plugin
- # by setting the value in the STUART_CODEQL_QUERY_SPECIFIERS
- # environment variable.
- if not query_specifiers:
- query_specifiers = builder.env.GetValue(
- "STUART_CODEQL_QUERY_SPECIFIERS")
-
- # Use this plugins query set file as the default fallback if it is
- # not overridden. It is possible the file is not present if modified
- # locally. In that case, skip the plugin.
- plugin_query_set = Path(Path(__file__).parent, "CodeQlQueries.qls")
-
- if not query_specifiers and plugin_query_set.is_file():
- query_specifiers = str(plugin_query_set.resolve())
-
- if not query_specifiers:
- logging.warning("Skipping CodeQL analysis since no CodeQL query "
- "specifiers were provided.")
- return 0
-
- codeql_params = (f'database analyze {self.codeql_db_path} '
- f'{query_specifiers} --format=sarifv2.1.0 '
- f'--output={self.codeql_sarif_path} --download '
- f'--threads=0')
-
- # CodeQL requires the sarif file parent directory to exist already.
- Path(self.codeql_sarif_path).parent.mkdir(exist_ok=True, parents=True)
-
- cmd_ret = RunCmd(self.codeql_path, codeql_params)
- if cmd_ret != 0:
- logging.critical(f"CodeQL CLI analysis failed with return code "
- f"{cmd_ret}.")
-
- if not os.path.isfile(self.codeql_sarif_path):
- logging.critical(f"The sarif file {self.codeql_sarif_path} was "
- f"not created. Analysis cannot continue.")
- return -1
-
- filter_pattern_data = []
- global_filter_file_value = builder.env.GetValue(
- "STUART_CODEQL_FILTER_FILES")
- if global_filter_file_value:
- global_filter_files = global_filter_file_value.strip().split(',')
- global_filter_files = [Path(f) for f in global_filter_files]
-
- for global_filter_file in global_filter_files:
- if global_filter_file.is_file():
- with open(global_filter_file, 'r') as ff:
- global_filter_file_data = yaml.safe_load(ff)
- if "Filters" in global_filter_file_data:
- current_pattern_data = \
- global_filter_file_data["Filters"]
- if type(current_pattern_data) is not list:
- logging.critical(
- f"CodeQL pattern data must be a list of "
- f"strings. Data in "
- f"{str(global_filter_file.resolve())} is "
- f"invalid. CodeQL analysis is incomplete.")
- return -1
- filter_pattern_data += current_pattern_data
- else:
- logging.critical(
- f"CodeQL global filter file "
- f"{str(global_filter_file.resolve())} is "
- f"malformed. Missing Filters section. CodeQL "
- f"analysis is incomplete.")
- return -1
- else:
- logging.critical(
- f"CodeQL global filter file "
- f"{str(global_filter_file.resolve())} was not found. "
- f"CodeQL analysis is incomplete.")
- return -1
-
- if plugin_data and "Filters" in plugin_data:
- if type(plugin_data["Filters"]) is not list:
- logging.critical(
- "CodeQL pattern data must be a list of strings. "
- "CodeQL analysis is incomplete.")
- return -1
- filter_pattern_data.extend(plugin_data["Filters"])
-
- if filter_pattern_data:
- logging.info("Applying CodeQL SARIF result filters.")
- analyze_filter.filter_sarif(
- self.codeql_sarif_path,
- self.codeql_sarif_path,
- filter_pattern_data,
- split_lines=False)
-
- with open(self.codeql_sarif_path, 'r') as sf:
- sarif_file_data = json.load(sf)
-
- try:
- # Perform minimal JSON parsing to find the number of errors.
- total_errors = 0
- for run in sarif_file_data['runs']:
- total_errors += len(run['results'])
- except KeyError:
- logging.critical("Sarif file does not contain expected data. "
- "Analysis cannot continue.")
- return -1
-
- if total_errors > 0:
- if audit_only:
- # Show a warning message so CodeQL analysis is not forgotten.
- # If the repo owners truly do not want to fix CodeQL issues,
- # analysis should be disabled entirely.
- logging.warning(f"{self.package} ({self.target}) CodeQL "
- f"analysis ignored {total_errors} errors due "
- f"to audit mode being enabled.")
- return 0
- else:
- logging.error(f"{self.package} ({self.target}) CodeQL "
- f"analysis failed with {total_errors} errors.")
-
- return total_errors
+# @file CodeQAnalyzePlugin.py +# +# A build plugin that analyzes a CodeQL database. +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +import json +import logging +import os +import yaml + +from analyze import analyze_filter +from common import codeql_plugin + +from edk2toolext import edk2_logging +from edk2toolext.environment.plugintypes.uefi_build_plugin import \ + IUefiBuildPlugin +from edk2toolext.environment.uefi_build import UefiBuilder +from edk2toollib.uefi.edk2.path_utilities import Edk2Path +from edk2toollib.utility_functions import RunCmd +from pathlib import Path + + +class CodeQlAnalyzePlugin(IUefiBuildPlugin): + + def do_post_build(self, builder: UefiBuilder) -> int: + """CodeQL analysis post-build functionality. + + Args: + builder (UefiBuilder): A UEFI builder object for this build. + + Returns: + int: The number of CodeQL errors found. Zero indicates that + AuditOnly mode is enabled or no failures were found. + """ + self.builder = builder + self.package = builder.edk2path.GetContainingPackage( + builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath( + builder.env.GetValue("ACTIVE_PLATFORM") + ) + ) + + self.package_path = Path( + builder.edk2path.GetAbsolutePathOnThisSystemFromEdk2RelativePath( + self.package + ) + ) + self.target = builder.env.GetValue("TARGET") + + self.codeql_db_path = codeql_plugin.get_codeql_db_path( + builder.ws, self.package, self.target, + new_path=False) + + self.codeql_path = codeql_plugin.get_codeql_cli_path() + if not self.codeql_path: + logging.critical("CodeQL build enabled but CodeQL CLI application " + "not found.") + return -1 + + codeql_sarif_dir_path = self.codeql_db_path[ + :self.codeql_db_path.rindex('-')] + codeql_sarif_dir_path = codeql_sarif_dir_path.replace( + "-db-", "-analysis-") + self.codeql_sarif_path = os.path.join( + codeql_sarif_dir_path, + (os.path.basename( + self.codeql_db_path) + + ".sarif")) + + edk2_logging.log_progress(f"Analyzing {self.package} ({self.target}) " + f"CodeQL database at:\n" + f" {self.codeql_db_path}") + edk2_logging.log_progress(f"Results will be written to:\n" + f" {self.codeql_sarif_path}") + + # Packages are allowed to specify package-specific query specifiers + # in the package CI YAML file that override the global query specifier. + audit_only = False + query_specifiers = None + package_config_file = Path(os.path.join( + self.package_path, self.package + ".ci.yaml")) + plugin_data = None + if package_config_file.is_file(): + with open(package_config_file, 'r') as cf: + package_config_file_data = yaml.safe_load(cf) + if "CodeQlAnalyze" in package_config_file_data: + plugin_data = package_config_file_data["CodeQlAnalyze"] + if "AuditOnly" in plugin_data: + audit_only = plugin_data["AuditOnly"] + if "QuerySpecifiers" in plugin_data: + logging.debug(f"Loading CodeQL query specifiers in " + f"{str(package_config_file)}") + query_specifiers = plugin_data["QuerySpecifiers"] + + global_audit_only = builder.env.GetValue("STUART_CODEQL_AUDIT_ONLY") + if global_audit_only: + if global_audit_only.strip().lower() == "true": + audit_only = True + + if audit_only: + logging.info(f"CodeQL Analyze plugin is in audit only mode for " + f"{self.package} ({self.target}).") + + # Builds can override the query specifiers defined in this plugin + # by setting the value in the STUART_CODEQL_QUERY_SPECIFIERS + # environment variable. + if not query_specifiers: + query_specifiers = builder.env.GetValue( + "STUART_CODEQL_QUERY_SPECIFIERS") + + # Use this plugins query set file as the default fallback if it is + # not overridden. It is possible the file is not present if modified + # locally. In that case, skip the plugin. + plugin_query_set = Path(Path(__file__).parent, "CodeQlQueries.qls") + + if not query_specifiers and plugin_query_set.is_file(): + query_specifiers = str(plugin_query_set.resolve()) + + if not query_specifiers: + logging.warning("Skipping CodeQL analysis since no CodeQL query " + "specifiers were provided.") + return 0 + + codeql_params = (f'database analyze {self.codeql_db_path} ' + f'{query_specifiers} --format=sarifv2.1.0 ' + f'--output={self.codeql_sarif_path} --download ' + f'--threads=0') + + # CodeQL requires the sarif file parent directory to exist already. + Path(self.codeql_sarif_path).parent.mkdir(exist_ok=True, parents=True) + + cmd_ret = RunCmd(self.codeql_path, codeql_params) + if cmd_ret != 0: + logging.critical(f"CodeQL CLI analysis failed with return code " + f"{cmd_ret}.") + + if not os.path.isfile(self.codeql_sarif_path): + logging.critical(f"The sarif file {self.codeql_sarif_path} was " + f"not created. Analysis cannot continue.") + return -1 + + filter_pattern_data = [] + global_filter_file_value = builder.env.GetValue( + "STUART_CODEQL_FILTER_FILES") + if global_filter_file_value: + global_filter_files = global_filter_file_value.strip().split(',') + global_filter_files = [Path(f) for f in global_filter_files] + + for global_filter_file in global_filter_files: + if global_filter_file.is_file(): + with open(global_filter_file, 'r') as ff: + global_filter_file_data = yaml.safe_load(ff) + if "Filters" in global_filter_file_data: + current_pattern_data = \ + global_filter_file_data["Filters"] + if type(current_pattern_data) is not list: + logging.critical( + f"CodeQL pattern data must be a list of " + f"strings. Data in " + f"{str(global_filter_file.resolve())} is " + f"invalid. CodeQL analysis is incomplete.") + return -1 + filter_pattern_data += current_pattern_data + else: + logging.critical( + f"CodeQL global filter file " + f"{str(global_filter_file.resolve())} is " + f"malformed. Missing Filters section. CodeQL " + f"analysis is incomplete.") + return -1 + else: + logging.critical( + f"CodeQL global filter file " + f"{str(global_filter_file.resolve())} was not found. " + f"CodeQL analysis is incomplete.") + return -1 + + if plugin_data and "Filters" in plugin_data: + if type(plugin_data["Filters"]) is not list: + logging.critical( + "CodeQL pattern data must be a list of strings. " + "CodeQL analysis is incomplete.") + return -1 + filter_pattern_data.extend(plugin_data["Filters"]) + + if filter_pattern_data: + logging.info("Applying CodeQL SARIF result filters.") + analyze_filter.filter_sarif( + self.codeql_sarif_path, + self.codeql_sarif_path, + filter_pattern_data, + split_lines=False) + + with open(self.codeql_sarif_path, 'r') as sf: + sarif_file_data = json.load(sf) + + try: + # Perform minimal JSON parsing to find the number of errors. + total_errors = 0 + for run in sarif_file_data['runs']: + total_errors += len(run['results']) + except KeyError: + logging.critical("Sarif file does not contain expected data. " + "Analysis cannot continue.") + return -1 + + if total_errors > 0: + if audit_only: + # Show a warning message so CodeQL analysis is not forgotten. + # If the repo owners truly do not want to fix CodeQL issues, + # analysis should be disabled entirely. + logging.warning(f"{self.package} ({self.target}) CodeQL " + f"analysis ignored {total_errors} errors due " + f"to audit mode being enabled.") + return 0 + else: + logging.error(f"{self.package} ({self.target}) CodeQL " + f"analysis failed with {total_errors} errors.") + + return total_errors |
