Skip to content

Commit

Permalink
parse codeql results without region (#546)
Browse files Browse the repository at this point in the history
  • Loading branch information
clavedeluna authored May 9, 2024
1 parent 8c51988 commit bc1f044
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 35 deletions.
24 changes: 12 additions & 12 deletions src/codemodder/codeql.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ class CodeQLLocation(Location):
def from_sarif(cls, sarif_location) -> Self:
artifact_location = sarif_location["physicalLocation"]["artifactLocation"]
file = Path(artifact_location["uri"])
start = LineInfo(
line=sarif_location["physicalLocation"]["region"]["startLine"],
column=sarif_location["physicalLocation"]["region"].get("startColumn"),
)

try:
region = sarif_location["physicalLocation"]["region"]
except KeyError:
# A location without a region indicates a result for the entire file.
# Use sentinel values of 0 index for start/end
zero = LineInfo(0)
return cls(file=file, start=zero, end=zero)

start = LineInfo(line=region["startLine"], column=region.get("startColumn"))
end = LineInfo(
line=sarif_location["physicalLocation"]["region"].get(
"endLine", start.line
),
column=sarif_location["physicalLocation"]["region"].get(
"endColumn", start.column
),
line=region.get("endLine", start.line),
column=region.get("endColumn", start.column),
)
return cls(file=file, start=start, end=end)

Expand All @@ -40,15 +42,13 @@ def from_sarif(
) -> Self:
extension_index = sarif_result["rule"]["toolComponent"]["index"]
tool_index = sarif_result["rule"]["index"]

rule_data = rule_extensions[extension_index]["rules"][tool_index]

locations: list[Location] = []
for location in sarif_result["locations"]:
try:
codeql_location = CodeQLLocation.from_sarif(location)
except KeyError:
# TODO: handle this case more gracefully
continue

locations.append(codeql_location)
Expand Down
91 changes: 68 additions & 23 deletions tests/test_codeql.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,19 @@
class TestCodeQLResultSet(TestCase):

def test_from_sarif(self):
# Given a SARIF file with known content
sarif_content = {
"runs": [
{
"tool": {
"driver": {"name": "CodeQL"},
"extensions": [{"rules": [{"id": "python/sql-injection"}]}],
"extensions": [
{
"rules": [
{"id": "python/sql-injection"},
{"id": "cs/web/missing-x-frame-options"},
]
},
],
},
"results": [
{
Expand All @@ -37,7 +43,28 @@ def test_from_sarif(self):
"toolComponent": {"index": 0},
"index": 0,
},
}
},
{
"ruleId": "cs/web/missing-x-frame-options",
"message": {
"text": "Configuration file is missing the X-Frame-Options setting."
},
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"index": 5,
"uri": "Web.config",
}
}
}
],
"rule": {
"id": "cs/web/missing-x-frame-options",
"toolComponent": {"index": 0},
"index": 1,
},
},
],
}
]
Expand All @@ -46,44 +73,62 @@ def test_from_sarif(self):
with mock.patch(
"builtins.open", mock.mock_open(read_data=json.dumps(sarif_content))
):
# When parsing the SARIF file
result_set = CodeQLResultSet.from_sarif(sarif_file)

# Then the result set should contain the expected results
self.assertEqual(len(result_set), 1)
self.assertEqual(len(result_set), 2)
self.assertIn("python/sql-injection", result_set)
self.assertEqual(len(result_set["python/sql-injection"]), 1)
self.assertIn("cs/web/missing-x-frame-options", result_set)

sql_result = result_set["python/sql-injection"]
self.assertEqual(len(sql_result), 1)
self.assertEqual(
result_set["python/sql-injection"][Path("example.py")][0].rule_id,
sql_result[Path("example.py")][0].rule_id,
"python/sql-injection",
)
self.assertEqual(
result_set["python/sql-injection"][Path("example.py")][0]
.locations[0]
.file,
sql_result[Path("example.py")][0].locations[0].file,
Path("example.py"),
)
self.assertEqual(
result_set["python/sql-injection"][Path("example.py")][0]
.locations[0]
.start.line,
sql_result[Path("example.py")][0].locations[0].start.line,
10,
)
self.assertEqual(
result_set["python/sql-injection"][Path("example.py")][0]
.locations[0]
.start.column,
sql_result[Path("example.py")][0].locations[0].start.column,
5,
)
self.assertEqual(
result_set["python/sql-injection"][Path("example.py")][0]
.locations[0]
.end.line,
sql_result[Path("example.py")][0].locations[0].end.line,
10,
)
self.assertEqual(
result_set["python/sql-injection"][Path("example.py")][0]
.locations[0]
.end.column,
sql_result[Path("example.py")][0].locations[0].end.column,
20,
)

xframe_result = result_set["cs/web/missing-x-frame-options"]
self.assertEqual(len(xframe_result), 1)
self.assertEqual(
xframe_result[Path("Web.config")][0].rule_id,
"cs/web/missing-x-frame-options",
)
self.assertEqual(
xframe_result[Path("Web.config")][0].locations[0].file,
Path("Web.config"),
)
self.assertEqual(
xframe_result[Path("Web.config")][0].locations[0].start.line,
0,
)
self.assertEqual(
xframe_result[Path("Web.config")][0].locations[0].start.column,
-1,
)
self.assertEqual(
xframe_result[Path("Web.config")][0].locations[0].end.line,
0,
)
self.assertEqual(
xframe_result[Path("Web.config")][0].locations[0].end.column,
-1,
)

0 comments on commit bc1f044

Please sign in to comment.