Skip to content

Commit d47075a

Browse files
committed
send errors to stderr
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 81c2e4a commit d47075a

4 files changed

Lines changed: 42 additions & 6 deletions

File tree

dejacode_toolkit/vulnerablecode.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ def get_vulnerable_purls(self, packages, details=False, timeout=10):
6060
"""
6161
Return a list of PURLs for which at least one `affected_by_vulnerabilities`
6262
was found in the VulnerableCodeDB for the given list of `packages`.
63+
Returns None when the API call fails (e.g. timeout or network error).
6364
"""
6465
plain_purls = get_plain_purls(packages)
6566

@@ -71,7 +72,9 @@ def get_vulnerable_purls(self, packages, details=False, timeout=10):
7172
details=details,
7273
timeout=timeout,
7374
)
74-
return (vulnerable_purls or {}).get("results") or []
75+
if vulnerable_purls is None:
76+
return None
77+
return vulnerable_purls.get("results") or []
7578

7679
def get_package_url_available_types(self):
7780
"""Return the list of supported package types from the VulnerableCode API."""

vulnerabilities/fetch.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# See https://aboutcode.org for more information about AboutCode FOSS projects.
77
#
88

9+
import logging
910
from timeit import default_timer as timer
1011

1112
from django.contrib.contenttypes.models import ContentType
@@ -19,14 +20,19 @@
1920
from component_catalog.models import Package
2021
from component_catalog.models import PackageAffectedByVulnerability
2122
from dejacode_toolkit.vulnerablecode import VulnerableCode
23+
from dejacode_toolkit.vulnerablecode import get_plain_purls
2224
from dje.models import DejacodeUser
2325
from dje.utils import chunked_queryset
2426
from dje.utils import humanize_time
2527
from notification.models import find_and_fire_hook
2628
from vulnerabilities.models import Vulnerability
2729

30+
logger = logging.getLogger("dje")
2831

29-
def fetch_from_vulnerablecode(dataspace, batch_size, update, timeout, log_func=None, verbosity=1):
32+
33+
def fetch_from_vulnerablecode(
34+
dataspace, batch_size, update, timeout, log_func=None, err_func=None, verbosity=1
35+
):
3036
"""Fetch vulnerability data from VulnerableCode for all eligible packages in ``dataspace``."""
3137
start_time = timer()
3238
vulnerablecode = VulnerableCode(dataspace)
@@ -57,6 +63,7 @@ def fetch_from_vulnerablecode(dataspace, batch_size, update, timeout, log_func=N
5763
update=update,
5864
timeout=timeout,
5965
log_func=log_func,
66+
err_func=err_func,
6067
verbosity=verbosity,
6168
)
6269

@@ -73,7 +80,14 @@ def fetch_from_vulnerablecode(dataspace, batch_size, update, timeout, log_func=N
7380

7481

7582
def fetch_for_packages(
76-
queryset, dataspace, batch_size=50, update=True, timeout=None, log_func=None, verbosity=1
83+
queryset,
84+
dataspace,
85+
batch_size=50,
86+
update=True,
87+
timeout=None,
88+
log_func=None,
89+
err_func=None,
90+
verbosity=1,
7791
):
7892
from product_portfolio.models import ProductPackage
7993

@@ -100,6 +114,21 @@ def fetch_for_packages(
100114
vc_entries = vulnerablecode.get_vulnerable_purls(batch, details=True, timeout=timeout)
101115
api_elapsed = timer() - api_start
102116

117+
if vc_entries is None:
118+
failed_purls = get_plain_purls(batch)
119+
error_msg = (
120+
f"VulnerableCode API call failed for batch {index} "
121+
f"({len(failed_purls)} purls, "
122+
f"progress: {intcomma(progress_count)}/{intcomma(object_count)}). "
123+
f"Purls: {' '.join(failed_purls)}"
124+
)
125+
logger.error(error_msg)
126+
if err_func:
127+
err_func(error_msg)
128+
elif log_func:
129+
log_func(f" API call failed for batch {index} - skipping.")
130+
continue
131+
103132
if log_func and verbosity >= 2:
104133
log_func(
105134
f" API call: {humanize_time(api_elapsed)} ({len(vc_entries)} vulnerable purls)"

vulnerabilities/management/commands/fetchvulnerabilities.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414

1515

1616
class Command(DataspacedCommand):
17-
help = "Fetch vulnerabilities for the provided Dataspace"
17+
help = (
18+
"Fetch vulnerabilities for the provided Dataspace. "
19+
"Progress is written to stdout; API errors (timeouts, network failures) go to stderr. "
20+
"To capture errors separately: ./manage.py fetchvulnerabilities 2>errors.log"
21+
)
1822

1923
def add_arguments(self, parser):
2024
super().add_arguments(parser)
@@ -55,6 +59,7 @@ def handle(self, *args, **options):
5559
update=True,
5660
timeout=timeout,
5761
log_func=self.stdout.write,
62+
err_func=self.stderr.write,
5863
verbosity=options["verbosity"],
5964
)
6065
except ValueError as error:

vulnerabilities/models.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,11 @@ def added_or_updated_today(self):
7777
return self.filter(last_modified_date__gte=today)
7878

7979

80-
# AdvisoryV2
8180
class Vulnerability(HistoryDateFieldsMixin, DataspacedModel):
8281
"""
8382
A software vulnerability with a unique identifier and alternate aliases.
8483
85-
Adapted from the VulnerableCode models at
84+
Adapted from the VulnerableCode AdvisoryV2 model at
8685
https://github.com/nexB/vulnerablecode/blob/main/vulnerabilities/models.py
8786
8887
Note that this model implements the HistoryDateFieldsMixin but not the

0 commit comments

Comments
 (0)