From 08c54b158950c8ec0c8e86b1e9d69233f9310297 Mon Sep 17 00:00:00 2001 From: Ayan Sinha Mahapatra Date: Mon, 1 Jul 2024 16:44:40 +0530 Subject: [PATCH] Resolve dependencies from lockfiles (#1244) * Resolve dependencies from lockfiles #1237 Reference: https://github.com/nexB/scancode.io/issues/1237 Reference: https://github.com/nexB/scancode.io/issues/1066 Signed-off-by: Ayan Sinha Mahapatra * Address feedback and add improvements Signed-off-by: Ayan Sinha Mahapatra * Improve dependency resolving from lockfiles #1237 Resolves dependency for cases where multiple requirements are resolved by one package and all the version requirements are joined for that package. Reference: https://github.com/nexB/scancode.io/issues/1237 Signed-off-by: Ayan Sinha Mahapatra * Update scancode-toolkit and fix tests Signed-off-by: Ayan Sinha Mahapatra * Bump scancode-toolkit to v32.2.0 Reference: https://github.com/nexB/scancode-toolkit/releases/tag/v32.2.0 Signed-off-by: Ayan Sinha Mahapatra * Regenerate test fixtures and expectations Signed-off-by: Ayan Sinha Mahapatra * Improve dependency resolver for lockfiles Handle various lockfile cases where: * Same package/dependencies are present in different lockfiles * Independent lockfiles without a manifest and root package * Ecosystems which have only a single version of package in their environment * Dependency graphs where a resolved package can have many parent packages. Signed-off-by: Ayan Sinha Mahapatra * Address feedback and refactor code Signed-off-by: Ayan Sinha Mahapatra * FIx bugs for resolving python packages Signed-off-by: Ayan Sinha Mahapatra * Add unit tests and refactor code Signed-off-by: Ayan Sinha Mahapatra * Address comments and add CHANGELOG entries Signed-off-by: Ayan Sinha Mahapatra --------- Signed-off-by: Ayan Sinha Mahapatra --- CHANGELOG.rst | 18 + scanpipe/api/serializers.py | 3 + scanpipe/filters.py | 8 + .../0062_dependency_resolver_update.py | 79 ++ scanpipe/models.py | 115 +- scanpipe/pipelines/inspect_packages.py | 20 +- scanpipe/pipelines/resolve_dependencies.py | 32 +- scanpipe/pipes/__init__.py | 78 +- scanpipe/pipes/scancode.py | 224 +++- .../templates/scanpipe/dependency_list.html | 3 + .../data/asgiref/asgiref-3.3.0.spdx.json | 42 +- .../data/asgiref/asgiref-3.3.0_fixtures.json | 478 +++---- ...asgiref-3.3.0_load_inventory_expected.json | 16 + .../asgiref-3.3.0_scanpipe_output.json | 82 +- .../asgiref/asgiref-3.3.0_toolkit_scan.json | 86 +- .../asgiref-3.3.0_walk_test_fixtures.json | 478 +++---- .../data/cyclonedx/asgiref-3.3.0.cdx.json | 18 +- .../tests/data/d2d/about_files/expected.json | 4 + .../tests/data/d2d/flume-ng-node-d2d.json | 2 + .../dependencies/resolved_dependencies.zip | Bin 0 -> 1577 bytes .../docker/alpine_3_15_4_scan_codebase.json | 28 + .../data/docker/centos_scan_codebase.json | 202 +++ .../data/docker/debian_scan_codebase.json | 4 + .../gcr_io_distroless_base_scan_codebase.json | 16 + .../openpdf-parent-1.3.11_scan_package.json | 28 +- ...esolved_dependencies_inspect_packages.json | 1143 +++++++++++++++++ .../rootfs/basic-rootfs_root_filesystems.json | 4 + ...-0.6.0-py3-none-any.whl_scan_codebase.json | 24 + .../scancode/is-npm-1.0.0_scan_codebase.json | 18 +- .../scancode/is-npm-1.0.0_scan_package.json | 22 +- .../is-npm-1.0.0_scan_package_summary.json | 8 +- .../data/scancode/is-npm-1.0.0_summary.json | 8 +- .../multiple-is-npm-1.0.0_scan_package.json | 40 +- ...ple-is-npm-1.0.0_scan_package_summary.json | 8 +- .../scancode/package_assembly_codebase.json | 28 +- scanpipe/tests/pipes/test_output.py | 2 +- scanpipe/tests/pipes/test_scancode.py | 126 ++ scanpipe/tests/test_api.py | 4 +- scanpipe/tests/test_models.py | 13 + scanpipe/tests/test_pipelines.py | 51 +- scanpipe/views.py | 9 +- setup.cfg | 2 +- 42 files changed, 2913 insertions(+), 661 deletions(-) create mode 100644 scanpipe/migrations/0062_dependency_resolver_update.py create mode 100644 scanpipe/tests/data/dependencies/resolved_dependencies.zip create mode 100644 scanpipe/tests/data/resolved_dependencies_inspect_packages.json diff --git a/CHANGELOG.rst b/CHANGELOG.rst index a52d53f53..2979b6998 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -15,6 +15,24 @@ v34.6.4 (unreleased) related work directories created more than a specified number of days ago. https://github.com/nexB/scancode.io/issues/1289 +- Update the ``inspect_packages`` pipeline to have an optional ``Static Resolver`` + group to create resolved packages and dependency relationships from lockfiles + and manifests having pre-resolved dependencies. Also update this pipeline to + perform package assembly from multiple manifests and files to create + discovered packages. Also update the ``resolve_dependencies`` pipeline to have + the same ``Static Resolver`` group and mode the dynamic resolution part to a new + optional ``Dynamic Resolver`` group. + See https://github.com/nexB/scancode.io/pull/1244 + +- Add a new attribute ``is_direct`` to the DiscoveredDependency model and two new + attributes ``is_private`` and ``is_virtual`` to the DiscoveredPackage model. + Also update the UIs to show these attributes and show the ``package_data`` field + contents for CodebaseResources in the ``extra_data`` tab. + See https://github.com/nexB/scancode.io/pull/1244 + +- Update scancode-toolkit to version ``32.2.0``. For the complete list of updates + and improvements see https://github.com/nexB/scancode-toolkit/releases/tag/v32.2.0 + v34.6.3 (2024-06-21) -------------------- diff --git a/scanpipe/api/serializers.py b/scanpipe/api/serializers.py index 98a039db2..f5369b2af 100644 --- a/scanpipe/api/serializers.py +++ b/scanpipe/api/serializers.py @@ -384,6 +384,8 @@ class Meta: "source_packages", "extra_data", "package_uid", + "is_private", + "is_virtual", "datasource_ids", "datafile_paths", "file_references", @@ -409,6 +411,7 @@ class Meta: "is_runtime", "is_optional", "is_resolved", + "is_direct", "dependency_uid", "for_package_uid", "resolved_to_package_uid", diff --git a/scanpipe/filters.py b/scanpipe/filters.py index 3a06db58c..a356a6fea 100644 --- a/scanpipe/filters.py +++ b/scanpipe/filters.py @@ -688,6 +688,8 @@ class PackageFilterSet(FilterSetUtilsMixin, django_filters.FilterSet): declared_license_expression = django_filters.filters.CharFilter( widget=HasValueDropdownWidget ) + is_private = StrictBooleanFilter() + is_virtual = StrictBooleanFilter() class Meta: model = DiscoveredPackage @@ -721,6 +723,8 @@ class Meta: "is_vulnerable", "compliance_alert", "tag", + "is_private", + "is_virtual", ] @@ -731,6 +735,7 @@ class DependencyFilterSet(FilterSetUtilsMixin, django_filters.FilterSet): "is_runtime", "is_optional", "is_resolved", + "is_direct", "datasource_id", "is_vulnerable", ] @@ -751,6 +756,7 @@ class DependencyFilterSet(FilterSetUtilsMixin, django_filters.FilterSet): "is_runtime", "is_optional", "is_resolved", + "is_direct", "for_package", "resolved_to_package", "datafile_resource", @@ -765,6 +771,7 @@ class DependencyFilterSet(FilterSetUtilsMixin, django_filters.FilterSet): is_runtime = StrictBooleanFilter() is_optional = StrictBooleanFilter() is_resolved = StrictBooleanFilter() + is_direct = StrictBooleanFilter() is_vulnerable = IsVulnerable(field_name="affected_by_vulnerabilities") class Meta: @@ -783,6 +790,7 @@ class Meta: "is_runtime", "is_optional", "is_resolved", + "is_direct", "datasource_id", "is_vulnerable", ] diff --git a/scanpipe/migrations/0062_dependency_resolver_update.py b/scanpipe/migrations/0062_dependency_resolver_update.py new file mode 100644 index 000000000..733b83c12 --- /dev/null +++ b/scanpipe/migrations/0062_dependency_resolver_update.py @@ -0,0 +1,79 @@ +# Generated by Django 5.0.6 on 2024-06-04 20:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("scanpipe", "0061_codebaseresource_is_legal_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="discovereddependency", + name="is_direct", + field=models.BooleanField( + default=False, + help_text="True if this is a direct, first-level dependency relationship for a package.", + ), + ), + migrations.AddField( + model_name="discoveredpackage", + name="is_private", + field=models.BooleanField( + default=False, + help_text="True if this is a private package, either not meant to be published on a repository, and/or a local package without a name and version used primarily to track dependencies and other information.", + ), + ), + migrations.AddField( + model_name="discoveredpackage", + name="is_virtual", + field=models.BooleanField( + default=False, + help_text="True if this package is created only from a manifest or lockfile, and not from its actual packaged code. The files of this package are not present in the codebase.", + ), + ), + migrations.AlterField( + model_name="discovereddependency", + name="is_optional", + field=models.BooleanField( + default=False, + help_text="True if this dependency is an optional dependency", + ), + ), + migrations.AlterField( + model_name="discovereddependency", + name="is_resolved", + field=models.BooleanField( + default=False, + help_text="True if this dependency version requirement has been pinned and this dependency points to an exact version.", + ), + ), + migrations.AlterField( + model_name="discovereddependency", + name="is_runtime", + field=models.BooleanField( + default=False, + help_text="True if this dependency is a runtime dependency.", + ), + ), + migrations.AddIndex( + model_name="discovereddependency", + index=models.Index( + fields=["is_direct"], name="scanpipe_di_is_dire_6dc594_idx" + ), + ), + migrations.AddIndex( + model_name="discoveredpackage", + index=models.Index( + fields=["is_private"], name="scanpipe_di_is_priv_9ffd1a_idx" + ), + ), + migrations.AddIndex( + model_name="discoveredpackage", + index=models.Index( + fields=["is_virtual"], name="scanpipe_di_is_virt_c5c176_idx" + ), + ), + ] diff --git a/scanpipe/models.py b/scanpipe/models.py index 06b55c4a6..14c84b9ec 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -74,6 +74,7 @@ from licensedcode.cache import get_licensing from matchcode_toolkit.fingerprinting import IGNORED_DIRECTORY_FINGERPRINTS from packagedcode.models import build_package_uid +from packagedcode.utils import get_base_purl from packageurl import PackageURL from packageurl import normalize_qualifiers from packageurl.contrib.django.models import PackageURLMixin @@ -1031,6 +1032,19 @@ def walk_codebase_path(self): """Return files and directories path of the codebase/ directory recursively.""" return self.codebase_path.rglob("*") + def get_resource(self, path): + """ + Return the codebase resource present for a given path, + or None the resource with that path does not exist. + This path is relative to the scan location. + This is same as the Codebase.get_resource() function. + """ + # We don't want to raise an exception if there is no resource + # as this function is also called from the SCTK side + resource = self.codebaseresources.get_or_none(path=path) + if resource: + return resource + @cached_property def can_change_inputs(self): """ @@ -3061,6 +3075,23 @@ class AbstractPackage(models.Model): blank=True, help_text=_("A notice text for this package."), ) + is_private = models.BooleanField( + default=False, + help_text=_( + "True if this is a private package, either not meant to be " + "published on a repository, and/or a local package without a " + "name and version used primarily to track dependencies and " + "other information." + ), + ) + is_virtual = models.BooleanField( + default=False, + help_text=_( + "True if this package is created only from a manifest or lockfile, " + "and not from its actual packaged code. The files of this package " + "are not present in the codebase." + ), + ) datasource_ids = models.JSONField( default=list, blank=True, @@ -3163,6 +3194,8 @@ class Meta: models.Index(fields=["sha512"]), models.Index(fields=["compliance_alert"]), models.Index(fields=["tag"]), + models.Index(fields=["is_private"]), + models.Index(fields=["is_virtual"]), ] constraints = [ models.UniqueConstraint( @@ -3190,15 +3223,7 @@ def purl(self): @classmethod def extract_purl_data(cls, package_data): - purl_data = {} - - for field_name in PURL_FIELDS: - value = package_data.get(field_name) - if field_name == "qualifiers": - value = normalize_qualifiers(value, encode=True) - purl_data[field_name] = value or "" - - return purl_data + return normalize_package_url_data(package_data) @classmethod def create_from_data(cls, project, package_data): @@ -3530,9 +3555,28 @@ class DiscoveredDependency( "The identifier for the datafile handler used to obtain this dependency." ), ) - is_runtime = models.BooleanField(default=False) - is_optional = models.BooleanField(default=False) - is_resolved = models.BooleanField(default=False) + is_runtime = models.BooleanField( + default=False, + help_text=_("True if this dependency is a runtime dependency."), + ) + is_optional = models.BooleanField( + default=False, + help_text=_("True if this dependency is an optional dependency"), + ) + is_resolved = models.BooleanField( + default=False, + help_text=_( + "True if this dependency version requirement has been pinned " + "and this dependency points to an exact version." + ), + ) + is_direct = models.BooleanField( + default=False, + help_text=_( + "True if this is a direct, first-level dependency relationship " + "for a package." + ), + ) objects = DiscoveredDependencyQuerySet.as_manager() @@ -3553,6 +3597,7 @@ class Meta: models.Index(fields=["is_runtime"]), models.Index(fields=["is_optional"]), models.Index(fields=["is_resolved"]), + models.Index(fields=["is_direct"]), ] constraints = [ models.UniqueConstraint( @@ -3574,6 +3619,10 @@ def get_absolute_url(self): def purl(self): return self.package_url + @property + def base_purl(self): + return get_base_purl(self.package_url) + @property def package_type(self): return self.type @@ -3599,6 +3648,7 @@ def create_from_data( project, dependency_data, for_package=None, + resolved_to_package=None, datafile_resource=None, datasource_id=None, strip_datafile_path_root=False, @@ -3638,6 +3688,13 @@ def create_from_data( package_uid=for_package_uid ) + if not resolved_to_package: + resolved_to_uid = dependency_data.get("resolved_to_uid") + if resolved_to_uid: + resolved_to_package = project.discoveredpackages.get( + package_uid=resolved_to_uid + ) + if not datafile_resource: datafile_path = dependency_data.get("datafile_path") if datafile_path: @@ -3663,10 +3720,25 @@ def create_from_data( return cls.objects.create( project=project, for_package=for_package, + resolved_to_package=resolved_to_package, datafile_resource=datafile_resource, **cleaned_data, ) + @classmethod + def extract_purl_data(cls, dependency_data, ignore_nulls=False): + purl_mapping = PackageURL.from_string( + purl=dependency_data.get("purl"), + ).to_dict() + + return normalize_package_url_data(purl_mapping, ignore_nulls) + + @classmethod + def populate_dependency_uuid(cls, dependency_data): + purl = PackageURL.from_string(purl=dependency_data.get("purl")) + purl.qualifiers["uuid"] = str(uuid.uuid4()) + dependency_data["dependency_uid"] = purl.to_string() + @property def spdx_id(self): return f"SPDXRef-scancodeio-{self._meta.model_name}-{self.dependency_uid}" @@ -3694,6 +3766,25 @@ def as_spdx(self): ) +def normalize_package_url_data(purl_mapping, ignore_nulls=False): + """ + Normalize a mapping of purl data so database queries with + purl data can be executed. + """ + normalized_purl_mapping = {} + for field_name in PURL_FIELDS: + value = purl_mapping.get(field_name) + if field_name == "qualifiers": + value = normalize_qualifiers(value, encode=True) + if not ignore_nulls: + normalized_purl_mapping[field_name] = value or "" + else: + if value: + normalized_purl_mapping[field_name] = value or "" + + return normalized_purl_mapping + + class WebhookSubscription(UUIDPKModel, ProjectRelatedModel): target_url = models.URLField(_("Target URL"), max_length=1024) created_date = models.DateTimeField(auto_now_add=True, editable=False) diff --git a/scanpipe/pipelines/inspect_packages.py b/scanpipe/pipelines/inspect_packages.py index a40528c3a..845fb6297 100644 --- a/scanpipe/pipelines/inspect_packages.py +++ b/scanpipe/pipelines/inspect_packages.py @@ -20,6 +20,7 @@ # ScanCode.io is a free software code scanning tool from nexB Inc. and others. # Visit https://github.com/nexB/scancode.io for support and download. +from scanpipe.pipelines import group from scanpipe.pipelines.scan_codebase import ScanCodebase from scanpipe.pipes import scancode @@ -49,7 +50,7 @@ def steps(cls): cls.flag_empty_files, cls.flag_ignored_resources, cls.scan_for_application_packages, - cls.create_packages_and_dependencies, + cls.resolve_dependencies, ) def scan_for_application_packages(self): @@ -57,15 +58,18 @@ def scan_for_application_packages(self): Scan resources for package information to add DiscoveredPackage and DiscoveredDependency objects from detected package data. """ - # `assemble` is set to False because here in this pipeline we - # only detect package_data in resources and create - # Package/Dependency instances directly instead of assembling - # the packages and assigning files to them scancode.scan_for_application_packages( project=self.project, - assemble=False, + assemble=True, package_only=True, + progress_logger=self.log, ) - def create_packages_and_dependencies(self): - scancode.process_package_data(self.project) + @group("Static Resolver") + def resolve_dependencies(self): + """ + Create packages and dependency relationships from + lockfiles or manifests containing pre-resolved + dependencies. + """ + scancode.resolve_dependencies(project=self.project) diff --git a/scanpipe/pipelines/resolve_dependencies.py b/scanpipe/pipelines/resolve_dependencies.py index d2597e8ee..03ddd702b 100644 --- a/scanpipe/pipelines/resolve_dependencies.py +++ b/scanpipe/pipelines/resolve_dependencies.py @@ -20,8 +20,10 @@ # ScanCode.io is a free software code scanning tool from nexB Inc. and others. # Visit https://github.com/nexB/scancode.io for support and download. +from scanpipe.pipelines import group from scanpipe.pipelines.scan_codebase import ScanCodebase from scanpipe.pipes import resolve +from scanpipe.pipes import scancode class ResolveDependencies(ScanCodebase): @@ -45,6 +47,8 @@ def steps(cls): cls.collect_and_create_codebase_resources, cls.flag_ignored_resources, cls.get_manifest_inputs, + cls.scan_for_application_packages, + cls.create_packages_and_dependencies, cls.get_packages_from_manifest, cls.create_resolved_packages, ) @@ -53,6 +57,28 @@ def get_manifest_inputs(self): """Locate package manifest files with a supported package resolver.""" self.manifest_resources = resolve.get_manifest_resources(self.project) + @group("Static Resolver") + def scan_for_application_packages(self): + """ + Scan and assemble application packages from package manifests + and lockfiles. + """ + scancode.scan_for_application_packages( + self.project, + assemble=True, + resource_qs=self.manifest_resources, + progress_logger=self.log, + ) + + @group("Static Resolver") + def create_packages_and_dependencies(self): + """ + Create the statically resolved packages and their dependencies + in the database. + """ + scancode.process_package_data(self.project, static_resolve=True) + + @group("Dynamic Resolver") def get_packages_from_manifest(self): """ Resolve package data from lockfiles/requirement files with package @@ -65,8 +91,12 @@ def get_packages_from_manifest(self): model="get_packages_from_manifest", ) + @group("Dynamic Resolver") def create_resolved_packages(self): - """Create the resolved packages and their dependencies in the database.""" + """ + Create the dynamically resolved packages and their dependencies + in the database. + """ resolve.create_packages_and_dependencies( project=self.project, packages=self.resolved_packages, diff --git a/scanpipe/pipes/__init__.py b/scanpipe/pipes/__init__.py index 61e2d2a79..1f52270df 100644 --- a/scanpipe/pipes/__init__.py +++ b/scanpipe/pipes/__init__.py @@ -168,7 +168,12 @@ def _clean_package_data(package_data): return package_data -def update_or_create_package(project, package_data, codebase_resources=None): +def update_or_create_package( + project, + package_data, + codebase_resources=None, + is_virtual=False, +): """ Get, update or create a DiscoveredPackage then return it. Use the `project` and `package_data` mapping to lookup and creates the @@ -239,6 +244,7 @@ def update_or_create_dependency( project, dependency_data, for_package=None, + resolved_to_package=None, datafile_resource=None, datasource_id=None, strip_datafile_path_root=False, @@ -254,27 +260,47 @@ def update_or_create_dependency( corresponding CodebaseResource for `datafile_path`. This is used in the case where Dependency data is imported from a scancode-toolkit scan, where the root path segments are not stripped for `datafile_path`. + If the dependency is resolved and a resolved package is created, we have the + corresponsing package_uid at `resolved_to`. """ - dependency = None - dependency_uid = dependency_data.get("dependency_uid") - if ignore_dependency_scope(project, dependency_data): return # Do not create the DiscoveredDependency record. - if not dependency_uid: - dependency_data["dependency_uid"] = uuid.uuid4() - else: - dependency = project.discovereddependencies.get_or_none( - dependency_uid=dependency_uid, + dependencies = get_dependencies(project, dependency_data) + + for dependency in dependencies: + is_for_new_package = ( + for_package + and dependency.for_package + and dependency.for_package != for_package ) + if is_for_new_package: + DiscoveredDependency.populate_dependency_uuid(dependency_data) + dependency = DiscoveredDependency.create_from_data( + project, + dependency_data, + for_package=for_package, + resolved_to_package=resolved_to_package, + datafile_resource=datafile_resource, + datasource_id=datasource_id, + strip_datafile_path_root=strip_datafile_path_root, + ) + break - if dependency: - dependency.update_from_data(dependency_data) - else: + elif dependency: + dependency.update_from_data(dependency_data) + if resolved_to_package and not dependency.resolved_to_package: + dependency.update(resolved_to_package=resolved_to_package) + if for_package and not dependency.for_package: + dependency.update(for_package=for_package) + + if not dependencies: + DiscoveredDependency.populate_dependency_uuid(dependency_data) dependency = DiscoveredDependency.create_from_data( project, dependency_data, for_package=for_package, + resolved_to_package=resolved_to_package, datafile_resource=datafile_resource, datasource_id=datasource_id, strip_datafile_path_root=strip_datafile_path_root, @@ -283,6 +309,34 @@ def update_or_create_dependency( return dependency +def get_dependencies(project, dependency_data): + """ + Given a `dependency_data` mapping, get a list of DiscoveredDependency objects + for that `project` with similar dependency data. + """ + dependency = None + dependency_uid = dependency_data.get("dependency_uid") + extracted_requirement = dependency_data.get("extracted_requirement") or "" + + dependencies = [] + if not dependency_uid: + purl_data = DiscoveredDependency.extract_purl_data(dependency_data) + dependencies = DiscoveredDependency.objects.filter( + project=project, + extracted_requirement=extracted_requirement, + **purl_data, + ) + else: + dependency = DiscoveredDependency.objects.get_or_none( + project=project, + dependency_uid=dependency_uid, + ) + if dependency: + dependencies.append(dependency) + + return dependencies + + def get_or_create_relation(project, relation_data): """ Get or create a CodebaseRelation then return it. diff --git a/scanpipe/pipes/scancode.py b/scanpipe/pipes/scancode.py index 51325b33f..9cb708284 100644 --- a/scanpipe/pipes/scancode.py +++ b/scanpipe/pipes/scancode.py @@ -47,6 +47,8 @@ from scanpipe import pipes from scanpipe.models import CodebaseResource +from scanpipe.models import DiscoveredDependency +from scanpipe.models import DiscoveredPackage from scanpipe.pipes import flag logger = logging.getLogger("scanpipe.pipes") @@ -368,7 +370,7 @@ def scan_for_files(project, resource_qs=None, progress_logger=None): def scan_for_application_packages( - project, assemble=True, package_only=False, progress_logger=None + project, assemble=True, package_only=False, resource_qs=None, progress_logger=None ): """ Run a package scan on resources without a status for a `project`, @@ -383,7 +385,8 @@ def scan_for_application_packages( Multiprocessing is enabled by default on this pipe, the number of processes can be controlled through the SCANCODEIO_PROCESSES setting. """ - resource_qs = project.codebaseresources.no_status() + if not resource_qs: + resource_qs = project.codebaseresources.no_status() scan_func_kwargs = { "package_only": package_only, @@ -473,7 +476,7 @@ def assemble_packages(project): logger.info(f"Unknown Package assembly item type: {item!r}") -def process_package_data(project): +def process_package_data(project, static_resolve=False): """ Create instances of DiscoveredPackage and DiscoveredDependency for `project` from the parsed package data present in the CodebaseResources of `project`. @@ -482,40 +485,213 @@ def process_package_data(project): package/dependency objects are created directly from package data. """ logger.info(f"Project {project} process_package_data:") - seen_resource_paths = set() for resource in project.codebaseresources.has_package_data(): - if resource.path in seen_resource_paths: - continue - logger.info(f" Processing: {resource.path}") for package_mapping in resource.package_data: - pd = packagedcode_models.PackageData.from_dict(mapping=package_mapping) - if not pd.can_assemble: - continue + create_packages_and_dependencies_from_mapping( + project=project, + resource=resource, + package_mapping=package_mapping, + find_package=False, + process_resolved=False, + ) - logger.info(f" Package data: {pd.purl}") + if static_resolve: + resolve_dependencies(project) - package_data = pd.to_dict() - dependencies = package_data.pop("dependencies") - package = None - if pd.purl: - package = pipes.update_or_create_package( - project=project, - package_data=package_data, - codebase_resources=[resource], - ) +def create_packages_and_dependencies_from_mapping( + project, + resource, + package_mapping, + find_package=False, + process_resolved=False, +): + """ + Create or update packages and dependencies from a `package_mapping`, + for a respective `resource` and `project`. + + If `find_package` is True, find the package with the respective purl data, + instead of trying to create it. + If `process_resolved` is True, also create packages and dependency relations + from the resolved packages of dependencies of this `package_mapping`. + """ + pd = packagedcode_models.PackageData.from_dict(mapping=package_mapping) + if not pd.can_assemble: + return + + logger.info(f" Package data: {pd.purl}") + + package_data = pd.to_dict() + dependencies = package_data.pop("dependencies") - for dep in dependencies: + package = None + if pd.purl: + if find_package: + purl_data = DiscoveredPackage.extract_purl_data(package_mapping) + packages = DiscoveredPackage.objects.filter( + project=project, + **purl_data, + ) + + for package in packages: + if resource.location in package.datafile_paths: + break + else: + package = pipes.update_or_create_package( + project=project, + package_data=package_data, + codebase_resources=[resource], + ) + + update_packages_and_dependencies( + project=project, + dependencies=dependencies, + package=package, + resource=resource, + datasource_id=pd.datasource_id, + process_resolved=process_resolved, + ) + + +def resolve_dependencies(project): + """ + Match and merge resolved dependencies to create a dependency graph of + direct dependency relations between resolved packages. + """ + logger.info(f"Project {project} resolve_dependencies:") + for resource in project.codebaseresources.has_package_data(): + for package_mapping in resource.package_data: + create_packages_and_dependencies_from_mapping( + project=project, + resource=resource, + package_mapping=package_mapping, + find_package=True, + process_resolved=True, + ) + + match_and_resolve_dependencies(project) + + +def update_packages_and_dependencies( + project, + dependencies, + package, + resource, + datasource_id, + process_resolved=True, +): + """ + Create DiscoveredPackage and DiscoveredDependency objects from + a package_data dependencies, and also from nested resolved packages + and dependencies if present. + + If `process_resolved` is True, also create packages and dependency relations + from the resolved packages of `dependencies`. + """ + for dep in dependencies: + resolved_package = dep.get("resolved_package") or {} + resolved_to_package = None + if process_resolved and resolved_package: + resolved_to_package = pipes.update_or_create_package( + project=project, + package_data=resolved_package, + codebase_resources=[resource], + is_virtual=True, + ) + + deps_from_resolved = resolved_package.get("dependencies") or [] + for dep_from_resolved in deps_from_resolved: pipes.update_or_create_dependency( project=project, - dependency_data=dep, - for_package=package, + dependency_data=dep_from_resolved, + for_package=resolved_to_package, datafile_resource=resource, - datasource_id=pd.datasource_id, + datasource_id=datasource_id, ) + pipes.update_or_create_dependency( + project=project, + dependency_data=dep, + for_package=package, + resolved_to_package=resolved_to_package, + datafile_resource=resource, + datasource_id=datasource_id, + ) + + +def match_and_resolve_dependencies(project): + """ + From a project with both direct dependency relationships (contains + only the parent package and the requirement) and indirect dependency + relationships like in lockfiles (this contains the resolved package + and the requirement), match and update dependencies to contain the + full dependency graph. + """ + for dependency in project.discovereddependencies.all(): + if dependency.resolved_to_package: + continue + + purl_data = DiscoveredDependency.extract_purl_data( + dependency_data={"purl": dependency.purl}, + ignore_nulls=True, + ) + extracted_requirement = dependency.extracted_requirement + if not extracted_requirement: + extracted_requirement = "" + + matched_dependencies = DiscoveredDependency.objects.filter( + project=project, + extracted_requirement=dependency.extracted_requirement, + **purl_data, + ) + + other_dependencies = [ + matched_dependency + for matched_dependency in matched_dependencies + if matched_dependency.purl != dependency.purl + ] + if not other_dependencies: + # We also have cases where multiple dependency requirements have one + # resolved package and the extracted requirements field is combined + matched_dependencies = DiscoveredDependency.objects.filter( + project=project, + **purl_data, + ) + other_dependencies = [ + matched_dependency + for matched_dependency in matched_dependencies + if ( + matched_dependency.purl != dependency.purl + and dependency.extracted_requirement + in matched_dependency.extracted_requirement + ) + ] + + # This should be done only in the case of lockfiles where only one version + # of a package is present for an environment + if not other_dependencies: + other_dependencies = [ + matched_dependency + for matched_dependency in matched_dependencies + if ( + matched_dependency.base_purl == dependency.base_purl + and matched_dependency.resolved_to_package + ) + ] + + if other_dependencies: + resolved_dependency = other_dependencies.pop() + dependency.update( + resolved_to_package=resolved_dependency.resolved_to_package, + ) + + # We need only the direct dependency relationships but not the from indirect + # dependency realtionships which are between the main package to resolved packages + indirect_dependencies = project.discovereddependencies.filter(is_direct=False) + indirect_dependencies.delete() + def get_packages_with_purl_from_resources(project): """ diff --git a/scanpipe/templates/scanpipe/dependency_list.html b/scanpipe/templates/scanpipe/dependency_list.html index e26ea9c24..51ba0821f 100644 --- a/scanpipe/templates/scanpipe/dependency_list.html +++ b/scanpipe/templates/scanpipe/dependency_list.html @@ -48,6 +48,9 @@ {{ dependency.is_resolved }} + + {{ dependency.is_direct }} + {% if dependency.for_package %} {# CAUTION: Avoid relying on get_absolute_url to prevent unnecessary query triggers #} diff --git a/scanpipe/tests/data/asgiref/asgiref-3.3.0.spdx.json b/scanpipe/tests/data/asgiref/asgiref-3.3.0.spdx.json index be3937874..0554dc617 100644 --- a/scanpipe/tests/data/asgiref/asgiref-3.3.0.spdx.json +++ b/scanpipe/tests/data/asgiref/asgiref-3.3.0.spdx.json @@ -3,7 +3,7 @@ "dataLicense": "CC0-1.0", "SPDXID": "SPDXRef-DOCUMENT", "name": "scancodeio_asgiref", - "documentNamespace": "https://scancode.io/spdxdocs/809b2669-0871-40e6-b932-50598310caac", + "documentNamespace": "https://scancode.io/spdxdocs/2f5f5927-2cad-4ecb-9043-fda5337bd501", "creationInfo": { "created": "2000-01-01T01:02:03Z", "creators": [ @@ -14,7 +14,7 @@ "packages": [ { "name": "asgiref", - "SPDXID": "SPDXRef-scancodeio-discoveredpackage-7549ef42-cbba-4fd9-a528-9055fcb66b8a", + "SPDXID": "SPDXRef-scancodeio-discoveredpackage-75b6bb66-de86-4a35-a780-bc1f635f11f4", "downloadLocation": "NOASSERTION", "licenseConcluded": "BSD-3-Clause", "copyrightText": "NOASSERTION", @@ -33,7 +33,7 @@ }, { "name": "asgiref", - "SPDXID": "SPDXRef-scancodeio-discoveredpackage-8fc54317-6054-4eb7-b189-f1b2822d3fa6", + "SPDXID": "SPDXRef-scancodeio-discoveredpackage-d10827fc-bcd1-4c10-ad6c-972dd4defa9c", "downloadLocation": "NOASSERTION", "licenseConcluded": "BSD-3-Clause", "copyrightText": "NOASSERTION", @@ -52,7 +52,7 @@ }, { "name": "pytest", - "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=5143b8e1-badc-4937-90da-d3d124ecdfd4", + "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=0928ca6e-d50e-439a-847d-ecb1366a8f2a", "downloadLocation": "NOASSERTION", "licenseConcluded": "NOASSERTION", "copyrightText": "NOASSERTION", @@ -68,7 +68,7 @@ }, { "name": "pytest", - "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=f0c50c37-e20a-416d-9395-9238c1c133c9", + "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=94372d19-8ab8-4b16-b6a7-72478e0b4cc4", "downloadLocation": "NOASSERTION", "licenseConcluded": "NOASSERTION", "copyrightText": "NOASSERTION", @@ -84,7 +84,7 @@ }, { "name": "pytest-asyncio", - "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=ba2634df-8cb1-48cc-875a-bc511888f27a", + "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=ccd9eb22-778d-4bd4-af59-8b63e4163b22", "downloadLocation": "NOASSERTION", "licenseConcluded": "NOASSERTION", "copyrightText": "NOASSERTION", @@ -100,7 +100,7 @@ }, { "name": "pytest-asyncio", - "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=baae1579-e28e-40d7-9900-29af699fe7a7", + "SPDXID": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=e751ec65-9351-4949-ae8f-5bc1a9efa336", "downloadLocation": "NOASSERTION", "licenseConcluded": "NOASSERTION", "copyrightText": "NOASSERTION", @@ -116,33 +116,33 @@ } ], "documentDescribes": [ - "SPDXRef-scancodeio-discoveredpackage-7549ef42-cbba-4fd9-a528-9055fcb66b8a", - "SPDXRef-scancodeio-discoveredpackage-8fc54317-6054-4eb7-b189-f1b2822d3fa6", - "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=5143b8e1-badc-4937-90da-d3d124ecdfd4", - "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=f0c50c37-e20a-416d-9395-9238c1c133c9", - "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=ba2634df-8cb1-48cc-875a-bc511888f27a", - "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=baae1579-e28e-40d7-9900-29af699fe7a7" + "SPDXRef-scancodeio-discoveredpackage-75b6bb66-de86-4a35-a780-bc1f635f11f4", + "SPDXRef-scancodeio-discoveredpackage-d10827fc-bcd1-4c10-ad6c-972dd4defa9c", + "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=0928ca6e-d50e-439a-847d-ecb1366a8f2a", + "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=94372d19-8ab8-4b16-b6a7-72478e0b4cc4", + "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=ccd9eb22-778d-4bd4-af59-8b63e4163b22", + "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=e751ec65-9351-4949-ae8f-5bc1a9efa336" ], "files": [], "relationships": [ { - "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=5143b8e1-badc-4937-90da-d3d124ecdfd4", - "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-7549ef42-cbba-4fd9-a528-9055fcb66b8a", + "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=0928ca6e-d50e-439a-847d-ecb1366a8f2a", + "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-75b6bb66-de86-4a35-a780-bc1f635f11f4", "relationshipType": "DEPENDENCY_OF" }, { - "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=f0c50c37-e20a-416d-9395-9238c1c133c9", - "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-8fc54317-6054-4eb7-b189-f1b2822d3fa6", + "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest?uuid=94372d19-8ab8-4b16-b6a7-72478e0b4cc4", + "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-d10827fc-bcd1-4c10-ad6c-972dd4defa9c", "relationshipType": "DEPENDENCY_OF" }, { - "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=ba2634df-8cb1-48cc-875a-bc511888f27a", - "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-7549ef42-cbba-4fd9-a528-9055fcb66b8a", + "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=ccd9eb22-778d-4bd4-af59-8b63e4163b22", + "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-75b6bb66-de86-4a35-a780-bc1f635f11f4", "relationshipType": "DEPENDENCY_OF" }, { - "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=baae1579-e28e-40d7-9900-29af699fe7a7", - "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-8fc54317-6054-4eb7-b189-f1b2822d3fa6", + "spdxElementId": "SPDXRef-scancodeio-discovereddependency-pkg:pypi/pytest-asyncio?uuid=e751ec65-9351-4949-ae8f-5bc1a9efa336", + "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-d10827fc-bcd1-4c10-ad6c-972dd4defa9c", "relationshipType": "DEPENDENCY_OF" } ], diff --git a/scanpipe/tests/data/asgiref/asgiref-3.3.0_fixtures.json b/scanpipe/tests/data/asgiref/asgiref-3.3.0_fixtures.json index 74ba27506..cc0e1c6aa 100644 --- a/scanpipe/tests/data/asgiref/asgiref-3.3.0_fixtures.json +++ b/scanpipe/tests/data/asgiref/asgiref-3.3.0_fixtures.json @@ -1,13 +1,13 @@ [ { "model": "scanpipe.project", - "pk": "809b2669-0871-40e6-b932-50598310caac", + "pk": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "fields": { "extra_data": {}, - "created_date": "2024-06-24T06:58:40.386Z", + "created_date": "2024-06-27T14:35:14.839Z", "name": "asgiref", - "slug": "asgiref-809b2669", - "work_directory": "/tmp/tmp30w3f9yy/projects/asgiref-809b2669", + "slug": "asgiref-2f5f5927", + "work_directory": "/tmp/tmp4olqovm8/projects/asgiref-2f5f5927", "is_archived": false, "notes": "", "settings": {} @@ -15,17 +15,17 @@ }, { "model": "scanpipe.run", - "pk": "4d888ac2-92f8-4841-8b4e-11996fcd0fd6", + "pk": "41bd06fa-6e75-45e9-8476-5602d1c1433f", "fields": { "task_id": null, "task_start_date": null, "task_end_date": null, "task_exitcode": null, "task_output": "", - "log": "2024-06-24 08:58:40.39 Pipeline [scan_codebase] starting\n2024-06-24 08:58:40.39 Step [download_missing_inputs] starting\n2024-06-24 08:58:40.39 Step [download_missing_inputs] completed in 0 seconds\n2024-06-24 08:58:40.39 Step [copy_inputs_to_codebase_directory] starting\n2024-06-24 08:58:40.39 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2024-06-24 08:58:40.39 Step [extract_archives] starting\n2024-06-24 08:58:40.46 Step [extract_archives] completed in 0 seconds\n2024-06-24 08:58:40.46 Step [collect_and_create_codebase_resources] starting\n2024-06-24 08:58:40.55 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2024-06-24 08:58:40.55 Step [flag_empty_files] starting\n2024-06-24 08:58:40.56 Step [flag_empty_files] completed in 0 seconds\n2024-06-24 08:58:40.56 Step [flag_ignored_resources] starting\n2024-06-24 08:58:40.56 Step [flag_ignored_resources] completed in 0 seconds\n2024-06-24 08:58:40.56 Step [scan_for_application_packages] starting\n2024-06-24 08:58:40.58 Progress: 11% (2/18)\n2024-06-24 08:58:40.59 Progress: 22% (4/18)\n2024-06-24 08:58:40.59 Progress: 33% (6/18)\n2024-06-24 08:58:40.59 Progress: 44% (8/18)\n2024-06-24 08:58:40.60 Progress: 55% (10/18)\n2024-06-24 08:58:40.60 Progress: 66% (12/18)\n2024-06-24 08:58:40.60 Progress: 77% (14/18)\n2024-06-24 08:58:40.60 Progress: 88% (16/18)\n2024-06-24 08:58:42.99 Progress: 100% (18/18)\n2024-06-24 08:58:43.10 Step [scan_for_application_packages] completed in 3 seconds\n2024-06-24 08:58:43.10 Step [scan_for_files] starting\n2024-06-24 08:58:45.36 Progress: 12% (2/16) ETA: 17 seconds\n2024-06-24 08:58:45.36 Progress: 25% (4/16) ETA: 7 seconds\n2024-06-24 08:58:45.50 Progress: 37% (6/16) ETA: 4 seconds\n2024-06-24 08:58:45.56 Progress: 50% (8/16) ETA: 2 seconds\n2024-06-24 08:58:45.71 Progress: 62% (10/16) ETA: 2 seconds\n2024-06-24 08:58:45.91 Progress: 75% (12/16) ETA: 1 seconds\n2024-06-24 08:58:46.22 Progress: 87% (14/16)\n2024-06-24 08:58:46.30 Progress: 100% (16/16)\n2024-06-24 08:58:46.33 Step [scan_for_files] completed in 3 seconds\n2024-06-24 08:58:46.33 Pipeline completed in 6 seconds\n", - "project": "809b2669-0871-40e6-b932-50598310caac", + "log": "2024-06-27 14:35:14.84 Pipeline [scan_codebase] starting\n2024-06-27 14:35:14.84 Step [download_missing_inputs] starting\n2024-06-27 14:35:14.84 Step [download_missing_inputs] completed in 0 seconds\n2024-06-27 14:35:14.84 Step [copy_inputs_to_codebase_directory] starting\n2024-06-27 14:35:14.84 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2024-06-27 14:35:14.84 Step [extract_archives] starting\n2024-06-27 14:35:14.89 Step [extract_archives] completed in 0 seconds\n2024-06-27 14:35:14.89 Step [collect_and_create_codebase_resources] starting\n2024-06-27 14:35:14.96 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [flag_empty_files] starting\n2024-06-27 14:35:14.96 Step [flag_empty_files] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [flag_ignored_resources] starting\n2024-06-27 14:35:14.96 Step [flag_ignored_resources] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [scan_for_application_packages] starting\n2024-06-27 14:35:14.98 Progress: 11% (2/18)\n2024-06-27 14:35:14.99 Progress: 22% (4/18)\n2024-06-27 14:35:14.99 Progress: 33% (6/18)\n2024-06-27 14:35:14.99 Progress: 44% (8/18)\n2024-06-27 14:35:14.99 Progress: 55% (10/18)\n2024-06-27 14:35:14.99 Progress: 66% (12/18)\n2024-06-27 14:35:14.99 Progress: 77% (14/18)\n2024-06-27 14:35:14.99 Progress: 88% (16/18)\n2024-06-27 14:35:17.74 Progress: 100% (18/18)\n2024-06-27 14:35:17.94 Step [scan_for_application_packages] completed in 3 seconds\n2024-06-27 14:35:17.94 Step [scan_for_files] starting\n2024-06-27 14:37:12.49 Progress: 12% (2/16) ETA: 840 seconds (14.0 minutes)\n2024-06-27 14:37:12.97 Progress: 25% (4/16) ETA: 345 seconds (5.8 minutes)\n2024-06-27 14:37:13.21 Progress: 37% (6/16) ETA: 196 seconds (3.3 minutes)\n2024-06-27 14:37:13.26 Progress: 50% (8/16) ETA: 115 seconds (1.9 minutes)\n2024-06-27 14:37:13.47 Progress: 62% (10/16) ETA: 71 seconds (1.2 minutes)\n2024-06-27 14:37:13.57 Progress: 75% (12/16) ETA: 39 seconds\n2024-06-27 14:37:13.64 Progress: 87% (14/16) ETA: 17 seconds\n2024-06-27 14:37:13.99 Progress: 100% (16/16)\n2024-06-27 14:37:14.17 Step [scan_for_files] completed in 116 seconds (1.9 minutes)\n2024-06-27 14:37:14.17 Pipeline completed in 119 seconds (2.0 minutes)\n", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "pipeline_name": "scan_codebase", - "created_date": "2024-06-24T06:58:40.390Z", + "created_date": "2024-06-27T14:35:14.841Z", "scancodeio_version": "", "description": "Scan a codebase for application packages, licenses, and copyrights.", "current_step": "", @@ -41,7 +41,7 @@ "sha256": "a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -117,6 +117,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "notice_text": null, @@ -125,6 +127,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -135,6 +138,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -346,7 +350,7 @@ "sha256": "", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -390,7 +394,7 @@ "sha256": "", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -434,7 +438,7 @@ "sha256": "", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -472,13 +476,136 @@ { "model": "scanpipe.codebaseresource", "pk": 5, + "fields": { + "md5": "680e61db4d95c8d9501b7a49fa2bf0b2", + "sha1": "612390bd0d0227c009f9c99b479878adf7ac2f23", + "sha256": "6e89108c2cf0c0446174188f76f60465ae1c1f14f83427807df40d52a27cb2c8", + "sha512": "", + "extra_data": {}, + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "detected_license_expression": "", + "detected_license_expression_spdx": "", + "license_detections": [], + "license_clues": [], + "percentage_of_license_text": null, + "copyrights": [], + "holders": [], + "authors": [], + "emails": [], + "urls": [], + "compliance_alert": "", + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/top_level.txt", + "rootfs_path": "", + "status": "scanned", + "size": 8, + "tag": "", + "type": "file", + "name": "top_level.txt", + "extension": ".txt", + "programming_language": "", + "mime_type": "text/plain", + "file_type": "ASCII text", + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "package_data": [] + } +}, +{ + "model": "scanpipe.codebaseresource", + "pk": 6, + "fields": { + "md5": "f09eb47206614a4954c51db8a94840fa", + "sha1": "baf11129ce63c4eef654f39a360b31cfc7d1ac67", + "sha256": "b846415d1b514e9c1dff14a22deb906d794bc546ca6129f950a18cd091e2a669", + "sha512": "", + "extra_data": {}, + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "detected_license_expression": "bsd-new", + "detected_license_expression_spdx": "BSD-3-Clause", + "license_detections": [ + { + "matches": [ + { + "score": 100.0, + "matcher": "2-aho", + "end_line": 27, + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/bsd-new_683.RULE", + "from_file": null, + "start_line": 4, + "matched_text": "Redistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n\n 3. Neither the name of Django nor the names of its contributors may be used\n to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "match_coverage": 100.0, + "matched_length": 214, + "rule_relevance": 100, + "rule_identifier": "bsd-new_683.RULE", + "license_expression": "bsd-new", + "spdx_license_expression": "BSD-3-Clause" + } + ], + "identifier": "bsd_new-72cae3bc-4423-3a9e-be84-ee8bb5120a4d", + "license_expression": "bsd-new", + "license_expression_spdx": "BSD-3-Clause" + } + ], + "license_clues": [], + "percentage_of_license_text": 95.11, + "copyrights": [ + { + "end_line": 1, + "copyright": "Copyright (c) Django Software Foundation and individual contributors", + "start_line": 1 + } + ], + "holders": [ + { + "holder": "Django Software Foundation and individual contributors", + "end_line": 1, + "start_line": 1 + } + ], + "authors": [], + "emails": [], + "urls": [], + "compliance_alert": "", + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/LICENSE", + "rootfs_path": "", + "status": "scanned", + "size": 1552, + "tag": "", + "type": "file", + "name": "LICENSE", + "extension": "", + "programming_language": "", + "mime_type": "text/plain", + "file_type": "ASCII text", + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "package_data": [] + } +}, +{ + "model": "scanpipe.codebaseresource", + "pk": 7, "fields": { "md5": "4b50d67ff7994afcad22c6ef154cf052", "sha1": "53d0f6e1cbf6a3c31fb0aa3089b2ca98ad95fc49", "sha256": "70f98f4eb9f6068b192b5464fcdf69e29a8ff09962bfce84bbb052baeee44f33", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -554,6 +681,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "notice_text": null, @@ -562,6 +691,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -572,6 +702,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -776,93 +907,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 6, - "fields": { - "md5": "f09eb47206614a4954c51db8a94840fa", - "sha1": "baf11129ce63c4eef654f39a360b31cfc7d1ac67", - "sha256": "b846415d1b514e9c1dff14a22deb906d794bc546ca6129f950a18cd091e2a669", - "sha512": "", - "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", - "detected_license_expression": "bsd-new", - "detected_license_expression_spdx": "BSD-3-Clause", - "license_detections": [ - { - "matches": [ - { - "score": 100.0, - "matcher": "2-aho", - "end_line": 27, - "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/bsd-new_683.RULE", - "from_file": null, - "start_line": 4, - "matched_text": "Redistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n\n 3. Neither the name of Django nor the names of its contributors may be used\n to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", - "match_coverage": 100.0, - "matched_length": 214, - "rule_relevance": 100, - "rule_identifier": "bsd-new_683.RULE", - "license_expression": "bsd-new", - "spdx_license_expression": "BSD-3-Clause" - } - ], - "identifier": "bsd_new-72cae3bc-4423-3a9e-be84-ee8bb5120a4d", - "license_expression": "bsd-new", - "license_expression_spdx": "BSD-3-Clause" - } - ], - "license_clues": [], - "percentage_of_license_text": 95.11, - "copyrights": [ - { - "end_line": 1, - "copyright": "Copyright (c) Django Software Foundation and individual contributors", - "start_line": 1 - } - ], - "holders": [ - { - "holder": "Django Software Foundation and individual contributors", - "end_line": 1, - "start_line": 1 - } - ], - "authors": [], - "emails": [], - "urls": [], - "compliance_alert": "", - "is_legal": false, - "is_manifest": false, - "is_readme": false, - "is_top_level": false, - "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/LICENSE", - "rootfs_path": "", - "status": "scanned", - "size": 1552, - "tag": "", - "type": "file", - "name": "LICENSE", - "extension": "", - "programming_language": "", - "mime_type": "text/plain", - "file_type": "ASCII text", - "is_binary": false, - "is_text": true, - "is_archive": false, - "is_media": false, - "package_data": [] - } -}, -{ - "model": "scanpipe.codebaseresource", - "pk": 7, + "pk": 8, "fields": { - "md5": "680e61db4d95c8d9501b7a49fa2bf0b2", - "sha1": "612390bd0d0227c009f9c99b479878adf7ac2f23", - "sha256": "6e89108c2cf0c0446174188f76f60465ae1c1f14f83427807df40d52a27cb2c8", + "md5": "5ccc7519eb42f1dfceee6e7d685f1ff5", + "sha1": "ddd91bc89b15fc5c66e0fa259392955c74ba041f", + "sha256": "11546323af45e6a5639bf620a9c4d73e74c0bf705f494af4595007b923f75e8a", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -879,14 +931,14 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/top_level.txt", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/WHEEL", "rootfs_path": "", "status": "scanned", - "size": 8, + "size": 92, "tag": "", "type": "file", - "name": "top_level.txt", - "extension": ".txt", + "name": "WHEEL", + "extension": "", "programming_language": "", "mime_type": "text/plain", "file_type": "ASCII text", @@ -899,14 +951,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 8, + "pk": 9, "fields": { "md5": "38e56802a5adcafeae35efc6e3d218ba", "sha1": "5854ecf1ad649848d7cda8096d09ac258c888208", "sha256": "2c1983592aa38f0bfb0afacc73ddc5b46ce10e8e89ceaa9fed1e5fc6361b608d", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -943,14 +995,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 9, + "pk": 10, "fields": { - "md5": "5ccc7519eb42f1dfceee6e7d685f1ff5", - "sha1": "ddd91bc89b15fc5c66e0fa259392955c74ba041f", - "sha256": "11546323af45e6a5639bf620a9c4d73e74c0bf705f494af4595007b923f75e8a", + "md5": "4910b756f4e611055140e80f757d9325", + "sha1": "91bc786d907bf3ca8b8e6277063107975780f9ca", + "sha256": "30f49b9094bff904a42caeec32515715fe625a56dc48bd7c0e3d9988c0ad4bd7", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -967,15 +1019,15 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/WHEEL", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/__init__.py", "rootfs_path": "", "status": "scanned", - "size": 92, + "size": 22, "tag": "", "type": "file", - "name": "WHEEL", - "extension": "", - "programming_language": "", + "name": "__init__.py", + "extension": ".py", + "programming_language": "Python", "mime_type": "text/plain", "file_type": "ASCII text", "is_binary": false, @@ -987,14 +1039,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 10, + "pk": 11, "fields": { "md5": "44ec43af7ee367c7d6a5808d37133144", "sha1": "702381ba6ecb30bbfdcaf0d466a25f470dd9938b", "sha256": "fa4651a3b79201a4dc44a4096cd49ec8f427e912ea0ee05c666357b413a8afe7", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1029,60 +1081,16 @@ "package_data": [] } }, -{ - "model": "scanpipe.codebaseresource", - "pk": 11, - "fields": { - "md5": "aff31de5fa753643adacf0311aa553f4", - "sha1": "534de2315197b14d0571edc5ed3b3b8ceade0d24", - "sha256": "ddbc8d455eceb68fc583c67e7c4ad0277c867fb39095c51ec5b37f70342e8334", - "sha512": "", - "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", - "detected_license_expression": "", - "detected_license_expression_spdx": "", - "license_detections": [], - "license_clues": [], - "percentage_of_license_text": null, - "copyrights": [], - "holders": [], - "authors": [], - "emails": [], - "urls": [], - "compliance_alert": "", - "is_legal": false, - "is_manifest": false, - "is_readme": false, - "is_top_level": false, - "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/testing.py", - "rootfs_path": "", - "status": "scanned", - "size": 3119, - "tag": "", - "type": "file", - "name": "testing.py", - "extension": ".py", - "programming_language": "Python", - "mime_type": "text/x-script.python", - "file_type": "Python script, ASCII text executable", - "is_binary": false, - "is_text": true, - "is_archive": false, - "is_media": false, - "package_data": [] - } -}, { "model": "scanpipe.codebaseresource", "pk": 12, "fields": { - "md5": "5b7619584de19d8f1a00fb5a43349153", - "sha1": "ebe97b4c2689537e9387dd8dac353c3e010f8f02", - "sha256": "885267fee0fea687875a02ceb929ca095312d47aaa57e20e4ce382f397caaf4d", + "md5": "e4103a2fcd6a3f23a036307c978271d7", + "sha1": "0de5075d1ce4a1a17d70ad6ee523e3d947074899", + "sha256": "ee0fcf4a8e6fa9df8a4643bb48e82892d496afce44b6c8b8aea2721755545e1c", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1099,13 +1107,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/server.py", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/local.py", "rootfs_path": "", "status": "scanned", - "size": 5915, + "size": 4849, "tag": "", "type": "file", - "name": "server.py", + "name": "local.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1121,12 +1129,12 @@ "model": "scanpipe.codebaseresource", "pk": 13, "fields": { - "md5": "e4103a2fcd6a3f23a036307c978271d7", - "sha1": "0de5075d1ce4a1a17d70ad6ee523e3d947074899", - "sha256": "ee0fcf4a8e6fa9df8a4643bb48e82892d496afce44b6c8b8aea2721755545e1c", + "md5": "5231077fd0628314246fcba7817b561e", + "sha1": "9c74e64e9a71903bb227907ea1806eac77e52434", + "sha256": "3151f66c476208c3154cb6c4fb557a2a253bab82f0ab33fb3c8b9f7976be9e33", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1143,13 +1151,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/local.py", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/compatibility.py", "rootfs_path": "", "status": "scanned", - "size": 4849, + "size": 1598, "tag": "", "type": "file", - "name": "local.py", + "name": "compatibility.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1165,12 +1173,12 @@ "model": "scanpipe.codebaseresource", "pk": 14, "fields": { - "md5": "5231077fd0628314246fcba7817b561e", - "sha1": "9c74e64e9a71903bb227907ea1806eac77e52434", - "sha256": "3151f66c476208c3154cb6c4fb557a2a253bab82f0ab33fb3c8b9f7976be9e33", + "md5": "b4c45f37055d88dd11b15eb4de51b074", + "sha1": "aacf7e5e2e5ba78ccfb67fa10e9e6b22c3935c9b", + "sha256": "ddd445b778c097fc75c2bf69ad964cbadd3bd6999d1dd2306d39d401855e8e3e", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1187,13 +1195,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/compatibility.py", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/current_thread_executor.py", "rootfs_path": "", "status": "scanned", - "size": 1598, + "size": 2974, "tag": "", "type": "file", - "name": "compatibility.py", + "name": "current_thread_executor.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1209,12 +1217,12 @@ "model": "scanpipe.codebaseresource", "pk": 15, "fields": { - "md5": "b4c45f37055d88dd11b15eb4de51b074", - "sha1": "aacf7e5e2e5ba78ccfb67fa10e9e6b22c3935c9b", - "sha256": "ddd445b778c097fc75c2bf69ad964cbadd3bd6999d1dd2306d39d401855e8e3e", + "md5": "aff31de5fa753643adacf0311aa553f4", + "sha1": "534de2315197b14d0571edc5ed3b3b8ceade0d24", + "sha256": "ddbc8d455eceb68fc583c67e7c4ad0277c867fb39095c51ec5b37f70342e8334", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1231,13 +1239,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/current_thread_executor.py", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/testing.py", "rootfs_path": "", "status": "scanned", - "size": 2974, + "size": 3119, "tag": "", "type": "file", - "name": "current_thread_executor.py", + "name": "testing.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1258,7 +1266,7 @@ "sha256": "126c3e3a8a75a517d2739612304607804cf5f34da63fa25d03a6f11f7edb6f2f", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "apache-2.0", "detected_license_expression_spdx": "Apache-2.0", "license_detections": [ @@ -1336,12 +1344,12 @@ "model": "scanpipe.codebaseresource", "pk": 17, "fields": { - "md5": "4910b756f4e611055140e80f757d9325", - "sha1": "91bc786d907bf3ca8b8e6277063107975780f9ca", - "sha256": "30f49b9094bff904a42caeec32515715fe625a56dc48bd7c0e3d9988c0ad4bd7", + "md5": "4eed1361d0e454149f95fca85c84f33f", + "sha1": "1f06eb4dd6d38b1a3e2a9b9e751744b303c37e0d", + "sha256": "f8bd1ea3fb8afddabb10f8efd66796d41446cad51168ef4d3c44b19c973d0ad0", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1358,17 +1366,17 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/__init__.py", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/wsgi.py", "rootfs_path": "", "status": "scanned", - "size": 22, + "size": 6575, "tag": "", "type": "file", - "name": "__init__.py", + "name": "wsgi.py", "extension": ".py", "programming_language": "Python", - "mime_type": "text/plain", - "file_type": "ASCII text", + "mime_type": "text/x-script.python", + "file_type": "Python script, ASCII text executable", "is_binary": false, "is_text": true, "is_archive": false, @@ -1380,12 +1388,12 @@ "model": "scanpipe.codebaseresource", "pk": 18, "fields": { - "md5": "4eed1361d0e454149f95fca85c84f33f", - "sha1": "1f06eb4dd6d38b1a3e2a9b9e751744b303c37e0d", - "sha256": "f8bd1ea3fb8afddabb10f8efd66796d41446cad51168ef4d3c44b19c973d0ad0", + "md5": "5b7619584de19d8f1a00fb5a43349153", + "sha1": "ebe97b4c2689537e9387dd8dac353c3e010f8f02", + "sha256": "885267fee0fea687875a02ceb929ca095312d47aaa57e20e4ce382f397caaf4d", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1402,13 +1410,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/wsgi.py", + "path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref/server.py", "rootfs_path": "", "status": "scanned", - "size": 6575, + "size": 5915, "tag": "", "type": "file", - "name": "wsgi.py", + "name": "server.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1439,7 +1447,7 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "compliance_alert": "", "affected_by_vulnerabilities": [], "filename": "", @@ -1510,6 +1518,8 @@ "other_license_detections": [], "extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n", "notice_text": "", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel" ], @@ -1526,10 +1536,10 @@ "email": "foundation@djangoproject.com" } ], - "uuid": "7549ef42-cbba-4fd9-a528-9055fcb66b8a", + "uuid": "75b6bb66-de86-4a35-a780-bc1f635f11f4", "missing_resources": [], "modified_resources": [], - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01", "keywords": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -1570,7 +1580,7 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "compliance_alert": "", "affected_by_vulnerabilities": [], "filename": "", @@ -1641,6 +1651,8 @@ "other_license_detections": [], "extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n", "notice_text": "", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel_metadata" ], @@ -1657,10 +1669,10 @@ "email": "foundation@djangoproject.com" } ], - "uuid": "8fc54317-6054-4eb7-b189-f1b2822d3fa6", + "uuid": "d10827fc-bcd1-4c10-ad6c-972dd4defa9c", "missing_resources": [], "modified_resources": [], - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", "keywords": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -1679,19 +1691,19 @@ "tag": "", "codebase_resources": [ 6, - 5, - 8, 7, 9, - 14, - 15, - 17, + 5, + 8, 13, - 12, + 14, 10, + 12, + 18, 11, + 15, 16, - 18 + 17 ] } }, @@ -1706,8 +1718,8 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest?uuid=5143b8e1-badc-4937-90da-d3d124ecdfd4", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest?uuid=0928ca6e-d50e-439a-847d-ecb1366a8f2a", "for_package": 1, "resolved_to_package": null, "datafile_resource": 1, @@ -1716,7 +1728,8 @@ "datasource_id": "pypi_wheel", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } }, { @@ -1730,8 +1743,8 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=ba2634df-8cb1-48cc-875a-bc511888f27a", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=ccd9eb22-778d-4bd4-af59-8b63e4163b22", "for_package": 1, "resolved_to_package": null, "datafile_resource": 1, @@ -1740,7 +1753,8 @@ "datasource_id": "pypi_wheel", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } }, { @@ -1754,17 +1768,18 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest?uuid=f0c50c37-e20a-416d-9395-9238c1c133c9", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest?uuid=94372d19-8ab8-4b16-b6a7-72478e0b4cc4", "for_package": 2, "resolved_to_package": null, - "datafile_resource": 5, + "datafile_resource": 7, "extracted_requirement": "pytest; extra == \"tests\"", "scope": "tests", "datasource_id": "pypi_wheel_metadata", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } }, { @@ -1778,17 +1793,18 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=baae1579-e28e-40d7-9900-29af699fe7a7", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=e751ec65-9351-4949-ae8f-5bc1a9efa336", "for_package": 2, "resolved_to_package": null, - "datafile_resource": 5, + "datafile_resource": 7, "extracted_requirement": "pytest-asyncio; extra == \"tests\"", "scope": "tests", "datasource_id": "pypi_wheel_metadata", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } } ] diff --git a/scanpipe/tests/data/asgiref/asgiref-3.3.0_load_inventory_expected.json b/scanpipe/tests/data/asgiref/asgiref-3.3.0_load_inventory_expected.json index 908e433f5..27ee3b409 100644 --- a/scanpipe/tests/data/asgiref/asgiref-3.3.0_load_inventory_expected.json +++ b/scanpipe/tests/data/asgiref/asgiref-3.3.0_load_inventory_expected.json @@ -136,6 +136,8 @@ "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel" ], @@ -255,6 +257,8 @@ "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel_metadata" ], @@ -275,6 +279,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/pytest?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -290,6 +295,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/pytest?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -305,6 +311,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -320,6 +327,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -402,6 +410,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "notice_text": null, "api_data_url": "https://pypi.org/pypi/asgiref/3.3.0/json", @@ -409,6 +419,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -419,6 +430,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -909,6 +921,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "notice_text": null, "api_data_url": "https://pypi.org/pypi/asgiref/3.3.0/json", @@ -916,6 +930,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -926,6 +941,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, diff --git a/scanpipe/tests/data/asgiref/asgiref-3.3.0_scanpipe_output.json b/scanpipe/tests/data/asgiref/asgiref-3.3.0_scanpipe_output.json index 2cbf3c28f..9d9e55066 100644 --- a/scanpipe/tests/data/asgiref/asgiref-3.3.0_scanpipe_output.json +++ b/scanpipe/tests/data/asgiref/asgiref-3.3.0_scanpipe_output.json @@ -2,18 +2,18 @@ "headers": [ { "tool_name": "scanpipe", - "tool_version": "34.6.3", + "tool_version": "v34.6.2-11-g72cef36", "other_tools": [ - "pkg:pypi/scancode-toolkit@32.1.0" + "pkg:pypi/scancode-toolkit@32.2.0" ], "notice": "Generated with ScanCode.io and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied.\nNo content created from ScanCode.io should be considered or used as legal advice.\nConsult an Attorney for any legal advice.\nScanCode.io is a free software code scanning tool from nexB Inc. and others\nlicensed under the Apache License version 2.0.\nScanCode is a trademark of nexB Inc.\nVisit https://github.com/nexB/scancode.io for support and download.\n", - "uuid": "809b2669-0871-40e6-b932-50598310caac", - "created_date": "2024-06-24T06:58:40.386Z", + "uuid": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "created_date": "2024-06-27T14:35:14.839Z", "notes": "", "settings": {}, "input_sources": [ { - "uuid": "146197f3-217a-4a6d-b287-7661929e5f0a", + "uuid": "0a1db27f-b451-48b6-9ba6-87770e62fd50", "filename": "asgiref-3.3.0-py3-none-any.whl", "download_url": "", "is_uploaded": true, @@ -28,15 +28,15 @@ "pipeline_name": "scan_codebase", "status": "not_started", "description": "Scan a codebase for application packages, licenses, and copyrights.", - "uuid": "4d888ac2-92f8-4841-8b4e-11996fcd0fd6", - "created_date": "2024-06-24T08:58:40.390918+02:00", + "uuid": "41bd06fa-6e75-45e9-8476-5602d1c1433f", + "created_date": "2024-06-27T14:35:14.841444Z", "scancodeio_version": "", "task_id": null, "task_start_date": null, "task_end_date": null, "task_exitcode": null, "task_output": "", - "log": "2024-06-24 08:58:40.39 Pipeline [scan_codebase] starting\n2024-06-24 08:58:40.39 Step [download_missing_inputs] starting\n2024-06-24 08:58:40.39 Step [download_missing_inputs] completed in 0 seconds\n2024-06-24 08:58:40.39 Step [copy_inputs_to_codebase_directory] starting\n2024-06-24 08:58:40.39 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2024-06-24 08:58:40.39 Step [extract_archives] starting\n2024-06-24 08:58:40.46 Step [extract_archives] completed in 0 seconds\n2024-06-24 08:58:40.46 Step [collect_and_create_codebase_resources] starting\n2024-06-24 08:58:40.55 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2024-06-24 08:58:40.55 Step [flag_empty_files] starting\n2024-06-24 08:58:40.56 Step [flag_empty_files] completed in 0 seconds\n2024-06-24 08:58:40.56 Step [flag_ignored_resources] starting\n2024-06-24 08:58:40.56 Step [flag_ignored_resources] completed in 0 seconds\n2024-06-24 08:58:40.56 Step [scan_for_application_packages] starting\n2024-06-24 08:58:40.58 Progress: 11% (2/18)\n2024-06-24 08:58:40.59 Progress: 22% (4/18)\n2024-06-24 08:58:40.59 Progress: 33% (6/18)\n2024-06-24 08:58:40.59 Progress: 44% (8/18)\n2024-06-24 08:58:40.60 Progress: 55% (10/18)\n2024-06-24 08:58:40.60 Progress: 66% (12/18)\n2024-06-24 08:58:40.60 Progress: 77% (14/18)\n2024-06-24 08:58:40.60 Progress: 88% (16/18)\n2024-06-24 08:58:42.99 Progress: 100% (18/18)\n2024-06-24 08:58:43.10 Step [scan_for_application_packages] completed in 3 seconds\n2024-06-24 08:58:43.10 Step [scan_for_files] starting\n2024-06-24 08:58:45.36 Progress: 12% (2/16) ETA: 17 seconds\n2024-06-24 08:58:45.36 Progress: 25% (4/16) ETA: 7 seconds\n2024-06-24 08:58:45.50 Progress: 37% (6/16) ETA: 4 seconds\n2024-06-24 08:58:45.56 Progress: 50% (8/16) ETA: 2 seconds\n2024-06-24 08:58:45.71 Progress: 62% (10/16) ETA: 2 seconds\n2024-06-24 08:58:45.91 Progress: 75% (12/16) ETA: 1 seconds\n2024-06-24 08:58:46.22 Progress: 87% (14/16)\n2024-06-24 08:58:46.30 Progress: 100% (16/16)\n2024-06-24 08:58:46.33 Step [scan_for_files] completed in 3 seconds\n2024-06-24 08:58:46.33 Pipeline completed in 6 seconds\n", + "log": "2024-06-27 14:35:14.84 Pipeline [scan_codebase] starting\n2024-06-27 14:35:14.84 Step [download_missing_inputs] starting\n2024-06-27 14:35:14.84 Step [download_missing_inputs] completed in 0 seconds\n2024-06-27 14:35:14.84 Step [copy_inputs_to_codebase_directory] starting\n2024-06-27 14:35:14.84 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2024-06-27 14:35:14.84 Step [extract_archives] starting\n2024-06-27 14:35:14.89 Step [extract_archives] completed in 0 seconds\n2024-06-27 14:35:14.89 Step [collect_and_create_codebase_resources] starting\n2024-06-27 14:35:14.96 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [flag_empty_files] starting\n2024-06-27 14:35:14.96 Step [flag_empty_files] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [flag_ignored_resources] starting\n2024-06-27 14:35:14.96 Step [flag_ignored_resources] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [scan_for_application_packages] starting\n2024-06-27 14:35:14.98 Progress: 11% (2/18)\n2024-06-27 14:35:14.99 Progress: 22% (4/18)\n2024-06-27 14:35:14.99 Progress: 33% (6/18)\n2024-06-27 14:35:14.99 Progress: 44% (8/18)\n2024-06-27 14:35:14.99 Progress: 55% (10/18)\n2024-06-27 14:35:14.99 Progress: 66% (12/18)\n2024-06-27 14:35:14.99 Progress: 77% (14/18)\n2024-06-27 14:35:14.99 Progress: 88% (16/18)\n2024-06-27 14:35:17.74 Progress: 100% (18/18)\n2024-06-27 14:35:17.94 Step [scan_for_application_packages] completed in 3 seconds\n2024-06-27 14:35:17.94 Step [scan_for_files] starting\n2024-06-27 14:37:12.49 Progress: 12% (2/16) ETA: 840 seconds (14.0 minutes)\n2024-06-27 14:37:12.97 Progress: 25% (4/16) ETA: 345 seconds (5.8 minutes)\n2024-06-27 14:37:13.21 Progress: 37% (6/16) ETA: 196 seconds (3.3 minutes)\n2024-06-27 14:37:13.26 Progress: 50% (8/16) ETA: 115 seconds (1.9 minutes)\n2024-06-27 14:37:13.47 Progress: 62% (10/16) ETA: 71 seconds (1.2 minutes)\n2024-06-27 14:37:13.57 Progress: 75% (12/16) ETA: 39 seconds\n2024-06-27 14:37:13.64 Progress: 87% (14/16) ETA: 17 seconds\n2024-06-27 14:37:13.99 Progress: 100% (16/16)\n2024-06-27 14:37:14.17 Step [scan_for_files] completed in 116 seconds (1.9 minutes)\n2024-06-27 14:37:14.17 Pipeline completed in 119 seconds (2.0 minutes)\n", "execution_time": null } ], @@ -154,7 +154,9 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel" ], @@ -276,7 +278,9 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel_metadata" ], @@ -297,8 +301,9 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, - "dependency_uid": "pkg:pypi/pytest?uuid=5143b8e1-badc-4937-90da-d3d124ecdfd4", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da", + "is_direct": true, + "dependency_uid": "pkg:pypi/pytest?uuid=0928ca6e-d50e-439a-847d-ecb1366a8f2a", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01", "resolved_to_package_uid": null, "datafile_path": "asgiref-3.3.0-py3-none-any.whl", "datasource_id": "pypi_wheel", @@ -312,8 +317,9 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, - "dependency_uid": "pkg:pypi/pytest?uuid=f0c50c37-e20a-416d-9395-9238c1c133c9", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", + "is_direct": true, + "dependency_uid": "pkg:pypi/pytest?uuid=94372d19-8ab8-4b16-b6a7-72478e0b4cc4", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", "resolved_to_package_uid": null, "datafile_path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA", "datasource_id": "pypi_wheel_metadata", @@ -327,8 +333,9 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=ba2634df-8cb1-48cc-875a-bc511888f27a", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da", + "is_direct": true, + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=ccd9eb22-778d-4bd4-af59-8b63e4163b22", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01", "resolved_to_package_uid": null, "datafile_path": "asgiref-3.3.0-py3-none-any.whl", "datasource_id": "pypi_wheel", @@ -342,8 +349,9 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=baae1579-e28e-40d7-9900-29af699fe7a7", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", + "is_direct": true, + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=e751ec65-9351-4949-ae8f-5bc1a9efa336", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", "resolved_to_package_uid": null, "datafile_path": "asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA", "datasource_id": "pypi_wheel_metadata", @@ -429,6 +437,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "notice_text": null, @@ -437,6 +447,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -447,6 +458,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -648,7 +660,7 @@ } ], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da" + "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01" ], "emails": [], "urls": [], @@ -841,7 +853,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -924,6 +936,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "notice_text": null, @@ -932,6 +946,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -942,6 +957,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -1143,7 +1159,7 @@ } ], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1184,7 +1200,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1225,7 +1241,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1266,7 +1282,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1307,7 +1323,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1348,7 +1364,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1389,7 +1405,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1430,7 +1446,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1471,7 +1487,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1512,7 +1528,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1553,7 +1569,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], @@ -1617,7 +1633,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [ @@ -1674,7 +1690,7 @@ "authors": [], "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" ], "emails": [], "urls": [], diff --git a/scanpipe/tests/data/asgiref/asgiref-3.3.0_toolkit_scan.json b/scanpipe/tests/data/asgiref/asgiref-3.3.0_toolkit_scan.json index 340431045..ce51bcaa9 100644 --- a/scanpipe/tests/data/asgiref/asgiref-3.3.0_toolkit_scan.json +++ b/scanpipe/tests/data/asgiref/asgiref-3.3.0_toolkit_scan.json @@ -2,7 +2,7 @@ "headers": [ { "tool_name": "scancode-toolkit", - "tool_version": "32.1.0", + "tool_version": "32.2.0", "options": { "--copyright": true, "--info": true, @@ -10,10 +10,10 @@ "--package": true }, "notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", - "start_timestamp": "2024-06-24T065846.335778", - "end_timestamp": "2024-06-24T065849.328641", - "output_format_version": "3.1.0", - "duration": 2.9929375648498535, + "start_timestamp": "2024-06-27T143714.174406", + "end_timestamp": "2024-06-27T143719.047147", + "output_format_version": "3.2.0", + "duration": 4.87275767326355, "message": null, "errors": [], "warnings": [], @@ -21,11 +21,11 @@ "system_environment": { "operating_system": "linux", "cpu_architecture": "64", - "platform": "Linux-6.6.31-linuxkit-x86_64-with-glibc2.36", - "platform_version": "#1 SMP Thu May 23 08:36:57 UTC 2024", - "python_version": "3.12.4 (main, Jun 13 2024, 05:37:23) [GCC 12.2.0]" + "platform": "Linux-5.15.0-112-generic-x86_64-with-glibc2.35", + "platform_version": "#122-Ubuntu SMP Thu May 23 07:48:21 UTC 2024", + "python_version": "3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]" }, - "spdx_license_list_version": "3.23", + "spdx_license_list_version": "3.24", "files_count": 15 } } @@ -130,6 +130,8 @@ "extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n", "notice_text": null, "source_packages": [], + "is_private": false, + "is_virtual": false, "extra_data": { "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions", @@ -138,7 +140,7 @@ "repository_homepage_url": "https://pypi.org/project/asgiref", "repository_download_url": "https://pypi.org/packages/source/a/asgiref/asgiref-3.3.0.tar.gz", "api_data_url": "https://pypi.org/pypi/asgiref/3.3.0/json", - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=cd8dacce-5ff3-48a2-bda0-ffd10fb7525a", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8d155673-d3d9-4b6f-882c-df1618a23c6a", "datafile_paths": [ "codebase/asgiref-3.3.0-py3-none-any.whl" ], @@ -246,6 +248,8 @@ "extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n", "notice_text": null, "source_packages": [], + "is_private": false, + "is_virtual": false, "extra_data": { "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions", @@ -254,7 +258,7 @@ "repository_homepage_url": "https://pypi.org/project/asgiref", "repository_download_url": "https://pypi.org/packages/source/a/asgiref/asgiref-3.3.0.tar.gz", "api_data_url": "https://pypi.org/pypi/asgiref/3.3.0/json", - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3", "datafile_paths": [ "codebase/asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA" ], @@ -272,10 +276,11 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, - "dependency_uid": "pkg:pypi/pytest?uuid=486f0f6e-4a22-4139-93fe-6b43106d6098", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=cd8dacce-5ff3-48a2-bda0-ffd10fb7525a", + "dependency_uid": "pkg:pypi/pytest?uuid=e80a74b5-6001-486d-ac15-f173a2fd5143", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8d155673-d3d9-4b6f-882c-df1618a23c6a", "datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl", "datasource_id": "pypi_wheel" }, @@ -286,10 +291,11 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=b466392e-ab98-4dc7-a07e-6fe98d334a80", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=cd8dacce-5ff3-48a2-bda0-ffd10fb7525a", + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=e68b22aa-e25c-43c5-b985-2f1ff4fd524b", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8d155673-d3d9-4b6f-882c-df1618a23c6a", "datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl", "datasource_id": "pypi_wheel" }, @@ -300,10 +306,11 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, - "dependency_uid": "pkg:pypi/pytest?uuid=c1d8418c-b3d1-4bdd-8be5-4d1c38dadb32", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd", + "dependency_uid": "pkg:pypi/pytest?uuid=e7398026-732a-4dc0-aa85-73676a43a504", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3", "datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA", "datasource_id": "pypi_wheel_metadata" }, @@ -314,10 +321,11 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=24b3b6ac-c5a4-4175-bdf8-19b9abb0eb0c", - "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd", + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=2ef16dc6-0efa-4000-a6a2-1c6e828fac4b", + "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3", "datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA", "datasource_id": "pypi_wheel_metadata" } @@ -455,7 +463,7 @@ "base_name": "asgiref-3.3.0-py3-none-any", "extension": ".whl", "size": 19948, - "date": "2024-06-24", + "date": "2024-06-27", "sha1": "c03f67211a311b13d1294ac8af7cb139ee34c4f9", "md5": "5bce1df6dedc53a41a9a6b40d7b1699e", "sha256": "a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e", @@ -696,6 +704,8 @@ "extra_data": {} } ], + "is_private": false, + "is_virtual": false, "extra_data": { "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions", @@ -709,6 +719,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -719,6 +730,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} } @@ -731,7 +743,7 @@ } ], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=cd8dacce-5ff3-48a2-bda0-ffd10fb7525a" + "pkg:pypi/asgiref@3.3.0?uuid=8d155673-d3d9-4b6f-882c-df1618a23c6a" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -838,7 +850,7 @@ "is_script": false, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -875,7 +887,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -912,7 +924,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -949,7 +961,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -986,7 +998,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -1023,7 +1035,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -1060,7 +1072,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -1097,7 +1109,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": "apache-2.0", "detected_license_expression_spdx": "Apache-2.0", @@ -1156,7 +1168,7 @@ "is_script": true, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -1228,7 +1240,7 @@ "is_script": false, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": "bsd-new", "detected_license_expression_spdx": "BSD-3-Clause", @@ -1525,6 +1537,8 @@ "extra_data": {} } ], + "is_private": false, + "is_virtual": false, "extra_data": { "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions", @@ -1538,6 +1552,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -1548,6 +1563,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} } @@ -1560,7 +1576,7 @@ } ], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": "bsd-new", "detected_license_expression_spdx": "BSD-3-Clause", @@ -1646,7 +1662,7 @@ "is_script": false, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -1683,7 +1699,7 @@ "is_script": false, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, @@ -1720,7 +1736,7 @@ "is_script": false, "package_data": [], "for_packages": [ - "pkg:pypi/asgiref@3.3.0?uuid=59e2f011-fbc0-4093-88c5-dcff5120d8bd" + "pkg:pypi/asgiref@3.3.0?uuid=d213d84b-a5e9-4cb3-9a8a-fd1146e156a3" ], "detected_license_expression": null, "detected_license_expression_spdx": null, diff --git a/scanpipe/tests/data/asgiref/asgiref-3.3.0_walk_test_fixtures.json b/scanpipe/tests/data/asgiref/asgiref-3.3.0_walk_test_fixtures.json index bfeac1ea4..d044a0103 100644 --- a/scanpipe/tests/data/asgiref/asgiref-3.3.0_walk_test_fixtures.json +++ b/scanpipe/tests/data/asgiref/asgiref-3.3.0_walk_test_fixtures.json @@ -1,13 +1,13 @@ [ { "model": "scanpipe.project", - "pk": "809b2669-0871-40e6-b932-50598310caac", + "pk": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "fields": { "extra_data": {}, - "created_date": "2024-06-24T06:58:40.386Z", + "created_date": "2024-06-27T14:35:14.839Z", "name": "asgiref", - "slug": "asgiref-809b2669", - "work_directory": "/tmp/tmp30w3f9yy/projects/asgiref-809b2669", + "slug": "asgiref-2f5f5927", + "work_directory": "/tmp/tmp4olqovm8/projects/asgiref-2f5f5927", "is_archived": false, "notes": "", "settings": {} @@ -15,17 +15,17 @@ }, { "model": "scanpipe.run", - "pk": "4d888ac2-92f8-4841-8b4e-11996fcd0fd6", + "pk": "41bd06fa-6e75-45e9-8476-5602d1c1433f", "fields": { "task_id": null, "task_start_date": null, "task_end_date": null, "task_exitcode": null, "task_output": "", - "log": "2024-06-24 08:58:40.39 Pipeline [scan_codebase] starting\n2024-06-24 08:58:40.39 Step [download_missing_inputs] starting\n2024-06-24 08:58:40.39 Step [download_missing_inputs] completed in 0 seconds\n2024-06-24 08:58:40.39 Step [copy_inputs_to_codebase_directory] starting\n2024-06-24 08:58:40.39 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2024-06-24 08:58:40.39 Step [extract_archives] starting\n2024-06-24 08:58:40.46 Step [extract_archives] completed in 0 seconds\n2024-06-24 08:58:40.46 Step [collect_and_create_codebase_resources] starting\n2024-06-24 08:58:40.55 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2024-06-24 08:58:40.55 Step [flag_empty_files] starting\n2024-06-24 08:58:40.56 Step [flag_empty_files] completed in 0 seconds\n2024-06-24 08:58:40.56 Step [flag_ignored_resources] starting\n2024-06-24 08:58:40.56 Step [flag_ignored_resources] completed in 0 seconds\n2024-06-24 08:58:40.56 Step [scan_for_application_packages] starting\n2024-06-24 08:58:40.58 Progress: 11% (2/18)\n2024-06-24 08:58:40.59 Progress: 22% (4/18)\n2024-06-24 08:58:40.59 Progress: 33% (6/18)\n2024-06-24 08:58:40.59 Progress: 44% (8/18)\n2024-06-24 08:58:40.60 Progress: 55% (10/18)\n2024-06-24 08:58:40.60 Progress: 66% (12/18)\n2024-06-24 08:58:40.60 Progress: 77% (14/18)\n2024-06-24 08:58:40.60 Progress: 88% (16/18)\n2024-06-24 08:58:42.99 Progress: 100% (18/18)\n2024-06-24 08:58:43.10 Step [scan_for_application_packages] completed in 3 seconds\n2024-06-24 08:58:43.10 Step [scan_for_files] starting\n2024-06-24 08:58:45.36 Progress: 12% (2/16) ETA: 17 seconds\n2024-06-24 08:58:45.36 Progress: 25% (4/16) ETA: 7 seconds\n2024-06-24 08:58:45.50 Progress: 37% (6/16) ETA: 4 seconds\n2024-06-24 08:58:45.56 Progress: 50% (8/16) ETA: 2 seconds\n2024-06-24 08:58:45.71 Progress: 62% (10/16) ETA: 2 seconds\n2024-06-24 08:58:45.91 Progress: 75% (12/16) ETA: 1 seconds\n2024-06-24 08:58:46.22 Progress: 87% (14/16)\n2024-06-24 08:58:46.30 Progress: 100% (16/16)\n2024-06-24 08:58:46.33 Step [scan_for_files] completed in 3 seconds\n2024-06-24 08:58:46.33 Pipeline completed in 6 seconds\n", - "project": "809b2669-0871-40e6-b932-50598310caac", + "log": "2024-06-27 14:35:14.84 Pipeline [scan_codebase] starting\n2024-06-27 14:35:14.84 Step [download_missing_inputs] starting\n2024-06-27 14:35:14.84 Step [download_missing_inputs] completed in 0 seconds\n2024-06-27 14:35:14.84 Step [copy_inputs_to_codebase_directory] starting\n2024-06-27 14:35:14.84 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2024-06-27 14:35:14.84 Step [extract_archives] starting\n2024-06-27 14:35:14.89 Step [extract_archives] completed in 0 seconds\n2024-06-27 14:35:14.89 Step [collect_and_create_codebase_resources] starting\n2024-06-27 14:35:14.96 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [flag_empty_files] starting\n2024-06-27 14:35:14.96 Step [flag_empty_files] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [flag_ignored_resources] starting\n2024-06-27 14:35:14.96 Step [flag_ignored_resources] completed in 0 seconds\n2024-06-27 14:35:14.96 Step [scan_for_application_packages] starting\n2024-06-27 14:35:14.98 Progress: 11% (2/18)\n2024-06-27 14:35:14.99 Progress: 22% (4/18)\n2024-06-27 14:35:14.99 Progress: 33% (6/18)\n2024-06-27 14:35:14.99 Progress: 44% (8/18)\n2024-06-27 14:35:14.99 Progress: 55% (10/18)\n2024-06-27 14:35:14.99 Progress: 66% (12/18)\n2024-06-27 14:35:14.99 Progress: 77% (14/18)\n2024-06-27 14:35:14.99 Progress: 88% (16/18)\n2024-06-27 14:35:17.74 Progress: 100% (18/18)\n2024-06-27 14:35:17.94 Step [scan_for_application_packages] completed in 3 seconds\n2024-06-27 14:35:17.94 Step [scan_for_files] starting\n2024-06-27 14:37:12.49 Progress: 12% (2/16) ETA: 840 seconds (14.0 minutes)\n2024-06-27 14:37:12.97 Progress: 25% (4/16) ETA: 345 seconds (5.8 minutes)\n2024-06-27 14:37:13.21 Progress: 37% (6/16) ETA: 196 seconds (3.3 minutes)\n2024-06-27 14:37:13.26 Progress: 50% (8/16) ETA: 115 seconds (1.9 minutes)\n2024-06-27 14:37:13.47 Progress: 62% (10/16) ETA: 71 seconds (1.2 minutes)\n2024-06-27 14:37:13.57 Progress: 75% (12/16) ETA: 39 seconds\n2024-06-27 14:37:13.64 Progress: 87% (14/16) ETA: 17 seconds\n2024-06-27 14:37:13.99 Progress: 100% (16/16)\n2024-06-27 14:37:14.17 Step [scan_for_files] completed in 116 seconds (1.9 minutes)\n2024-06-27 14:37:14.17 Pipeline completed in 119 seconds (2.0 minutes)\n", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "pipeline_name": "scan_codebase", - "created_date": "2024-06-24T06:58:40.390Z", + "created_date": "2024-06-27T14:35:14.841Z", "scancodeio_version": "", "description": "Scan a codebase for application packages, licenses, and copyrights.", "current_step": "", @@ -41,7 +41,7 @@ "sha256": "a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -117,6 +117,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "notice_text": null, @@ -125,6 +127,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -135,6 +138,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -346,7 +350,7 @@ "sha256": "", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -390,7 +394,7 @@ "sha256": "", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -434,7 +438,7 @@ "sha256": "", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -472,13 +476,136 @@ { "model": "scanpipe.codebaseresource", "pk": 5, + "fields": { + "md5": "680e61db4d95c8d9501b7a49fa2bf0b2", + "sha1": "612390bd0d0227c009f9c99b479878adf7ac2f23", + "sha256": "6e89108c2cf0c0446174188f76f60465ae1c1f14f83427807df40d52a27cb2c8", + "sha512": "", + "extra_data": {}, + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "detected_license_expression": "", + "detected_license_expression_spdx": "", + "license_detections": [], + "license_clues": [], + "percentage_of_license_text": null, + "copyrights": [], + "holders": [], + "authors": [], + "emails": [], + "urls": [], + "compliance_alert": "", + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "path": "asgiref-3.3.0.whl-extract/asgiref-3.3.0.dist-info/top_level.txt", + "rootfs_path": "", + "status": "scanned", + "size": 8, + "tag": "", + "type": "file", + "name": "top_level.txt", + "extension": ".txt", + "programming_language": "", + "mime_type": "text/plain", + "file_type": "ASCII text", + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "package_data": [] + } + }, + { + "model": "scanpipe.codebaseresource", + "pk": 6, + "fields": { + "md5": "f09eb47206614a4954c51db8a94840fa", + "sha1": "baf11129ce63c4eef654f39a360b31cfc7d1ac67", + "sha256": "b846415d1b514e9c1dff14a22deb906d794bc546ca6129f950a18cd091e2a669", + "sha512": "", + "extra_data": {}, + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "detected_license_expression": "bsd-new", + "detected_license_expression_spdx": "BSD-3-Clause", + "license_detections": [ + { + "matches": [ + { + "score": 100.0, + "matcher": "2-aho", + "end_line": 27, + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/bsd-new_683.RULE", + "from_file": null, + "start_line": 4, + "matched_text": "Redistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n\n 3. Neither the name of Django nor the names of its contributors may be used\n to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", + "match_coverage": 100.0, + "matched_length": 214, + "rule_relevance": 100, + "rule_identifier": "bsd-new_683.RULE", + "license_expression": "bsd-new", + "spdx_license_expression": "BSD-3-Clause" + } + ], + "identifier": "bsd_new-72cae3bc-4423-3a9e-be84-ee8bb5120a4d", + "license_expression": "bsd-new", + "license_expression_spdx": "BSD-3-Clause" + } + ], + "license_clues": [], + "percentage_of_license_text": 95.11, + "copyrights": [ + { + "end_line": 1, + "copyright": "Copyright (c) Django Software Foundation and individual contributors", + "start_line": 1 + } + ], + "holders": [ + { + "holder": "Django Software Foundation and individual contributors", + "end_line": 1, + "start_line": 1 + } + ], + "authors": [], + "emails": [], + "urls": [], + "compliance_alert": "", + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "path": "asgiref-3.3.0.whl-extract/asgiref-3.3.0.dist-info/LICENSE", + "rootfs_path": "", + "status": "scanned", + "size": 1552, + "tag": "", + "type": "file", + "name": "LICENSE", + "extension": "", + "programming_language": "", + "mime_type": "text/plain", + "file_type": "ASCII text", + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "package_data": [] + } + }, + { + "model": "scanpipe.codebaseresource", + "pk": 7, "fields": { "md5": "4b50d67ff7994afcad22c6ef154cf052", "sha1": "53d0f6e1cbf6a3c31fb0aa3089b2ca98ad95fc49", "sha256": "70f98f4eb9f6068b192b5464fcdf69e29a8ff09962bfce84bbb052baeee44f33", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -554,6 +681,8 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "notice_text": null, @@ -562,6 +691,7 @@ { "purl": "pkg:pypi/pytest", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -572,6 +702,7 @@ { "purl": "pkg:pypi/pytest-asyncio", "scope": "tests", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -776,93 +907,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 6, - "fields": { - "md5": "f09eb47206614a4954c51db8a94840fa", - "sha1": "baf11129ce63c4eef654f39a360b31cfc7d1ac67", - "sha256": "b846415d1b514e9c1dff14a22deb906d794bc546ca6129f950a18cd091e2a669", - "sha512": "", - "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", - "detected_license_expression": "bsd-new", - "detected_license_expression_spdx": "BSD-3-Clause", - "license_detections": [ - { - "matches": [ - { - "score": 100.0, - "matcher": "2-aho", - "end_line": 27, - "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/bsd-new_683.RULE", - "from_file": null, - "start_line": 4, - "matched_text": "Redistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n 1. Redistributions of source code must retain the above copyright notice,\n this list of conditions and the following disclaimer.\n\n 2. Redistributions in binary form must reproduce the above copyright\n notice, this list of conditions and the following disclaimer in the\n documentation and/or other materials provided with the distribution.\n\n 3. Neither the name of Django nor the names of its contributors may be used\n to endorse or promote products derived from this software without\n specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", - "match_coverage": 100.0, - "matched_length": 214, - "rule_relevance": 100, - "rule_identifier": "bsd-new_683.RULE", - "license_expression": "bsd-new", - "spdx_license_expression": "BSD-3-Clause" - } - ], - "identifier": "bsd_new-72cae3bc-4423-3a9e-be84-ee8bb5120a4d", - "license_expression": "bsd-new", - "license_expression_spdx": "BSD-3-Clause" - } - ], - "license_clues": [], - "percentage_of_license_text": 95.11, - "copyrights": [ - { - "end_line": 1, - "copyright": "Copyright (c) Django Software Foundation and individual contributors", - "start_line": 1 - } - ], - "holders": [ - { - "holder": "Django Software Foundation and individual contributors", - "end_line": 1, - "start_line": 1 - } - ], - "authors": [], - "emails": [], - "urls": [], - "compliance_alert": "", - "is_legal": false, - "is_manifest": false, - "is_readme": false, - "is_top_level": false, - "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref-3.3.0.dist-info/LICENSE", - "rootfs_path": "", - "status": "scanned", - "size": 1552, - "tag": "", - "type": "file", - "name": "LICENSE", - "extension": "", - "programming_language": "", - "mime_type": "text/plain", - "file_type": "ASCII text", - "is_binary": false, - "is_text": true, - "is_archive": false, - "is_media": false, - "package_data": [] - } - }, - { - "model": "scanpipe.codebaseresource", - "pk": 7, + "pk": 8, "fields": { - "md5": "680e61db4d95c8d9501b7a49fa2bf0b2", - "sha1": "612390bd0d0227c009f9c99b479878adf7ac2f23", - "sha256": "6e89108c2cf0c0446174188f76f60465ae1c1f14f83427807df40d52a27cb2c8", + "md5": "5ccc7519eb42f1dfceee6e7d685f1ff5", + "sha1": "ddd91bc89b15fc5c66e0fa259392955c74ba041f", + "sha256": "11546323af45e6a5639bf620a9c4d73e74c0bf705f494af4595007b923f75e8a", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -879,14 +931,14 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref-3.3.0.dist-info/top_level.txt", + "path": "asgiref-3.3.0.whl-extract/asgiref-3.3.0.dist-info/WHEEL", "rootfs_path": "", "status": "scanned", - "size": 8, + "size": 92, "tag": "", "type": "file", - "name": "top_level.txt", - "extension": ".txt", + "name": "WHEEL", + "extension": "", "programming_language": "", "mime_type": "text/plain", "file_type": "ASCII text", @@ -899,14 +951,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 8, + "pk": 9, "fields": { "md5": "38e56802a5adcafeae35efc6e3d218ba", "sha1": "5854ecf1ad649848d7cda8096d09ac258c888208", "sha256": "2c1983592aa38f0bfb0afacc73ddc5b46ce10e8e89ceaa9fed1e5fc6361b608d", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -943,14 +995,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 9, + "pk": 10, "fields": { - "md5": "5ccc7519eb42f1dfceee6e7d685f1ff5", - "sha1": "ddd91bc89b15fc5c66e0fa259392955c74ba041f", - "sha256": "11546323af45e6a5639bf620a9c4d73e74c0bf705f494af4595007b923f75e8a", + "md5": "4910b756f4e611055140e80f757d9325", + "sha1": "91bc786d907bf3ca8b8e6277063107975780f9ca", + "sha256": "30f49b9094bff904a42caeec32515715fe625a56dc48bd7c0e3d9988c0ad4bd7", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -967,15 +1019,15 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref-3.3.0.dist-info/WHEEL", + "path": "asgiref-3.3.0.whl-extract/asgiref/__init__.py", "rootfs_path": "", "status": "scanned", - "size": 92, + "size": 22, "tag": "", "type": "file", - "name": "WHEEL", - "extension": "", - "programming_language": "", + "name": "__init__.py", + "extension": ".py", + "programming_language": "Python", "mime_type": "text/plain", "file_type": "ASCII text", "is_binary": false, @@ -987,14 +1039,14 @@ }, { "model": "scanpipe.codebaseresource", - "pk": 10, + "pk": 11, "fields": { "md5": "44ec43af7ee367c7d6a5808d37133144", "sha1": "702381ba6ecb30bbfdcaf0d466a25f470dd9938b", "sha256": "fa4651a3b79201a4dc44a4096cd49ec8f427e912ea0ee05c666357b413a8afe7", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1029,60 +1081,16 @@ "package_data": [] } }, - { - "model": "scanpipe.codebaseresource", - "pk": 11, - "fields": { - "md5": "aff31de5fa753643adacf0311aa553f4", - "sha1": "534de2315197b14d0571edc5ed3b3b8ceade0d24", - "sha256": "ddbc8d455eceb68fc583c67e7c4ad0277c867fb39095c51ec5b37f70342e8334", - "sha512": "", - "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", - "detected_license_expression": "", - "detected_license_expression_spdx": "", - "license_detections": [], - "license_clues": [], - "percentage_of_license_text": null, - "copyrights": [], - "holders": [], - "authors": [], - "emails": [], - "urls": [], - "compliance_alert": "", - "is_legal": false, - "is_manifest": false, - "is_readme": false, - "is_top_level": false, - "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/testing.py", - "rootfs_path": "", - "status": "scanned", - "size": 3119, - "tag": "", - "type": "file", - "name": "testing.py", - "extension": ".py", - "programming_language": "Python", - "mime_type": "text/x-script.python", - "file_type": "Python script, ASCII text executable", - "is_binary": false, - "is_text": true, - "is_archive": false, - "is_media": false, - "package_data": [] - } - }, { "model": "scanpipe.codebaseresource", "pk": 12, "fields": { - "md5": "5b7619584de19d8f1a00fb5a43349153", - "sha1": "ebe97b4c2689537e9387dd8dac353c3e010f8f02", - "sha256": "885267fee0fea687875a02ceb929ca095312d47aaa57e20e4ce382f397caaf4d", + "md5": "e4103a2fcd6a3f23a036307c978271d7", + "sha1": "0de5075d1ce4a1a17d70ad6ee523e3d947074899", + "sha256": "ee0fcf4a8e6fa9df8a4643bb48e82892d496afce44b6c8b8aea2721755545e1c", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1099,13 +1107,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/server.py", + "path": "asgiref-3.3.0.whl-extract/asgiref/local.py", "rootfs_path": "", "status": "scanned", - "size": 5915, + "size": 4849, "tag": "", "type": "file", - "name": "server.py", + "name": "local.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1121,12 +1129,12 @@ "model": "scanpipe.codebaseresource", "pk": 13, "fields": { - "md5": "e4103a2fcd6a3f23a036307c978271d7", - "sha1": "0de5075d1ce4a1a17d70ad6ee523e3d947074899", - "sha256": "ee0fcf4a8e6fa9df8a4643bb48e82892d496afce44b6c8b8aea2721755545e1c", + "md5": "5231077fd0628314246fcba7817b561e", + "sha1": "9c74e64e9a71903bb227907ea1806eac77e52434", + "sha256": "3151f66c476208c3154cb6c4fb557a2a253bab82f0ab33fb3c8b9f7976be9e33", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1143,13 +1151,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/local.py", + "path": "asgiref-3.3.0.whl-extract/asgiref/compatibility.py", "rootfs_path": "", "status": "scanned", - "size": 4849, + "size": 1598, "tag": "", "type": "file", - "name": "local.py", + "name": "compatibility.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1165,12 +1173,12 @@ "model": "scanpipe.codebaseresource", "pk": 14, "fields": { - "md5": "5231077fd0628314246fcba7817b561e", - "sha1": "9c74e64e9a71903bb227907ea1806eac77e52434", - "sha256": "3151f66c476208c3154cb6c4fb557a2a253bab82f0ab33fb3c8b9f7976be9e33", + "md5": "b4c45f37055d88dd11b15eb4de51b074", + "sha1": "aacf7e5e2e5ba78ccfb67fa10e9e6b22c3935c9b", + "sha256": "ddd445b778c097fc75c2bf69ad964cbadd3bd6999d1dd2306d39d401855e8e3e", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1187,13 +1195,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/compatibility.py", + "path": "asgiref-3.3.0.whl-extract/asgiref/current_thread_executor.py", "rootfs_path": "", "status": "scanned", - "size": 1598, + "size": 2974, "tag": "", "type": "file", - "name": "compatibility.py", + "name": "current_thread_executor.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1209,12 +1217,12 @@ "model": "scanpipe.codebaseresource", "pk": 15, "fields": { - "md5": "b4c45f37055d88dd11b15eb4de51b074", - "sha1": "aacf7e5e2e5ba78ccfb67fa10e9e6b22c3935c9b", - "sha256": "ddd445b778c097fc75c2bf69ad964cbadd3bd6999d1dd2306d39d401855e8e3e", + "md5": "aff31de5fa753643adacf0311aa553f4", + "sha1": "534de2315197b14d0571edc5ed3b3b8ceade0d24", + "sha256": "ddbc8d455eceb68fc583c67e7c4ad0277c867fb39095c51ec5b37f70342e8334", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1231,13 +1239,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/current_thread_executor.py", + "path": "asgiref-3.3.0.whl-extract/asgiref/testing.py", "rootfs_path": "", "status": "scanned", - "size": 2974, + "size": 3119, "tag": "", "type": "file", - "name": "current_thread_executor.py", + "name": "testing.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1258,7 +1266,7 @@ "sha256": "126c3e3a8a75a517d2739612304607804cf5f34da63fa25d03a6f11f7edb6f2f", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "apache-2.0", "detected_license_expression_spdx": "Apache-2.0", "license_detections": [ @@ -1336,12 +1344,12 @@ "model": "scanpipe.codebaseresource", "pk": 17, "fields": { - "md5": "4910b756f4e611055140e80f757d9325", - "sha1": "91bc786d907bf3ca8b8e6277063107975780f9ca", - "sha256": "30f49b9094bff904a42caeec32515715fe625a56dc48bd7c0e3d9988c0ad4bd7", + "md5": "4eed1361d0e454149f95fca85c84f33f", + "sha1": "1f06eb4dd6d38b1a3e2a9b9e751744b303c37e0d", + "sha256": "f8bd1ea3fb8afddabb10f8efd66796d41446cad51168ef4d3c44b19c973d0ad0", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1358,17 +1366,17 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/__init__.py", + "path": "asgiref-3.3.0.whl-extract/asgiref/wsgi.py", "rootfs_path": "", "status": "scanned", - "size": 22, + "size": 6575, "tag": "", "type": "file", - "name": "__init__.py", + "name": "wsgi.py", "extension": ".py", "programming_language": "Python", - "mime_type": "text/plain", - "file_type": "ASCII text", + "mime_type": "text/x-script.python", + "file_type": "Python script, ASCII text executable", "is_binary": false, "is_text": true, "is_archive": false, @@ -1380,12 +1388,12 @@ "model": "scanpipe.codebaseresource", "pk": 18, "fields": { - "md5": "4eed1361d0e454149f95fca85c84f33f", - "sha1": "1f06eb4dd6d38b1a3e2a9b9e751744b303c37e0d", - "sha256": "f8bd1ea3fb8afddabb10f8efd66796d41446cad51168ef4d3c44b19c973d0ad0", + "md5": "5b7619584de19d8f1a00fb5a43349153", + "sha1": "ebe97b4c2689537e9387dd8dac353c3e010f8f02", + "sha256": "885267fee0fea687875a02ceb929ca095312d47aaa57e20e4ce382f397caaf4d", "sha512": "", "extra_data": {}, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "detected_license_expression": "", "detected_license_expression_spdx": "", "license_detections": [], @@ -1402,13 +1410,13 @@ "is_readme": false, "is_top_level": false, "is_key_file": false, - "path": "asgiref-3.3.0.whl-extract/asgiref/wsgi.py", + "path": "asgiref-3.3.0.whl-extract/asgiref/server.py", "rootfs_path": "", "status": "scanned", - "size": 6575, + "size": 5915, "tag": "", "type": "file", - "name": "wsgi.py", + "name": "server.py", "extension": ".py", "programming_language": "Python", "mime_type": "text/x-script.python", @@ -1439,7 +1447,7 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "compliance_alert": "", "affected_by_vulnerabilities": [], "filename": "", @@ -1510,6 +1518,8 @@ "other_license_detections": [], "extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n", "notice_text": "", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel" ], @@ -1526,10 +1536,10 @@ "email": "foundation@djangoproject.com" } ], - "uuid": "7549ef42-cbba-4fd9-a528-9055fcb66b8a", + "uuid": "75b6bb66-de86-4a35-a780-bc1f635f11f4", "missing_resources": [], "modified_resources": [], - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01", "keywords": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -1570,7 +1580,7 @@ "Documentation": "https://asgi.readthedocs.io/", "Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions" }, - "project": "809b2669-0871-40e6-b932-50598310caac", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "compliance_alert": "", "affected_by_vulnerabilities": [], "filename": "", @@ -1641,6 +1651,8 @@ "other_license_detections": [], "extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n", "notice_text": "", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel_metadata" ], @@ -1657,10 +1669,10 @@ "email": "foundation@djangoproject.com" } ], - "uuid": "8fc54317-6054-4eb7-b189-f1b2822d3fa6", + "uuid": "d10827fc-bcd1-4c10-ad6c-972dd4defa9c", "missing_resources": [], "modified_resources": [], - "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", + "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", "keywords": [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment", @@ -1679,19 +1691,19 @@ "tag": "", "codebase_resources": [ 6, - 5, - 8, 7, 9, - 14, - 15, - 17, + 5, + 8, 13, - 12, + 14, 10, + 12, + 18, 11, + 15, 16, - 18 + 17 ] } }, @@ -1706,8 +1718,8 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest?uuid=5143b8e1-badc-4937-90da-d3d124ecdfd4", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest?uuid=0928ca6e-d50e-439a-847d-ecb1366a8f2a", "for_package": 1, "resolved_to_package": null, "datafile_resource": 1, @@ -1716,7 +1728,8 @@ "datasource_id": "pypi_wheel", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } }, { @@ -1730,8 +1743,8 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=ba2634df-8cb1-48cc-875a-bc511888f27a", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=ccd9eb22-778d-4bd4-af59-8b63e4163b22", "for_package": 1, "resolved_to_package": null, "datafile_resource": 1, @@ -1740,7 +1753,8 @@ "datasource_id": "pypi_wheel", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } }, { @@ -1754,17 +1768,18 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest?uuid=f0c50c37-e20a-416d-9395-9238c1c133c9", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest?uuid=94372d19-8ab8-4b16-b6a7-72478e0b4cc4", "for_package": 2, "resolved_to_package": null, - "datafile_resource": 5, + "datafile_resource": 7, "extracted_requirement": "pytest; extra == \"tests\"", "scope": "tests", "datasource_id": "pypi_wheel_metadata", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } }, { @@ -1778,17 +1793,18 @@ "qualifiers": "", "subpath": "", "affected_by_vulnerabilities": [], - "project": "809b2669-0871-40e6-b932-50598310caac", - "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=baae1579-e28e-40d7-9900-29af699fe7a7", + "project": "2f5f5927-2cad-4ecb-9043-fda5337bd501", + "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=e751ec65-9351-4949-ae8f-5bc1a9efa336", "for_package": 2, "resolved_to_package": null, - "datafile_resource": 5, + "datafile_resource": 7, "extracted_requirement": "pytest-asyncio; extra == \"tests\"", "scope": "tests", "datasource_id": "pypi_wheel_metadata", "is_runtime": true, "is_optional": true, - "is_resolved": false + "is_resolved": false, + "is_direct": true } } ] \ No newline at end of file diff --git a/scanpipe/tests/data/cyclonedx/asgiref-3.3.0.cdx.json b/scanpipe/tests/data/cyclonedx/asgiref-3.3.0.cdx.json index ed60f0d3e..5446ae93c 100644 --- a/scanpipe/tests/data/cyclonedx/asgiref-3.3.0.cdx.json +++ b/scanpipe/tests/data/cyclonedx/asgiref-3.3.0.cdx.json @@ -6,7 +6,7 @@ "version": 1, "metadata": { "component": { - "bom-ref": "809b2669-0871-40e6-b932-50598310caac", + "bom-ref": "2f5f5927-2cad-4ecb-9043-fda5337bd501", "name": "asgiref", "type": "library" }, @@ -26,7 +26,7 @@ }, "components": [ { - "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da", + "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01", "copyright": "", "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "externalReferences": [ @@ -64,7 +64,7 @@ "version": "3.3.0" }, { - "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", + "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", "copyright": "", "description": "ASGI specs, helper code, and adapters\nasgiref\n=======\n\n.. image:: https://api.travis-ci.org/django/asgiref.svg\n :target: https://travis-ci.org/django/asgiref\n\n.. image:: https://img.shields.io/pypi/v/asgiref.svg\n :target: https://pypi.python.org/pypi/asgiref\n\nASGI is a standard for Python asynchronous web apps and servers to communicate\nwith each other, and positioned as an asynchronous successor to WSGI. You can\nread more at https://asgi.readthedocs.io/en/latest/\n\nThis package includes ASGI base libraries, such as:\n\n* Sync-to-async and async-to-sync function wrappers, ``asgiref.sync``\n* Server base classes, ``asgiref.server``\n* A WSGI-to-ASGI adapter, in ``asgiref.wsgi``\n\n\nFunction wrappers\n-----------------\n\nThese allow you to wrap or decorate async or sync functions to call them from\nthe other style (so you can call async functions from a synchronous thread,\nor vice-versa).\n\nIn particular:\n\n* AsyncToSync lets a synchronous subthread stop and wait while the async\n function is called on the main thread's event loop, and then control is\n returned to the thread when the async function is finished.\n\n* SyncToAsync lets async code call a synchronous function, which is run in\n a threadpool and control returned to the async coroutine when the synchronous\n function completes.\n\nThe idea is to make it easier to call synchronous APIs from async code and\nasynchronous APIs from synchronous code so it's easier to transition code from\none style to the other. In the case of Channels, we wrap the (synchronous)\nDjango view system with SyncToAsync to allow it to run inside the (asynchronous)\nASGI server.\n\nNote that exactly what threads things run in is very specific, and aimed to\nkeep maximum compatibility with old synchronous code. See\n\"Synchronous code & Threads\" below for a full explanation. By default,\n``sync_to_async`` will run all synchronous code in the program in the same\nthread for safety reasons; you can disable this for more performance with\n``@sync_to_async(thread_sensitive=False)``, but make sure that your code does\nnot rely on anything bound to threads (like database connections) when you do.\n\n\nThreadlocal replacement\n-----------------------\n\nThis is a drop-in replacement for ``threading.local`` that works with both\nthreads and asyncio Tasks. Even better, it will proxy values through from a\ntask-local context to a thread-local context when you use ``sync_to_async``\nto run things in a threadpool, and vice-versa for ``async_to_sync``.\n\nIf you instead want true thread- and task-safety, you can set\n``thread_critical`` on the Local object to ensure this instead.\n\n\nServer base classes\n-------------------\n\nIncludes a ``StatelessServer`` class which provides all the hard work of\nwriting a stateless server (as in, does not handle direct incoming sockets\nbut instead consumes external streams or sockets to work out what is happening).\n\nAn example of such a server would be a chatbot server that connects out to\na central chat server and provides a \"connection scope\" per user chatting to\nit. There's only one actual connection, but the server has to separate things\ninto several scopes for easier writing of the code.\n\nYou can see an example of this being used in `frequensgi `_.\n\n\nWSGI-to-ASGI adapter\n--------------------\n\nAllows you to wrap a WSGI application so it appears as a valid ASGI application.\n\nSimply wrap it around your WSGI application like so::\n\n asgi_application = WsgiToAsgi(wsgi_application)\n\nThe WSGI application will be run in a synchronous threadpool, and the wrapped\nASGI application will be one that accepts ``http`` class messages.\n\nPlease note that not all extended features of WSGI may be supported (such as\nfile handles for incoming POST bodies).\n\n\nDependencies\n------------\n\n``asgiref`` requires Python 3.5 or higher.\n\n\nContributing\n------------\n\nPlease refer to the\n`main Channels contributing docs `_.\n\n\nTesting\n'''''''\n\nTo run tests, make sure you have installed the ``tests`` extra with the package::\n\n cd asgiref/\n pip install -e .[tests]\n pytest\n\n\nBuilding the documentation\n''''''''''''''''''''''''''\n\nThe documentation uses `Sphinx `_::\n\n cd asgiref/docs/\n pip install sphinx\n\nTo build the docs, you can use the default tools::\n\n sphinx-build -b html . _build/html # or `make html`, if you've got make set up\n cd _build/html\n python -m http.server\n\n...or you can use ``sphinx-autobuild`` to run a server and rebuild/reload\nyour documentation changes automatically::\n\n pip install sphinx-autobuild\n sphinx-autobuild . _build/html\n\n\nImplementation Details\n----------------------\n\nSynchronous code & threads\n''''''''''''''''''''''''''\n\nThe ``asgiref.sync`` module provides two wrappers that let you go between\nasynchronous and synchronous code at will, while taking care of the rough edges\nfor you.\n\nUnfortunately, the rough edges are numerous, and the code has to work especially\nhard to keep things in the same thread as much as possible. Notably, the\nrestrictions we are working with are:\n\n* All synchronous code called through ``SyncToAsync`` and marked with\n ``thread_sensitive`` should run in the same thread as each other (and if the\n outer layer of the program is synchronous, the main thread)\n\n* If a thread already has a running async loop, ``AsyncToSync`` can't run things\n on that loop if it's blocked on synchronous code that is above you in the\n call stack.\n\nThe first compromise you get to might be that ``thread_sensitive`` code should\njust run in the same thread and not spawn in a sub-thread, fulfilling the first\nrestriction, but that immediately runs you into the second restriction.\n\nThe only real solution is to essentially have a variant of ThreadPoolExecutor\nthat executes any ``thread_sensitive`` code on the outermost synchronous\nthread - either the main thread, or a single spawned subthread.\n\nThis means you now have two basic states:\n\n* If the outermost layer of your program is synchronous, then all async code\n run through ``AsyncToSync`` will run in a per-call event loop in arbitary\n sub-threads, while all ``thread_sensitive`` code will run in the main thread.\n\n* If the outermost layer of your program is asynchronous, then all async code\n runs on the main thread's event loop, and all ``thread_sensitive`` synchronous\n code will run in a single shared sub-thread.\n\nCruicially, this means that in both cases there is a thread which is a shared\nresource that all ``thread_sensitive`` code must run on, and there is a chance\nthat this thread is currently blocked on its own ``AsyncToSync`` call. Thus,\n``AsyncToSync`` needs to act as an executor for thread code while it's blocking.\n\nThe ``CurrentThreadExecutor`` class provides this functionality; rather than\nsimply waiting on a Future, you can call its ``run_until_future`` method and\nit will run submitted code until that Future is done. This means that code\ninside the call can then run code on your thread.\n\n\nMaintenance and Security\n------------------------\n\nTo report security issues, please contact security@djangoproject.com. For GPG\nsignatures and more security process information, see\nhttps://docs.djangoproject.com/en/dev/internals/security/.\n\nTo report bugs or request new features, please open a new GitHub issue.\n\nThis repository is part of the Channels project. For the shepherd and maintenance team, please see the\n`main Channels readme `_.", "evidence": { @@ -112,23 +112,23 @@ "dependencies": [ { "dependsOn": [ - "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e", - "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da" + "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a", + "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01" ], - "ref": "809b2669-0871-40e6-b932-50598310caac" + "ref": "2f5f5927-2cad-4ecb-9043-fda5337bd501" }, { - "ref": "pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "ref": "pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" }, { - "ref": "pkg:pypi/asgiref@3.3.0?uuid=fd86b29f-e974-4880-9cc5-c8191a8241da" + "ref": "pkg:pypi/asgiref@3.3.0?uuid=8203628e-74ff-42c0-b96d-cdd2c56a0f01" } ], "vulnerabilities": [ { "affects": [ { - "ref": "urn:cdx:pkg:pypi/asgiref@3.3.0?uuid=abf2b1fe-4a9d-46fa-bfd9-550fd278dc5e" + "ref": "urn:cdx:pkg:pypi/asgiref@3.3.0?uuid=6dc8a3e1-c9d2-41a0-aa6c-99999115001a" } ], "bom-ref": "BomRef", diff --git a/scanpipe/tests/data/d2d/about_files/expected.json b/scanpipe/tests/data/d2d/about_files/expected.json index 8d839666d..2037990be 100644 --- a/scanpipe/tests/data/d2d/about_files/expected.json +++ b/scanpipe/tests/data/d2d/about_files/expected.json @@ -71,6 +71,8 @@ "notice_text": "", "source_packages": [], "extra_data": {}, + "is_private": false, + "is_virtual": false, "package_uid": "pkg:local-files/analysis-90cb6382/90cb6382-431c-4187-be76-d4f1a2199a2f?uuid=fixed-uid-done-for-testing-5642512d1758", "datasource_ids": [], "datafile_paths": [], @@ -122,6 +124,8 @@ "*flume-ng-node-*.jar-extract/org/apache/flume/node/ConfigurationProvider.class" ] }, + "is_private": false, + "is_virtual": false, "package_uid": "pkg:maven/log4j/log4j@1.2.13?uuid=fixed-uid-done-for-testing-5642512d1758", "datasource_ids": [], "datafile_paths": [], diff --git a/scanpipe/tests/data/d2d/flume-ng-node-d2d.json b/scanpipe/tests/data/d2d/flume-ng-node-d2d.json index 34a7055b4..efa03f203 100644 --- a/scanpipe/tests/data/d2d/flume-ng-node-d2d.json +++ b/scanpipe/tests/data/d2d/flume-ng-node-d2d.json @@ -71,6 +71,8 @@ "notice_text": "", "source_packages": [], "extra_data": {}, + "is_private": false, + "is_virtual": false, "package_uid": "pkg:local-files/analysis-b74fe5df/b74fe5df-e965-415e-ba65-f38421a0695d?uuid=fixed-uid-done-for-testing-5642512d1758", "datasource_ids": [], "datafile_paths": [], diff --git a/scanpipe/tests/data/dependencies/resolved_dependencies.zip b/scanpipe/tests/data/dependencies/resolved_dependencies.zip new file mode 100644 index 0000000000000000000000000000000000000000..9b6ab79671888fa1c54db19b36aad8aefc667299 GIT binary patch literal 1577 zcmWIWW@Zs#-~d9e*uxPFQ1FY9fq{oXfuSHVIXf{uRWGYJKQA-Jjd2e){7T>ReNs!PP-&o;7I=5 z;S9uxxg;?2k93Gj>Yf)YU0SXpvJO$Tzk(O#KALHF@?}f+ zT+vMl_0?;|55E4kjH%wo-5~wmiET2cO>I{z@A=v`O{K)G$@mk?>dT+=*2kqTyj;9? zoB1Ezt8p#G6P6w-^A{4!Um4I8wN^|ddls9Lt*p_k=j-1`Oj7-_SdByV?5B$PTwlFb z7Ps!-aDSSK(5u&rES}iUI@`1E(Vi3ME?xaGVU5bB`=;|{XFuA{vhma8uB%T~c_yxM zZIOsLY?a2yE5cBk=CDM&ib0WsckTeoq}^BE`rm%S>#b2cY%dv{TXel# zW2I0<6Pv1U&_2eum%AVTk~w;6F;l96t06~#^QsK4Ai?Cug$Ek~EV(qV_As;huzIqqTIxBtfY0A4VzFQ)! zjOJBLUb4`l>%Ng$p1S7YyD9E>l8!oFl?#b`A23g#rs&sw9=S4^L&;+KW}<8i8u9Up zEY6l(Auf^+Pp__O2x$`tY2XR6 zv%qrF?&g0--}zqIXMJ~91gpu*@}%AJ+ia%n?h9TOIK}Vn&Z*CqZ+y7>?a#zd@|8dL zDE50#?X6mx_dRgJ`kiem3p_ul74dv@7b)stP~_utRcH}#Rtb*1#?$*MLX}6#r`zPI{yc{{bsE{*b0dp>co+KQ z1j*n2S8-&<{l^D)=>Dp@|M}&AZO@dFp;gSeT&bCVgT7B+pke+h+H!5z#~m-%O4NUUWWBXwMj=c8 z&Q(X(ibgQHEm$p)5IS)pqlA9ry7s^mKQgx-Fz9eA)VQp_?nm|B+vl&J&Rl(e@0q}y zDeBvQr&ngN$iH|UbKm&L;waV4alhF?ncU@tB1a#vU<7650B=Sn5oSagi(CMJ%2*iK u(g\n2009 Philipp Kern \n2011 Michael Shuler \nVarious Debian Contributors\nMozilla Contributors", "namespace": null, "extra_data": {}, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "notice_text": null, "api_data_url": null, diff --git a/scanpipe/tests/data/manifests/openpdf-parent-1.3.11_scan_package.json b/scanpipe/tests/data/manifests/openpdf-parent-1.3.11_scan_package.json index 224e7c545..5582c1598 100644 --- a/scanpipe/tests/data/manifests/openpdf-parent-1.3.11_scan_package.json +++ b/scanpipe/tests/data/manifests/openpdf-parent-1.3.11_scan_package.json @@ -14,12 +14,12 @@ "--summary": true }, "notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", - "output_format_version": "3.1.0", + "output_format_version": "3.2.0", "message": null, "errors": [], "warnings": [], "extra_data": { - "spdx_license_list_version": "3.23", + "spdx_license_list_version": "3.24", "files_count": 1 } } @@ -116,6 +116,8 @@ "source_packages": [ "pkg:maven/com.github.librepdf/openpdf-parent@1.3.11?classifier=sources" ], + "is_private": false, + "is_virtual": false, "extra_data": {}, "repository_homepage_url": "https://repo1.maven.org/maven2/com/github/librepdf/openpdf-parent/1.3.11/", "repository_download_url": "https://repo1.maven.org/maven2/com/github/librepdf/openpdf-parent/1.3.11/openpdf-parent-1.3.11.jar", @@ -138,6 +140,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.assertj/assertj-core@3.12.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -152,6 +155,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.junit.jupiter/junit-jupiter-api@5.5.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -166,6 +170,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.junit.jupiter/junit-jupiter-params@5.5.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -180,6 +185,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.junit.jupiter/junit-jupiter-engine@5.5.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -194,6 +200,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.mockito/mockito-core@2.25.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -208,6 +215,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.hamcrest/hamcrest-library@2.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -222,6 +230,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.hamcrest/hamcrest-core@2.1?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -236,6 +245,7 @@ "is_runtime": false, "is_optional": false, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.bouncycastle/bcprov-jdk15on@1.63?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -250,6 +260,7 @@ "is_runtime": false, "is_optional": false, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/org.bouncycastle/bcpkix-jdk15on@1.63?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -264,6 +275,7 @@ "is_runtime": false, "is_optional": false, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:maven/com.github.spotbugs/spotbugs@3.1.12?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -440,6 +452,8 @@ "pkg:maven/com.github.librepdf/openpdf-parent@1.3.11?classifier=sources" ], "file_references": [], + "is_private": false, + "is_virtual": false, "extra_data": {}, "dependencies": [ { @@ -449,6 +463,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -459,6 +474,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -469,6 +485,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -479,6 +496,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -489,6 +507,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -499,6 +518,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -509,6 +529,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -519,6 +540,7 @@ "is_runtime": false, "is_optional": false, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -529,6 +551,7 @@ "is_runtime": false, "is_optional": false, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} }, @@ -539,6 +562,7 @@ "is_runtime": false, "is_optional": false, "is_resolved": true, + "is_direct": true, "resolved_package": {}, "extra_data": {} } diff --git a/scanpipe/tests/data/resolved_dependencies_inspect_packages.json b/scanpipe/tests/data/resolved_dependencies_inspect_packages.json new file mode 100644 index 000000000..bcb708fd6 --- /dev/null +++ b/scanpipe/tests/data/resolved_dependencies_inspect_packages.json @@ -0,0 +1,1143 @@ +{ + "headers": [ + { + "tool_name": "scanpipe", + "notice": "Generated with ScanCode.io and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied.\nNo content created from ScanCode.io should be considered or used as legal advice.\nConsult an Attorney for any legal advice.\nScanCode.io is a free software code scanning tool from nexB Inc. and others\nlicensed under the Apache License version 2.0.\nScanCode is a trademark of nexB Inc.\nVisit https://github.com/nexB/scancode.io for support and download.\n", + "input_sources": [ + { + "filename": "resolved_dependencies.zip", + "is_uploaded": false, + "is_file": true, + "exists": true + } + ], + "runs": [ + { + "pipeline_name": "inspect_packages", + "status": "not_started", + "scancodeio_version": "", + "task_id": null, + "task_start_date": null, + "task_end_date": null, + "task_exitcode": null, + "task_output": "", + "execution_time": null + } + ], + "extra_data": {} + } + ], + "packages": [ + { + "purl": "pkg:npm/athena-express@6.0.4", + "type": "npm", + "namespace": "", + "name": "athena-express", + "version": "6.0.4", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.yarnpkg.com/athena-express/-/athena-express-6.0.4.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "https://www.npmjs.com/package/athena-express", + "repository_download_url": "https://registry.npmjs.org/athena-express/-/athena-express-6.0.4.tgz", + "api_data_url": "https://registry.npmjs.org/athena-express/6.0.4", + "md5": "", + "sha1": "bb457dcc967686faea2138f934828a331b98c8f6", + "sha256": "", + "sha512": "02d0272ee0a30050812b2780926a607d4ccbd0d0c0bda64d82992e914ac1f68e7e53ffb0cdcac7bdc2a946e7c2f905c9ed6ffc512f5b3c28fc275b28d2c8ff7c", + "copyright": "", + "holder": "", + "declared_license_expression": "", + "declared_license_expression_spdx": "", + "license_detections": [], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/athena-express@6.0.4?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": true, + "datasource_ids": [ + "yarn_lock_v1" + ], + "datafile_paths": [], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/bluebird@3.7.2", + "type": "npm", + "namespace": "", + "name": "bluebird", + "version": "3.7.2", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "https://www.npmjs.com/package/bluebird", + "repository_download_url": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "api_data_url": "https://registry.npmjs.org/bluebird/3.7.2", + "md5": "", + "sha1": "9f229c15be272454ffa973ace0dbee79a1b0c36f", + "sha256": "", + "sha512": "5e9363e860d0cdd7d6fabd969e7ef189201ded33378f39311970464ed58ab925efd71515f9acf1026f2375664dd3a413424fb63765c1f6344392f6e6426711b6", + "copyright": "", + "holder": "", + "declared_license_expression": "", + "declared_license_expression_spdx": "", + "license_detections": [], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/bluebird@3.7.2?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": true, + "datasource_ids": [ + "yarn_lock_v1" + ], + "datafile_paths": [], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/create-athena-partition@1.0.0", + "type": "npm", + "namespace": "", + "name": "create-athena-partition", + "version": "1.0.0", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.npmjs.org/create-athena-partition/-/create-athena-partition-1.0.0.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "", + "repository_download_url": "", + "api_data_url": "", + "md5": "", + "sha1": "", + "sha256": "", + "sha512": "", + "copyright": "", + "holder": "", + "declared_license_expression": "unknown", + "declared_license_expression_spdx": "LicenseRef-scancode-unknown", + "license_detections": [ + { + "matches": [ + { + "score": 100.0, + "matcher": "5-undetected", + "end_line": 1, + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/package-manifest-unknown-cb9ea49fe36cb2e1ba6d87c68e1195a492f762cf", + "from_file": "resolved_dependencies.zip-extract/package.json", + "start_line": 1, + "matched_text": "license - UNLICENSED", + "match_coverage": 100.0, + "matched_length": 2, + "rule_relevance": 100, + "rule_identifier": "package-manifest-unknown-cb9ea49fe36cb2e1ba6d87c68e1195a492f762cf", + "license_expression": "unknown", + "spdx_license_expression": "LicenseRef-scancode-unknown" + } + ], + "identifier": "unknown-0669ac45-20f6-defd-ec9f-2b6aafc9f944", + "license_expression": "unknown", + "license_expression_spdx": "LicenseRef-scancode-unknown" + } + ], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "- UNLICENSED\n", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/create-athena-partition@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": true, + "is_virtual": false, + "datasource_ids": [ + "npm_package_json" + ], + "datafile_paths": [ + "resolved_dependencies.zip-extract/package.json" + ], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/csvtojson@2.0.10", + "type": "npm", + "namespace": "", + "name": "csvtojson", + "version": "2.0.10", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.yarnpkg.com/csvtojson/-/csvtojson-2.0.10.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "https://www.npmjs.com/package/csvtojson", + "repository_download_url": "https://registry.npmjs.org/csvtojson/-/csvtojson-2.0.10.tgz", + "api_data_url": "https://registry.npmjs.org/csvtojson/2.0.10", + "md5": "", + "sha1": "11e7242cc630da54efce7958a45f443210357574", + "sha256": "", + "sha512": "954585c462b286b68a096f10821cfa6747f697f3ea0755b700ed07289cc6210e49452951eb9d5e9090e21896c14f8b1134dbf975d9d2195127b313fd5d1095a5", + "copyright": "", + "holder": "", + "declared_license_expression": "", + "declared_license_expression_spdx": "", + "license_detections": [], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/csvtojson@2.0.10?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": true, + "datasource_ids": [ + "yarn_lock_v1" + ], + "datafile_paths": [], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/is-utf8@0.2.1", + "type": "npm", + "namespace": "", + "name": "is-utf8", + "version": "0.2.1", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "https://www.npmjs.com/package/is-utf8", + "repository_download_url": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "api_data_url": "https://registry.npmjs.org/is-utf8/0.2.1", + "md5": "", + "sha1": "4b0da1442104d1b336340e80797e865cf39f7d72", + "sha256": "", + "sha512": "", + "copyright": "", + "holder": "", + "declared_license_expression": "", + "declared_license_expression_spdx": "", + "license_detections": [], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/is-utf8@0.2.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": true, + "datasource_ids": [ + "yarn_lock_v1" + ], + "datafile_paths": [], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/lodash@4.17.21", + "type": "npm", + "namespace": "", + "name": "lodash", + "version": "4.17.21", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "https://www.npmjs.com/package/lodash", + "repository_download_url": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "api_data_url": "https://registry.npmjs.org/lodash/4.17.21", + "md5": "", + "sha1": "679591c564c3bffaae8454cf0b3df370c3d6911c", + "sha256": "", + "sha512": "bf690311ee7b95e713ba568322e3533f2dd1cb880b189e99d4edef13592b81764daec43e2c54c61d5c558dc5cfb35ecb85b65519e74026ff17675b6f8f916f4a", + "copyright": "", + "holder": "", + "declared_license_expression": "", + "declared_license_expression_spdx": "", + "license_detections": [], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/lodash@4.17.21?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": true, + "datasource_ids": [ + "yarn_lock_v1" + ], + "datafile_paths": [], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/strip-bom@2.0.0", + "type": "npm", + "namespace": "", + "name": "strip-bom", + "version": "2.0.0", + "qualifiers": "", + "subpath": "", + "tag": "", + "primary_language": "JavaScript", + "release_date": null, + "parties": [], + "keywords": [], + "homepage_url": "", + "download_url": "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz", + "bug_tracking_url": "", + "code_view_url": "", + "vcs_url": "", + "repository_homepage_url": "https://www.npmjs.com/package/strip-bom", + "repository_download_url": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "api_data_url": "https://registry.npmjs.org/strip-bom/2.0.0", + "md5": "", + "sha1": "6219a85616520491f35788bdbf1447a99c7e6b0e", + "sha256": "", + "sha512": "", + "copyright": "", + "holder": "", + "declared_license_expression": "", + "declared_license_expression_spdx": "", + "license_detections": [], + "other_license_expression": "", + "other_license_expression_spdx": "", + "other_license_detections": [], + "extracted_license_statement": "", + "notice_text": "", + "source_packages": [], + "extra_data": {}, + "package_uid": "pkg:npm/strip-bom@2.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": true, + "datasource_ids": [ + "yarn_lock_v1" + ], + "datafile_paths": [], + "file_references": [], + "missing_resources": [], + "modified_resources": [], + "affected_by_vulnerabilities": [] + } + ], + "dependencies": [ + { + "purl": "pkg:npm/athena-express", + "extracted_requirement": "^6.0.4", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_resolved": false, + "is_direct": true, + "dependency_uid": "pkg:npm/athena-express?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/create-athena-partition@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "resolved_to_package_uid": "pkg:npm/athena-express@6.0.4?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "resolved_dependencies.zip-extract/package.json", + "datasource_id": "npm_package_json", + "package_type": "npm", + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/bluebird", + "extracted_requirement": "^3.5.1", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "is_direct": true, + "dependency_uid": "pkg:npm/bluebird?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/csvtojson@2.0.10?uuid=fixed-uid-done-for-testing-5642512d1758", + "resolved_to_package_uid": "pkg:npm/bluebird@3.7.2?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "resolved_dependencies.zip-extract/yarn.lock", + "datasource_id": "yarn_lock_v1", + "package_type": "npm", + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/csvtojson", + "extracted_requirement": "^2.0.10", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "is_direct": true, + "dependency_uid": "pkg:npm/csvtojson?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/athena-express@6.0.4?uuid=fixed-uid-done-for-testing-5642512d1758", + "resolved_to_package_uid": "pkg:npm/csvtojson@2.0.10?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "resolved_dependencies.zip-extract/yarn.lock", + "datasource_id": "yarn_lock_v1", + "package_type": "npm", + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/is-utf8", + "extracted_requirement": "^0.2.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "is_direct": true, + "dependency_uid": "pkg:npm/is-utf8?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/strip-bom@2.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "resolved_to_package_uid": "pkg:npm/is-utf8@0.2.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "resolved_dependencies.zip-extract/yarn.lock", + "datasource_id": "yarn_lock_v1", + "package_type": "npm", + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/lodash", + "extracted_requirement": "^4.17.3", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "is_direct": true, + "dependency_uid": "pkg:npm/lodash?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/csvtojson@2.0.10?uuid=fixed-uid-done-for-testing-5642512d1758", + "resolved_to_package_uid": "pkg:npm/lodash@4.17.21?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "resolved_dependencies.zip-extract/yarn.lock", + "datasource_id": "yarn_lock_v1", + "package_type": "npm", + "affected_by_vulnerabilities": [] + }, + { + "purl": "pkg:npm/strip-bom", + "extracted_requirement": "^2.0.0", + "scope": "dependencies", + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "is_direct": true, + "dependency_uid": "pkg:npm/strip-bom?uuid=fixed-uid-done-for-testing-5642512d1758", + "for_package_uid": "pkg:npm/csvtojson@2.0.10?uuid=fixed-uid-done-for-testing-5642512d1758", + "resolved_to_package_uid": "pkg:npm/strip-bom@2.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "datafile_path": "resolved_dependencies.zip-extract/yarn.lock", + "datasource_id": "yarn_lock_v1", + "package_type": "npm", + "affected_by_vulnerabilities": [] + } + ], + "files": [ + { + "path": "resolved_dependencies.zip", + "type": "file", + "name": "resolved_dependencies.zip", + "status": "", + "tag": "", + "extension": ".zip", + "md5": "412ba8411bd121539d151f0bd39e2ed2", + "sha1": "215dfb066677df22a2cd61f2550deaa7d1583472", + "sha256": "0d4157ba9da49fbf101cd21b37ac93175568d2d5e30884b235002fb2f5f31c6a", + "sha512": "", + "programming_language": "", + "is_binary": true, + "is_text": false, + "is_archive": true, + "is_media": false, + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "detected_license_expression": "", + "detected_license_expression_spdx": "", + "license_detections": [], + "license_clues": [], + "percentage_of_license_text": null, + "copyrights": [], + "holders": [], + "authors": [], + "package_data": [], + "for_packages": [], + "emails": [], + "urls": [], + "extra_data": {} + }, + { + "path": "resolved_dependencies.zip-extract", + "type": "directory", + "name": "resolved_dependencies.zip-extract", + "status": "", + "tag": "", + "extension": ".zip-extract", + "md5": "", + "sha1": "", + "sha256": "", + "sha512": "", + "programming_language": "", + "is_binary": false, + "is_text": false, + "is_archive": false, + "is_media": false, + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "detected_license_expression": "", + "detected_license_expression_spdx": "", + "license_detections": [], + "license_clues": [], + "percentage_of_license_text": null, + "copyrights": [], + "holders": [], + "authors": [], + "package_data": [], + "for_packages": [], + "emails": [], + "urls": [], + "extra_data": {} + }, + { + "path": "resolved_dependencies.zip-extract/package.json", + "type": "file", + "name": "package.json", + "status": "application-package", + "tag": "", + "extension": ".json", + "md5": "7001c0ea1ebdc9e52bf8225ad9e997c0", + "sha1": "f86079c55d42a7204a9e5e8aa6617174d43d4fc5", + "sha256": "15861d5a2202f1334290ac3a4fbd80991e41497e58134dde4d94d10d67752dbe", + "sha512": "", + "programming_language": "", + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "detected_license_expression": "", + "detected_license_expression_spdx": "", + "license_detections": [], + "license_clues": [], + "percentage_of_license_text": null, + "copyrights": [], + "holders": [], + "authors": [], + "package_data": [ + { + "md5": null, + "name": "create-athena-partition", + "purl": "pkg:npm/create-athena-partition@1.0.0", + "sha1": null, + "type": "npm", + "holder": null, + "sha256": null, + "sha512": null, + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "1.0.0", + "keywords": [], + "copyright": null, + "namespace": null, + "extra_data": {}, + "is_private": true, + "is_virtual": false, + "qualifiers": {}, + "notice_text": null, + "api_data_url": null, + "dependencies": [ + { + "purl": "pkg:npm/athena-express", + "scope": "dependencies", + "is_direct": true, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": false, + "resolved_package": {}, + "extracted_requirement": "^6.0.4" + } + ], + "download_url": "https://registry.npmjs.org/create-athena-partition/-/create-athena-partition-1.0.0.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "npm_package_json", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [ + { + "matches": [ + { + "score": 100.0, + "matcher": "5-undetected", + "end_line": 1, + "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/package-manifest-unknown-cb9ea49fe36cb2e1ba6d87c68e1195a492f762cf", + "from_file": null, + "start_line": 1, + "matched_text": "license - UNLICENSED", + "match_coverage": 100.0, + "matched_length": 2, + "rule_relevance": 100, + "rule_identifier": "package-manifest-unknown-cb9ea49fe36cb2e1ba6d87c68e1195a492f762cf", + "license_expression": "unknown", + "spdx_license_expression": "LicenseRef-scancode-unknown" + } + ], + "identifier": "unknown-0669ac45-20f6-defd-ec9f-2b6aafc9f944", + "license_expression": "unknown", + "license_expression_spdx": "LicenseRef-scancode-unknown" + } + ], + "repository_download_url": null, + "repository_homepage_url": null, + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": "unknown", + "extracted_license_statement": "- UNLICENSED\n", + "other_license_expression_spdx": null, + "declared_license_expression_spdx": "LicenseRef-scancode-unknown" + } + ], + "for_packages": [ + "pkg:npm/create-athena-partition@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "emails": [], + "urls": [], + "extra_data": {} + }, + { + "path": "resolved_dependencies.zip-extract/yarn.lock", + "type": "file", + "name": "yarn.lock", + "status": "application-package", + "tag": "", + "extension": ".lock", + "md5": "0481ffd2443fcad568a09fae75b9d231", + "sha1": "396a29e290d34e6409e1801510d6b674ee4a2d98", + "sha256": "af63cd9d3ce4b209f073cc750a9b19a92a2cfdf3ad44cd9b4b207258d702ceba", + "sha512": "", + "programming_language": "", + "is_binary": false, + "is_text": true, + "is_archive": false, + "is_media": false, + "is_legal": false, + "is_manifest": false, + "is_readme": false, + "is_top_level": false, + "is_key_file": false, + "detected_license_expression": "", + "detected_license_expression_spdx": "", + "license_detections": [], + "license_clues": [], + "percentage_of_license_text": null, + "copyrights": [], + "holders": [], + "authors": [], + "package_data": [ + { + "md5": null, + "name": null, + "purl": null, + "sha1": null, + "type": "npm", + "holder": null, + "sha256": null, + "sha512": null, + "parties": [], + "subpath": null, + "vcs_url": null, + "version": null, + "keywords": [], + "copyright": null, + "namespace": null, + "extra_data": {}, + "is_private": false, + "is_virtual": false, + "qualifiers": {}, + "notice_text": null, + "api_data_url": null, + "dependencies": [ + { + "purl": "pkg:npm/athena-express@6.0.4", + "scope": "dependencies", + "is_direct": false, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": { + "md5": null, + "name": "athena-express", + "purl": "pkg:npm/athena-express@6.0.4", + "sha1": "bb457dcc967686faea2138f934828a331b98c8f6", + "type": "npm", + "holder": null, + "sha256": null, + "sha512": "02d0272ee0a30050812b2780926a607d4ccbd0d0c0bda64d82992e914ac1f68e7e53ffb0cdcac7bdc2a946e7c2f905c9ed6ffc512f5b3c28fc275b28d2c8ff7c", + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "6.0.4", + "keywords": [], + "copyright": null, + "namespace": "", + "extra_data": {}, + "is_private": false, + "is_virtual": true, + "qualifiers": {}, + "notice_text": null, + "api_data_url": "https://registry.npmjs.org/athena-express/6.0.4", + "dependencies": [ + { + "purl": "pkg:npm/csvtojson", + "scope": "dependencies", + "is_direct": true, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": {}, + "extracted_requirement": "^2.0.10" + } + ], + "download_url": "https://registry.yarnpkg.com/athena-express/-/athena-express-6.0.4.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": "https://registry.npmjs.org/athena-express/-/athena-express-6.0.4.tgz", + "repository_homepage_url": "https://www.npmjs.com/package/athena-express", + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + }, + "extracted_requirement": "^6.0.4" + }, + { + "purl": "pkg:npm/bluebird@3.7.2", + "scope": "dependencies", + "is_direct": false, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": { + "md5": null, + "name": "bluebird", + "purl": "pkg:npm/bluebird@3.7.2", + "sha1": "9f229c15be272454ffa973ace0dbee79a1b0c36f", + "type": "npm", + "holder": null, + "sha256": null, + "sha512": "5e9363e860d0cdd7d6fabd969e7ef189201ded33378f39311970464ed58ab925efd71515f9acf1026f2375664dd3a413424fb63765c1f6344392f6e6426711b6", + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "3.7.2", + "keywords": [], + "copyright": null, + "namespace": "", + "extra_data": {}, + "is_private": false, + "is_virtual": true, + "qualifiers": {}, + "notice_text": null, + "api_data_url": "https://registry.npmjs.org/bluebird/3.7.2", + "dependencies": [], + "download_url": "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "repository_homepage_url": "https://www.npmjs.com/package/bluebird", + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + }, + "extracted_requirement": "^3.5.1" + }, + { + "purl": "pkg:npm/csvtojson@2.0.10", + "scope": "dependencies", + "is_direct": false, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": { + "md5": null, + "name": "csvtojson", + "purl": "pkg:npm/csvtojson@2.0.10", + "sha1": "11e7242cc630da54efce7958a45f443210357574", + "type": "npm", + "holder": null, + "sha256": null, + "sha512": "954585c462b286b68a096f10821cfa6747f697f3ea0755b700ed07289cc6210e49452951eb9d5e9090e21896c14f8b1134dbf975d9d2195127b313fd5d1095a5", + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "2.0.10", + "keywords": [], + "copyright": null, + "namespace": "", + "extra_data": {}, + "is_private": false, + "is_virtual": true, + "qualifiers": {}, + "notice_text": null, + "api_data_url": "https://registry.npmjs.org/csvtojson/2.0.10", + "dependencies": [ + { + "purl": "pkg:npm/bluebird", + "scope": "dependencies", + "is_direct": true, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": {}, + "extracted_requirement": "^3.5.1" + }, + { + "purl": "pkg:npm/lodash", + "scope": "dependencies", + "is_direct": true, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": {}, + "extracted_requirement": "^4.17.3" + }, + { + "purl": "pkg:npm/strip-bom", + "scope": "dependencies", + "is_direct": true, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": {}, + "extracted_requirement": "^2.0.0" + } + ], + "download_url": "https://registry.yarnpkg.com/csvtojson/-/csvtojson-2.0.10.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": "https://registry.npmjs.org/csvtojson/-/csvtojson-2.0.10.tgz", + "repository_homepage_url": "https://www.npmjs.com/package/csvtojson", + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + }, + "extracted_requirement": "^2.0.10" + }, + { + "purl": "pkg:npm/is-utf8@0.2.1", + "scope": "dependencies", + "is_direct": false, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": { + "md5": null, + "name": "is-utf8", + "purl": "pkg:npm/is-utf8@0.2.1", + "sha1": "4b0da1442104d1b336340e80797e865cf39f7d72", + "type": "npm", + "holder": null, + "sha256": null, + "sha512": null, + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "0.2.1", + "keywords": [], + "copyright": null, + "namespace": "", + "extra_data": {}, + "is_private": false, + "is_virtual": true, + "qualifiers": {}, + "notice_text": null, + "api_data_url": "https://registry.npmjs.org/is-utf8/0.2.1", + "dependencies": [], + "download_url": "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "repository_homepage_url": "https://www.npmjs.com/package/is-utf8", + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + }, + "extracted_requirement": "^0.2.0" + }, + { + "purl": "pkg:npm/lodash@4.17.21", + "scope": "dependencies", + "is_direct": false, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": { + "md5": null, + "name": "lodash", + "purl": "pkg:npm/lodash@4.17.21", + "sha1": "679591c564c3bffaae8454cf0b3df370c3d6911c", + "type": "npm", + "holder": null, + "sha256": null, + "sha512": "bf690311ee7b95e713ba568322e3533f2dd1cb880b189e99d4edef13592b81764daec43e2c54c61d5c558dc5cfb35ecb85b65519e74026ff17675b6f8f916f4a", + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "4.17.21", + "keywords": [], + "copyright": null, + "namespace": "", + "extra_data": {}, + "is_private": false, + "is_virtual": true, + "qualifiers": {}, + "notice_text": null, + "api_data_url": "https://registry.npmjs.org/lodash/4.17.21", + "dependencies": [], + "download_url": "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "repository_homepage_url": "https://www.npmjs.com/package/lodash", + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + }, + "extracted_requirement": "^4.17.3" + }, + { + "purl": "pkg:npm/strip-bom@2.0.0", + "scope": "dependencies", + "is_direct": false, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": { + "md5": null, + "name": "strip-bom", + "purl": "pkg:npm/strip-bom@2.0.0", + "sha1": "6219a85616520491f35788bdbf1447a99c7e6b0e", + "type": "npm", + "holder": null, + "sha256": null, + "sha512": null, + "parties": [], + "subpath": null, + "vcs_url": null, + "version": "2.0.0", + "keywords": [], + "copyright": null, + "namespace": "", + "extra_data": {}, + "is_private": false, + "is_virtual": true, + "qualifiers": {}, + "notice_text": null, + "api_data_url": "https://registry.npmjs.org/strip-bom/2.0.0", + "dependencies": [ + { + "purl": "pkg:npm/is-utf8", + "scope": "dependencies", + "is_direct": true, + "extra_data": {}, + "is_runtime": true, + "is_optional": false, + "is_resolved": true, + "resolved_package": {}, + "extracted_requirement": "^0.2.0" + } + ], + "download_url": "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz", + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "repository_homepage_url": "https://www.npmjs.com/package/strip-bom", + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + }, + "extracted_requirement": "^2.0.0" + } + ], + "download_url": null, + "homepage_url": null, + "release_date": null, + "code_view_url": null, + "datasource_id": "yarn_lock_v1", + "file_references": [], + "source_packages": [], + "bug_tracking_url": null, + "primary_language": "JavaScript", + "license_detections": [], + "repository_download_url": null, + "repository_homepage_url": null, + "other_license_detections": [], + "other_license_expression": null, + "declared_license_expression": null, + "extracted_license_statement": null, + "other_license_expression_spdx": null, + "declared_license_expression_spdx": null + } + ], + "for_packages": [ + "pkg:npm/athena-express@6.0.4?uuid=fixed-uid-done-for-testing-5642512d1758", + "pkg:npm/bluebird@3.7.2?uuid=fixed-uid-done-for-testing-5642512d1758", + "pkg:npm/create-athena-partition@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "pkg:npm/csvtojson@2.0.10?uuid=fixed-uid-done-for-testing-5642512d1758", + "pkg:npm/is-utf8@0.2.1?uuid=fixed-uid-done-for-testing-5642512d1758", + "pkg:npm/lodash@4.17.21?uuid=fixed-uid-done-for-testing-5642512d1758", + "pkg:npm/strip-bom@2.0.0?uuid=fixed-uid-done-for-testing-5642512d1758" + ], + "emails": [], + "urls": [], + "extra_data": {} + } + ], + "relations": [] +} \ No newline at end of file diff --git a/scanpipe/tests/data/rootfs/basic-rootfs_root_filesystems.json b/scanpipe/tests/data/rootfs/basic-rootfs_root_filesystems.json index 287e3405e..52e184a31 100644 --- a/scanpipe/tests/data/rootfs/basic-rootfs_root_filesystems.json +++ b/scanpipe/tests/data/rootfs/basic-rootfs_root_filesystems.json @@ -199,6 +199,8 @@ "multi_arch": "same" }, "package_uid": "pkg:deb/ubuntu/libncurses5@6.1-1ubuntu1.18.04?arch=amd64&uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "debian_installed_status_db", "debian_copyright_in_package" @@ -317,6 +319,8 @@ "multi_arch": "same" }, "package_uid": "pkg:deb/ubuntu/libndp0@1.4-2ubuntu0.16.04.1?arch=amd64&uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "debian_installed_status_db", "debian_copyright_in_package" diff --git a/scanpipe/tests/data/scancode/daglib-0.6.0-py3-none-any.whl_scan_codebase.json b/scanpipe/tests/data/scancode/daglib-0.6.0-py3-none-any.whl_scan_codebase.json index 3bbfbff3b..aa3350c8a 100644 --- a/scanpipe/tests/data/scancode/daglib-0.6.0-py3-none-any.whl_scan_codebase.json +++ b/scanpipe/tests/data/scancode/daglib-0.6.0-py3-none-any.whl_scan_codebase.json @@ -127,6 +127,8 @@ "Documentation": "https://mharrisb1.github.io/daglib/" }, "package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel" ], @@ -235,6 +237,8 @@ "Documentation": "https://mharrisb1.github.io/daglib/" }, "package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "pypi_wheel_metadata" ], @@ -255,6 +259,7 @@ "is_runtime": true, "is_optional": false, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/dask?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -270,6 +275,7 @@ "is_runtime": true, "is_optional": false, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/dask?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -285,6 +291,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/graphviz?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -300,6 +307,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/graphviz?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -315,6 +323,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/ipycytoscape?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -330,6 +339,7 @@ "is_runtime": true, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/ipycytoscape?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -345,6 +355,7 @@ "is_runtime": true, "is_optional": false, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/networkx?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -360,6 +371,7 @@ "is_runtime": true, "is_optional": false, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:pypi/networkx?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:pypi/daglib@0.6.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -431,6 +443,8 @@ "extra_data": { "Documentation": "https://mharrisb1.github.io/daglib/" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "notice_text": null, "api_data_url": "https://pypi.org/pypi/daglib/0.6.0/json", @@ -438,6 +452,7 @@ { "purl": "pkg:pypi/dask", "scope": "install", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": false, @@ -448,6 +463,7 @@ { "purl": "pkg:pypi/graphviz", "scope": "graphviz", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -458,6 +474,7 @@ { "purl": "pkg:pypi/ipycytoscape", "scope": "ipycytoscape", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -468,6 +485,7 @@ { "purl": "pkg:pypi/networkx", "scope": "install", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": false, @@ -843,6 +861,8 @@ "extra_data": { "Documentation": "https://mharrisb1.github.io/daglib/" }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "notice_text": null, "api_data_url": "https://pypi.org/pypi/daglib/0.6.0/json", @@ -850,6 +870,7 @@ { "purl": "pkg:pypi/dask", "scope": "install", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": false, @@ -860,6 +881,7 @@ { "purl": "pkg:pypi/graphviz", "scope": "graphviz", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -870,6 +892,7 @@ { "purl": "pkg:pypi/ipycytoscape", "scope": "ipycytoscape", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": true, @@ -880,6 +903,7 @@ { "purl": "pkg:pypi/networkx", "scope": "install", + "is_direct": true, "extra_data": {}, "is_runtime": true, "is_optional": false, diff --git a/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_codebase.json b/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_codebase.json index d8ee83c42..080076241 100644 --- a/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_codebase.json +++ b/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_codebase.json @@ -104,8 +104,14 @@ "extracted_license_statement": "- MIT\n", "notice_text": "", "source_packages": [], - "extra_data": {}, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "package_uid": "pkg:npm/is-npm@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "npm_package_json" ], @@ -126,6 +132,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "dependency_uid": "pkg:npm/ava?uuid=fixed-uid-done-for-testing-5642512d1758", "for_package_uid": "pkg:npm/is-npm@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", "resolved_to_package_uid": null, @@ -339,7 +346,13 @@ ], "copyright": null, "namespace": null, - "extra_data": {}, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, + "is_private": false, + "is_virtual": false, "qualifiers": {}, "notice_text": null, "api_data_url": "https://registry.npmjs.org/is-npm/1.0.0", @@ -347,6 +360,7 @@ { "purl": "pkg:npm/ava", "scope": "devDependencies", + "is_direct": true, "extra_data": {}, "is_runtime": false, "is_optional": true, diff --git a/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package.json b/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package.json index 9348bc77e..db1010775 100644 --- a/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package.json +++ b/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package.json @@ -14,12 +14,12 @@ "--summary": true }, "notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", - "output_format_version": "3.1.0", + "output_format_version": "3.2.0", "message": null, "errors": [], "warnings": [], "extra_data": { - "spdx_license_list_version": "3.23", + "spdx_license_list_version": "3.24", "files_count": 3 } } @@ -121,7 +121,13 @@ "extracted_license_statement": "- MIT\n", "notice_text": null, "source_packages": [], - "extra_data": {}, + "is_private": false, + "is_virtual": false, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "repository_homepage_url": "https://www.npmjs.com/package/is-npm", "repository_download_url": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", "api_data_url": "https://registry.npmjs.org/is-npm/1.0.0", @@ -143,6 +149,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:npm/ava?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -396,7 +403,13 @@ "notice_text": null, "source_packages": [], "file_references": [], - "extra_data": {}, + "is_private": false, + "is_virtual": false, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "dependencies": [ { "purl": "pkg:npm/ava", @@ -405,6 +418,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} } diff --git a/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package_summary.json b/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package_summary.json index a50380d8d..a683ec1a0 100644 --- a/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package_summary.json +++ b/scanpipe/tests/data/scancode/is-npm-1.0.0_scan_package_summary.json @@ -223,8 +223,14 @@ "extracted_license_statement": "- MIT\n", "notice_text": "", "source_packages": [], - "extra_data": {}, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "package_uid": "pkg:npm/is-npm@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "npm_package_json" ], diff --git a/scanpipe/tests/data/scancode/is-npm-1.0.0_summary.json b/scanpipe/tests/data/scancode/is-npm-1.0.0_summary.json index 4b94bede8..99b9792fb 100644 --- a/scanpipe/tests/data/scancode/is-npm-1.0.0_summary.json +++ b/scanpipe/tests/data/scancode/is-npm-1.0.0_summary.json @@ -230,8 +230,14 @@ "compliance_alert": "", "notice_text": "", "source_packages": [], - "extra_data": {}, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "package_uid": "pkg:npm/is-npm@1.0.0?uuid=ba110d49-b6f2-4c86-8d89-a6fd34838ca8", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "npm_package_json" ], diff --git a/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package.json b/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package.json index bfcf90c9f..fcba01031 100644 --- a/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package.json +++ b/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package.json @@ -14,12 +14,12 @@ "--summary": true }, "notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", - "output_format_version": "3.1.0", + "output_format_version": "3.2.0", "message": null, "errors": [], "warnings": [], "extra_data": { - "spdx_license_list_version": "3.23", + "spdx_license_list_version": "3.24", "files_count": 6 } } @@ -121,7 +121,13 @@ "extracted_license_statement": "- MIT\n", "notice_text": null, "source_packages": [], - "extra_data": {}, + "is_private": false, + "is_virtual": false, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "repository_homepage_url": "https://www.npmjs.com/package/is-npm", "repository_download_url": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", "api_data_url": "https://registry.npmjs.org/is-npm/1.0.0", @@ -203,7 +209,13 @@ "extracted_license_statement": "- MIT\n", "notice_text": null, "source_packages": [], - "extra_data": {}, + "is_private": false, + "is_virtual": false, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "repository_homepage_url": "https://www.npmjs.com/package/is-npm", "repository_download_url": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", "api_data_url": "https://registry.npmjs.org/is-npm/1.0.0", @@ -225,6 +237,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:npm/ava?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -239,6 +252,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {}, "dependency_uid": "pkg:npm/ava?uuid=fixed-uid-done-for-testing-5642512d1758", @@ -602,7 +616,13 @@ "notice_text": null, "source_packages": [], "file_references": [], - "extra_data": {}, + "is_private": false, + "is_virtual": false, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "dependencies": [ { "purl": "pkg:npm/ava", @@ -611,6 +631,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} } @@ -865,7 +886,13 @@ "notice_text": null, "source_packages": [], "file_references": [], - "extra_data": {}, + "is_private": false, + "is_virtual": false, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "dependencies": [ { "purl": "pkg:npm/ava", @@ -874,6 +901,7 @@ "is_runtime": false, "is_optional": true, "is_resolved": false, + "is_direct": true, "resolved_package": {}, "extra_data": {} } diff --git a/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package_summary.json b/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package_summary.json index 1de0eb039..dd045cd1e 100644 --- a/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package_summary.json +++ b/scanpipe/tests/data/scancode/multiple-is-npm-1.0.0_scan_package_summary.json @@ -247,8 +247,14 @@ "extracted_license_statement": "- MIT\n", "notice_text": "", "source_packages": [], - "extra_data": {}, + "extra_data": { + "engines": { + "node": ">=0.10.0" + } + }, "package_uid": "pkg:npm/is-npm@1.0.0?uuid=fixed-uid-done-for-testing-5642512d1758", + "is_private": false, + "is_virtual": false, "datasource_ids": [ "npm_package_json" ], diff --git a/scanpipe/tests/data/scancode/package_assembly_codebase.json b/scanpipe/tests/data/scancode/package_assembly_codebase.json index a0691cd68..1df477a57 100644 --- a/scanpipe/tests/data/scancode/package_assembly_codebase.json +++ b/scanpipe/tests/data/scancode/package_assembly_codebase.json @@ -2,16 +2,16 @@ "headers": [ { "tool_name": "scancode-toolkit", - "tool_version": "32.1.0", + "tool_version": "32.2.0", "options": { "--info": true, "--package": true }, "notice": "Generated with ScanCode and provided on an \"AS IS\" BASIS, WITHOUT WARRANTIES\nOR CONDITIONS OF ANY KIND, either express or implied. No content created from\nScanCode should be considered or used as legal advice. Consult an Attorney\nfor any legal advice.\nScanCode is a free software code scanning tool from nexB Inc. and others.\nVisit https://github.com/nexB/scancode-toolkit/ for support and download.", - "start_timestamp": "2024-06-24T065849.455991", - "end_timestamp": "2024-06-24T065849.495306", - "output_format_version": "3.1.0", - "duration": 0.039336442947387695, + "start_timestamp": "2024-06-27T143719.216423", + "end_timestamp": "2024-06-27T143719.360348", + "output_format_version": "3.2.0", + "duration": 0.1439366340637207, "message": null, "errors": [], "warnings": [], @@ -19,11 +19,11 @@ "system_environment": { "operating_system": "linux", "cpu_architecture": "64", - "platform": "Linux-6.6.31-linuxkit-x86_64-with-glibc2.36", - "platform_version": "#1 SMP Thu May 23 08:36:57 UTC 2024", - "python_version": "3.12.4 (main, Jun 13 2024, 05:37:23) [GCC 12.2.0]" + "platform": "Linux-5.15.0-112-generic-x86_64-with-glibc2.35", + "platform_version": "#122-Ubuntu SMP Thu May 23 07:48:21 UTC 2024", + "python_version": "3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]" }, - "spdx_license_list_version": "3.23", + "spdx_license_list_version": "3.24", "files_count": 3 } } @@ -85,11 +85,13 @@ "extracted_license_statement": "- MIT\n", "notice_text": null, "source_packages": [], + "is_private": false, + "is_virtual": false, "extra_data": {}, "repository_homepage_url": "https://www.npmjs.com/package/test", "repository_download_url": "https://registry.npmjs.org/test/-/test-0.1.0.tgz", "api_data_url": "https://registry.npmjs.org/test/0.1.0", - "package_uid": "pkg:npm/test@0.1.0?uuid=a1c8fc52-8f7d-4480-8ae7-423720d31d31", + "package_uid": "pkg:npm/test@0.1.0?uuid=c92f1e83-0543-4669-9482-56a54db489e8", "datafile_paths": [ "package_assembly_codebase.tar.gz-extract/test/get_package_resources/package.json" ], @@ -260,6 +262,8 @@ "notice_text": null, "source_packages": [], "file_references": [], + "is_private": false, + "is_virtual": false, "extra_data": {}, "dependencies": [], "repository_homepage_url": "https://www.npmjs.com/package/test", @@ -270,7 +274,7 @@ } ], "for_packages": [ - "pkg:npm/test@0.1.0?uuid=a1c8fc52-8f7d-4480-8ae7-423720d31d31" + "pkg:npm/test@0.1.0?uuid=c92f1e83-0543-4669-9482-56a54db489e8" ], "files_count": 0, "dirs_count": 0, @@ -299,7 +303,7 @@ "is_script": false, "package_data": [], "for_packages": [ - "pkg:npm/test@0.1.0?uuid=a1c8fc52-8f7d-4480-8ae7-423720d31d31" + "pkg:npm/test@0.1.0?uuid=c92f1e83-0543-4669-9482-56a54db489e8" ], "files_count": 0, "dirs_count": 0, diff --git a/scanpipe/tests/pipes/test_output.py b/scanpipe/tests/pipes/test_output.py index ed2e04944..9161a3c37 100644 --- a/scanpipe/tests/pipes/test_output.py +++ b/scanpipe/tests/pipes/test_output.py @@ -247,7 +247,7 @@ def test_scanpipe_pipes_outputs_to_cyclonedx(self, regen=FIXTURES_REGEN): project = Project.objects.get(name="asgiref") package = project.discoveredpackages.get( - uuid="8fc54317-6054-4eb7-b189-f1b2822d3fa6" + uuid="d10827fc-bcd1-4c10-ad6c-972dd4defa9c" ) package.other_license_expression_spdx = "Apache-2.0 AND LicenseRef-test" diff --git a/scanpipe/tests/pipes/test_scancode.py b/scanpipe/tests/pipes/test_scancode.py index 2a24b59d1..cf16de928 100644 --- a/scanpipe/tests/pipes/test_scancode.py +++ b/scanpipe/tests/pipes/test_scancode.py @@ -569,3 +569,129 @@ def test_scanpipe_scancode_process_package_data(self): self.assertEqual(1, project1.discoveredpackages.count()) self.assertEqual(6, project1.discovereddependencies.count()) + + def test_scanpipe_scancode_create_packages_and_dependencies_from_mapping(self): + pipeline_name = "inspect_packages" + project1 = Project.objects.create(name="Analysis") + + input_location = self.data / "dependencies" / "resolved_dependencies.zip" + project1.copy_input_from(input_location) + + run = project1.add_pipeline( + pipeline_name=pipeline_name, + selected_groups=[], + ) + pipeline = run.make_pipeline_instance() + exitcode, out = pipeline.execute() + self.assertEqual(0, exitcode, msg=out) + + self.assertEqual(1, project1.discoveredpackages.count()) + self.assertEqual(7, project1.discovereddependencies.count()) + + yarn_resource = project1.codebaseresources.get( + path="resolved_dependencies.zip-extract/yarn.lock" + ) + lockfile_package_data = yarn_resource.package_data[0] + scancode.create_packages_and_dependencies_from_mapping( + project=project1, + resource=yarn_resource, + package_mapping=lockfile_package_data, + find_package=False, + process_resolved=True, + ) + + self.assertEqual(7, project1.discoveredpackages.count()) + self.assertEqual(12, project1.discovereddependencies.count()) + + def test_scanpipe_scancode_resolve_dependencies(self): + project1 = Project.objects.create(name="Analysis") + pkg_1 = DiscoveredPackage.objects.create( + project=project1, + type="npm", + name="bluebird", + version="3.7.2", + ) + DiscoveredDependency.objects.create( + project=project1, + type="npm", + name="bluebird", + extracted_requirement="^3.5.1", + is_direct=False, + resolved_to_package=pkg_1, + ) + dep_2 = DiscoveredDependency.objects.create( + project=project1, + type="npm", + name="bluebird", + extracted_requirement="^3.5.1", + is_direct=True, + ) + scancode.match_and_resolve_dependencies(project1) + + self.assertEqual(1, project1.discoveredpackages.count()) + self.assertEqual(1, project1.discovereddependencies.count()) + resolved_dep = project1.discovereddependencies.get(name="bluebird") + self.assertEqual(resolved_dep, dep_2) + self.assertEqual(resolved_dep.resolved_to_package, pkg_1) + + def test_scanpipe_scancode_resolve_dependencies_complex_requirements(self): + project1 = Project.objects.create(name="Analysis") + pkg_1 = DiscoveredPackage.objects.create( + project=project1, + type="npm", + name="bluebird", + version="3.7.2", + ) + DiscoveredDependency.objects.create( + project=project1, + type="npm", + name="bluebird", + extracted_requirement="^3.5.1", + is_direct=False, + resolved_to_package=pkg_1, + ) + dep_2 = DiscoveredDependency.objects.create( + project=project1, + type="npm", + name="bluebird", + extracted_requirement="^3.5.1 || ^3.5.0", + is_direct=True, + ) + scancode.match_and_resolve_dependencies(project1) + + self.assertEqual(1, project1.discoveredpackages.count()) + self.assertEqual(1, project1.discovereddependencies.count()) + resolved_dep = project1.discovereddependencies.get(name="bluebird") + self.assertEqual(resolved_dep, dep_2) + self.assertEqual(resolved_dep.resolved_to_package, pkg_1) + + def test_scanpipe_scancode_resolve_dependencies_no_requirements(self): + project1 = Project.objects.create(name="Analysis") + pkg_1 = DiscoveredPackage.objects.create( + project=project1, + type="npm", + name="bluebird", + version="3.7.2", + ) + DiscoveredDependency.objects.create( + project=project1, + type="npm", + name="bluebird", + extracted_requirement="^3.5.1", + is_direct=False, + resolved_to_package=pkg_1, + ) + dep_2 = DiscoveredDependency.objects.create( + project=project1, + type="npm", + name="bluebird", + extracted_requirement="", + is_direct=True, + ) + scancode.match_and_resolve_dependencies(project1) + + self.assertEqual(1, project1.discoveredpackages.count()) + self.assertEqual(1, project1.discovereddependencies.count()) + resolved_dep = project1.discovereddependencies.get(name="bluebird") + self.assertEqual(resolved_dep, dep_2) + self.assertEqual(resolved_dep.resolved_to_package, pkg_1) diff --git a/scanpipe/tests/test_api.py b/scanpipe/tests/test_api.py index 91de78be3..3181189ea 100644 --- a/scanpipe/tests/test_api.py +++ b/scanpipe/tests/test_api.py @@ -997,8 +997,8 @@ def test_scanpipe_api_serializer_get_model_serializer(self): get_model_serializer(None) def test_scanpipe_api_serializer_get_serializer_fields(self): - self.assertEqual(46, len(get_serializer_fields(DiscoveredPackage))) - self.assertEqual(13, len(get_serializer_fields(DiscoveredDependency))) + self.assertEqual(48, len(get_serializer_fields(DiscoveredPackage))) + self.assertEqual(14, len(get_serializer_fields(DiscoveredDependency))) self.assertEqual(37, len(get_serializer_fields(CodebaseResource))) self.assertEqual(5, len(get_serializer_fields(CodebaseRelation))) self.assertEqual(7, len(get_serializer_fields(ProjectMessage))) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index d7c89bd44..dc1f2c935 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -49,6 +49,7 @@ from django.utils import timezone from packagedcode.models import PackageData +from packageurl import PackageURL from requests.exceptions import RequestException from rq.job import JobStatus @@ -65,6 +66,7 @@ from scanpipe.models import UUIDTaggedItem from scanpipe.models import convert_glob_to_django_regex from scanpipe.models import get_project_work_directory +from scanpipe.models import normalize_package_url_data from scanpipe.pipes.fetch import Download from scanpipe.pipes.input import copy_input from scanpipe.tests import dependency_data1 @@ -730,6 +732,17 @@ def test_scanpipe_project_get_ignored_dependency_scopes_index(self): expected = {"npm": ["devDependencies"], "pypi": ["tests", "build"]} self.assertEqual(expected, self.project1.get_ignored_dependency_scopes_index()) + def test_scanpipe_normalize_package_url_data(self): + purl = PackageURL.from_string("pkg:npm/athena-express@6.0.4") + purl_data = normalize_package_url_data(purl_mapping=purl.to_dict()) + self.assertEqual(purl_data.get("namespace"), "") + + purl_data = normalize_package_url_data( + purl_mapping=purl.to_dict(), + ignore_nulls=True, + ) + self.assertEqual(purl_data.get("namespace"), None) + def test_scanpipe_project_get_ignored_vulnerabilities_set(self): self.project1.settings = { "ignored_vulnerabilities": [ diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index 9f6f8a282..010a0ec76 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -557,6 +557,12 @@ def _normalize_package_uids(self, data): Return the `data`, where any `package_uid` value has been normalized with `purl_with_fake_uuid()` """ + fields_with_package_uids = [ + "package_uid", + "dependency_uid", + "for_package_uid", + "resolved_to_package_uid", + ] if isinstance(data, list): return [self._normalize_package_uids(entry) for entry in data] @@ -568,16 +574,15 @@ def _normalize_package_uids(self, data): for key, value in data.items(): if isinstance(value, (list, dict)): value = self._normalize_package_uids(value) - if ( - key in ("package_uid", "dependency_uid", "for_package_uid") - and value - ): + if key in fields_with_package_uids and value: value = purl_with_fake_uuid(value) if key == "for_packages" and value: - value = [ - self.purl_fields_with_fake_uuid(package_uid, key) - for package_uid in value - ] + value = sorted( + [ + self.purl_fields_with_fake_uuid(package_uid, key) + for package_uid in value + ] + ) if is_local_files and key in ("name", "namespace", "purl") and value: value = self.purl_fields_with_fake_uuid(value, key) normalized_data[key] = value @@ -766,11 +771,14 @@ def test_scanpipe_inspect_packages_creates_packages_npm(self): package = project1.discoveredpackages.get() dependency = project1.discovereddependencies.get() - self.assertEqual(1, package.codebase_resources.count()) + self.assertEqual(3, package.codebase_resources.count()) self.assertEqual("pkg:npm/is-npm@1.0.0", dependency.for_package.purl) self.assertEqual(package.datasource_ids, [dependency.datasource_id]) self.assertEqual( - package.codebase_resources.get().path, dependency.datafile_resource.path + package.codebase_resources.get( + path="is-npm-1.0.0.tgz-extract/package/package.json" + ).path, + dependency.datafile_resource.path, ) def test_scanpipe_inspect_packages_creates_packages_pypi(self): @@ -789,6 +797,29 @@ def test_scanpipe_inspect_packages_creates_packages_pypi(self): self.assertEqual(0, project1.discoveredpackages.count()) self.assertEqual(26, project1.discovereddependencies.count()) + def test_scanpipe_inspect_packages_with_resolved_dependencies(self): + pipeline_name = "inspect_packages" + project1 = Project.objects.create(name="Analysis") + + input_location = self.data / "dependencies" / "resolved_dependencies.zip" + project1.copy_input_from(input_location) + + run = project1.add_pipeline( + pipeline_name=pipeline_name, + selected_groups=["Static Resolver"], + ) + pipeline = run.make_pipeline_instance() + + exitcode, out = pipeline.execute() + self.assertEqual(0, exitcode, msg=out) + self.assertEqual(4, project1.codebaseresources.count()) + self.assertEqual(7, project1.discoveredpackages.count()) + self.assertEqual(6, project1.discovereddependencies.count()) + + result_file = output.to_json(project1) + expected_file = self.data / "resolved_dependencies_inspect_packages.json" + self.assertPipelineResultEqual(expected_file, result_file) + def test_scanpipe_scan_codebase_can_process_wheel(self): pipeline_name = "scan_codebase" project1 = Project.objects.create(name="Analysis") diff --git a/scanpipe/views.py b/scanpipe/views.py index 14f5153a6..c5b1f87af 100644 --- a/scanpipe/views.py +++ b/scanpipe/views.py @@ -1546,6 +1546,10 @@ class DiscoveredDependencyListView( "field_name": "is_resolved", "filter_fieldname": "is_resolved", }, + { + "field_name": "is_direct", + "filter_fieldname": "is_direct", + }, "for_package", "resolved_to_package", "datafile_resource", @@ -1735,7 +1739,7 @@ class CodebaseResourceDetailsView( "template": "scanpipe/tabset/tab_relations.html", }, "extra_data": { - "fields": ["extra_data"], + "fields": ["extra_data", "package_data"], "verbose_name": "Extra", "icon_class": "fa-solid fa-plus-square", }, @@ -1888,6 +1892,8 @@ class DiscoveredPackageDetailsView( "missing_resources", "modified_resources", "package_uid", + "is_private", + "is_virtual", "datasource_ids", "datafile_paths", ], @@ -2050,6 +2056,7 @@ class DiscoveredDependencyDetailsView( "is_runtime", "is_optional", "is_resolved", + "is_direct", ], "icon_class": "fa-solid fa-info-circle", }, diff --git a/setup.cfg b/setup.cfg index 2e32f5196..e7d730c87 100644 --- a/setup.cfg +++ b/setup.cfg @@ -72,7 +72,7 @@ install_requires = # Docker container-inspector==33.0.0 # ScanCode-toolkit - scancode-toolkit[packages]==32.1.0 + scancode-toolkit[packages]==32.2.0 extractcode[full]==31.0.0 commoncode==31.2.1 # FetchCode