ds-reporting-lib 6.3.0__tar.gz → 6.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/PKG-INFO +1 -1
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/pyproject.toml +1 -1
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/ds_reporting_lib.egg-info/PKG-INFO +1 -1
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/reporting_lib/htmlgen.py +37 -19
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/README.md +0 -0
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/setup.cfg +0 -0
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/ds_reporting_lib.egg-info/SOURCES.txt +0 -0
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/ds_reporting_lib.egg-info/dependency_links.txt +0 -0
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/ds_reporting_lib.egg-info/top_level.txt +0 -0
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/reporting_lib/__init__.py +0 -0
- {ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/reporting_lib/template.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import html
|
|
3
3
|
import re
|
|
4
|
+
from typing import Any, Dict, List, Optional
|
|
4
5
|
|
|
5
6
|
from reporting_lib.template import (
|
|
6
7
|
PRIORITIZED_VULNERABILITIES,
|
|
@@ -123,11 +124,11 @@ class ReportGenerator:
|
|
|
123
124
|
|
|
124
125
|
def __init__(
|
|
125
126
|
self,
|
|
126
|
-
report_output_path,
|
|
127
|
-
input_vdr_json_path=None,
|
|
128
|
-
input_rich_html_path=None,
|
|
129
|
-
input_txt_path=None,
|
|
130
|
-
raw_content=False,
|
|
127
|
+
report_output_path: str,
|
|
128
|
+
input_vdr_json_path: Optional[str] = None,
|
|
129
|
+
input_rich_html_path: Optional[str] = None,
|
|
130
|
+
input_txt_path: Optional[str] = None,
|
|
131
|
+
raw_content: bool = False,
|
|
131
132
|
):
|
|
132
133
|
input_counter = 0
|
|
133
134
|
|
|
@@ -150,8 +151,11 @@ class ReportGenerator:
|
|
|
150
151
|
self.input_txt_path = input_txt_path
|
|
151
152
|
self.raw_content = raw_content
|
|
152
153
|
|
|
153
|
-
def extract_depscan_reports_from_vdr_json(self):
|
|
154
|
+
def extract_depscan_reports_from_vdr_json(self) -> List[str]:
|
|
154
155
|
depscan_reports = set()
|
|
156
|
+
# The constructor guarantees exactly one input path was supplied; the
|
|
157
|
+
# caller only reaches here for the VDR-JSON flavour.
|
|
158
|
+
assert self.input_vdr_json_path is not None
|
|
155
159
|
with open(self.input_vdr_json_path, "r", encoding="utf-8") as file:
|
|
156
160
|
data = json.load(file)
|
|
157
161
|
if "annotations" not in data:
|
|
@@ -172,6 +176,7 @@ class ReportGenerator:
|
|
|
172
176
|
return list(depscan_reports)
|
|
173
177
|
|
|
174
178
|
def extract_depscan_report_from_rich_html(self):
|
|
179
|
+
assert self.input_rich_html_path is not None
|
|
175
180
|
with open(self.input_rich_html_path, "r", encoding="utf-8") as file:
|
|
176
181
|
data = file.read()
|
|
177
182
|
|
|
@@ -193,6 +198,7 @@ class ReportGenerator:
|
|
|
193
198
|
return depscan_report, styles
|
|
194
199
|
|
|
195
200
|
def extract_depscan_report_from_txt(self):
|
|
201
|
+
assert self.input_txt_path is not None
|
|
196
202
|
with open(self.input_txt_path, "r", encoding="utf-8") as file:
|
|
197
203
|
data = file.read()
|
|
198
204
|
return data
|
|
@@ -284,13 +290,18 @@ class ReportGenerator:
|
|
|
284
290
|
last_seen_reachable_flows = None
|
|
285
291
|
current_location = None
|
|
286
292
|
current_table_row = []
|
|
287
|
-
|
|
293
|
+
# Set from the table's top border when a data section starts; the
|
|
294
|
+
# rsplit(maxsplit=...) sites below only run inside that state.
|
|
295
|
+
current_columns_count = 0
|
|
288
296
|
summary_column = ""
|
|
289
297
|
reachable_flow_column = ""
|
|
290
298
|
reachable_packages_column = ""
|
|
291
299
|
recommendation_column = ""
|
|
292
300
|
|
|
293
|
-
|
|
301
|
+
# Parsed report sections keyed by display name. The tree mixes leaf
|
|
302
|
+
# strings and nested dicts (per-section summary/headers/data), so the
|
|
303
|
+
# values are deliberately typed as Any.
|
|
304
|
+
sections_tree: Dict[str, Any] = {
|
|
294
305
|
self.VULNERABILITY_DISCLOSURE_REPORT: {
|
|
295
306
|
self.DEPENDENCY_SCAN_RESULTS_BOM: {
|
|
296
307
|
self.TITLE: self.DEPENDENCY_SCAN_RESULTS_BOM,
|
|
@@ -569,7 +580,9 @@ class ReportGenerator:
|
|
|
569
580
|
|
|
570
581
|
if (
|
|
571
582
|
current_location == self.DEPENDENCY_SCAN_RESULTS_BOM
|
|
572
|
-
and self.normalized_text_matches(
|
|
583
|
+
and self.normalized_text_matches(
|
|
584
|
+
line, r"Vulnerabilities count: \d+( \(\d+ unique\))?"
|
|
585
|
+
)
|
|
573
586
|
):
|
|
574
587
|
sections_tree[self.VULNERABILITY_DISCLOSURE_REPORT][
|
|
575
588
|
self.DEPENDENCY_SCAN_RESULTS_BOM
|
|
@@ -1418,11 +1431,15 @@ class ReportGenerator:
|
|
|
1418
1431
|
if tree_is_from_html is False:
|
|
1419
1432
|
current_content = html.escape(current_content)
|
|
1420
1433
|
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1434
|
+
# The caption counts (id, affects) pairs and may append the unique
|
|
1435
|
+
# vulnerability count when merged entries were expanded per component
|
|
1436
|
+
# (discussion #527 follow-up). Only the leading number gates the
|
|
1437
|
+
# recount fallback; the suffix stays in the badge.
|
|
1438
|
+
count_match = re.fullmatch(r"(\d+)( \(\d+ unique\))?", current_content)
|
|
1439
|
+
if count_match:
|
|
1440
|
+
vulnerabilities_count = int(count_match.group(1))
|
|
1441
|
+
else:
|
|
1424
1442
|
vulnerabilities_count = -1
|
|
1425
|
-
pass
|
|
1426
1443
|
if vulnerabilities_count == -1:
|
|
1427
1444
|
all_cves = set()
|
|
1428
1445
|
for row_data in sections_tree[self.VULNERABILITY_DISCLOSURE_REPORT][
|
|
@@ -2197,13 +2214,12 @@ class ReportGenerator:
|
|
|
2197
2214
|
self, sections_tree, report_content, table_inits, tree_is_from_html, piece_id
|
|
2198
2215
|
):
|
|
2199
2216
|
info = INFO
|
|
2200
|
-
malware_alert = MALWARE_ALERT
|
|
2201
2217
|
if piece_id is None:
|
|
2202
2218
|
info = info.replace("<PIECE_ID_PLACEHOLDER>", "", 1)
|
|
2203
2219
|
else:
|
|
2204
2220
|
if tree_is_from_html is False:
|
|
2205
2221
|
piece_id = html.escape(piece_id)
|
|
2206
|
-
info =
|
|
2222
|
+
info = info.replace("<PIECE_ID_PLACEHOLDER>", f"{piece_id} {SEPARATOR} ", 1)
|
|
2207
2223
|
|
|
2208
2224
|
current_content = sections_tree[self.INFO][self.SUMMARY]
|
|
2209
2225
|
if tree_is_from_html is False:
|
|
@@ -2222,13 +2238,15 @@ class ReportGenerator:
|
|
|
2222
2238
|
|
|
2223
2239
|
def generate_html(
|
|
2224
2240
|
self,
|
|
2225
|
-
sections_tree=None,
|
|
2226
|
-
sections_trees=None,
|
|
2227
|
-
tree_is_from_html=False,
|
|
2228
|
-
styles="",
|
|
2241
|
+
sections_tree: Optional[Dict[str, Any]] = None,
|
|
2242
|
+
sections_trees: Optional[Dict[Any, Dict[str, Any]]] = None,
|
|
2243
|
+
tree_is_from_html: bool = False,
|
|
2244
|
+
styles: str = "",
|
|
2229
2245
|
):
|
|
2230
2246
|
if sections_tree is not None:
|
|
2231
2247
|
sections_trees = {None: sections_tree}
|
|
2248
|
+
if sections_trees is None:
|
|
2249
|
+
raise ValueError("generate_html requires sections_tree or sections_trees")
|
|
2232
2250
|
|
|
2233
2251
|
main_report = HTML_REPORT
|
|
2234
2252
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/ds_reporting_lib.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ds_reporting_lib-6.3.0 → ds_reporting_lib-6.3.2}/src/ds_reporting_lib.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|