Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion scanpipe/pipes/clamav.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from pathlib import Path

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist

import clamd

Expand All @@ -47,7 +48,19 @@ def scan_for_virus(project):
status, reason = results
resource_path = Path(resource_location).relative_to(project.codebase_path)

resource = project.codebaseresources.get(path=resource_path)
try:
resource = project.codebaseresources.get(path=str(resource_path))
except ObjectDoesNotExist:
project.add_error(
description="CodebaseResource not found for ClamAV result",
model="ScanForVirus",
details={
"resource_location": resource_location,
"resource_path": str(resource_path),
},
)
continue

virus_report = {
"calmav": {
"status": status,
Expand Down
31 changes: 31 additions & 0 deletions scanpipe/tests/pipes/test_clamav.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,34 @@ def test_scanpipe_pipes_clamav_scan_for_virus(self, mock_multiscan):
}
}
self.assertEqual(expected_virus_report_extra_data, resource1.extra_data)

@mock.patch("clamd.ClamdNetworkSocket.multiscan")
def test_scanpipe_pipes_clamav_scan_for_virus_missing_resource(self, mock_multiscan):
"""Test that scan_for_virus handles missing CodebaseResource gracefully."""
project = Project.objects.create(name="project")
r1 = make_resource_file(project=project, path="existing.zip")

# Simulate ClamAV returning results for both existing and non-existing resources
mock_multiscan.return_value = {
r1.location: ("FOUND", "Win.Test.EICAR_HDB-1"),
str(project.codebase_path / "missing_file.exe"): ("FOUND", "Trojan.Test"),
}

# Should not raise an exception
clamav.scan_for_virus(project)

# Should have 2 error messages: one for virus, one for missing resource
messages = list(project.projectmessages.all())
self.assertEqual(2, len(messages))

# Check that missing resource error was logged
missing_resource_error = project.projectmessages.filter(
description="CodebaseResource not found for ClamAV result"
).first()
self.assertIsNotNone(missing_resource_error)
self.assertEqual("missing_file.exe", missing_resource_error.details["resource_path"])

# Check that existing resource still got processed
virus_error = project.projectmessages.filter(description="Virus detected").first()
self.assertIsNotNone(virus_error)
self.assertEqual("existing.zip", virus_error.details["resource_path"])