owasp-depscan 6.0.0a3__py3-none-any.whl → 6.0.0b3__py3-none-any.whl

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.
depscan/cli.py CHANGED
@@ -54,6 +54,8 @@ from depscan.lib.config import (
54
54
  from depscan.lib.license import build_license_data, bulk_lookup
55
55
  from depscan.lib.logger import DEBUG, LOG, SPINNER, console, IS_CI
56
56
 
57
+ from reporting_lib.htmlgen import ReportGenerator
58
+
57
59
  if sys.platform == "win32" and os.environ.get("PYTHONIOENCODING") is None:
58
60
  sys.stdin.reconfigure(encoding="utf-8")
59
61
  sys.stdout.reconfigure(encoding="utf-8")
@@ -100,6 +102,7 @@ def vdr_analyze_summarize(
100
102
  scoped_pkgs,
101
103
  bom_file,
102
104
  bom_dir,
105
+ reports_dir,
103
106
  pkg_list,
104
107
  reachability_analyzer,
105
108
  reachability_options,
@@ -115,6 +118,7 @@ def vdr_analyze_summarize(
115
118
  :param scoped_pkgs: Dict containing package scopes.
116
119
  :param bom_file: Single BOM file.
117
120
  :param bom_dir: Directory containining bom files.
121
+ :param reports_dir: Directory containining report files.
118
122
  :param pkg_list: Direct list of packages when the bom file is empty.
119
123
  :param reachability_analyzer: Reachability Analyzer specified.
120
124
  :param reachability_options: Reachability Analyzer options.
@@ -165,7 +169,11 @@ def vdr_analyze_summarize(
165
169
  )
166
170
  ds_version = get_version()
167
171
  vdr_result = VDRAnalyzer(vdr_options=options).process()
168
- vdr_file = bom_file.replace(".cdx.json", ".vdr.json") if bom_file else None
172
+ # Set vdr_file in report folder
173
+ vdr_file = (
174
+ os.path.join(reports_dir, os.path.basename(bom_file)) if bom_file else None
175
+ )
176
+ vdr_file = vdr_file.replace(".cdx.json", ".vdr.json") if vdr_file else None
169
177
  if not vdr_file and bom_dir:
170
178
  vdr_file = os.path.join(bom_dir, DEPSCAN_DEFAULT_VDR_FILE)
171
179
  if vdr_result.success:
@@ -617,15 +625,11 @@ def run_depscan(args):
617
625
  html_report_file = depscan_options.get(
618
626
  "html_report_file", os.path.join(reports_dir, "depscan.html")
619
627
  )
620
- pdf_report_file = depscan_options.get(
621
- "pdf_report_file", os.path.join(reports_dir, "depscan.pdf")
622
- )
623
628
  txt_report_file = depscan_options.get(
624
629
  "txt_report_file", os.path.join(reports_dir, "depscan.txt")
625
630
  )
626
631
  run_config_file = os.path.join(reports_dir, "depscan.toml.sample")
627
632
  depscan_options["html_report_file"] = html_report_file
628
- depscan_options["pdf_report_file"] = pdf_report_file
629
633
  depscan_options["txt_report_file"] = txt_report_file
630
634
  # Create reports directory
631
635
  if reports_dir and not os.path.exists(reports_dir):
@@ -934,6 +938,7 @@ def run_depscan(args):
934
938
  scoped_pkgs=scoped_pkgs,
935
939
  bom_file=bom_files[0] if len(bom_files) == 1 else None,
936
940
  bom_dir=args.bom_dir,
941
+ reports_dir=args.reports_dir,
937
942
  pkg_list=pkg_list,
938
943
  reachability_analyzer=reachability_analyzer,
939
944
  reachability_options=reachability_options,
@@ -975,7 +980,13 @@ def run_depscan(args):
975
980
  theme=(MONOKAI if os.getenv("USE_DARK_THEME") else DEFAULT_TERMINAL_THEME),
976
981
  )
977
982
  console.save_text(txt_report_file, clear=False)
978
- utils.export_pdf(html_report_file, pdf_report_file)
983
+ # Prettify the rich html report
984
+ html_report_generator = ReportGenerator(
985
+ input_rich_html_path=html_report_file,
986
+ report_output_path=html_report_file,
987
+ raw_content=False,
988
+ )
989
+ html_report_generator.parse_and_generate_report()
979
990
  # This logic needs refactoring
980
991
  # render report into template if wished
981
992
  if args.report_template and os.path.isfile(args.report_template):
depscan/lib/bom.py CHANGED
@@ -556,7 +556,11 @@ def annotate_vdr(vdr_file, txt_report_file):
556
556
  return
557
557
  vdr = json_load(vdr_file)
558
558
  metadata = vdr.get("metadata", {})
559
- tools = metadata.get("tools", {}).get("components", {})
559
+ # Some cyclonedx sbom don't containg tools.components
560
+ if "components" in metadata.get("tools"):
561
+ tools = metadata.get("tools", {}).get("components", {})
562
+ else:
563
+ tools = {}
560
564
  with open(txt_report_file, errors="ignore", encoding="utf-8") as txt_fp:
561
565
  report = txt_fp.read()
562
566
  annotations = vdr.get("annotations", []) or []
depscan/lib/explainer.py CHANGED
@@ -47,9 +47,14 @@ def explain(project_type, src_dir, bom_dir, vdr_file, vdr_result, explanation_mo
47
47
  rsection = Markdown("""## Service Endpoints
48
48
 
49
49
  The following endpoints and code hotspots were identified by depscan. Verify that proper authentication and authorization mechanisms are in place to secure them.""")
50
- console.print(rsection)
50
+ any_endpoints_shown = False
51
51
  for ospec in openapi_spec_files:
52
- pattern_methods = print_endpoints(ospec)
52
+ pattern_methods = print_endpoints(
53
+ ospec, rsection if not any_endpoints_shown else None
54
+ )
55
+ if not any_endpoints_shown and pattern_methods:
56
+ any_endpoints_shown = True
57
+
53
58
  # Return early for endpoints only explanations
54
59
  if explanation_mode in ("Endpoints",):
55
60
  return
@@ -109,7 +114,7 @@ def _track_usage_targets(usage_targets, usages_object):
109
114
  usage_targets.add(f"{file}#{l}")
110
115
 
111
116
 
112
- def print_endpoints(ospec):
117
+ def print_endpoints(ospec, header_section=None):
113
118
  if not ospec:
114
119
  return
115
120
  paths = json_load(ospec).get("paths") or {}
@@ -151,6 +156,9 @@ def print_endpoints(ospec):
151
156
  sorted_areas.sort()
152
157
  rtable.add_row(k, ("\n".join(v)).upper(), "\n".join(sorted_areas))
153
158
  if pattern_methods:
159
+ # Print the header section
160
+ if header_section:
161
+ console.print(header_section)
154
162
  console.print()
155
163
  console.print(rtable)
156
164
  return pattern_methods
@@ -178,6 +186,7 @@ def explain_reachables(
178
186
  reachable_explanations = 0
179
187
  checked_flows = 0
180
188
  has_crypto_flows = False
189
+ explained_ids = {}
181
190
  purls_reachable_explanations = defaultdict(int)
182
191
  source_reachable_explanations = defaultdict(int)
183
192
  sink_reachable_explanations = defaultdict(int)
@@ -194,16 +203,9 @@ def explain_reachables(
194
203
  or (not areach.get("purls") and not cpp_flow)
195
204
  ):
196
205
  continue
197
- # Focus only on the prioritized list if available
198
- # if project_type in ("java",) and pkg_group_rows:
199
- # is_prioritized = False
200
- # for apurl in areach.get("purls"):
201
- # if pkg_group_rows.get(apurl):
202
- # is_prioritized = True
203
- # if not is_prioritized:
204
- # continue
205
206
  (
206
207
  flow_tree,
208
+ added_ids,
207
209
  comment,
208
210
  source_sink_desc,
209
211
  source_code_str,
@@ -218,7 +220,13 @@ def explain_reachables(
218
220
  project_type,
219
221
  vdr_result,
220
222
  )
221
- if not source_sink_desc or not flow_tree or len(flow_tree.children) < 5:
223
+ # The goal is to reduce duplicate explanations by checking if a given flow is similar to one we have explained
224
+ # before. We do this by checking the node ids, source-sink explanations, purl tags and so on.
225
+ added_ids_str = "-".join(added_ids)
226
+ # Have we seen this sequence before?
227
+ if explained_ids.get(added_ids_str) or len(added_ids) < 4:
228
+ continue
229
+ if not source_sink_desc or not flow_tree or len(flow_tree.children) < 4:
222
230
  continue
223
231
  # In non-reachables mode, we are not interested in reachable flows.
224
232
  if (
@@ -269,6 +277,7 @@ def explain_reachables(
269
277
  header_shown = True
270
278
  console.print()
271
279
  console.print(rtable)
280
+ explained_ids[added_ids_str] = True
272
281
  reachable_explanations += 1
273
282
  if purls_str:
274
283
  purls_reachable_explanations[purls_str] += 1
@@ -428,7 +437,7 @@ def filter_tags(tags):
428
437
 
429
438
 
430
439
  def is_filterable_code(project_type, code):
431
- if len(code) < 5:
440
+ if len(code) < 3:
432
441
  return True
433
442
  for c in (
434
443
  "console.log",
@@ -455,8 +464,16 @@ def flow_to_str(explanation_mode, flow, project_type):
455
464
  and flow.get("lineNumber")
456
465
  and not flow.get("parentFileName").startswith("unknown")
457
466
  ):
458
- file_loc = f"{flow.get('parentFileName').replace('src/main/java/', '').replace('src/main/scala/', '')}#{flow.get('lineNumber')} "
467
+ # strip common prefixes
468
+ name = flow.get('parentFileName', '')
469
+ for p in ('src/main/java/', 'src/main/scala/'):
470
+ name = name.removeprefix(p)
471
+ file_loc = f"{name}#{flow.get('lineNumber')} "
459
472
  node_desc = flow.get("code").split("\n")[0]
473
+ if (len(node_desc) < 3 or node_desc.endswith("{")) and len(flow.get("code")) > 3:
474
+ node_desc = " ".join(flow.get("code", "").split())
475
+ if "(" in node_desc:
476
+ node_desc = node_desc.split("(")[0] + "() ..."
460
477
  if node_desc.endswith("("):
461
478
  node_desc = f":diamond_suit: {node_desc})"
462
479
  elif node_desc.startswith("return "):
@@ -510,6 +527,7 @@ def explain_flows(explanation_mode, flows, purls, project_type, vdr_result):
510
527
  if purls:
511
528
  purls_str = "\n".join(purls)
512
529
  comments.append(f"[info]Reachable Packages:[/info]\n{purls_str}")
530
+ added_ids = []
513
531
  added_flows = []
514
532
  added_node_desc = []
515
533
  has_check_tag = False
@@ -547,6 +565,7 @@ def explain_flows(explanation_mode, flows, purls, project_type, vdr_result):
547
565
  if flow_str in added_flows or node_desc in added_node_desc:
548
566
  continue
549
567
  added_flows.append(flow_str)
568
+ added_ids.append(str(aflow.get("id", "")))
550
569
  added_node_desc.append(node_desc)
551
570
  if not tree:
552
571
  tree = Tree(flow_str)
@@ -561,6 +580,7 @@ def explain_flows(explanation_mode, flows, purls, project_type, vdr_result):
561
580
  )
562
581
  return (
563
582
  tree,
583
+ added_ids,
564
584
  "\n".join(comments),
565
585
  source_sink_desc,
566
586
  source_code_str,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: owasp-depscan
3
- Version: 6.0.0a3
3
+ Version: 6.0.0b3
4
4
  Summary: Fully open-source security audit for project dependencies based on known vulnerabilities and advisories.
5
5
  Author-email: Team AppThreat <cloud@appthreat.com>
6
6
  License-Expression: MIT
@@ -20,7 +20,7 @@ Classifier: Topic :: Utilities
20
20
  Requires-Python: >=3.10
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
- Requires-Dist: appthreat-vulnerability-db[oras]
23
+ Requires-Dist: appthreat-vulnerability-db[oras]>=6.4.3
24
24
  Requires-Dist: custom-json-diff>=2.1.6
25
25
  Requires-Dist: defusedxml>=0.7.1
26
26
  Requires-Dist: PyYAML>=6.0.2
@@ -31,6 +31,7 @@ Requires-Dist: cvss>=3.4
31
31
  Requires-Dist: tomli>=2.2.1; python_full_version <= "3.11"
32
32
  Requires-Dist: ds-xbom-lib
33
33
  Requires-Dist: ds-analysis-lib
34
+ Requires-Dist: ds-reporting-lib
34
35
  Provides-Extra: dev
35
36
  Requires-Dist: black>=25.1.0; extra == "dev"
36
37
  Requires-Dist: flake8>=7.1.2; extra == "dev"
@@ -1,11 +1,11 @@
1
1
  depscan/__init__.py,sha256=u_HyD63vlgVi48bUU6bI8O1fdXJOLPaNwCrMJdCnzJE,165
2
- depscan/cli.py,sha256=bGTNQ6PV_GNz2YG-cGNJL57t4Ekkjr2l5FYsXKLJsAs,40885
2
+ depscan/cli.py,sha256=7QDlrQz4g_fLwGjWxyAnLoIISG1Yg8WdIGtRKhyk3NU,41229
3
3
  depscan/cli_options.py,sha256=zKje-zoM0OjCVW0pC6cRWb_8D6T-R1PTSjfGBjmSzZ8,9468
4
4
  depscan/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  depscan/lib/audit.py,sha256=i6sE-vN0Fk5gc-npHIhrrior4772_tTlPVAlznyuogo,1582
6
- depscan/lib/bom.py,sha256=OUFESoyPmYz0Igm9zoLn8ap6dLUJdQUb1VFN8i5lEgE,20823
6
+ depscan/lib/bom.py,sha256=bByZcT8EFfO-GBOcSlsu43hZHw2-nnEOjC85cjIr1T8,20960
7
7
  depscan/lib/config.py,sha256=v3Rv4nyPMjvk-EbpWSSYcloQa4v2N0bTzXKWF5nDJvg,9572
8
- depscan/lib/explainer.py,sha256=Gw1So2sQ9qNbKYxJ0mx1KEraEltuYX284Cxy1MQeMrY,21165
8
+ depscan/lib/explainer.py,sha256=yyGE7FwXmzcTniYewHBSkxtfgR6wilG5KXn6WgyyiWY,22018
9
9
  depscan/lib/github.py,sha256=h6e_12xLwspXJbt_7lW6vuHaqgJQgyFSRCLrfUndCH4,1697
10
10
  depscan/lib/license.py,sha256=ChwqAXPrMcDQJqSgDag7Th8VwoRCq8oMvwPt64iL4gw,2404
11
11
  depscan/lib/logger.py,sha256=gU5epbOHlhvuFhMqRTgn71AJ4KPB5Gf2iAmgTx3qI-4,2837
@@ -17,7 +17,7 @@ depscan/lib/package_query/metadata.py,sha256=Nnh6ctLIXPRTMoHOjZC7uhmFM3ogGljg22d
17
17
  depscan/lib/package_query/npm_pkg.py,sha256=eXdTeq1ffxLN3fWfMh3QcGG1u0VYLGR4-0BmVoD5BPk,15443
18
18
  depscan/lib/package_query/pkg_query.py,sha256=ODnRegpD3gv5FIKy0ogXMEITcdfVVV-eoIaWf7UhrQU,7038
19
19
  depscan/lib/package_query/pypi_pkg.py,sha256=scn6UhMWqA0ajS-u5UVMGV7Vx-6PEY75lN6uET9yU5c,4808
20
- owasp_depscan-6.0.0a3.dist-info/licenses/LICENSE,sha256=oQnCbnZtJ_NLDdOLc-rVY1D1N0RNWLHPpYXcc77xzSo,1073
20
+ owasp_depscan-6.0.0b3.dist-info/licenses/LICENSE,sha256=oQnCbnZtJ_NLDdOLc-rVY1D1N0RNWLHPpYXcc77xzSo,1073
21
21
  vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  vendor/choosealicense.com/_data/fields.yml,sha256=ydNsITXFUuADzGPM-jcUcJnN0r_qSGgH51oV27nX3Qs,819
23
23
  vendor/choosealicense.com/_data/meta.yml,sha256=rSNmnx0LE6VA9wnR29Y_P9s-TnADQqbdw2enE4i1mWM,1792
@@ -69,9 +69,9 @@ vendor/choosealicense.com/_licenses/upl-1.0.txt,sha256=yJ3mfZkFmzSHesz6uOF9S0fX6
69
69
  vendor/choosealicense.com/_licenses/vim.txt,sha256=d5GQjXB328L8EBkhKgxcjk344D3K7UfcJmP1barrhHI,6119
70
70
  vendor/choosealicense.com/_licenses/wtfpl.txt,sha256=BxXeubkvQm32MDmlZsBcbzJzBpR5kWgw0JxSR9d7f3k,948
71
71
  vendor/choosealicense.com/_licenses/zlib.txt,sha256=e6dfCeLhxD3NCnIkY4cVIagRaWdRvencjNhHZ1APvpc,1678
72
- vendor/spdx/json/licenses.json,sha256=66zBMswN5ufUL8M9TIMV0PQH9aZK_X5mtHm3OkwKmVU,314245
73
- owasp_depscan-6.0.0a3.dist-info/METADATA,sha256=PNMzv77rY6OnnLcFgiZAhIU03rKYFblllVl7M_CTV14,17394
74
- owasp_depscan-6.0.0a3.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
75
- owasp_depscan-6.0.0a3.dist-info/entry_points.txt,sha256=FxQKHFWZTfKU2eBxHPFRxwhSNexntYygYhquykS8zxA,69
76
- owasp_depscan-6.0.0a3.dist-info/top_level.txt,sha256=qbHOZvNU2dXANv946hMdP2vOi0ESQB5t2ZY5ktKtXvQ,15
77
- owasp_depscan-6.0.0a3.dist-info/RECORD,,
72
+ vendor/spdx/json/licenses.json,sha256=FXeJupGYSuy6XGe4QWjbvUGiNbkQp1aapkv0KoiyQpA,318777
73
+ owasp_depscan-6.0.0b3.dist-info/METADATA,sha256=4Vun159I4kjIAXBrdNGZLwAmDzupQn2qP57CV40VHk4,17433
74
+ owasp_depscan-6.0.0b3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
75
+ owasp_depscan-6.0.0b3.dist-info/entry_points.txt,sha256=QvBVhjzm1Vx1CQkACbQWeNykZInIXUFUi6scoOYA7XY,45
76
+ owasp_depscan-6.0.0b3.dist-info/top_level.txt,sha256=qbHOZvNU2dXANv946hMdP2vOi0ESQB5t2ZY5ktKtXvQ,15
77
+ owasp_depscan-6.0.0b3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.4.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,3 +1,2 @@
1
1
  [console_scripts]
2
2
  depscan = depscan.cli:main
3
- scan = depscan.cli:main