Skip to content

Commit

Permalink
Add base for the vulnerabilities webhook notification #106
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <[email protected]>
  • Loading branch information
tdruez committed Dec 30, 2024
1 parent e9fb4aa commit 1cc6f03
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
5 changes: 5 additions & 0 deletions dejacode/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -644,11 +644,16 @@ def get_fake_redis_connection(config, use_strict_redis):
HOOK_DELIVERER = "notification.tasks.deliver_hook_wrapper"
HOOK_EVENTS = {
# 'any.event.name': 'App.Model.Action' (created/updated/deleted)
# If you want a Hook to be triggered for all users, add '+' to built-in Hooks.
"request.added": "workflow.Request.created+",
"request.updated": "workflow.Request.updated+",
"request_comment.added": "workflow.RequestComment.created+",
"user.added_or_updated": None,
"user.locked_out": None,
"vulnerability.added": "vulnerabilities.Vulnerability.created+",
"vulnerability.packages_affected": None,
"vulnerability.products_affected": None,
"vulnerability.data_update": None,
}
# Provide context variables to the `Webhook` values such as `extra_headers`.
HOOK_ENV = env.dict("HOOK_ENV", default={})
Expand Down
39 changes: 39 additions & 0 deletions vulnerabilities/fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@

from django.contrib.humanize.templatetags.humanize import intcomma
from django.core.management.base import CommandError
from django.urls import reverse
from django.utils import timezone

from component_catalog.models import PACKAGE_URL_FIELDS
from component_catalog.models import Package
from dejacode_toolkit.vulnerablecode import VulnerableCode
from dje.utils import chunked_queryset
from dje.utils import humanize_time
from notification.models import find_and_fire_hook
from vulnerabilities.models import Vulnerability


Expand Down Expand Up @@ -132,3 +134,40 @@ def create_or_update_vulnerability(

vulnerability.add_affected_packages(affected_packages)
return vulnerability


def notify_vulnerability_data_update(dataspace):
"""
Trigger the notifications related to fetching vulnerability data from
VulnerableCode.
"""
today = timezone.now().date()
vulnerability_qs = Vulnerability.objects.scope(dataspace).filter(last_modified_date__date=today)
package_qs = Package.objects.scope(dataspace).filter(
affected_by_vulnerabilities=vulnerability_qs
)
# product_qs = Product.objects.scope(dataspace).filter(packages=package_qs)

vulnerability_count = vulnerability_qs.count()
if not vulnerability_count:
return

package_count = package_qs.count()
subject = "[DejaCode] New vulnerabilities detected!"

package_list_url = reverse("component_catalog:package_list")
vulnerability_list_url = reverse("vulnerabilities:vulnerability_list")

# TODO: Add filter by ?last_modified_date=today
message = (
f"{vulnerability_count} vulnerabilities at {vulnerability_list_url}\n"
f"{package_count} packages affected at {package_list_url}?is_vulnerable=yes\n"
)

find_and_fire_hook(
"vulnerability.data_update",
instance=None,
dataspace=dataspace,
payload_override={"text": f"{subject}\n{message}"},
)
print(f"{subject}\n{message}")
12 changes: 10 additions & 2 deletions vulnerabilities/management/commands/fetchvulnerabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from dejacode_toolkit.vulnerablecode import VulnerableCode
from dje.management.commands import DataspacedCommand
from vulnerabilities.fetch import fetch_from_vulnerablecode
from vulnerabilities import fetch


class Command(DataspacedCommand):
Expand All @@ -30,6 +30,11 @@ def add_arguments(self, parser):
default=30,
help="Request timeout in seconds",
)
parser.add_argument(
"--no-notification",
action="store_true",
help="Do not trigger any notifications.",
)

def handle(self, *args, **options):
super().handle(*args, **options)
Expand All @@ -43,10 +48,13 @@ def handle(self, *args, **options):
if not vulnerablecode.is_configured():
raise CommandError("VulnerableCode is not configured.")

fetch_from_vulnerablecode(
fetch.fetch_from_vulnerablecode(
self.dataspace,
batch_size=batch_size,
update=True,
timeout=timeout,
log_func=self.stdout.write,
)

if not options["no_notification"]:
fetch.notify_vulnerability_data_update(self.dataspace)

0 comments on commit 1cc6f03

Please sign in to comment.