Skip to content

Commit

Permalink
start sonar secure random rule
Browse files Browse the repository at this point in the history
  • Loading branch information
clavedeluna committed Mar 19, 2024
1 parent d55b669 commit 0aaa5f3
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 27 deletions.
4 changes: 2 additions & 2 deletions integration_tests/test_secure_random.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
BaseIntegrationTest,
original_and_expected_from_code_path,
)
from core_codemods.secure_random import SecureRandom
from core_codemods.secure_random import SecureRandom, SecureRandomTransformer


class TestSecureRandom(BaseIntegrationTest):
Expand All @@ -19,4 +19,4 @@ class TestSecureRandom(BaseIntegrationTest):

expected_diff = '--- \n+++ \n@@ -1,4 +1,4 @@\n-import random\n+import secrets\n \n-random.random()\n+secrets.SystemRandom().random()\n var = "hello"\n'
expected_line_change = "3"
change_description = SecureRandom.change_description
change_description = SecureRandomTransformer.change_description
60 changes: 35 additions & 25 deletions src/core_codemods/secure_random.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
from codemodder.codemods.libcst_transformer import (
LibcstResultTransformer,
LibcstTransformerPipeline,
)
from codemodder.codemods.semgrep import SemgrepRuleDetector
from codemodder.codemods.utils_mixin import NameResolutionMixin
from core_codemods.api import Metadata, Reference, ReviewGuidance, SimpleCodemod
from core_codemods.api import CoreCodemod, Metadata, Reference, ReviewGuidance


class SecureRandom(SimpleCodemod, NameResolutionMixin):
metadata = Metadata(
name="secure-random",
review_guidance=ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW,
summary="Secure Source of Randomness",
references=[
Reference(
url="https://owasp.org/www-community/vulnerabilities/Insecure_Randomness",
),
Reference(
url="https://docs.python.org/3/library/random.html",
),
],
)

detector_pattern = """
- patterns:
- pattern: random.$F(...)
- pattern-not: random.SystemRandom()
- pattern-inside: |
import random
...
"""

class SecureRandomTransformer(LibcstResultTransformer, NameResolutionMixin):
change_description = (
"Replace random.{func} with more secure secrets library functions."
)
Expand All @@ -37,3 +19,31 @@ def on_result_found(self, original_node, updated_node):
if self.find_base_name(original_node.func) == "random.choice":
return self.update_call_target(updated_node, "secrets")
return self.update_call_target(updated_node, "secrets.SystemRandom()")


SecureRandom = CoreCodemod(
metadata=Metadata(
name="secure-random",
review_guidance=ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW,
summary="Secure Source of Randomness",
references=[
Reference(
url="https://owasp.org/www-community/vulnerabilities/Insecure_Randomness",
),
Reference(
url="https://docs.python.org/3/library/random.html",
),
],
),
detector=SemgrepRuleDetector(
"""
- patterns:
- pattern: random.$F(...)
- pattern-not: random.SystemRandom()
- pattern-inside: |
import random
...
"""
),
transformer=LibcstTransformerPipeline(SecureRandomTransformer),
)
10 changes: 10 additions & 0 deletions src/core_codemods/sonar/sonar_secure_random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from codemodder.codemods.sonar import SonarCodemod
from core_codemods.secure_random import SecureRandom

SonarSecureRandom = SonarCodemod.from_core_codemod(
name="secure-random-S2245",
other=SecureRandom,
rule_id="python:S2245",
rule_name="Using pseudorandom number generators (PRNGs) is security-sensitive",
rule_url="https://rules.sonarsource.com/python/type/Security%20Hotspot/RSPEC-2245/",
)
57 changes: 57 additions & 0 deletions tests/codemods/test_sonar_secure_random.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import json

from codemodder.codemods.test import BaseSASTCodemodTest
from core_codemods.sonar.sonar_secure_random import SonarSecureRandom


class TestSonarSecureRandom(BaseSASTCodemodTest):
codemod = SonarSecureRandom
tool = "sonar"

def test_name(self):
assert self.codemod.name == "secure-random-S2245"

def test_simple(self, tmpdir):
input_code = """
import random
random.getrandbits(1)
random.randint(0, 9)
random.random()
random.sample(["a", "b"], 1)
random.choice(["a", "b"])
random.choices(["a", "b"])
"""
expected_output = """
import secrets
secrets.SystemRandom().getrandbits(1)
secrets.SystemRandom().randint(0, 9)
secrets.SystemRandom().random()
secrets.SystemRandom().sample(["a", "b"], 1)
secrets.choice(["a", "b"])
secrets.SystemRandom().choices(["a", "b"])
"""
# todo: not issues, notspots
issues = {
"issues": [
{
"rule": "python:S5905",
"status": "OPEN",
"component": "code.py",
"textRange": {
"startLine": 2,
"endLine": 2,
"startOffset": 8,
"endOffset": 15,
},
}
]
}
self.run_and_assert(
tmpdir,
input_code,
expected_output,
results=json.dumps(issues),
num_changes=3,
)

0 comments on commit 0aaa5f3

Please sign in to comment.