owasp-depscan 4.2.7__py3-none-any.whl → 4.3.0__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
@@ -4,6 +4,7 @@
4
4
  import argparse
5
5
  import json
6
6
  import os
7
+ import sys
7
8
  import tempfile
8
9
 
9
10
  from quart import Quart, request
@@ -11,7 +12,6 @@ from rich.panel import Panel
11
12
  from rich.terminal_theme import MONOKAI
12
13
  from vdb.lib import config
13
14
  from vdb.lib import db as db_lib
14
- from vdb.lib.aqua import AquaSource
15
15
  from vdb.lib.config import data_dir
16
16
  from vdb.lib.gha import GitHubSource
17
17
  from vdb.lib.nvd import NvdSource
@@ -20,6 +20,7 @@ from vdb.lib.utils import parse_purl
20
20
 
21
21
  import oras.client
22
22
 
23
+ from depscan.lib.csaf import export_csaf, write_toml
23
24
  from depscan.lib import privado, utils
24
25
  from depscan.lib.analysis import (
25
26
  PrepareVexOptions,
@@ -31,8 +32,18 @@ from depscan.lib.analysis import (
31
32
  summary_stats,
32
33
  )
33
34
  from depscan.lib.audit import audit, risk_audit, risk_audit_map, type_audit_map
34
- from depscan.lib.bom import create_bom, get_pkg_by_type, get_pkg_list, submit_bom
35
- from depscan.lib.config import UNIVERSAL_SCAN_TYPE, license_data_dir, spdx_license_list, vdb_database_url
35
+ from depscan.lib.bom import (
36
+ create_bom,
37
+ get_pkg_by_type,
38
+ get_pkg_list,
39
+ submit_bom,
40
+ )
41
+ from depscan.lib.config import (
42
+ UNIVERSAL_SCAN_TYPE,
43
+ license_data_dir,
44
+ spdx_license_list,
45
+ vdb_database_url,
46
+ )
36
47
  from depscan.lib.license import build_license_data, bulk_lookup
37
48
  from depscan.lib.logger import LOG, console
38
49
  from depscan.lib.utils import get_version
@@ -77,7 +88,15 @@ def build_args():
77
88
  action="store_true",
78
89
  default=False,
79
90
  dest="cache",
80
- help="Cache vulnerability information in platform specific " "user_data_dir",
91
+ help="Cache vulnerability information in platform specific "
92
+ "user_data_dir",
93
+ )
94
+ parser.add_argument(
95
+ "--csaf",
96
+ action="store_true",
97
+ default=False,
98
+ dest="csaf",
99
+ help="Generate a CSAF",
81
100
  )
82
101
  parser.add_argument(
83
102
  "--sync",
@@ -92,12 +111,15 @@ def build_args():
92
111
  action="store_true",
93
112
  default=True,
94
113
  dest="suggest",
95
- help="DEPRECATED: Suggest is the default mode for determining fix " "version.",
114
+ help="DEPRECATED: Suggest is the default mode for determining fix "
115
+ "version.",
96
116
  )
97
117
  parser.add_argument(
98
118
  "--risk-audit",
99
119
  action="store_true",
100
- default=True if os.getenv("ENABLE_OSS_RISK", "") in ["true", "1"] else False,
120
+ default=True
121
+ if os.getenv("ENABLE_OSS_RISK", "") in ["true", "1"]
122
+ else False,
101
123
  dest="risk_audit",
102
124
  help="Perform package risk audit (slow operation). Npm only.",
103
125
  )
@@ -137,7 +159,9 @@ def build_args():
137
159
  )
138
160
  parser.add_argument(
139
161
  "--reports-dir",
140
- default=os.getenv("DEPSCAN_REPORTS_DIR", os.path.join(os.getcwd(), "reports")),
162
+ default=os.getenv(
163
+ "DEPSCAN_REPORTS_DIR", os.path.join(os.getcwd(), "reports")
164
+ ),
141
165
  dest="reports_dir",
142
166
  help="Reports directory",
143
167
  )
@@ -264,7 +288,9 @@ def scan(db, project_type, pkg_list, suggest_mode):
264
288
  LOG.debug("Empty package search attempted!")
265
289
  else:
266
290
  LOG.debug("Scanning %d oss dependencies for issues", len(pkg_list))
267
- results, pkg_aliases, purl_aliases = utils.search_pkgs(db, project_type, pkg_list)
291
+ results, pkg_aliases, purl_aliases = utils.search_pkgs(
292
+ db, project_type, pkg_list
293
+ )
268
294
  # pkg_aliases is a dict that can be used to find the original vendor and
269
295
  # package name This way we consistently use the same names used by the
270
296
  # caller irrespective of how the result was obtained
@@ -321,7 +347,9 @@ def scan(db, project_type, pkg_list, suggest_mode):
321
347
  "Re-checking our suggestion to ensure there are no further "
322
348
  "vulnerabilities"
323
349
  )
324
- override_results, _, _ = utils.search_pkgs(db, project_type, sug_pkg_list)
350
+ override_results, _, _ = utils.search_pkgs(
351
+ db, project_type, sug_pkg_list
352
+ )
325
353
  if override_results:
326
354
  new_sug_dict = suggest_version(override_results)
327
355
  LOG.debug("Received override results: %s", new_sug_dict)
@@ -427,7 +455,7 @@ def summarise(
427
455
  bom_data["services"] = []
428
456
  bom_data["services"].insert(0, pservice)
429
457
  with open(vex_file, mode="w", encoding="utf-8") as vexfp:
430
- json.dump(bom_data, vexfp)
458
+ json.dump(bom_data, vexfp, indent=4)
431
459
  LOG.info("VEX file %s generated successfully", vex_file)
432
460
  except Exception:
433
461
  LOG.warning("Unable to generate VEX file for this scan")
@@ -453,8 +481,8 @@ async def cache():
453
481
  db = db_lib.get()
454
482
  if not db_lib.index_count(db["index_file"]):
455
483
  oras_client = oras.client.OrasClient()
456
- paths_list = oras_client.pull(target = vdb_database_url, outdir = data_dir)
457
- LOG.debug(f'VDB data is stored at: {paths_list}')
484
+ paths_list = oras_client.pull(target=vdb_database_url, outdir=data_dir)
485
+ LOG.debug(f"VDB data is stored at: {paths_list}")
458
486
  return {
459
487
  "error": "false",
460
488
  "message": "vulnerability database cached successfully",
@@ -551,7 +579,8 @@ async def run_scan():
551
579
  else:
552
580
  return {
553
581
  "error": "true",
554
- "message": "Unable to generate SBoM. Check your input path or " "url.",
582
+ "message": "Unable to generate SBoM. Check your input path or "
583
+ "url.",
555
584
  }, 500
556
585
 
557
586
 
@@ -562,7 +591,9 @@ def run_server(args):
562
591
  :param args: Command line arguments passed to the function.
563
592
  """
564
593
  print(at_logo)
565
- console.print(f"Depscan server running on {args.server_host}:{args.server_port}")
594
+ console.print(
595
+ f"Depscan server running on {args.server_host}:{args.server_port}"
596
+ )
566
597
  app.config["CDXGEN_SERVER_URL"] = args.cdxgen_server
567
598
  app.run(
568
599
  host=args.server_host,
@@ -583,9 +614,24 @@ def main():
583
614
  if not args.no_banner:
584
615
  print(at_logo)
585
616
  src_dir = args.src_dir_image
586
- if not src_dir:
617
+ if not src_dir or src_dir == ".":
587
618
  src_dir = os.getcwd()
588
619
  reports_dir = args.reports_dir
620
+ if args.csaf:
621
+ toml_file_path = os.path.join(src_dir, "csaf.toml")
622
+ if not os.path.exists(toml_file_path):
623
+ LOG.info("CSAF toml not found, creating template in %s", src_dir)
624
+ write_toml(toml_file_path)
625
+ LOG.info(
626
+ "Please fill out the toml with your details and rerun depscan."
627
+ )
628
+ LOG.info("Check out our CSAF documentation for an explanation of "
629
+ "this feature. https://github.com/owasp-dep-scan/dep-scan"
630
+ "/blob/master/contrib/CSAF_README.md")
631
+ LOG.info("If you're just checking out how our generator works, "
632
+ "feel free to skip filling out the toml and just rerun "
633
+ "depscan.")
634
+ sys.exit(0)
589
635
  # Detect the project types and perform the right type of scan
590
636
  if args.project_type:
591
637
  project_types_list = args.project_type.split(",")
@@ -623,7 +669,9 @@ def main():
623
669
  for project_type in project_types_list:
624
670
  results = []
625
671
  report_file = areport_file.replace(".json", f"-{project_type}.json")
626
- risk_report_file = areport_file.replace(".json", f"-risk.{project_type}.json")
672
+ risk_report_file = areport_file.replace(
673
+ ".json", f"-risk.{project_type}.json"
674
+ )
627
675
  LOG.info("=" * 80)
628
676
  if args.bom and os.path.exists(args.bom):
629
677
  bom_file = args.bom
@@ -660,7 +708,9 @@ def main():
660
708
  license_report_file = os.path.join(
661
709
  reports_dir, "license-" + project_type + ".json"
662
710
  )
663
- analyse_licenses(project_type, licenses_results, license_report_file)
711
+ analyse_licenses(
712
+ project_type, licenses_results, license_report_file
713
+ )
664
714
  if project_type in risk_audit_map:
665
715
  if args.risk_audit:
666
716
  console.print(
@@ -708,14 +758,16 @@ def main():
708
758
  try:
709
759
  audit_results = audit(project_type, pkg_list)
710
760
  if audit_results:
711
- LOG.debug("Remote audit yielded %d results", len(audit_results))
761
+ LOG.debug(
762
+ "Remote audit yielded %d results", len(audit_results)
763
+ )
712
764
  results = results + audit_results
713
765
  except Exception as e:
714
766
  LOG.error("Remote audit was not successful")
715
767
  LOG.error(e)
716
768
  results = []
717
- # In case of docker, bom, or universal type, check if there are any npm packages that can be
718
- # audited remotely
769
+ # In case of docker, bom, or universal type, check if there are any
770
+ # npm packages that can be audited remotely
719
771
  if project_type in ("podman", "docker", "oci", "bom", "universal"):
720
772
  npm_pkg_list = get_pkg_by_type(pkg_list, "npm")
721
773
  if npm_pkg_list:
@@ -734,15 +786,23 @@ def main():
734
786
  if not db_lib.index_count(db["index_file"]):
735
787
  run_cacher = True
736
788
  else:
737
- LOG.debug("Vulnerability database loaded from %s", config.vdb_bin_file)
789
+ LOG.debug(
790
+ "Vulnerability database loaded from %s", config.vdb_bin_file
791
+ )
738
792
 
739
793
  sources_list = [OSVSource(), NvdSource()]
740
794
  if os.environ.get("GITHUB_TOKEN"):
741
795
  sources_list.insert(0, GitHubSource())
742
796
  if run_cacher:
797
+ LOG.debug(
798
+ "About to download vdb from %s. This might take a while ...",
799
+ vdb_database_url,
800
+ )
743
801
  oras_client = oras.client.OrasClient()
744
- paths_list = oras_client.pull(target = vdb_database_url, outdir = data_dir)
745
- LOG.debug(f'VDB data is stored at: {paths_list}')
802
+ paths_list = oras_client.pull(
803
+ target=vdb_database_url, outdir=data_dir
804
+ )
805
+ LOG.debug("VDB data is stored at: %s", paths_list)
746
806
  run_cacher = False
747
807
  elif args.sync:
748
808
  for s in sources_list:
@@ -758,7 +818,12 @@ def main():
758
818
  db, project_type, pkg_list, args.suggest
759
819
  )
760
820
  if vdb_results:
761
- results = results + vdb_results
821
+ results += vdb_results
822
+ if args.csaf:
823
+ new_res = []
824
+ for r in results:
825
+ new_res.append(r.to_dict())
826
+ export_csaf(new_res, src_dir, reports_dir)
762
827
  # Summarise and print results
763
828
  summarise(
764
829
  project_type,
depscan/lib/bom.py CHANGED
@@ -38,7 +38,7 @@ def exec_tool(args, cwd=None, stdout=subprocess.PIPE):
38
38
  stderr=subprocess.STDOUT,
39
39
  cwd=cwd,
40
40
  env=os.environ.copy(),
41
- shell=False,
41
+ shell=True if sys.platform == "win32" else False,
42
42
  encoding="utf-8",
43
43
  )
44
44
  LOG.debug(cp.stdout)
@@ -245,8 +245,8 @@ def resource_path(relative_path):
245
245
  return os.path.join(base_path, relative_path)
246
246
 
247
247
 
248
- def exec_cdxgen(bin=True):
249
- if bin:
248
+ def exec_cdxgen(use_bin=True):
249
+ if use_bin:
250
250
  cdxgen_cmd = os.environ.get("CDXGEN_CMD", "cdxgen")
251
251
  if not shutil.which(cdxgen_cmd):
252
252
  local_bin = resource_path(
@@ -269,7 +269,8 @@ def exec_cdxgen(bin=True):
269
269
  return cdxgen_cmd
270
270
  except Exception:
271
271
  return None
272
-
272
+ else:
273
+ return cdxgen_cmd
273
274
  else:
274
275
  # cdxgen_cmd = (
275
276
  # os.environ.get("CDXGEN_CMD", "cdxgen")