Skip to content

Commit da4b945

Browse files
authored
Merge pull request #1961 from tisnik/lcore-2631-vulnerability-report-script-processing-part
LCORE-2631: Vulnerability report script: Dependabot data processing part
2 parents 17de4a0 + e183249 commit da4b945

1 file changed

Lines changed: 112 additions & 9 deletions

File tree

scripts/vulnerability_report.py

Lines changed: 112 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,39 @@
55
Rretrieves Dependabot issues, analyses issues, generates graphs, and generates
66
HTML page with Vulnerability report. Is is also possible to compare two
77
repositories.
8+
9+
# Usage:
10+
usage: vulnerability_report.py [-h] [-v] --organization ORGANIZATION
11+
--repository REPOSITORY [-r] [-g] [-p]
12+
[-c COMPARISON [COMPARISON ...]]
13+
14+
Vulnerability report tool
15+
16+
options:
17+
-h, --help show this help message and exit
18+
-v, --verbose make it verbose
19+
--organization ORGANIZATION
20+
GitHub organization.
21+
--repository REPOSITORY
22+
GitHub repository.
23+
-r, --retrieve-issues
24+
Retrieve issues
25+
-g, --generate-graphs
26+
Generate graphs with vulnerabilities info
27+
-p, --generate-page Generate page with vulnerabilities info
28+
-c, --comparison COMPARISON [COMPARISON ...]
29+
Compare two or more repositories and generate
30+
comparison report. Multiple JSON files with Dependabot
31+
alerts needs to be provided
832
"""
933

10-
from argparse import ArgumentParser
34+
from argparse import ArgumentParser, Namespace
35+
import json
36+
37+
from typing import Any
38+
39+
type DependabotAlert = dict[str, Any]
40+
type DependabotAlerts = list[DependabotAlert]
1141

1242

1343
def create_argument_parser() -> ArgumentParser:
@@ -46,35 +76,107 @@ def create_argument_parser() -> ArgumentParser:
4676
parser.add_argument(
4777
"-r",
4878
"--retrieve-issues",
49-
default=True,
79+
action="store_true",
80+
default=False,
5081
help="Retrieve issues",
5182
)
5283

5384
parser.add_argument(
5485
"-g",
5586
"--generate-graphs",
56-
default=True,
87+
action="store_true",
88+
default=False,
5789
help="Generate graphs with vulnerabilities info",
5890
)
5991

6092
parser.add_argument(
6193
"-p",
6294
"--generate-page",
63-
default=True,
95+
action="store_true",
96+
default=False,
6497
help="Generate page with vulnerabilities info",
6598
)
6699

67100
parser.add_argument(
68101
"-c",
69102
"--comparison",
70-
default=False,
71-
help="Compare two repositories and generate comparison report. "
72-
"Need to be used with --data1 and --data2 options",
103+
required=False,
104+
nargs="+",
105+
default=[],
106+
help="Compare two or more repositories and generate comparison report. "
107+
"Multiple JSON files with Dependabot alerts needs to be provided",
73108
)
74109

75110
return parser
76111

77112

113+
def dependabot_file_name(args: Namespace) -> str:
114+
"""Construct file name containing Dependabot alerts."""
115+
return f"{args.organization}__{args.repository}.json"
116+
117+
118+
def load_dependabot_file(filename: str) -> Any:
119+
"""Load JSON file containing Dependabot alerts."""
120+
with open(filename, "r") as fin:
121+
return json.load(fin)
122+
123+
124+
def has_attribute_with_value(item: DependabotAlert, attribute: str, value: str) -> bool:
125+
"""Check if dictionary has attribute with given value."""
126+
return bool(item[attribute] == value)
127+
128+
129+
def has_deep_attribute_with_value(
130+
item: DependabotAlert, selector: str, attribute: str, value: str
131+
) -> bool:
132+
"""Check if dictionary has deep attribute with given value."""
133+
return bool(item[selector][attribute] == value)
134+
135+
136+
def count_attribute_with_value(
137+
items: DependabotAlerts, attribute: str, value: str
138+
) -> int:
139+
"""Count all attributes with given value."""
140+
cnt: int = 0
141+
for item in items:
142+
if has_attribute_with_value(item, attribute, value):
143+
cnt += 1
144+
return cnt
145+
146+
147+
def count_deep_attribute_with_value(
148+
items: DependabotAlerts, selector: str, attribute: str, value: str
149+
) -> int:
150+
"""Count all deep attributes with given value."""
151+
cnt: int = 0
152+
for item in items:
153+
if has_deep_attribute_with_value(item, selector, attribute, value):
154+
cnt += 1
155+
return cnt
156+
157+
158+
def opened_cves(source_data: DependabotAlerts) -> int:
159+
"""Compute how many CVEs are opened."""
160+
return count_attribute_with_value(source_data, "state", "open")
161+
162+
163+
def fixed_cves(source_data: DependabotAlerts) -> int:
164+
"""Compute how many CVEs has been fixed opened."""
165+
return count_attribute_with_value(source_data, "state", "fixed")
166+
167+
168+
def with_severity(severity: str, source_data: DependabotAlerts) -> int:
169+
"""Count number of CVE having specified severity."""
170+
return count_deep_attribute_with_value(
171+
source_data, "security_advisory", "severity", severity
172+
)
173+
174+
175+
def process_dependabot_file(dependabot_file: str, prefix: str) -> dict[str, Any]:
176+
"""Read Dependabot alerts and prepare statistic info."""
177+
return {}
178+
179+
78180
def main() -> int:
79181
"""
80182
CLI entry point that retrieves Dependabot issues and produces Vulnerability report.
@@ -94,8 +196,9 @@ def main() -> int:
94196
"""
95197
parser = create_argument_parser()
96198
args = parser.parse_args()
97-
98-
print(args)
199+
dependabot_file = dependabot_file_name(args)
200+
prefix = args.repository
201+
process_dependabot_file(dependabot_file, prefix)
99202
return 0
100203

101204

0 commit comments

Comments
 (0)