summaryrefslogtreecommitdiff
path: root/BaseTools/Plugin/CodeQL/analyze
diff options
context:
space:
mode:
Diffstat (limited to 'BaseTools/Plugin/CodeQL/analyze')
-rw-r--r--BaseTools/Plugin/CodeQL/analyze/analyze_filter.py368
-rw-r--r--BaseTools/Plugin/CodeQL/analyze/globber.py254
2 files changed, 311 insertions, 311 deletions
diff --git a/BaseTools/Plugin/CodeQL/analyze/analyze_filter.py b/BaseTools/Plugin/CodeQL/analyze/analyze_filter.py
index f363dd378f..e0e9dfbc55 100644
--- a/BaseTools/Plugin/CodeQL/analyze/analyze_filter.py
+++ b/BaseTools/Plugin/CodeQL/analyze/analyze_filter.py
@@ -1,184 +1,184 @@
-# @file analyze_filter.py
-#
-# Filters results in a SARIF file.
-#
-# Apache License
-# Version 2.0, January 2004
-# http://www.apache.org/licenses/
-#
-# 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.
-#
-# This file has been altered from its original form. Based on code in:
-# https://github.com/advanced-security/filter-sarif
-#
-# It primarily contains modifications made to integrate with the CodeQL plugin.
-#
-# Specifically:
-# https://github.com/advanced-security/filter-sarif/blob/main/filter_sarif.py
-#
-# View the full and complete license as provided by that repository here:
-# https://github.com/advanced-security/filter-sarif/blob/main/LICENSE
-#
-# SPDX-License-Identifier: Apache-2.0
-##
-
-import json
-import logging
-import re
-from os import PathLike
-from typing import Iterable, List, Tuple
-
-from analyze.globber import match
-
-
-def _match_path_and_rule(
- path: str, rule: str, patterns: Iterable[str]) -> bool:
- """Returns whether a given path matches a given rule.
-
- Args:
- path (str): A file path string.
- rule (str): A rule file path string.
- patterns (Iterable[str]): An iterable of pattern strings.
-
- Returns:
- bool: True if the path matches a rule. Otherwise, False.
- """
- result = True
- for s, fp, rp in patterns:
- if match(rp, rule) and match(fp, path):
- result = s
- return result
-
-
-def _parse_pattern(line: str) -> Tuple[str]:
- """Parses a given pattern line.
-
- Args:
- line (str): The line string that contains the rule.
-
- Returns:
- Tuple[str]: The parsed sign, file pattern, and rule pattern from the
- line.
- """
- sep_char = ':'
- esc_char = '\\'
- file_pattern = ''
- rule_pattern = ''
- seen_separator = False
- sign = True
-
- # inclusion or exclusion pattern?
- u_line = line
- if line:
- if line[0] == '-':
- sign = False
- u_line = line[1:]
- elif line[0] == '+':
- u_line = line[1:]
-
- i = 0
- while i < len(u_line):
- c = u_line[i]
- i = i + 1
- if c == sep_char:
- if seen_separator:
- raise Exception(
- 'Invalid pattern: "' + line + '" Contains more than one '
- 'separator!')
- seen_separator = True
- continue
- elif c == esc_char:
- next_c = u_line[i] if (i < len(u_line)) else None
- if next_c in ['+' , '-', esc_char, sep_char]:
- i = i + 1
- c = next_c
- if seen_separator:
- rule_pattern = rule_pattern + c
- else:
- file_pattern = file_pattern + c
-
- if not rule_pattern:
- rule_pattern = '**'
-
- return sign, file_pattern, rule_pattern
-
-
-def filter_sarif(input_sarif: PathLike,
- output_sarif: PathLike,
- patterns: List[str],
- split_lines: bool) -> None:
- """Filters a SARIF file with a given set of filter patterns.
-
- Args:
- input_sarif (PathLike): Input SARIF file path.
- output_sarif (PathLike): Output SARIF file path.
- patterns (PathLike): List of filter pattern strings.
- split_lines (PathLike): Whether to split lines in individual patterns.
- """
- if split_lines:
- tmp = []
- for p in patterns:
- tmp = tmp + re.split('\r?\n', p)
- patterns = tmp
-
- patterns = [_parse_pattern(p) for p in patterns if p]
-
- logging.debug('Given patterns:')
- for s, fp, rp in patterns:
- logging.debug(
- 'files: {file_pattern} rules: {rule_pattern} ({sign})'.format(
- file_pattern=fp,
- rule_pattern=rp,
- sign='positive' if s else 'negative'))
-
- with open(input_sarif, 'r') as f:
- s = json.load(f)
-
- for run in s.get('runs', []):
- if run.get('results', []):
- new_results = []
- for r in run['results']:
- if r.get('locations', []):
- new_locations = []
- for l in r['locations']:
- # TODO: The uri field is optional. We might have to
- # fetch the actual uri from "artifacts" via
- # "index"
- # (see https://github.com/microsoft/sarif-tutorials/blob/main/docs/2-Basics.md#-linking-results-to-artifacts)
- uri = l.get(
- 'physicalLocation', {}).get(
- 'artifactLocation', {}).get(
- 'uri', None)
-
- # TODO: The ruleId field is optional and potentially
- # ambiguous. We might have to fetch the actual
- # ruleId from the rule metadata via the ruleIndex
- # field.
- # (see https://github.com/microsoft/sarif-tutorials/blob/main/docs/2-Basics.md#rule-metadata)
- ruleId = r['ruleId']
-
- if (uri is None or
- _match_path_and_rule(uri, ruleId, patterns)):
- new_locations.append(l)
- r['locations'] = new_locations
- if new_locations:
- new_results.append(r)
- else:
- # locations array doesn't exist or is empty, so we can't
- # match on anything. Therefore, we include the result in
- # the output.
- new_results.append(r)
- run['results'] = new_results
-
- with open(output_sarif, 'w') as f:
- json.dump(s, f, indent=2)
+# @file analyze_filter.py
+#
+# Filters results in a SARIF file.
+#
+# Apache License
+# Version 2.0, January 2004
+# http://www.apache.org/licenses/
+#
+# 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.
+#
+# This file has been altered from its original form. Based on code in:
+# https://github.com/advanced-security/filter-sarif
+#
+# It primarily contains modifications made to integrate with the CodeQL plugin.
+#
+# Specifically:
+# https://github.com/advanced-security/filter-sarif/blob/main/filter_sarif.py
+#
+# View the full and complete license as provided by that repository here:
+# https://github.com/advanced-security/filter-sarif/blob/main/LICENSE
+#
+# SPDX-License-Identifier: Apache-2.0
+##
+
+import json
+import logging
+import re
+from os import PathLike
+from typing import Iterable, List, Tuple
+
+from analyze.globber import match
+
+
+def _match_path_and_rule(
+ path: str, rule: str, patterns: Iterable[str]) -> bool:
+ """Returns whether a given path matches a given rule.
+
+ Args:
+ path (str): A file path string.
+ rule (str): A rule file path string.
+ patterns (Iterable[str]): An iterable of pattern strings.
+
+ Returns:
+ bool: True if the path matches a rule. Otherwise, False.
+ """
+ result = True
+ for s, fp, rp in patterns:
+ if match(rp, rule) and match(fp, path):
+ result = s
+ return result
+
+
+def _parse_pattern(line: str) -> Tuple[str]:
+ """Parses a given pattern line.
+
+ Args:
+ line (str): The line string that contains the rule.
+
+ Returns:
+ Tuple[str]: The parsed sign, file pattern, and rule pattern from the
+ line.
+ """
+ sep_char = ':'
+ esc_char = '\\'
+ file_pattern = ''
+ rule_pattern = ''
+ seen_separator = False
+ sign = True
+
+ # inclusion or exclusion pattern?
+ u_line = line
+ if line:
+ if line[0] == '-':
+ sign = False
+ u_line = line[1:]
+ elif line[0] == '+':
+ u_line = line[1:]
+
+ i = 0
+ while i < len(u_line):
+ c = u_line[i]
+ i = i + 1
+ if c == sep_char:
+ if seen_separator:
+ raise Exception(
+ 'Invalid pattern: "' + line + '" Contains more than one '
+ 'separator!')
+ seen_separator = True
+ continue
+ elif c == esc_char:
+ next_c = u_line[i] if (i < len(u_line)) else None
+ if next_c in ['+' , '-', esc_char, sep_char]:
+ i = i + 1
+ c = next_c
+ if seen_separator:
+ rule_pattern = rule_pattern + c
+ else:
+ file_pattern = file_pattern + c
+
+ if not rule_pattern:
+ rule_pattern = '**'
+
+ return sign, file_pattern, rule_pattern
+
+
+def filter_sarif(input_sarif: PathLike,
+ output_sarif: PathLike,
+ patterns: List[str],
+ split_lines: bool) -> None:
+ """Filters a SARIF file with a given set of filter patterns.
+
+ Args:
+ input_sarif (PathLike): Input SARIF file path.
+ output_sarif (PathLike): Output SARIF file path.
+ patterns (PathLike): List of filter pattern strings.
+ split_lines (PathLike): Whether to split lines in individual patterns.
+ """
+ if split_lines:
+ tmp = []
+ for p in patterns:
+ tmp = tmp + re.split('\r?\n', p)
+ patterns = tmp
+
+ patterns = [_parse_pattern(p) for p in patterns if p]
+
+ logging.debug('Given patterns:')
+ for s, fp, rp in patterns:
+ logging.debug(
+ 'files: {file_pattern} rules: {rule_pattern} ({sign})'.format(
+ file_pattern=fp,
+ rule_pattern=rp,
+ sign='positive' if s else 'negative'))
+
+ with open(input_sarif, 'r') as f:
+ s = json.load(f)
+
+ for run in s.get('runs', []):
+ if run.get('results', []):
+ new_results = []
+ for r in run['results']:
+ if r.get('locations', []):
+ new_locations = []
+ for l in r['locations']:
+ # TODO: The uri field is optional. We might have to
+ # fetch the actual uri from "artifacts" via
+ # "index"
+ # (see https://github.com/microsoft/sarif-tutorials/blob/main/docs/2-Basics.md#-linking-results-to-artifacts)
+ uri = l.get(
+ 'physicalLocation', {}).get(
+ 'artifactLocation', {}).get(
+ 'uri', None)
+
+ # TODO: The ruleId field is optional and potentially
+ # ambiguous. We might have to fetch the actual
+ # ruleId from the rule metadata via the ruleIndex
+ # field.
+ # (see https://github.com/microsoft/sarif-tutorials/blob/main/docs/2-Basics.md#rule-metadata)
+ ruleId = r['ruleId']
+
+ if (uri is None or
+ _match_path_and_rule(uri, ruleId, patterns)):
+ new_locations.append(l)
+ r['locations'] = new_locations
+ if new_locations:
+ new_results.append(r)
+ else:
+ # locations array doesn't exist or is empty, so we can't
+ # match on anything. Therefore, we include the result in
+ # the output.
+ new_results.append(r)
+ run['results'] = new_results
+
+ with open(output_sarif, 'w') as f:
+ json.dump(s, f, indent=2)
diff --git a/BaseTools/Plugin/CodeQL/analyze/globber.py b/BaseTools/Plugin/CodeQL/analyze/globber.py
index 5d45abaa1f..11ef9d6cef 100644
--- a/BaseTools/Plugin/CodeQL/analyze/globber.py
+++ b/BaseTools/Plugin/CodeQL/analyze/globber.py
@@ -1,127 +1,127 @@
-# @file globber.py
-#
-# Provides global functionality for use by the CodeQL plugin.
-#
-# Copyright 2019 Jaakko Kangasharju
-#
-# Apache License
-# Version 2.0, January 2004
-# http://www.apache.org/licenses/
-#
-# 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.
-#
-# This file has been altered from its original form. Based on code in:
-# https://github.com/advanced-security/filter-sarif
-#
-# Specifically:
-# https://github.com/advanced-security/filter-sarif/blob/main/filter_sarif.py
-#
-# It primarily contains modifications made to integrate with the CodeQL plugin.
-#
-# SPDX-License-Identifier: Apache-2.0
-##
-
-import re
-
-_double_star_after_invalid_regex = re.compile(r'[^/\\]\*\*')
-_double_star_first_before_invalid_regex = re.compile('^\\*\\*[^/]')
-_double_star_middle_before_invalid_regex = re.compile(r'[^\\]\*\*[^/]')
-
-
-def _match_component(pattern_component, file_name_component):
- if len(pattern_component) == 0 and len(file_name_component) == 0:
- return True
- elif len(pattern_component) == 0:
- return False
- elif len(file_name_component) == 0:
- return pattern_component == '*'
- elif pattern_component[0] == '*':
- return (_match_component(pattern_component, file_name_component[1:]) or
- _match_component(pattern_component[1:], file_name_component))
- elif pattern_component[0] == '?':
- return _match_component(pattern_component[1:], file_name_component[1:])
- elif pattern_component[0] == '\\':
- return (len(pattern_component) >= 2 and
- pattern_component[1] == file_name_component[0] and
- _match_component(
- pattern_component[2:], file_name_component[1:]))
- elif pattern_component[0] != file_name_component[0]:
- return False
- else:
- return _match_component(pattern_component[1:], file_name_component[1:])
-
-
-def _match_components(pattern_components, file_name_components):
- if len(pattern_components) == 0 and len(file_name_components) == 0:
- return True
- if len(pattern_components) == 0:
- return False
- if len(file_name_components) == 0:
- return len(pattern_components) == 1 and pattern_components[0] == '**'
- if pattern_components[0] == '**':
- return (_match_components(pattern_components, file_name_components[1:])
- or _match_components(
- pattern_components[1:], file_name_components))
- else:
- return (
- _match_component(
- pattern_components[0], file_name_components[0]) and
- _match_components(
- pattern_components[1:], file_name_components[1:]))
-
-
-def match(pattern: str, file_name: str):
- """Match a glob pattern against a file name.
-
- Glob pattern matching is for file names, which do not need to exist as
- files on the file system.
-
- A file name is a sequence of directory names, possibly followed by the name
- of a file, with the components separated by a path separator. A glob
- pattern is similar, except it may contain special characters: A '?' matches
- any character in a name. A '*' matches any sequence of characters (possibly
- empty) in a name. Both of these match only within a single component, i.e.,
- they will not match a path separator. A component in a pattern may also be
- a literal '**', which matches zero or more components in the complete file
- name. A backslash '\\' in a pattern acts as an escape character, and
- indicates that the following character is to be matched literally, even if
- it is a special character.
-
- Args:
- pattern (str): The pattern to match. The path separator in patterns is
- always '/'.
- file_name (str): The file name to match against. The path separator in
- file names is the platform separator
-
- Returns:
- bool: True if the pattern matches, False otherwise.
- """
- if (_double_star_after_invalid_regex.search(pattern) is not None or
- _double_star_first_before_invalid_regex.search(
- pattern) is not None or
- _double_star_middle_before_invalid_regex.search(pattern) is not None):
- raise ValueError(
- '** in {} not alone between path separators'.format(pattern))
-
- pattern = pattern.rstrip('/')
- file_name = file_name.rstrip('/')
-
- while '**/**' in pattern:
- pattern = pattern.replace('**/**', '**')
-
- pattern_components = pattern.split('/')
-
- # We split on '\' as well as '/' to support unix and windows-style paths
- file_name_components = re.split(r'[\\/]', file_name)
-
- return _match_components(pattern_components, file_name_components)
+# @file globber.py
+#
+# Provides global functionality for use by the CodeQL plugin.
+#
+# Copyright 2019 Jaakko Kangasharju
+#
+# Apache License
+# Version 2.0, January 2004
+# http://www.apache.org/licenses/
+#
+# 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.
+#
+# This file has been altered from its original form. Based on code in:
+# https://github.com/advanced-security/filter-sarif
+#
+# Specifically:
+# https://github.com/advanced-security/filter-sarif/blob/main/filter_sarif.py
+#
+# It primarily contains modifications made to integrate with the CodeQL plugin.
+#
+# SPDX-License-Identifier: Apache-2.0
+##
+
+import re
+
+_double_star_after_invalid_regex = re.compile(r'[^/\\]\*\*')
+_double_star_first_before_invalid_regex = re.compile('^\\*\\*[^/]')
+_double_star_middle_before_invalid_regex = re.compile(r'[^\\]\*\*[^/]')
+
+
+def _match_component(pattern_component, file_name_component):
+ if len(pattern_component) == 0 and len(file_name_component) == 0:
+ return True
+ elif len(pattern_component) == 0:
+ return False
+ elif len(file_name_component) == 0:
+ return pattern_component == '*'
+ elif pattern_component[0] == '*':
+ return (_match_component(pattern_component, file_name_component[1:]) or
+ _match_component(pattern_component[1:], file_name_component))
+ elif pattern_component[0] == '?':
+ return _match_component(pattern_component[1:], file_name_component[1:])
+ elif pattern_component[0] == '\\':
+ return (len(pattern_component) >= 2 and
+ pattern_component[1] == file_name_component[0] and
+ _match_component(
+ pattern_component[2:], file_name_component[1:]))
+ elif pattern_component[0] != file_name_component[0]:
+ return False
+ else:
+ return _match_component(pattern_component[1:], file_name_component[1:])
+
+
+def _match_components(pattern_components, file_name_components):
+ if len(pattern_components) == 0 and len(file_name_components) == 0:
+ return True
+ if len(pattern_components) == 0:
+ return False
+ if len(file_name_components) == 0:
+ return len(pattern_components) == 1 and pattern_components[0] == '**'
+ if pattern_components[0] == '**':
+ return (_match_components(pattern_components, file_name_components[1:])
+ or _match_components(
+ pattern_components[1:], file_name_components))
+ else:
+ return (
+ _match_component(
+ pattern_components[0], file_name_components[0]) and
+ _match_components(
+ pattern_components[1:], file_name_components[1:]))
+
+
+def match(pattern: str, file_name: str):
+ """Match a glob pattern against a file name.
+
+ Glob pattern matching is for file names, which do not need to exist as
+ files on the file system.
+
+ A file name is a sequence of directory names, possibly followed by the name
+ of a file, with the components separated by a path separator. A glob
+ pattern is similar, except it may contain special characters: A '?' matches
+ any character in a name. A '*' matches any sequence of characters (possibly
+ empty) in a name. Both of these match only within a single component, i.e.,
+ they will not match a path separator. A component in a pattern may also be
+ a literal '**', which matches zero or more components in the complete file
+ name. A backslash '\\' in a pattern acts as an escape character, and
+ indicates that the following character is to be matched literally, even if
+ it is a special character.
+
+ Args:
+ pattern (str): The pattern to match. The path separator in patterns is
+ always '/'.
+ file_name (str): The file name to match against. The path separator in
+ file names is the platform separator
+
+ Returns:
+ bool: True if the pattern matches, False otherwise.
+ """
+ if (_double_star_after_invalid_regex.search(pattern) is not None or
+ _double_star_first_before_invalid_regex.search(
+ pattern) is not None or
+ _double_star_middle_before_invalid_regex.search(pattern) is not None):
+ raise ValueError(
+ '** in {} not alone between path separators'.format(pattern))
+
+ pattern = pattern.rstrip('/')
+ file_name = file_name.rstrip('/')
+
+ while '**/**' in pattern:
+ pattern = pattern.replace('**/**', '**')
+
+ pattern_components = pattern.split('/')
+
+ # We split on '\' as well as '/' to support unix and windows-style paths
+ file_name_components = re.split(r'[\\/]', file_name)
+
+ return _match_components(pattern_components, file_name_components)