Skip to content

Commit 01195fe

Browse files
committed
Initial version of SonarSecureCookie
1 parent b22f441 commit 01195fe

File tree

4 files changed

+79
-26
lines changed

4 files changed

+79
-26
lines changed

src/core_codemods/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@
8989
SonarRemoveAssertionInPytestRaises,
9090
)
9191
from .sonar.sonar_sandbox_process_creation import SonarSandboxProcessCreation
92+
from .sonar.sonar_secure_cookie import SonarSecureCookie
9293
from .sonar.sonar_secure_random import SonarSecureRandom
9394
from .sonar.sonar_sql_parameterization import SonarSQLParameterization
9495
from .sonar.sonar_tempfile_mktemp import SonarTempfileMktemp
@@ -204,6 +205,7 @@
204205
SonarInvertedBooleanCheck,
205206
SonarTimezoneAwareDatetime,
206207
SonarSandboxProcessCreation,
208+
SonarSecureCookie,
207209
],
208210
)
209211

src/core_codemods/secure_flask_cookie.py

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
from core_codemods.api import Metadata, Reference, ReviewGuidance, SimpleCodemod
1+
from codemodder.codemods.libcst_transformer import (
2+
LibcstResultTransformer,
3+
LibcstTransformerPipeline,
4+
)
5+
from codemodder.codemods.semgrep import SemgrepRuleDetector
6+
from core_codemods.api import Metadata, Reference, ReviewGuidance
7+
from core_codemods.api.core_codemod import CoreCodemod
28
from core_codemods.secure_cookie_mixin import SecureCookieMixin
39

410

5-
class SecureFlaskCookie(SimpleCodemod, SecureCookieMixin):
6-
metadata = Metadata(
11+
class SecureCookieTransformer(LibcstResultTransformer, SecureCookieMixin):
12+
def on_result_found(self, original_node, updated_node):
13+
new_args = self.replace_args(
14+
original_node, self._choose_new_args(original_node)
15+
)
16+
return self.update_arg_target(updated_node, new_args)
17+
18+
19+
SecureFlaskCookie = CoreCodemod(
20+
metadata=Metadata(
721
name="secure-flask-cookie",
822
summary="Use Safe Parameters in `flask` Response `set_cookie` Call",
923
review_guidance=ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW,
@@ -14,10 +28,14 @@ class SecureFlaskCookie(SimpleCodemod, SecureCookieMixin):
1428
Reference(
1529
url="https://owasp.org/www-community/controls/SecureCookieAttribute"
1630
),
31+
Reference(url="https://cwe.mitre.org/data/definitions/1004"),
32+
Reference(url="https://cwe.mitre.org/data/definitions/311"),
33+
Reference(url="https://cwe.mitre.org/data/definitions/315"),
34+
Reference(url="https://cwe.mitre.org/data/definitions/614"),
1735
],
18-
)
19-
change_description = "Flask response `set_cookie` call should be called with `secure=True`, `httponly=True`, and `samesite='Lax'`."
20-
detector_pattern = """
36+
),
37+
detector=SemgrepRuleDetector(
38+
"""
2139
rules:
2240
- id: secure-flask-cookie
2341
mode: taint
@@ -38,10 +56,7 @@ class SecureFlaskCookie(SimpleCodemod, SecureCookieMixin):
3856
- pattern: $SINK.set_cookie(...)
3957
- pattern-not: $SINK.set_cookie(..., secure=True, ..., httponly=True, ..., samesite="Lax", ...)
4058
- pattern-not: $SINK.set_cookie(..., secure=True, ..., httponly=True, ..., samesite="Strict", ...)
41-
"""
42-
43-
def on_result_found(self, original_node, updated_node):
44-
new_args = self.replace_args(
45-
original_node, self._choose_new_args(original_node)
46-
)
47-
return self.update_arg_target(updated_node, new_args)
59+
"""
60+
),
61+
transformer=LibcstTransformerPipeline(SecureCookieTransformer),
62+
)

src/core_codemods/sonar/api.py

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,53 @@ def origin(self):
1515
return "sonar"
1616

1717
@classmethod
18-
def from_core_codemod(
18+
def from_core_codemod_with_multiple_rules(
1919
cls,
2020
name: str,
2121
other: CoreCodemod,
22-
rule_id: str,
23-
rule_name: str,
22+
rules: list[ToolRule],
2423
transformer: BaseTransformerPipeline | None = None,
2524
):
26-
rule_url = sonar_url_from_id(rule_id)
2725
return SonarCodemod(
2826
metadata=Metadata(
2927
name=name,
3028
summary=other.summary,
3129
review_guidance=other._metadata.review_guidance,
3230
references=(
33-
other.references + [Reference(url=rule_url, description=rule_name)]
31+
other.references
32+
+ [Reference(url=tr.url or "", description=tr.name) for tr in rules]
3433
),
3534
description=other.description,
3635
tool=ToolMetadata(
3736
name="Sonar",
38-
rules=[
39-
ToolRule(
40-
id=rule_id,
41-
name=rule_name,
42-
url=rule_url,
43-
)
44-
],
37+
rules=rules,
4538
),
4639
),
4740
transformer=transformer if transformer else other.transformer,
4841
detector=SonarDetector(),
4942
default_extensions=other.default_extensions,
50-
requested_rules=[rule_id],
43+
requested_rules=[tr.id for tr in rules],
44+
)
45+
46+
@classmethod
47+
def from_core_codemod(
48+
cls,
49+
name: str,
50+
other: CoreCodemod,
51+
rule_id: str,
52+
rule_name: str,
53+
transformer: BaseTransformerPipeline | None = None,
54+
):
55+
rule_url = sonar_url_from_id(rule_id)
56+
rules = [
57+
ToolRule(
58+
id=rule_id,
59+
name=rule_name,
60+
url=rule_url,
61+
),
62+
]
63+
return cls.from_core_codemod_with_multiple_rules(
64+
name, other, rules, transformer
5165
)
5266

5367

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from codemodder.codemods.base_codemod import ToolRule
2+
from core_codemods.secure_flask_cookie import SecureFlaskCookie
3+
from core_codemods.sonar.api import SonarCodemod
4+
5+
rules = [
6+
ToolRule(
7+
id="python:S3330",
8+
name='Creating cookies without the "HttpOnly" flag is security-sensitive',
9+
url="https://rules.sonarsource.com/python/RSPEC-3330/",
10+
),
11+
ToolRule(
12+
id="python:S2092",
13+
name='Creating cookies without the "secure" flag is security-sensitive',
14+
url="ahttps://rules.sonarsource.com/python/RSPEC-2092/",
15+
),
16+
]
17+
18+
SonarSecureCookie = SonarCodemod.from_core_codemod_with_multiple_rules(
19+
name="secure-random",
20+
other=SecureFlaskCookie,
21+
rules=rules,
22+
)

0 commit comments

Comments
 (0)