From 124a565e6d2d177a5ff6131766f46428704146b8 Mon Sep 17 00:00:00 2001 From: Eric Brown Date: Sun, 4 Feb 2024 20:26:09 -0800 Subject: [PATCH] Use artifact in context * Pass the artifact to the location instead of just file name * Load the snippet with the initialization of the location Signed-off-by: Eric Brown --- precli/core/location.py | 55 ------------------- precli/core/result.py | 48 ++++++++++------ precli/parsers/__init__.py | 13 +---- precli/renderers/detailed.py | 35 +++++------- precli/renderers/json.py | 6 +- precli/renderers/plain.py | 8 +-- precli/rules/go/stdlib/crypto_weak_cipher.py | 8 +-- precli/rules/go/stdlib/crypto_weak_hash.py | 14 ++--- precli/rules/go/stdlib/crypto_weak_key.py | 14 ++--- precli/rules/python/stdlib/assert.py | 7 +-- precli/rules/python/stdlib/crypt_weak_hash.py | 12 ++-- .../rules/python/stdlib/ftplib_cleartext.py | 20 +++---- .../rules/python/stdlib/hashlib_weak_hash.py | 20 +++---- .../rules/python/stdlib/hmac_timing_attack.py | 10 ++-- precli/rules/python/stdlib/hmac_weak_hash.py | 14 ++--- .../rules/python/stdlib/imaplib_cleartext.py | 6 +- precli/rules/python/stdlib/json_load.py | 8 +-- .../stdlib/logging_insecure_listen_config.py | 8 +-- precli/rules/python/stdlib/marshal_load.py | 8 +-- .../rules/python/stdlib/nntplib_cleartext.py | 8 +-- precli/rules/python/stdlib/pickle_load.py | 8 +-- .../rules/python/stdlib/poplib_cleartext.py | 8 +-- precli/rules/python/stdlib/shelve_open.py | 8 +-- .../rules/python/stdlib/smtplib_cleartext.py | 8 +-- .../python/stdlib/ssl_context_weak_key.py | 6 +- .../stdlib/ssl_create_unverified_context.py | 8 +-- .../python/stdlib/ssl_insecure_tls_version.py | 18 ++---- .../python/stdlib/telnetlib_cleartext.py | 8 +-- .../stdlib/tempfile_mktemp_race_condition.py | 6 +- 29 files changed, 141 insertions(+), 259 deletions(-) diff --git a/precli/core/location.py b/precli/core/location.py index 098f020f..0b8b570b 100644 --- a/precli/core/location.py +++ b/precli/core/location.py @@ -5,17 +5,12 @@ class Location: def __init__( self, - file_name: str = None, - url: str = None, node: Node = None, start_line: int = 0, end_line: int = -1, start_column: int = 1, end_column: int = -1, - snippet: str = None, ): - self._file_name = file_name - self._url = url if node is not None: self._start_line = node.start_point[0] + 1 self._start_column = node.start_point[1] @@ -27,37 +22,6 @@ def __init__( self._start_column = start_column # TODO: default to end of line self._end_column = end_column - self._snippet = snippet - - @property - def file_name(self) -> str: - """ - Name of the file. - - :return: file name - :rtype: str - """ - return self._file_name - - @property - def url(self) -> str: - """ - If the original target was given as a URL, this - property will return that address. - - :return: URL - :rtype: str - """ - return self._url - - @url.setter - def url(self, url: str): - """ - Set the file location as a URL - - :param str url: file network location - """ - self._url = url @property def start_line(self) -> int: @@ -98,22 +62,3 @@ def end_column(self) -> int: :rtype: int """ return self._end_column - - @property - def snippet(self) -> str: - """ - Snippet of context of the code. - - :return: snippet of context - :rtype: str - """ - return self._snippet - - @snippet.setter - def snippet(self, snippet): - """ - Set the code context snippet. - - :param str snippet: context snippet - """ - self._snippet = snippet diff --git a/precli/core/result.py b/precli/core/result.py index b92d0b67..c8f0b72a 100644 --- a/precli/core/result.py +++ b/precli/core/result.py @@ -1,7 +1,9 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC +from precli.core.artifact import Artifact from precli.core.fix import Fix from precli.core.kind import Kind from precli.core.level import Level +from precli.core.linecache import LineCache from precli.core.location import Location from precli.core.suppression import Suppression from precli.rules import Rule @@ -11,14 +13,17 @@ class Result: def __init__( self, rule_id: str, + artifact: Artifact = None, kind: Kind = Kind.FAIL, level: Level = None, location: Location = None, message: str = None, fixes: list[Fix] = None, suppression: Suppression = None, + snippet: str = None, ): self._rule_id = rule_id + self._artifact = artifact self._kind = kind default_config = Rule.get_by_id(self._rule_id).default_config self._rank = default_config.rank @@ -34,6 +39,17 @@ def __init__( self._fixes = fixes if fixes is not None else [] self._suppression = suppression + if snippet is not None: + self._snippet = snippet + else: + linecache = LineCache( + artifact.file_name, + artifact.contents.decode(), + ) + self._snippet = "" + for i in range(location.start_line - 1, location.end_line + 2): + self._snippet += linecache.getline(i) + @property def rule_id(self) -> str: """ @@ -48,24 +64,14 @@ def rule_id(self) -> str: return self._rule_id @property - def source_language(self) -> str: + def artifact(self) -> Artifact: """ - The source language. + Artifact, typically the file. - :return: language of the source code - :rtype: str + :return: the artifact + :rtype: Artifact """ - match (self._rule_id[:2]): - case "GO": - return "go" - case "JV": - return "java" - case "PY": - return "python" - case "RB": - return "ruby" - case "RS": - return "rust" + return self._artifact @property def location(self) -> Location: @@ -159,3 +165,13 @@ def suppression(self, suppression): :param Suppression suppression: suppression """ self._suppression = suppression + + @property + def snippet(self) -> str: + """ + Snippet of context of the code. + + :return: snippet of context + :rtype: str + """ + return self._snippet diff --git a/precli/parsers/__init__.py b/precli/parsers/__init__.py index f786c377..623a139f 100644 --- a/precli/parsers/__init__.py +++ b/precli/parsers/__init__.py @@ -6,7 +6,6 @@ from tree_sitter import Node from precli.core.artifact import Artifact -from precli.core.linecache import LineCache from precli.core.location import Location from precli.core.result import Result from precli.core.suppression import Suppression @@ -78,22 +77,14 @@ def parse(self, artifact: Artifact) -> list[Result]: :rtype: list """ self.results = [] - self.context = {"file_name": artifact.file_name} + self.context = {"artifact": artifact} if artifact.contents is None: with open(artifact.file_name, "rb") as fdata: artifact.contents = fdata.read() tree = self.tree_sitter_parser.parse(artifact.contents) self.visit([tree.root_node]) - linecache = LineCache(artifact.file_name, artifact.contents.decode()) - for result in self.results: - start = result.location.start_line - 1 - stop = result.location.end_line + 2 - result.location.snippet = "" - for i in range(start, stop): - result.location.snippet += linecache.getline(i) - suppression = self.suppressions.get(result.location.start_line) if suppression and result.rule_id in suppression.rules: result.suppression = suppression @@ -161,7 +152,7 @@ def visit_ERROR(self, nodes: list[Node]): raise SyntaxError( "Syntax error while parsing file.", ( - self.context["file_name"], + self.context["artifact"].file_name, err_node.start_point[0] + 1, err_node.start_point[1] + 1, err_node.text.decode(errors="ignore"), diff --git a/precli/renderers/detailed.py b/precli/renderers/detailed.py index 470c1e1c..eb481e87 100644 --- a/precli/renderers/detailed.py +++ b/precli/renderers/detailed.py @@ -1,12 +1,11 @@ # Copyright 2024 Secure Saurce LLC -import linecache - from rich import box from rich import console from rich import syntax from rich.table import Table from precli.core.level import Level +from precli.core.linecache import LineCache from precli.core.metrics import Metrics from precli.core.result import Result from precli.renderers import Renderer @@ -36,10 +35,10 @@ def render(self, results: list[Result], metrics: Metrics): emoji = ":information-emoji: " style = "blue" - if result.location.url is not None: - file_name = result.location.url + if result.artifact.uri is not None: + file_name = result.artifact.uri else: - file_name = result.location.file_name + file_name = result.artifact.file_name self.console.print( f"{emoji} {result.level.name.title()} on line " @@ -59,8 +58,8 @@ def render(self, results: list[Result], metrics: Metrics): line_offset = result.location.start_line - 2 code = syntax.Syntax( - result.location.snippet, - result.source_language, + result.snippet, + result.artifact.language, line_numbers=True, start_line=line_offset + 1, line_range=( @@ -91,29 +90,25 @@ def render(self, results: list[Result], metrics: Metrics): start_column = fix.deleted_location.start_column end_column = fix.deleted_location.end_column + linecache = LineCache( + result.artifact.file_name, + result.artifact.contents.decode(), + ) + if (start_line - 1) in highlight_lines: line_before = "" before = 0 else: - line_before = linecache.getline( - filename=result.location.file_name, - lineno=start_line - 1, - ) + line_before = linecache.getline(lineno=start_line - 1) before = 1 - code = linecache.getline( - filename=result.location.file_name, - lineno=start_line, - ) + code = linecache.getline(lineno=start_line) if (start_line + 1) in highlight_lines: line_after = "" after = 0 else: - line_after = linecache.getline( - filename=result.location.file_name, - lineno=start_line + 1, - ) + line_after = linecache.getline(lineno=start_line + 1) after = 1 code = ( @@ -127,7 +122,7 @@ def render(self, results: list[Result], metrics: Metrics): code = syntax.Syntax( code, - result.source_language, + result.artifact.language, line_numbers=True, line_range=(start_line - before, end_line + after), highlight_lines=highlight_lines, diff --git a/precli/renderers/json.py b/precli/renderers/json.py index 8b64a990..fd672825 100644 --- a/precli/renderers/json.py +++ b/precli/renderers/json.py @@ -19,10 +19,10 @@ def render(self, results: list[Result], metrics: Metrics): for result in results: rule = Rule.get_by_id(result.rule_id) - if result.location.url is not None: - file_name = result.location.url + if result.artifact.uri is not None: + file_name = result.artifact.uri else: - file_name = result.location.file_name + file_name = result.artifact.file_name results_json["results"].append( { diff --git a/precli/renderers/plain.py b/precli/renderers/plain.py index 31673664..5e9bc880 100644 --- a/precli/renderers/plain.py +++ b/precli/renderers/plain.py @@ -35,17 +35,17 @@ def render(self, results: list[Result], metrics: Metrics): f"{rule.id}: {rule.cwe.name}", ) - if result.location.url is not None: - file_name = result.location.url + if result.artifact.uri is not None: + file_name = result.artifact.uri else: - file_name = result.location.file_name + file_name = result.artifact.file_name # TODO(ericwb): replace hardcoded with actual scope self.console.print( f' File "{file_name}", line ' f"{result.location.start_line}, in ", ) - code_lines = result.location.snippet.splitlines(keepends=True) + code_lines = result.snippet.splitlines(keepends=True) code_line = code_lines[1] if len(code_lines) > 1 else code_lines[0] underline_width = ( result.location.end_column - result.location.start_column diff --git a/precli/rules/go/stdlib/crypto_weak_cipher.py b/precli/rules/go/stdlib/crypto_weak_cipher.py index ea7fa768..1ed69d84 100644 --- a/precli/rules/go/stdlib/crypto_weak_cipher.py +++ b/precli/rules/go/stdlib/crypto_weak_cipher.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ================================================================== Use of a Broken or Risky Cryptographic Algorithm in Crypto Package @@ -158,10 +158,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(call.name), fixes=fixes, diff --git a/precli/rules/go/stdlib/crypto_weak_hash.py b/precli/rules/go/stdlib/crypto_weak_hash.py index e134b8b3..8e83e5f9 100644 --- a/precli/rules/go/stdlib/crypto_weak_hash.py +++ b/precli/rules/go/stdlib/crypto_weak_hash.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ========================================= Reversible One Way Hash in Crypto Package @@ -106,10 +106,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(call.name_qualified), fixes=fixes, @@ -126,10 +124,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(call.name_qualified), fixes=fixes, diff --git a/precli/rules/go/stdlib/crypto_weak_key.py b/precli/rules/go/stdlib/crypto_weak_key.py index d3e84814..9f6e3d0d 100644 --- a/precli/rules/go/stdlib/crypto_weak_key.py +++ b/precli/rules/go/stdlib/crypto_weak_key.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ================================================================ Inadequate Encryption Strength Using Weak Keys in Crypto Package @@ -125,10 +125,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=argument.identifier_node), level=Level.ERROR, message=self.message.format("DSA", 2048), fixes=fixes, @@ -147,10 +145,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.node, - ), + artifact=context["artifact"], + location=Location(node=argument.node), level=Level.ERROR if bits <= 1024 else Level.WARNING, message=self.message.format("RSA", 2048), fixes=fixes, diff --git a/precli/rules/python/stdlib/assert.py b/precli/rules/python/stdlib/assert.py index ba04d6da..fa87adee 100644 --- a/precli/rules/python/stdlib/assert.py +++ b/precli/rules/python/stdlib/assert.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC from precli.core.location import Location from precli.core.result import Result from precli.rules import Rule @@ -19,7 +19,6 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if context["node"].type == "assert": return Result( rule_id=self.id, - location=Location( - context["file_name"], kwargs.get("func_node") - ), + artifact=context["artifact"], + location=Location(kwargs.get("func_node")), ) diff --git a/precli/rules/python/stdlib/crypt_weak_hash.py b/precli/rules/python/stdlib/crypt_weak_hash.py index cfa53b24..197d9358 100644 --- a/precli/rules/python/stdlib/crypt_weak_hash.py +++ b/precli/rules/python/stdlib/crypt_weak_hash.py @@ -134,10 +134,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if isinstance(name, str) and name in WEAK_CRYPT_HASHES: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(name), ) elif call.name_qualified in ["crypt.mksalt"]: @@ -146,9 +144,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if isinstance(name, str) and name in WEAK_CRYPT_HASHES: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(name), ) diff --git a/precli/rules/python/stdlib/ftplib_cleartext.py b/precli/rules/python/stdlib/ftplib_cleartext.py index 1f35647c..cd73f0b2 100644 --- a/precli/rules/python/stdlib/ftplib_cleartext.py +++ b/precli/rules/python/stdlib/ftplib_cleartext.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ==================================================================== Cleartext Transmission of Sensitive Information in the Ftplib Module @@ -154,10 +154,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if call.get_argument(position=2, name="passwd").value is not None: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=f"The '{call.name_qualified}' module will " f"transmit the password argument in cleartext.", @@ -166,10 +164,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: else: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), fixes=fixes, ) @@ -180,10 +176,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if call.get_argument(position=1, name="passwd").value is not None: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=call.identifier_node), level=Level.ERROR, message=f"The '{call.name_qualified}' function will " f"transmit the password argument in cleartext.", diff --git a/precli/rules/python/stdlib/hashlib_weak_hash.py b/precli/rules/python/stdlib/hashlib_weak_hash.py index 2282103c..753dd63c 100644 --- a/precli/rules/python/stdlib/hashlib_weak_hash.py +++ b/precli/rules/python/stdlib/hashlib_weak_hash.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ========================================= Reversible One Way Hash in Hashlib Module @@ -137,10 +137,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if used_for_security is True: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(call.name_qualified), ) @@ -159,10 +157,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if isinstance(hash_name, str) and hash_name.lower() in WEAK_HASHES: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(hash_name), ) @@ -180,10 +176,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if used_for_security is True: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(name), ) diff --git a/precli/rules/python/stdlib/hmac_timing_attack.py b/precli/rules/python/stdlib/hmac_timing_attack.py index 388962d6..2571fff3 100644 --- a/precli/rules/python/stdlib/hmac_timing_attack.py +++ b/precli/rules/python/stdlib/hmac_timing_attack.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ============================================ Observable Timing Discrepancy in Hmac Module @@ -125,7 +125,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: context=context, deleted_location=Location(node=comparison.node), description="Use the 'hmac.compare_digest' function instead " - "of the '=='' operator to reduce the vulnerability to timing " + "of the '==' operator to reduce the vulnerability to timing " "attacks.", inserted_content=f"hmac.compare_digest(" f"{comparison.left_node.text.decode()}, " @@ -134,10 +134,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=comparison.operator_node, - ), + artifact=context["artifact"], + location=Location(node=comparison.operator_node), level=Level.ERROR, fixes=fixes, ) diff --git a/precli/rules/python/stdlib/hmac_weak_hash.py b/precli/rules/python/stdlib/hmac_weak_hash.py index e3b8cc57..d0313d87 100644 --- a/precli/rules/python/stdlib/hmac_weak_hash.py +++ b/precli/rules/python/stdlib/hmac_weak_hash.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ====================================== Reversible One Way Hash in Hmac Module @@ -123,10 +123,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) or digestmod in HASHLIB_WEAK_HASHES: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.node, - ), + artifact=context["artifact"], + location=Location(node=argument.node), level=Level.ERROR, message=self.message.format(digestmod), ) @@ -142,10 +140,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) or digest in HASHLIB_WEAK_HASHES: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.node, - ), + artifact=context["artifact"], + location=Location(node=argument.node), level=Level.ERROR, message=self.message.format(digest), ) diff --git a/precli/rules/python/stdlib/imaplib_cleartext.py b/precli/rules/python/stdlib/imaplib_cleartext.py index e7f2a271..eb9e5da8 100644 --- a/precli/rules/python/stdlib/imaplib_cleartext.py +++ b/precli/rules/python/stdlib/imaplib_cleartext.py @@ -116,10 +116,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=call.identifier_node), level=Level.ERROR, message=f"The '{call.name_qualified}' function will " f"transmit authentication information such as a user, " diff --git a/precli/rules/python/stdlib/json_load.py b/precli/rules/python/stdlib/json_load.py index 8c289050..f01ee462 100644 --- a/precli/rules/python/stdlib/json_load.py +++ b/precli/rules/python/stdlib/json_load.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ==================================================== Deserialization of Untrusted Data in the Json Module @@ -109,9 +109,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: """ return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), ) diff --git a/precli/rules/python/stdlib/logging_insecure_listen_config.py b/precli/rules/python/stdlib/logging_insecure_listen_config.py index 3bd73408..4112f7f9 100644 --- a/precli/rules/python/stdlib/logging_insecure_listen_config.py +++ b/precli/rules/python/stdlib/logging_insecure_listen_config.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ================================ Code Injection in Logging Config @@ -83,9 +83,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if call.get_argument(position=1, name="verify").value is None: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), ) diff --git a/precli/rules/python/stdlib/marshal_load.py b/precli/rules/python/stdlib/marshal_load.py index dd53e7a5..c14cb651 100644 --- a/precli/rules/python/stdlib/marshal_load.py +++ b/precli/rules/python/stdlib/marshal_load.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ======================================================= Deserialization of Untrusted Data in the Marshal Module @@ -78,9 +78,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: """ return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), ) diff --git a/precli/rules/python/stdlib/nntplib_cleartext.py b/precli/rules/python/stdlib/nntplib_cleartext.py index b49ca1ff..b0df7993 100644 --- a/precli/rules/python/stdlib/nntplib_cleartext.py +++ b/precli/rules/python/stdlib/nntplib_cleartext.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ===================================================================== Cleartext Transmission of Sensitive Information in the Nntplib Module @@ -97,10 +97,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=call.identifier_node), level=Level.ERROR, message=f"The '{call.name_qualified}' function will " f"transmit authentication information such as a user, " diff --git a/precli/rules/python/stdlib/pickle_load.py b/precli/rules/python/stdlib/pickle_load.py index 92fb9a37..99a23f9b 100644 --- a/precli/rules/python/stdlib/pickle_load.py +++ b/precli/rules/python/stdlib/pickle_load.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ================================================== Deserialization of Untrusted Data in Pickle Module @@ -90,9 +90,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ]: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), ) diff --git a/precli/rules/python/stdlib/poplib_cleartext.py b/precli/rules/python/stdlib/poplib_cleartext.py index 89d52dcc..8471aeb8 100644 --- a/precli/rules/python/stdlib/poplib_cleartext.py +++ b/precli/rules/python/stdlib/poplib_cleartext.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ==================================================================== Cleartext Transmission of Sensitive Information in the Poplib Module @@ -113,10 +113,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=call.identifier_node), level=Level.ERROR, message=f"The '{call.name_qualified}' function will " f"transmit authentication information such as a user, " diff --git a/precli/rules/python/stdlib/shelve_open.py b/precli/rules/python/stdlib/shelve_open.py index 869379d3..10d1ac0d 100644 --- a/precli/rules/python/stdlib/shelve_open.py +++ b/precli/rules/python/stdlib/shelve_open.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ====================================================== Deserialization of Untrusted Data in the Shelve Module @@ -72,9 +72,7 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if call.name_qualified in ["shelve.open", "shelve.DbfilenameShelf"]: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), ) diff --git a/precli/rules/python/stdlib/smtplib_cleartext.py b/precli/rules/python/stdlib/smtplib_cleartext.py index ce267398..910cc6cd 100644 --- a/precli/rules/python/stdlib/smtplib_cleartext.py +++ b/precli/rules/python/stdlib/smtplib_cleartext.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ===================================================================== Cleartext Transmission of Sensitive Information in the Smtplib Module @@ -144,10 +144,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=call.identifier_node), level=Level.ERROR, message=f"The '{call.name_qualified}' function will " f"transmit authentication information such as a user, " diff --git a/precli/rules/python/stdlib/ssl_context_weak_key.py b/precli/rules/python/stdlib/ssl_context_weak_key.py index d4709ae0..1e525471 100644 --- a/precli/rules/python/stdlib/ssl_context_weak_key.py +++ b/precli/rules/python/stdlib/ssl_context_weak_key.py @@ -110,10 +110,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=arg.node, - ), + artifact=context["artifact"], + location=Location(node=arg.node), level=Level.ERROR if key_size < 160 else Level.WARNING, message=self.message.format("EC", 224), fixes=fixes, diff --git a/precli/rules/python/stdlib/ssl_create_unverified_context.py b/precli/rules/python/stdlib/ssl_create_unverified_context.py index 3103691a..9c16d22a 100644 --- a/precli/rules/python/stdlib/ssl_create_unverified_context.py +++ b/precli/rules/python/stdlib/ssl_create_unverified_context.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ==================================================================== Improper Certificate Validation Using ssl._create_unverified_context @@ -116,10 +116,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(call.name_qualified), fixes=fixes, ) diff --git a/precli/rules/python/stdlib/ssl_insecure_tls_version.py b/precli/rules/python/stdlib/ssl_insecure_tls_version.py index 08401772..56752aeb 100644 --- a/precli/rules/python/stdlib/ssl_insecure_tls_version.py +++ b/precli/rules/python/stdlib/ssl_insecure_tls_version.py @@ -124,10 +124,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=argument.identifier_node), level=Level.ERROR, message=self.message.format(version), fixes=fixes, @@ -167,10 +165,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=argument.identifier_node), level=Level.ERROR, message=self.message.format(version), fixes=fixes, @@ -197,10 +193,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: ) return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=argument.identifier_node, - ), + artifact=context["artifact"], + location=Location(node=argument.identifier_node), level=Level.ERROR, message=self.message.format(protocol), fixes=fixes, diff --git a/precli/rules/python/stdlib/telnetlib_cleartext.py b/precli/rules/python/stdlib/telnetlib_cleartext.py index d5207021..1739a145 100644 --- a/precli/rules/python/stdlib/telnetlib_cleartext.py +++ b/precli/rules/python/stdlib/telnetlib_cleartext.py @@ -1,4 +1,4 @@ -# Copyright 2023 Secure Saurce LLC +# Copyright 2024 Secure Saurce LLC r""" ======================================================================= Cleartext Transmission of Sensitive Information in the Telnetlib Module @@ -138,10 +138,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: if call.name_qualified in ["telnetlib.Telnet"]: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), level=Level.ERROR, message=self.message.format(call.name_qualified), ) diff --git a/precli/rules/python/stdlib/tempfile_mktemp_race_condition.py b/precli/rules/python/stdlib/tempfile_mktemp_race_condition.py index 7ad743e1..ec82699f 100644 --- a/precli/rules/python/stdlib/tempfile_mktemp_race_condition.py +++ b/precli/rules/python/stdlib/tempfile_mktemp_race_condition.py @@ -178,10 +178,8 @@ def analyze(self, context: dict, **kwargs: dict) -> Result: return Result( rule_id=self.id, - location=Location( - file_name=context["file_name"], - node=call.function_node, - ), + artifact=context["artifact"], + location=Location(node=call.function_node), message=self.message.format(file_arg.value), fixes=fixes, )