Skip to content

Commit

Permalink
Refactor BaseService to take a dataspace in place of user #94 (#142)
Browse files Browse the repository at this point in the history
* Refactor BaseService to take a dataspace in place of user #94

This change is required to call integration in the context of a scheduler where only Dataspace instances are available, not a user.

Signed-off-by: tdruez <tdruez@nexb.com>

* Fix an issue with inject_scan_data on Component instances

Signed-off-by: tdruez <tdruez@nexb.com>

---------

Signed-off-by: tdruez <tdruez@nexb.com>
  • Loading branch information
tdruez committed Jul 4, 2024
1 parent 8ef0057 commit a1ce0cf
Show file tree
Hide file tree
Showing 16 changed files with 97 additions and 79 deletions.
16 changes: 9 additions & 7 deletions component_catalog/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,7 @@ class Meta:
def create(self, validated_data):
"""Collect data, purl, and submit scan if `collect_data` is provided."""
user = self.context["request"].user
dataspace = user.dataspace

collect_data = validated_data.pop("collect_data", None)
download_url = validated_data.get("download_url")
Expand All @@ -706,14 +707,14 @@ def create(self, validated_data):
package = super().create(validated_data)

# Submit the scan if Package was properly created
scancodeio = ScanCodeIO(user)
if scancodeio.is_configured() and user.dataspace.enable_package_scanning:
scancodeio = ScanCodeIO(dataspace)
if scancodeio.is_configured() and dataspace.enable_package_scanning:
# Ensure the task is executed after the transaction is successfully committed
transaction.on_commit(
lambda: tasks.scancodeio_submit_scan.delay(
uris=download_url,
user_uuid=user.uuid,
dataspace_uuid=user.dataspace.uuid,
dataspace_uuid=dataspace.uuid,
)
)

Expand Down Expand Up @@ -804,7 +805,8 @@ class Meta:


def collect_create_scan(download_url, user):
package_qs = Package.objects.filter(download_url=download_url, dataspace=user.dataspace)
dataspace = user.dataspace
package_qs = Package.objects.filter(download_url=download_url, dataspace=dataspace)
if package_qs.exists():
return False

Expand All @@ -819,12 +821,12 @@ def collect_create_scan(download_url, user):

package = Package.create_from_data(user, package_data)

scancodeio = ScanCodeIO(user)
if scancodeio.is_configured() and user.dataspace.enable_package_scanning:
scancodeio = ScanCodeIO(dataspace)
if scancodeio.is_configured() and dataspace.enable_package_scanning:
tasks.scancodeio_submit_scan.delay(
uris=download_url,
user_uuid=user.uuid,
dataspace_uuid=user.dataspace.uuid,
dataspace_uuid=dataspace.uuid,
)

return package
Expand Down
2 changes: 1 addition & 1 deletion component_catalog/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ class Meta:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

scancodeio = ScanCodeIO(self.user)
scancodeio = ScanCodeIO(self.dataspace)
self.submit_scan_enabled = all(
[
self.is_addition,
Expand Down
2 changes: 1 addition & 1 deletion component_catalog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2420,7 +2420,7 @@ def get_purldb_entries(self, user, max_request_call=0, timeout=None):
if max_request_call and index >= max_request_call:
return

packages_data = PurlDB(user).find_packages(payload, timeout)
packages_data = PurlDB(user.dataspace).find_packages(payload, timeout)
if packages_data:
return packages_data

Expand Down
10 changes: 5 additions & 5 deletions component_catalog/tests/test_scancodeio.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_scancodeio_submit_scan_task(self, mock_submit_scan, mock_request_head):

@mock.patch("requests.sessions.Session.get")
def test_scancodeio_fetch_scan_list(self, mock_session_get):
scancodeio = ScanCodeIO(self.basic_user)
scancodeio = ScanCodeIO(self.dataspace)
self.assertIsNone(scancodeio.fetch_scan_list())
self.assertFalse(mock_session_get.called)

Expand Down Expand Up @@ -108,7 +108,7 @@ def test_scancodeio_fetch_scan_list(self, mock_session_get):
@mock.patch("requests.sessions.Session.get")
def test_scancodeio_fetch_scan_info(self, mock_session_get):
uri = "https://uri"
scancodeio = ScanCodeIO(self.basic_user)
scancodeio = ScanCodeIO(self.dataspace)

scancodeio.fetch_scan_info(uri=uri)
params = mock_session_get.call_args.kwargs["params"]
Expand All @@ -131,7 +131,7 @@ def test_scancodeio_fetch_scan_info(self, mock_session_get):

@mock.patch("dejacode_toolkit.scancodeio.ScanCodeIO.request_get")
def test_scancodeio_find_project(self, mock_request_get):
scancodeio = ScanCodeIO(self.basic_user)
scancodeio = ScanCodeIO(self.dataspace)
scancodeio.find_project(name="project_name")
params = mock_request_get.call_args.kwargs["params"]
expected = {"name": "project_name"}
Expand Down Expand Up @@ -170,7 +170,7 @@ def test_scancodeio_find_project(self, mock_request_get):
def test_scancodeio_update_from_scan(self, mock_fetch_scan_data, mock_get_scan_results):
self.package1.license_expression = ""
self.package1.save()
scancodeio = ScanCodeIO(self.basic_user)
scancodeio = ScanCodeIO(self.dataspace)

mock_get_scan_results.return_value = None
mock_fetch_scan_data.return_value = None
Expand Down Expand Up @@ -279,7 +279,7 @@ def test_scancodeio_map_detected_package_data(self):

@mock.patch("dejacode_toolkit.scancodeio.ScanCodeIO.request_get")
def test_scancodeio_fetch_project_packages(self, mock_request_get):
scancodeio = ScanCodeIO(self.basic_user)
scancodeio = ScanCodeIO(self.dataspace)

mock_request_get.return_value = None
with self.assertRaises(Exception):
Expand Down
6 changes: 3 additions & 3 deletions component_catalog/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3131,7 +3131,7 @@ def test_vulnerablecode_get_plain_purls(self):
self.assertEqual(["pkg:pypi/django@2.1"], purls)

def test_vulnerablecode_get_vulnerable_purls(self):
vulnerablecode = VulnerableCode(self.basic_user)
vulnerablecode = VulnerableCode(self.dataspace)
vulnerable_purls = vulnerablecode.get_vulnerable_purls(packages=[])
self.assertEqual([], vulnerable_purls)

Expand All @@ -3155,7 +3155,7 @@ def test_vulnerablecode_get_vulnerable_purls(self):
self.assertEqual(["pkg:pypi/django@2.1"], vulnerable_purls)

def test_vulnerablecode_get_vulnerable_cpes(self):
vulnerablecode = VulnerableCode(self.basic_user)
vulnerablecode = VulnerableCode(self.dataspace)
vulnerable_cpes = vulnerablecode.get_vulnerable_cpes(components=[])
self.assertEqual([], vulnerable_cpes)

Expand Down Expand Up @@ -3187,7 +3187,7 @@ def test_vulnerablecode_get_vulnerable_cpes(self):

@mock.patch("dejacode_toolkit.vulnerablecode.VulnerableCode.request_get")
def test_vulnerablecode_get_vulnerabilities_cache(self, mock_request_get):
vulnerablecode = VulnerableCode(self.basic_user)
vulnerablecode = VulnerableCode(self.dataspace)

self.package1.set_package_url("pkg:pypi/django@2.1")
self.package1.save()
Expand Down
58 changes: 33 additions & 25 deletions component_catalog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class TabVulnerabilityMixin:
def tab_vulnerabilities(self):
matching_value = getattr(self.object, self.vulnerability_matching_field)
dataspace = self.object.dataspace
vulnerablecode = VulnerableCode(self.request.user)
vulnerablecode = VulnerableCode(self.request.user.dataspace)

# The display of vulnerabilities is controlled by the object Dataspace
display_tab = all(
Expand Down Expand Up @@ -479,7 +479,7 @@ def get_queryset(self):

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
vulnerablecode = VulnerableCode(self.request.user)
vulnerablecode = VulnerableCode(self.request.user.dataspace)

# The display of vulnerabilities is controlled by the objects Dataspace
enable_vulnerabilities = all(
Expand Down Expand Up @@ -1128,7 +1128,7 @@ def get_context_data(self, **kwargs):
if self.request.user.has_perm("component_catalog.change_component"):
context["add_to_component_form"] = AddMultipleToComponentForm(self.request)

vulnerablecode = VulnerableCode(self.request.user)
vulnerablecode = VulnerableCode(self.request.user.dataspace)
# The display of vulnerabilities is controlled by the objects Dataspace
enable_vulnerabilities = all(
[
Expand Down Expand Up @@ -1438,11 +1438,12 @@ def tab_product_usage(self):
return {"fields": [(None, productpackages, None, template)]}

def tab_scan(self):
scancodeio = ScanCodeIO(self.request.user)
user_dataspace = self.request.user.dataspace
scancodeio = ScanCodeIO(user_dataspace)
scan_tab_display_conditions = [
self.object.download_url,
scancodeio.is_configured(),
self.request.user.dataspace.enable_package_scanning,
user_dataspace.enable_package_scanning,
self.is_user_dataspace,
]

Expand All @@ -1462,10 +1463,11 @@ def tab_scan(self):
return {"fields": [(None, tab_context, None, template)]}

def tab_purldb(self):
dataspace = self.request.user.dataspace
display_tab_purldb = [
PurlDB(self.request.user).is_configured(),
dataspace.enable_purldb_access,
PurlDB(dataspace).is_configured(),
self.is_user_dataspace,
self.request.user.dataspace.enable_purldb_access,
]

if not all(display_tab_purldb):
Expand Down Expand Up @@ -1569,17 +1571,18 @@ def post(self, request, *args, **kwargs):
@login_required
def package_scan_view(request, dataspace, uuid):
user = request.user
package = get_object_or_404(Package, uuid=uuid, dataspace=user.dataspace)
dataspace = user.dataspace
package = get_object_or_404(Package, uuid=uuid, dataspace=dataspace)
download_url = package.download_url

scancodeio = ScanCodeIO(request.user)
if scancodeio.is_configured() and user.dataspace.enable_package_scanning:
scancodeio = ScanCodeIO(dataspace)
if scancodeio.is_configured() and dataspace.enable_package_scanning:
if is_available(download_url):
# Run the task synchronously to prevent from race condition.
tasks.scancodeio_submit_scan(
uris=download_url,
user_uuid=user.uuid,
dataspace_uuid=user.dataspace.uuid,
dataspace_uuid=dataspace.uuid,
)
scancode_msg = "The Package URL was submitted to ScanCode.io for scanning."
messages.success(request, scancode_msg)
Expand All @@ -1594,6 +1597,8 @@ def package_scan_view(request, dataspace, uuid):
@require_POST
def package_create_ajax_view(request):
user = request.user
dataspace = user.dataspace

if not user.has_perm("component_catalog.add_package"):
return JsonResponse({"error_message": "Permission denied"}, status=403)

Expand All @@ -1618,13 +1623,13 @@ def package_create_ajax_view(request):
redirect_url = reverse("component_catalog:package_list")
len_created = len(created)

scancodeio = ScanCodeIO(request.user)
if scancodeio.is_configured() and user.dataspace.enable_package_scanning:
scancodeio = ScanCodeIO(dataspace)
if scancodeio.is_configured() and dataspace.enable_package_scanning:
# The availability of the each `download_url` is checked in the task.
tasks.scancodeio_submit_scan.delay(
uris=[package.download_url for package in created if package.download_url],
user_uuid=user.uuid,
dataspace_uuid=user.dataspace.uuid,
dataspace_uuid=dataspace.uuid,
)
scan_msg = " and submitted to ScanCode.io for scanning"

Expand Down Expand Up @@ -1672,10 +1677,11 @@ def component_create_ajax_view(request):

@login_required
def send_scan_data_as_file_view(request, project_uuid, filename):
if not request.user.dataspace.enable_package_scanning:
dataspace = request.user.dataspace
if not dataspace.enable_package_scanning:
raise Http404

scancodeio = ScanCodeIO(request.user)
scancodeio = ScanCodeIO(dataspace)
scan_results_url = scancodeio.get_scan_results_url(project_uuid)
scan_results = scancodeio.fetch_scan_data(scan_results_url)
scan_summary_url = scancodeio.get_scan_summary_url(project_uuid)
Expand All @@ -1694,10 +1700,11 @@ def send_scan_data_as_file_view(request, project_uuid, filename):

@login_required
def delete_scan_view(request, project_uuid):
if not request.user.dataspace.enable_package_scanning:
dataspace = request.user.dataspace
if not dataspace.enable_package_scanning:
raise Http404

scancodeio = ScanCodeIO(request.user)
scancodeio = ScanCodeIO(dataspace)
scan_list = scancodeio.fetch_scan_list(uuid=str(project_uuid))

if not scan_list or scan_list.get("count") != 1:
Expand Down Expand Up @@ -1736,7 +1743,7 @@ def get_queryset(self):
"page": self.request.GET.get("page"),
}

scancodeio = ScanCodeIO(user)
scancodeio = ScanCodeIO(dataspace)
self.list_data = (
scancodeio.fetch_scan_list(
dataspace=dataspace,
Expand Down Expand Up @@ -1805,7 +1812,7 @@ def send_scan_notification(request, key):

run = json_data.get("run")
scan_status = run.get("status")
scancodeio = ScanCodeIO(user)
scancodeio = ScanCodeIO(dataspace)

update_package_from_scan = all(
[
Expand Down Expand Up @@ -1959,12 +1966,12 @@ def get_initial(self):
return initial

def get_entry_from_purldb(self):
user = self.request.user
purldb = PurlDB(user)
dataspace = self.request.user.dataspace
purldb = PurlDB(dataspace)
is_purldb_enabled = all(
[
purldb.is_configured(),
user.dataspace.enable_purldb_access,
dataspace.enable_purldb_access,
]
)

Expand Down Expand Up @@ -2476,11 +2483,12 @@ def scan_status_fields(self, scan):

def tab_scan(self):
user = self.request.user
scancodeio = ScanCodeIO(user)
dataspace = user.dataspace
scancodeio = ScanCodeIO(dataspace)

scan = scancodeio.get_scan_results(
download_url=self.object.download_url,
dataspace=user.dataspace,
dataspace=dataspace,
)

if not scan:
Expand Down
9 changes: 4 additions & 5 deletions dejacode_toolkit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,17 @@ class BaseService:
api_key_field_name = None
default_timeout = 5

def __init__(self, user):
if not user:
raise
self.user = user
def __init__(self, dataspace):
if not dataspace:
raise ValueError("Dataspace must be provided.")

self.service_url = None
self.service_api_key = None
self.basic_auth_user = None
self.basic_auth_password = None

try:
dataspace_configuration = user.dataspace.configuration
dataspace_configuration = dataspace.configuration
except ObjectDoesNotExist:
dataspace_configuration = None

Expand Down
4 changes: 2 additions & 2 deletions dejacode_toolkit/purldb.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ class PurlDB(BaseService):
url_field_name = "purldb_url"
api_key_field_name = "purldb_api_key"

def __init__(self, user):
super().__init__(user)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.package_api_url = f"{self.api_url}packages/"

def get_package_list(
Expand Down
4 changes: 2 additions & 2 deletions dejacode_toolkit/scancodeio.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class ScanCodeIO(BaseService):
url_field_name = "scancodeio_url"
api_key_field_name = "scancodeio_api_key"

def __init__(self, user):
super().__init__(user)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.project_api_url = f"{self.api_url}projects/"

def get_scan_detail_url(self, project_uuid):
Expand Down
5 changes: 3 additions & 2 deletions dje/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ def scancodeio_submit_scan(uris, user_uuid, dataspace_uuid):
if not isinstance(uris, list):
uris = [uris]

scancodeio = ScanCodeIO(user.dataspace)
for uri in uris:
if is_available(uri):
ScanCodeIO(user).submit_scan(uri, user_uuid, dataspace_uuid)
scancodeio.submit_scan(uri, user_uuid, dataspace_uuid)
else:
logger.info(f'uri="{uri}" is not reachable.')

Expand All @@ -133,7 +134,7 @@ def scancodeio_submit_project(scancodeproject_uuid, user_uuid, pipeline_name):
except ObjectDoesNotExist:
return

scancodeio = ScanCodeIO(user)
scancodeio = ScanCodeIO(user.dataspace)

# Create a Project instance on ScanCode.io without immediate execution of the
# pipeline. This allows to get instant feedback from ScanCode.io about the Project
Expand Down
Loading

0 comments on commit a1ce0cf

Please sign in to comment.