Skip to content

Commit 9535cb9

Browse files
authored
feat: No Scan SOC for language parsers (#5143)
Signed-off-by: joydeep049 <[email protected]>
1 parent bd84c97 commit 9535cb9

21 files changed

+397
-221
lines changed

cve_bin_tool/cli.py

Lines changed: 102 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -823,112 +823,113 @@ def main(argv=None):
823823
)
824824
enabled_sources = [source_nvd] + enabled_sources
825825

826-
# Database update related settings
827-
# Connect to the database
828-
cvedb_orig = CVEDB(
829-
sources=enabled_sources,
830-
version_check=not version_check,
831-
error_mode=error_mode,
832-
)
833-
834-
# if OLD_CACHE_DIR (from cvedb.py) exists, print warning
835-
if Path(OLD_CACHE_DIR).exists():
836-
LOGGER.warning(
837-
f"Obsolete cache dir {OLD_CACHE_DIR} is no longer needed and can be removed."
826+
if not args["no_scan"]:
827+
# Database update related settings
828+
# Connect to the database
829+
cvedb_orig = CVEDB(
830+
sources=enabled_sources,
831+
version_check=not version_check,
832+
error_mode=error_mode,
838833
)
839834

840-
# Check database exists if operating in offline mode.
841-
if args["offline"] and not cvedb_orig.check_db_exists():
842-
LOGGER.critical("Database does not exist.")
843-
LOGGER.info(
844-
"Consult the documentation at https://cve-bin-tool.readthedocs.io/en/latest/how_to_guides/offline.html to find out how to setup offline operation."
845-
)
846-
return ERROR_CODES[CVEDBNotExist]
835+
# if OLD_CACHE_DIR (from cvedb.py) exists, print warning
836+
if Path(OLD_CACHE_DIR).exists():
837+
LOGGER.warning(
838+
f"Obsolete cache dir {OLD_CACHE_DIR} is no longer needed and can be removed."
839+
)
847840

848-
if args["use_mirror"] and not args["offline"]:
849-
if (
850-
cvedb_orig.fetch_from_mirror(
851-
mirror=args["use_mirror"],
841+
# Check database exists if operating in offline mode.
842+
if args["offline"] and not cvedb_orig.check_db_exists():
843+
LOGGER.critical("Database does not exist.")
844+
LOGGER.info(
845+
"Consult the documentation at https://cve-bin-tool.readthedocs.io/en/latest/how_to_guides/offline.html to find out how to setup offline operation."
846+
)
847+
return ERROR_CODES[CVEDBNotExist]
848+
849+
if args["use_mirror"] and not args["offline"]:
850+
if (
851+
cvedb_orig.fetch_from_mirror(
852+
mirror=args["use_mirror"],
853+
pubkey=args["verify"],
854+
ignore_signature=args["ignore_sig"],
855+
log_signature_error=args["log_signature_error"],
856+
)
857+
== -1
858+
):
859+
return ERROR_CODES[MirrorError]
860+
861+
# import database from JSON chopped by years
862+
if args["import_json"] and cvedb_orig.check_db_exists():
863+
return_code = cvedb_orig.json_to_db_wrapper(
864+
path=args["import_json"],
852865
pubkey=args["verify"],
853866
ignore_signature=args["ignore_sig"],
854867
log_signature_error=args["log_signature_error"],
855868
)
856-
== -1
857-
):
858-
return ERROR_CODES[MirrorError]
859-
860-
# import database from JSON chopped by years
861-
if args["import_json"] and cvedb_orig.check_db_exists():
862-
return_code = cvedb_orig.json_to_db_wrapper(
863-
path=args["import_json"],
864-
pubkey=args["verify"],
865-
ignore_signature=args["ignore_sig"],
866-
log_signature_error=args["log_signature_error"],
867-
)
868-
# And terminate operation
869-
return return_code
870-
871-
# Export database as JSON chopped by years
872-
if args["export_json"] and cvedb_orig.check_db_exists():
873-
return_code = cvedb_orig.db_to_json(
874-
path=args["export_json"],
875-
private_key=args["pgp_sign"],
876-
passphrase=args["passphrase"],
877-
)
878-
# And terminate operation
879-
return return_code
880-
881-
# Import database if file exists
882-
if args["import"] and Path(args["import"]).exists():
883-
LOGGER.info(f'Import database from {args["import"]}')
884-
cvedb_orig.copy_db(filename=args["import"], export=False)
885-
886-
# Export database if database exists
887-
if args["export"] and cvedb_orig.check_db_exists():
888-
LOGGER.info(f'Export database to {args["export"]}')
889-
cvedb_orig.copy_db(filename=args["export"], export=True)
890-
# And terminate operation
891-
return 0
892-
893-
# Clear data if -u now is set
894-
if db_update == "now":
895-
cvedb_orig.clear_cached_data()
869+
# And terminate operation
870+
return return_code
871+
872+
# Export database as JSON chopped by years
873+
if args["export_json"] and cvedb_orig.check_db_exists():
874+
return_code = cvedb_orig.db_to_json(
875+
path=args["export_json"],
876+
private_key=args["pgp_sign"],
877+
passphrase=args["passphrase"],
878+
)
879+
# And terminate operation
880+
return return_code
881+
882+
# Import database if file exists
883+
if args["import"] and Path(args["import"]).exists():
884+
LOGGER.info(f'Import database from {args["import"]}')
885+
cvedb_orig.copy_db(filename=args["import"], export=False)
886+
887+
# Export database if database exists
888+
if args["export"] and cvedb_orig.check_db_exists():
889+
LOGGER.info(f'Export database to {args["export"]}')
890+
cvedb_orig.copy_db(filename=args["export"], export=True)
891+
# And terminate operation
892+
return 0
896893

897-
if db_update == "latest":
898-
cvedb_orig.refresh_cache_and_update_db()
894+
# Clear data if -u now is set
895+
if db_update == "now":
896+
cvedb_orig.clear_cached_data()
897+
898+
if db_update == "latest":
899+
cvedb_orig.refresh_cache_and_update_db()
900+
901+
# update db if needed
902+
if db_update != "never":
903+
cvedb_orig.get_cvelist_if_stale()
904+
else:
905+
LOGGER.warning("Not verifying CVE DB cache")
906+
if not cvedb_orig.check_cve_entries():
907+
with ErrorHandler(mode=error_mode, logger=LOGGER):
908+
raise EmptyCache(cvedb_orig.cachedir)
909+
if not cvedb_orig.latest_schema():
910+
LOGGER.critical("Database does not have the latest schema.")
911+
LOGGER.info("Please update database, by using --update 'now'")
912+
if args["offline"]:
913+
LOGGER.info(
914+
"Consult the documentation at https://cve-bin-tool.readthedocs.io/en/latest/how_to_guides/offline.html to find out how to setup offline operation."
915+
)
916+
return ERROR_CODES[CVEDBOutdatedSchema]
899917

900-
# update db if needed
901-
if db_update != "never":
902-
cvedb_orig.get_cvelist_if_stale()
903-
else:
904-
LOGGER.warning("Not verifying CVE DB cache")
918+
# CVE Database validation
905919
if not cvedb_orig.check_cve_entries():
906920
with ErrorHandler(mode=error_mode, logger=LOGGER):
907-
raise EmptyCache(cvedb_orig.cachedir)
908-
if not cvedb_orig.latest_schema():
909-
LOGGER.critical("Database does not have the latest schema.")
910-
LOGGER.info("Please update database, by using --update 'now'")
911-
if args["offline"]:
912-
LOGGER.info(
913-
"Consult the documentation at https://cve-bin-tool.readthedocs.io/en/latest/how_to_guides/offline.html to find out how to setup offline operation."
914-
)
915-
return ERROR_CODES[CVEDBOutdatedSchema]
921+
raise CVEDataMissing("No data in CVE Database")
916922

917-
# CVE Database validation
918-
if not cvedb_orig.check_cve_entries():
919-
with ErrorHandler(mode=error_mode, logger=LOGGER):
920-
raise CVEDataMissing("No data in CVE Database")
921-
922-
# Report time of last database update
923-
db_date = time.strftime(
924-
"%d %B %Y at %H:%M:%S", time.localtime(cvedb_orig.get_db_update_date())
925-
)
926-
LOGGER.info(
927-
"CVE database contains CVEs from National Vulnerability Database (NVD), Open Source Vulnerability Database (OSV), Gitlab Advisory Database (GAD) and RedHat"
928-
)
929-
LOGGER.info(f"CVE database last updated on {db_date}")
923+
# Report time of last database update
924+
db_date = time.strftime(
925+
"%d %B %Y at %H:%M:%S", time.localtime(cvedb_orig.get_db_update_date())
926+
)
927+
LOGGER.info(
928+
"CVE database contains CVEs from National Vulnerability Database (NVD), Open Source Vulnerability Database (OSV), Gitlab Advisory Database (GAD) and RedHat"
929+
)
930+
LOGGER.info(f"CVE database last updated on {db_date}")
930931

931-
cvedb_orig.remove_cache_backup()
932+
cvedb_orig.remove_cache_backup()
932933

933934
output_formats = set(args["format"].split(","))
934935
output_formats = [output_format.strip() for output_format in output_formats]
@@ -1084,14 +1085,18 @@ def main(argv=None):
10841085
# Root package for generated SBOM. Will be updated to reflect input data
10851086
sbom_root = "CVE-SCAN"
10861087

1088+
if args["no_scan"]:
1089+
cvedb_orig = None
1090+
disabled_sources = None
1091+
10871092
with CVEScanner(
10881093
score=score,
10891094
check_metrics=metrics,
10901095
epss_percentile=epss_percentile,
10911096
epss_probability=epss_probability,
10921097
check_exploits=args["exploits"],
1093-
exploits_list=cvedb_orig.get_exploits_list(),
1094-
disabled_sources=disabled_sources,
1098+
exploits_list=cvedb_orig.get_exploits_list() if cvedb_orig else [],
1099+
disabled_sources=disabled_sources or [],
10951100
no_scan=args["no_scan"],
10961101
) as cve_scanner:
10971102
triage_data: TriageData
@@ -1159,7 +1164,8 @@ def main(argv=None):
11591164
LOGGER.debug(f"Triage Data: {triage_data}")
11601165
parsed_data[product_info] = triage_data
11611166

1162-
cve_scanner.get_cves(product_info, triage_data)
1167+
if not args["no_scan"]:
1168+
cve_scanner.get_cves(product_info, triage_data)
11631169
total_files = version_scanner.total_scanned_files
11641170
LOGGER.info(f"Total files: {total_files}")
11651171

cve_bin_tool/parsers/ccpp.py

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import re
77

88
from cve_bin_tool.parsers import Parser
9+
from cve_bin_tool.util import ProductInfo, ScanInfo
910

1011

1112
class CCppParser(Parser):
@@ -51,15 +52,31 @@ def run_checker(self, filename):
5152
product = require.split("#")[0].split("/")[0]
5253
version = require.split("#")[0].split("/")[1]
5354
purl = self.generate_purl(product)
54-
vendor = self.get_vendor(purl, product, version)
55-
if vendor is not None:
56-
yield from vendor
55+
if not self.cve_db:
56+
yield from [
57+
ScanInfo(
58+
ProductInfo("UNKNOWN", product, version, purl),
59+
" ",
60+
),
61+
]
62+
else:
63+
vendor = self.get_vendor(purl, product, version)
64+
if vendor is not None:
65+
yield from vendor
5766
if build_requires:
5867
for build_require in build_requires:
5968
product = build_require.split("#")[0].split("/")[0]
6069
version = build_require.split("#")[0].split("/")[1]
6170
purl = self.generate_purl(product)
62-
vendor = self.get_vendor(purl, product, version)
63-
if vendor is not None:
64-
yield from vendor
71+
if not self.cve_db:
72+
yield from [
73+
ScanInfo(
74+
ProductInfo("UNKNOWN", product, version, purl),
75+
" ",
76+
),
77+
]
78+
else:
79+
vendor = self.get_vendor(purl, product, version)
80+
if vendor is not None:
81+
yield from vendor
6582
self.logger.debug(f"Done scanning file: {self.filename}")

cve_bin_tool/parsers/dart.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import yaml
77

88
from cve_bin_tool.parsers import Parser
9+
from cve_bin_tool.util import ProductInfo, ScanInfo
910

1011

1112
class DartParser(Parser):
@@ -54,7 +55,16 @@ def run_checker(self, filename):
5455
product = package_name
5556
version = package_detail.get("version").replace('"', "")
5657
purl = self.generate_purl(product)
57-
vendor = self.get_vendor(purl, product, version)
58-
if vendor:
59-
yield from vendor
58+
59+
if not self.cve_db:
60+
yield from [
61+
ScanInfo(
62+
ProductInfo("UNKNOWN", product, version, purl),
63+
" ",
64+
),
65+
]
66+
else:
67+
vendor = self.get_vendor(purl, product, version)
68+
if vendor:
69+
yield from vendor
6070
self.logger.debug(f"Done scanning file: {self.filename}")

cve_bin_tool/parsers/env.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ class EnvParser(Parser):
4545
requirements.txt) and generate PURLs (Package URLs) for the listed packages.
4646
"""
4747

48+
def __init__(self, cve_db, logger):
49+
super().__init__(cve_db, logger)
50+
self.cve_db = cve_db
51+
self.logger = logger
52+
4853
PARSER_MATCH_FILENAMES = [
4954
".env",
5055
]
@@ -127,10 +132,11 @@ def run_checker(self, filename):
127132
for _namespace, cve in env_config.namespaces.items()
128133
]
129134

130-
with self.cve_db.with_cursor() as cursor:
131-
self.cve_db.populate_cve_metrics(severity_data, cursor)
132-
self.cve_db.populate_severity(severity_data, cursor, data_source)
133-
self.cve_db.populate_affected(affected_data, cursor, data_source)
135+
if self.cve_db:
136+
with self.cve_db.with_cursor() as cursor:
137+
self.cve_db.populate_cve_metrics(severity_data, cursor)
138+
self.cve_db.populate_severity(severity_data, cursor, data_source)
139+
self.cve_db.populate_affected(affected_data, cursor, data_source)
134140

135141
for _namespace, cve in env_config.namespaces.items():
136142
yield ScanInfo(

cve_bin_tool/parsers/go.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55

66
from cve_bin_tool.parsers import Parser
7+
from cve_bin_tool.util import ProductInfo, ScanInfo
78

89

910
class GoParser(Parser):
@@ -75,7 +76,15 @@ def run_checker(self, filename):
7576
product = line.split(" ")[0].split("/")[-1]
7677
version = line.split(" ")[1][1:].split("-")[0].split("+")[0]
7778
purl = self.generate_purl(product)
78-
vendors = self.get_vendor(purl, product, version)
79-
if vendors is not None:
80-
yield from vendors
79+
if not self.cve_db:
80+
yield from [
81+
ScanInfo(
82+
ProductInfo("UNKNOWN", product, version, purl),
83+
" ",
84+
),
85+
]
86+
else:
87+
vendors = self.get_vendor(purl, product, version)
88+
if vendors is not None:
89+
yield from vendors
8190
self.logger.debug(f"Done scanning file: {self.filename}")

0 commit comments

Comments
 (0)