Skip to content

Commit 970e8c3

Browse files
committed
2023.0.2
1 parent 977a203 commit 970e8c3

File tree

13 files changed

+408
-120
lines changed

13 files changed

+408
-120
lines changed

‎CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
All major and minor version changes will be documented in this file. Details of
44
patch-level version changes can be found in [commit messages](../../commits/master).
55

6+
## 2023.0.2 - 2023/06/27
7+
8+
- Add `Level.CRIT`
9+
- Misc fixes to make plugins more resilient
10+
- Test plugin utility functions
11+
612
## 2023.0.1 - 2023/06/27
713

814
- Fix `csv` writer

‎documentation/reference/simplesecurity/level.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ Level
1818

1919
Levels for confidence and severity.
2020

21-
UNKNOWN = 0
22-
LOW = 1
23-
MED = 2
24-
HIGH = 3
25-
2621
#### Signature
2722

2823
```python
@@ -32,7 +27,7 @@ class Level(IntEnum):
3227

3328
### Level().__repr__
3429

35-
[Show source in level.py:27](../../../simplesecurity/level.py#L27)
30+
[Show source in level.py:22](../../../simplesecurity/level.py#L22)
3631

3732
__repr__ method.
3833

@@ -49,7 +44,7 @@ def __repr__(self) -> str:
4944

5045
### Level().__str__
5146

52-
[Show source in level.py:35](../../../simplesecurity/level.py#L35)
47+
[Show source in level.py:30](../../../simplesecurity/level.py#L30)
5348

5449
__str__ method (tostring).
5550

@@ -66,7 +61,7 @@ def __str__(self) -> str:
6661

6762
### Level().toSarif
6863

69-
[Show source in level.py:49](../../../simplesecurity/level.py#L49)
64+
[Show source in level.py:45](../../../simplesecurity/level.py#L45)
7065

7166
Convert to sarif representation.
7267

‎documentation/reference/simplesecurity/plugins.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Plugins
1616

1717
## bandit
1818

19-
[Show source in plugins.py:90](../../../simplesecurity/plugins.py#L90)
19+
[Show source in plugins.py:92](../../../simplesecurity/plugins.py#L92)
2020

2121
Generate list of findings using bandit. requires bandit on the system path.
2222

@@ -47,7 +47,7 @@ def bandit(scanDir=".") -> list[Finding]:
4747

4848
## dlint
4949

50-
[Show source in plugins.py:247](../../../simplesecurity/plugins.py#L247)
50+
[Show source in plugins.py:274](../../../simplesecurity/plugins.py#L274)
5151

5252
Generate list of findings using _tool_. requires _tool_ on the system path.
5353

@@ -78,7 +78,7 @@ def dlint(scanDir=".") -> list[Finding]:
7878

7979
## dodgy
8080

81-
[Show source in plugins.py:211](../../../simplesecurity/plugins.py#L211)
81+
[Show source in plugins.py:237](../../../simplesecurity/plugins.py#L237)
8282

8383
Generate list of findings using _tool_. requires _tool_ on the system path.
8484

@@ -137,7 +137,7 @@ def extractEvidence(desiredLine: int, file: str) -> list[Line]:
137137

138138
## safety
139139

140-
[Show source in plugins.py:172](../../../simplesecurity/plugins.py#L172)
140+
[Show source in plugins.py:198](../../../simplesecurity/plugins.py#L198)
141141

142142
Generate list of findings using _tool_. requires _tool_ on the system path.
143143

@@ -168,7 +168,7 @@ def safety(scanDir=".") -> list[Finding]:
168168

169169
## semgrep
170170

171-
[Show source in plugins.py:302](../../../simplesecurity/plugins.py#L302)
171+
[Show source in plugins.py:331](../../../simplesecurity/plugins.py#L331)
172172

173173
Generate list of findings using for semgrep. Requires semgrep on the
174174
system path (wsl in windows).

‎pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "simplesecurity"
3-
version = "2023.0.1"
3+
version = "2023.0.2"
44
license = "mit"
55
description = "Combine multiple popular python security tools and generate reports or output into different formats"
66
authors = ["FredHappyface"]

‎simplesecurity/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def _processPlugin(args) -> list[Callable]:
7979
},
8080
"safety": {
8181
"func": plugins.safety,
82-
"max_severity": 2,
82+
"max_severity": 4,
8383
"max_confidence": 3,
8484
"fast": True,
8585
},
@@ -91,7 +91,7 @@ def _processPlugin(args) -> list[Callable]:
9191
},
9292
"dlint": {
9393
"func": plugins.dlint,
94-
"max_severity": 3,
94+
"max_severity": 4,
9595
"max_confidence": 2,
9696
"fast": True,
9797
},

‎simplesecurity/level.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,13 @@
1111

1212

1313
class Level(IntEnum):
14-
"""Levels for confidence and severity.
15-
16-
UNKNOWN = 0
17-
LOW = 1
18-
MED = 2
19-
HIGH = 3
20-
"""
14+
"""Levels for confidence and severity."""
2115

2216
UNKNOWN = 0
2317
LOW = 1
2418
MED = 2
2519
HIGH = 3
20+
CRIT = 4
2621

2722
def __repr__(self) -> str:
2823
"""__repr__ method.
@@ -43,15 +38,17 @@ def __str__(self) -> str:
4338
Level.LOW: "Low",
4439
Level.MED: "Medium",
4540
Level.HIGH: "High",
41+
Level.CRIT: "Critical",
4642
}
4743
return reprMap[self]
4844

4945
def toSarif(self) -> str:
5046
"""Convert to sarif representation."""
5147
reprMap = {
5248
Level.UNKNOWN: "note",
53-
Level.LOW: "warning",
49+
Level.LOW: "note",
5450
Level.MED: "warning",
5551
Level.HIGH: "error",
52+
Level.CRIT: "error",
5653
}
5754
return reprMap[self]

‎simplesecurity/plugins.py

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,17 @@ def extractEvidence(desiredLine: int, file: str) -> list[Line]:
7575
"""
7676
with open(file, encoding="utf-8", errors="ignore") as fileContents:
7777
start = max(desiredLine - 3, 0)
78-
for line in range(start):
79-
next(fileContents)
8078
content = []
81-
for line in range(start + 1, desiredLine + 3):
82-
try:
79+
try:
80+
for line in range(start):
81+
next(fileContents)
82+
for line in range(start + 1, desiredLine + 3):
8383
lineContent = next(fileContents).rstrip().replace("\t", " ")
84-
except StopIteration:
85-
break
86-
content.append({"selected": line == desiredLine, "line": line, "content": lineContent})
84+
content.append(
85+
{"selected": line == desiredLine, "line": line, "content": lineContent}
86+
)
87+
except StopIteration:
88+
pass
8789
return content
8890

8991

@@ -115,20 +117,22 @@ def bandit(scanDir=".") -> list[Finding]:
115117
)[1]
116118
)["results"]
117119
for result in results:
118-
file = result["filename"].replace("\\", "/")
120+
file = result.get("filename").replace("\\", "/")
121+
resultId = result.get("test_id")
122+
line = result.get("line_number")
119123
findings.append(
120124
{
121-
"id": result["test_id"],
122-
"title": f"{result['test_id']}: {result['test_name']}",
123-
"description": result["issue_text"],
125+
"id": resultId,
126+
"title": f"{resultId}: {result.get('test_name')}",
127+
"description": result.get("issue_text"),
124128
"file": file,
125-
"evidence": extractEvidence(result["line_number"], file),
126-
"severity": levelMap[result["issue_severity"]],
127-
"confidence": levelMap[result["issue_confidence"]],
128-
"line": result["line_number"],
129+
"evidence": extractEvidence(line, file),
130+
"severity": levelMap[result.get("issue_severity")],
131+
"confidence": levelMap[result.get("issue_confidence")],
132+
"line": line,
129133
"_other": {
130-
"more_info": result["more_info"],
131-
"line_range": result["line_range"],
134+
"more_info": result.get("more_info"),
135+
"line_range": result.get("line_range"),
132136
},
133137
}
134138
)
@@ -138,23 +142,45 @@ def bandit(scanDir=".") -> list[Finding]:
138142
def _doSafetyProcessing(results: dict[str, Any]) -> list[Finding]:
139143
findings = []
140144
for result in results["vulnerabilities"]:
145+
vulnerabilityId = result.get("vulnerability_id")
146+
packageName = result.get("package_name")
147+
advisory = result.get("advisory")
148+
149+
moreInfo = result.get("more_info_url")
150+
affectedVersions = "; ".join(result.get("affected_versions"))
151+
152+
content = f"{packageName}, version(s)={affectedVersions}"
153+
description = (
154+
f"Vulnerability found in package {packageName},"
155+
f"version(s)={affectedVersions}. {advisory}. More info available at {moreInfo}"
156+
)
157+
158+
cvssv3Score = result.get("severity").get("cvssv3", {}).get("base_score", 0)
159+
severity = Level.LOW
160+
if cvssv3Score > 3.9:
161+
severity = Level.MED
162+
if cvssv3Score > 6.9:
163+
severity = Level.HIGH
164+
if cvssv3Score > 8.9:
165+
severity = Level.CRIT
166+
141167
findings.append(
142168
{
143-
"id": result[4],
144-
"title": f"{result[4]}: {result[0]}",
145-
"description": result[3],
169+
"id": vulnerabilityId,
170+
"title": f"{vulnerabilityId}: {packageName}",
171+
"description": description,
146172
"file": "Project Requirements",
147173
"evidence": [
148174
{
149175
"selected": True,
150176
"line": 0,
151-
"content": f"{result[0]} version={result[2]} affects{result[1]}",
177+
"content": content,
152178
}
153179
],
154-
"severity": Level.MED,
180+
"severity": severity,
155181
"confidence": Level.HIGH,
156182
"line": "Unknown",
157-
"_other": {"id": result[4], "affected": result[1]},
183+
"_other": {"id": vulnerabilityId, "affectedVersions": affectedVersions},
158184
}
159185
)
160186
return findings
@@ -227,17 +253,18 @@ def dodgy(scanDir=".") -> list[Finding]:
227253
rawResults = _doSysExec(f"dodgy {scanDir} -i {' '.join(EXCLUDED)}")[1]
228254
results = loads(rawResults)["warnings"]
229255
for result in results:
230-
file = "./" + result["path"].replace("\\", "/")
256+
file = "./" + result.get("path").replace("\\", "/")
257+
message = result.get("message")
231258
findings.append(
232259
{
233-
"id": result["code"],
234-
"title": result["message"],
235-
"description": result["message"],
260+
"id": result.get("code"),
261+
"title": message,
262+
"description": message,
236263
"file": file,
237-
"evidence": extractEvidence(result["line"], file),
264+
"evidence": extractEvidence(result.get("line"), file),
238265
"severity": Level.MED,
239266
"confidence": Level.MED,
240-
"line": result["line"],
267+
"line": result.get("line"),
241268
"_other": {},
242269
}
243270
)
@@ -269,29 +296,31 @@ def dlint(scanDir=".") -> list[Finding]:
269296
"info": Level.LOW,
270297
"minor": Level.MED,
271298
"major": Level.MED,
272-
"critical": Level.HIGH,
273-
"blocker": Level.HIGH,
299+
"critical": Level.CRIT,
300+
"blocker": Level.CRIT,
274301
}
275302
for filePath, scanResults in jsonResults.items():
276-
for scanResult in scanResults:
303+
for result in scanResults:
304+
message = f"{result.get('check_name')}: " f"{result.get('description')}"
305+
positions = result.get("location", {}).get("positions", {})
306+
line = positions.get("begin", {}).get("line", 0)
277307
findings.append(
278308
{
279-
"id": scanResult["check_name"],
280-
"title": f"{scanResult['check_name']}: " f"{scanResult['description']}",
281-
"description": f"{scanResult['check_name']}: " f"{scanResult['description']}",
309+
"id": result.get("check_name"),
310+
"title": message,
311+
"description": message,
282312
"file": filePath,
283313
"evidence": extractEvidence(
284-
scanResult["location"]["positions"]["begin"]["line"],
314+
line,
285315
filePath,
286316
),
287-
"severity": levelMap[scanResult["severity"]],
317+
"severity": levelMap[result.get("severity")],
288318
"confidence": Level.MED,
289-
"line": scanResult["location"]["positions"]["begin"]["line"],
319+
"line": line,
290320
"_other": {
291-
"col": scanResult["location"]["positions"]["begin"]["column"],
292-
"start": scanResult["location"]["positions"]["begin"]["line"],
293-
"end": scanResult["location"]["positions"]["end"]["line"],
294-
"fingerprint": scanResult["fingerprint"],
321+
"start": line,
322+
"end": positions.get("end", {}).get("line", 0),
323+
"fingerprint": result.get("fingerprint"),
295324
},
296325
}
297326
)
@@ -324,23 +353,24 @@ def semgrep(scanDir=".") -> list[Finding]:
324353
)["results"]
325354
levelMap = {"INFO": Level.LOW, "WARNING": Level.MED, "ERROR": Level.HIGH}
326355
for result in results:
327-
filePath = result["Target"].replace("\\", "/")
356+
filePath = result.get("Target").replace("\\", "/")
328357
file = f"{scanDir}/{filePath}"
358+
resultId = result.get("check_id", "")
359+
extras = result.get("extra", {})
360+
line = result.get("start", {}).get("line", 0)
329361
findings.append(
330362
{
331-
"id": result["check_id"],
332-
"title": result["check_id"].split(".")[-1],
333-
"description": result["extra"]["message"].strip(),
363+
"id": resultId,
364+
"title": resultId.split(".")[-1],
365+
"description": extras("message").strip(),
334366
"file": file,
335-
"evidence": extractEvidence(result["start"]["line"], file),
336-
"severity": levelMap[result["extra"]["severity"]],
367+
"evidence": extractEvidence(line, file),
368+
"severity": levelMap[extras("severity")],
337369
"confidence": Level.HIGH,
338-
"line": result["start"]["line"],
370+
"line": line,
339371
"_other": {
340-
"col": result["start"]["col"],
341-
"start": result["start"],
342-
"end": result["end"],
343-
"extra": result["extra"],
372+
"end": result.get("end"),
373+
"extra": extras,
344374
},
345375
}
346376
)

‎tests/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +0,0 @@
1-

‎tests/data/advanced.sarif

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
},
4343
{
4444
"ruleId": "TEST_ID2",
45-
"level": "warning",
45+
"level": "note",
4646
"message": {
4747
"text": "TEST2: This is a test2"
4848
},

0 commit comments

Comments
 (0)