diff --git a/surface/sca/admin.py b/surface/sca/admin.py index 3cf580e4..62edb5ac 100644 --- a/surface/sca/admin.py +++ b/surface/sca/admin.py @@ -75,11 +75,17 @@ class EndOfLifeDependencyAdmin(DefaultModelAdmin, DefaultFilterMixin, EndOfLifeD "no_support", "is_discontinued", "is_lts", - "link", + "get_link", ] list_filter = ["product", EndOfLifeDependencyBoolFilter, LTSFilter, DiscontinuedFilter, SupportFilter] search_fields = ["product"] + @admin.display(description="Link") + def get_link(self, obj): + if obj.link: + return format_html(f'{obj.link}') + return "" + class SCADependencyForm(forms.ModelForm): class Meta: @@ -248,7 +254,16 @@ class SCAProjectAdmin(DefaultModelAdmin): "git_source", ("git_source__apps", RelatedFieldAjaxListFilter), ] - search_fields = ["name", "purl", "depends_on__name", "depends_on__purl", "git_source__repo_url"] + search_fields = [ + "name", + "purl", + "depends_on__name", + "depends_on__purl", + "git_source__repo_url", + "dependencies_list", + ] + + readonly_fields = [] def change_view(self, request, object_id, form_url="", extra_context=None): extra_context = extra_context or {} @@ -276,7 +291,11 @@ def change_view(self, request, object_id, form_url="", extra_context=None): vulnerabilities = self.get_vulnerabilities(obj) # set fixed_in as True by default if not passed in the request - if "fixed_in" not in request.GET: + if ( + "fixed_in" not in request.GET + and int(request.GET.get("finding_type", models.SCAFinding.FindingType.VULN)) + != models.SCAFinding.FindingType.EOL + ): request.GET = request.GET.copy() request.GET["fixed_in"] = "true" extra_context["vulns_filter"] = SCAFindingFilter(request.GET, queryset=vulnerabilities) @@ -372,7 +391,7 @@ def get_git_source(self, obj): def get_sbom_link(self, obj): if obj.sbom_uuid: return format_html( - 'Download sbom json', + 'download', reverse("sca:download_sbom_as_json", args=[obj.sbom_uuid, obj.name]), ) diff --git a/surface/sca/management/commands/resync_sbom_repo.py b/surface/sca/management/commands/resync_sbom_repo.py index 7a9f7f7b..5853b7c3 100644 --- a/surface/sca/management/commands/resync_sbom_repo.py +++ b/surface/sca/management/commands/resync_sbom_repo.py @@ -238,6 +238,8 @@ def handle_sbom(self, sbom: str) -> bool: if project: project.update_vulnerability_counters() + project.dependencies_list = project.dependencies + project.save() self.processed += 1 return True diff --git a/surface/sca/management/commands/resync_vulns_counters.py b/surface/sca/management/commands/resync_vulns_counters.py index 1d74905c..dce9ad0c 100644 --- a/surface/sca/management/commands/resync_vulns_counters.py +++ b/surface/sca/management/commands/resync_vulns_counters.py @@ -6,7 +6,7 @@ class Command(LogBaseCommand): - help = "Re-sync SCA Projects Vulnerabilities Counters" + help = "Re-sync SCA Projects Vulnerabilities Counters and dependencies list." processed_projects = 0 @@ -14,6 +14,8 @@ def handle(self, *args, **options): self.sync_time = timezone.now() for project in tqdm.tqdm(SCADependency.objects.filter(is_project=True)): project.update_vulnerability_counters() + project.dependencies_list = project.dependencies + project.save(update_fields=["dependencies_list"]) self.processed_projects += 1 SCAFindingCounter.objects.filter(last_sync__lt=self.sync_time).update( diff --git a/surface/sca/migrations/0004_scadependency_dependencies_list.py b/surface/sca/migrations/0004_scadependency_dependencies_list.py new file mode 100644 index 00000000..41fd7a2c --- /dev/null +++ b/surface/sca/migrations/0004_scadependency_dependencies_list.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.8 on 2025-11-11 16:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sca', '0003_scadependency_sbom_uuid_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='scadependency', + name='dependencies_list', + field=models.JSONField(default=list), + ), + ] diff --git a/surface/sca/models.py b/surface/sca/models.py index 6701fede..b1140fea 100644 --- a/surface/sca/models.py +++ b/surface/sca/models.py @@ -70,6 +70,7 @@ class SCADependency(models.Model): updated_at = models.DateTimeField(auto_now=True) last_scan = models.DateTimeField() sbom_uuid = models.CharField(max_length=255, default=None, null=True) + dependencies_list = models.JSONField(default=list) @staticmethod def get_dependencies_recursively( diff --git a/surface/sca/templates/views/dependencies.html b/surface/sca/templates/views/dependencies.html index 1fb34b75..817f535f 100644 --- a/surface/sca/templates/views/dependencies.html +++ b/surface/sca/templates/views/dependencies.html @@ -110,7 +110,7 @@