@@ -22,7 +23,17 @@
{{ match.from_file }}
|
- {{ match.rule_url }}
+ {{ match.matched_text }}
+ |
+
+ {% if match.rule_url %}
+
+ {{ match.rule_identifier }}
+
+
+ {% else %}
+ {{ match.rule_identifier }}
+ {% endif %}
|
{{ match.score }}
@@ -47,7 +58,7 @@
- | Detection Log |
+ Detection log |
@@ -64,9 +75,9 @@
- | Resource Path |
- Start Line |
- End Line |
+ Resource path |
+ Start line |
+ End line |
diff --git a/scanpipe/templates/scanpipe/tabset/tab_package_detections.html b/scanpipe/templates/scanpipe/tabset/tab_package_detections.html
index af09167b8b..c033a74a64 100644
--- a/scanpipe/templates/scanpipe/tabset/tab_package_detections.html
+++ b/scanpipe/templates/scanpipe/tabset/tab_package_detections.html
@@ -2,7 +2,7 @@
- | Datafile Paths |
+ Datafile paths |
@@ -35,9 +35,9 @@
- | License Detections |
- License Expression |
- License Expression SPDX |
+ License detections |
+ License expression |
+ License expression SPDX |
@@ -61,9 +61,9 @@
- | License Detections |
- License Expression |
- License Expression SPDX |
+ License detections |
+ License expression |
+ License expression SPDX |
diff --git a/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html b/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html
index 4cd3c37eda..d5165a3f21 100644
--- a/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html
+++ b/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html
@@ -3,9 +3,9 @@
- | License Detections |
- License Expression |
- License Expression SPDX |
+ License detections |
+ License expression |
+ License expression SPDX |
@@ -29,8 +29,8 @@
- | License Expression |
- License Clue Detials |
+ License expression |
+ License clue detials |
@@ -52,8 +52,8 @@
| Email |
- Start Line |
- End Line |
+ Start line |
+ End line |
@@ -78,8 +78,8 @@
| URL |
- Start Line |
- End Line |
+ Start line |
+ End line |
From b1fad21471334d846df661eb3c25b5c1d234f0a2 Mon Sep 17 00:00:00 2001
From: Ayan Sinha Mahapatra
Date: Thu, 3 Jul 2025 17:19:51 +0530
Subject: [PATCH 12/14] Add license detections to Compliance alerts panel
Signed-off-by: Ayan Sinha Mahapatra
---
scanpipe/pipes/compliance.py | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scanpipe/pipes/compliance.py b/scanpipe/pipes/compliance.py
index 0a0c0c776c..79be3f3f4f 100644
--- a/scanpipe/pipes/compliance.py
+++ b/scanpipe/pipes/compliance.py
@@ -105,6 +105,11 @@ def get_project_compliance_alerts(project, fail_level="error"):
.only(*PACKAGE_URL_FIELDS, "compliance_alert")
.order_by(*PACKAGE_URL_FIELDS)
)
+ licenses_qs = (
+ project.discoveredlicenses.compliance_issues(severity=fail_level)
+ .only("identifier", "compliance_alert")
+ .order_by("identifier")
+ )
resource_qs = (
project.codebaseresources.compliance_issues(severity=fail_level)
.only("path", "compliance_alert")
@@ -113,6 +118,7 @@ def get_project_compliance_alerts(project, fail_level="error"):
queryset_mapping = {
"packages": package_qs,
+ "license_detections": licenses_qs,
"resources": resource_qs,
}
From 645d5aefdf6ce458f157271e6b0b141b2ee73cb1 Mon Sep 17 00:00:00 2001
From: Ayan Sinha Mahapatra
Date: Mon, 14 Jul 2025 20:00:56 +0530
Subject: [PATCH 13/14] Add support for viewing license clues
Reference: https://github.com/aboutcode-org/scancode.io/issues/1355
Signed-off-by: Ayan Sinha Mahapatra
---
scanpipe/filters.py | 2 +
.../0074_discovered_license_models.py | 7 +++
scanpipe/models.py | 14 +++++-
scanpipe/pipes/__init__.py | 7 ++-
scanpipe/pipes/scancode.py | 43 +++++++++++++++++++
.../scanpipe/license_detection_list.html | 3 ++
.../panels/license_detections_summary.html | 14 +++++-
.../tabset/tab_resource_detections.html | 2 +-
scanpipe/views.py | 36 +++++++++++++---
9 files changed, 116 insertions(+), 12 deletions(-)
diff --git a/scanpipe/filters.py b/scanpipe/filters.py
index 50de01ee8e..6a826c02a8 100644
--- a/scanpipe/filters.py
+++ b/scanpipe/filters.py
@@ -856,6 +856,7 @@ class LicenseFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
compliance_alert = django_filters.ChoiceFilter(
choices=[(EMPTY_VAR, "None")] + CodebaseResource.Compliance.choices,
)
+ is_license_clue = StrictBooleanFilter()
class Meta:
model = DiscoveredLicense
@@ -866,6 +867,7 @@ class Meta:
"license_expression",
"license_expression_spdx",
"compliance_alert",
+ "is_license_clue",
]
diff --git a/scanpipe/migrations/0074_discovered_license_models.py b/scanpipe/migrations/0074_discovered_license_models.py
index 3c1dd6ae2a..5aa0ad5bea 100644
--- a/scanpipe/migrations/0074_discovered_license_models.py
+++ b/scanpipe/migrations/0074_discovered_license_models.py
@@ -95,6 +95,13 @@ class Migration(migrations.Migration):
verbose_name="Detection Locations",
),
),
+ (
+ "is_license_clue",
+ models.BooleanField(
+ default=False,
+ help_text='True if this is not a proper license detection which should be considered in the license_expression for the parent resource/package. A license match is considered as a clue if it could be a possiblefalse positives or the matched rule is tagged as a clue explicitly.',
+ ),
+ ),
(
"project",
models.ForeignKey(
diff --git a/scanpipe/models.py b/scanpipe/models.py
index c0e6f22ad4..2f7e6238ae 100644
--- a/scanpipe/models.py
+++ b/scanpipe/models.py
@@ -2321,10 +2321,10 @@ def without_symlinks(self):
return self.filter(~Q(type=self.model.Type.SYMLINK))
def has_license_detections(self):
- return self.filter(~Q(license_detections=[]))
+ return self.filter(~Q(license_detections=[]) | ~Q(license_clues=[]))
def has_no_license_detections(self):
- return self.filter(license_detections=[])
+ return self.filter(Q(license_detections=[]) & Q(license_clues=[]))
def has_package_data(self):
return self.filter(~Q(package_data=[]))
@@ -4218,6 +4218,16 @@ class DiscoveredLicense(
# this is True, and False if this was discovered in a file.
from_package = None
+ is_license_clue = models.BooleanField(
+ default=False,
+ help_text=_(
+ "True if this is not a proper license detection which should be "
+ "considered in the license_expression for the parent resource/package. "
+ "A license match is considered as a clue if it could be a possible"
+ "false positives or the matched rule is tagged as a clue explicitly."
+ ),
+ )
+
detection_count = models.BigIntegerField(
blank=True,
null=True,
diff --git a/scanpipe/pipes/__init__.py b/scanpipe/pipes/__init__.py
index 2edf302cb5..91fc2c2069 100644
--- a/scanpipe/pipes/__init__.py
+++ b/scanpipe/pipes/__init__.py
@@ -328,6 +328,7 @@ def update_or_create_license_detection(
resource_path=None,
from_package=False,
count_detection=True,
+ is_license_clue=False,
):
"""
Get, update or create a DiscoveredLicense object then return it.
@@ -339,7 +340,11 @@ def update_or_create_license_detection(
already. `from_package` is True if the license detection was in a
`extracted_license_statement` from a package metadata.
"""
+ if is_license_clue:
+ detection_data = scancode.get_detection_data_from_clue(detection_data)
+
detection_identifier = detection_data["identifier"]
+ detection_data["is_license_clue"] = is_license_clue
license_detection = project.discoveredlicenses.get_or_none(
identifier=detection_identifier,
@@ -355,10 +360,10 @@ def update_or_create_license_detection(
)
if not license_detection:
+ detection_data["resource_path"] = resource_path
project.add_error(
model="update_or_create_license_detection",
details=detection_data,
- resource=resource_path,
)
return
diff --git a/scanpipe/pipes/scancode.py b/scanpipe/pipes/scancode.py
index 2e9607f597..7f9bd4e521 100644
--- a/scanpipe/pipes/scancode.py
+++ b/scanpipe/pipes/scancode.py
@@ -39,7 +39,10 @@
from commoncode import fileutils
from commoncode.resource import VirtualCodebase
from extractcode import api as extractcode_api
+from licensedcode.detection import DetectionCategory
from licensedcode.detection import FileRegion
+from licensedcode.detection import LicenseDetectionFromResult
+from licensedcode.detection import LicenseMatchFromResult
from packagedcode import get_package_handler
from packagedcode import models as packagedcode_models
from scancode import Scanner
@@ -488,6 +491,14 @@ def collect_and_create_license_detections(project):
resource_path=resource.path,
)
+ for clue_data in resource.license_clues:
+ pipes.update_or_create_license_detection(
+ project=project,
+ detection_data=clue_data,
+ resource_path=resource.path,
+ is_license_clue=True,
+ )
+
for resource in project.codebaseresources.has_package_data():
for package_mapping in resource.package_data:
package_data = packagedcode_models.PackageData.from_dict(
@@ -511,6 +522,28 @@ def collect_and_create_license_detections(project):
)
+def get_detection_data_from_clue(clue_data):
+ """
+ From a LicenseMatch mapping, create a LicenseDetection mapping by
+ populating the identifier and license_expression fields.
+ """
+ license_match = LicenseMatchFromResult.from_dict(clue_data)
+ license_detection = LicenseDetectionFromResult.from_matches(
+ matches=[license_match],
+ analysis=DetectionCategory.LICENSE_CLUES.value,
+ )
+ license_detection.license_expression = license_match.rule.license_expression
+ license_detection.license_expression_spdx = (
+ license_match.rule.spdx_license_expression()
+ )
+ license_detection.identifier = license_detection.identifier_with_expression
+ return license_detection.to_dict(
+ include_text=True,
+ license_diagnostics=True,
+ license_text_diagnostics=True,
+ )
+
+
def get_file_region(detection_data, resource_path):
"""
From a LicenseDetection mapping `detection_data`, create a FileRegion
@@ -909,6 +942,16 @@ def create_codebase_resources(project, scanned_codebase):
)
logger.debug(f"Add {codebase_resource} to {detection_identifier}")
+ license_clues = getattr(scanned_resource, "license_clues", [])
+ for clue_data in license_clues:
+ pipes.update_or_create_license_detection(
+ project=project,
+ detection_data=clue_data,
+ resource_path=resource_path,
+ is_license_clue=True,
+ )
+ logger.debug(f"Add license clue at {codebase_resource}")
+
packages = getattr(scanned_resource, "package_data", [])
for package_data in packages:
license_detections = package_data.get("license_detections", [])
diff --git a/scanpipe/templates/scanpipe/license_detection_list.html b/scanpipe/templates/scanpipe/license_detection_list.html
index 6b5ced7892..7ae9141f53 100644
--- a/scanpipe/templates/scanpipe/license_detection_list.html
+++ b/scanpipe/templates/scanpipe/license_detection_list.html
@@ -39,6 +39,9 @@
{{ license_detection.detection_count }}
|
+
+ {{ license_detection.is_license_clue }}
+ |
{% if display_compliance_alert %}
diff --git a/scanpipe/templates/scanpipe/panels/license_detections_summary.html b/scanpipe/templates/scanpipe/panels/license_detections_summary.html
index 91bba80863..d9e8b5654d 100644
--- a/scanpipe/templates/scanpipe/panels/license_detections_summary.html
+++ b/scanpipe/templates/scanpipe/panels/license_detections_summary.html
@@ -15,7 +15,7 @@
{% endfor %}
{% if total_counts.all %}
-
+
See all license detections
{{ total_counts.all|intcomma }}
{% if total_counts.with_compliance_error %}
@@ -26,6 +26,18 @@
{% endif %}
{% endif %}
+ {% if license_clues %}
+
+ See all license clues
+ {{ clue_counts.all|intcomma }}
+ {% if clue_counts.with_compliance_error %}
+
+
+ {{ clue_counts.with_compliance_error|intcomma }}
+
+ {% endif %}
+
+ {% endif %}
{% endif %}
\ No newline at end of file
diff --git a/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html b/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html
index d5165a3f21..43bb635e4e 100644
--- a/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html
+++ b/scanpipe/templates/scanpipe/tabset/tab_resource_detections.html
@@ -30,7 +30,7 @@
| License expression |
- License clue detials |
+ License clue details |
|
diff --git a/scanpipe/views.py b/scanpipe/views.py
index c13d323475..4f47eee11b 100644
--- a/scanpipe/views.py
+++ b/scanpipe/views.py
@@ -1107,8 +1107,11 @@ class ProjectLicenseDetectionSummaryView(ConditionalLoginRequired, generic.Detai
@staticmethod
def get_license_detection_summary(project, limit=10):
+ proper_license_detections = project.discoveredlicenses.filter(
+ is_license_clue=False,
+ )
license_counter = count_group_by(
- project.discoveredlicenses, "license_expression"
+ proper_license_detections, "license_expression"
)
if list(license_counter.keys()) == [""]:
@@ -1126,7 +1129,7 @@ def get_license_detection_summary(project, limit=10):
expressions_with_compliance_alert = []
for license_expression in top_licenses.keys():
has_compliance_alert = (
- project.discoveredlicenses.filter(license_expression=license_expression)
+ proper_license_detections.filter(license_expression=license_expression)
.has_compliance_alert()
.exists()
)
@@ -1135,21 +1138,39 @@ def get_license_detection_summary(project, limit=10):
total_counts = {
"with_compliance_error": (
- project.discoveredlicenses.has_compliance_alert().count()
+ proper_license_detections.has_compliance_alert().count()
),
- "all": project.discoveredlicenses.count(),
+ "all": proper_license_detections.count(),
}
- return top_licenses, expressions_with_compliance_alert, total_counts
+ license_clues = project.discoveredlicenses.filter(
+ is_license_clue=True,
+ )
+ clue_counts = {}
+ if license_clues.exists():
+ clue_counts = {
+ "with_compliance_error": (license_clues.has_compliance_alert().count()),
+ "all": license_clues.count(),
+ }
+
+ return (
+ top_licenses,
+ expressions_with_compliance_alert,
+ total_counts,
+ license_clues,
+ clue_counts,
+ )
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
- summary, expressions, counts = self.get_license_detection_summary(
- project=self.object
+ summary, expressions, counts, clues, clue_counts = (
+ self.get_license_detection_summary(project=self.object)
)
context["license_detection_summary"] = summary
context["expressions_with_compliance_alert"] = expressions
context["total_counts"] = counts
+ context["license_clues"] = clues
+ context["clue_counts"] = clue_counts
context["project_licenses_url"] = reverse(
"project_licenses", args=[self.object.slug]
)
@@ -1850,6 +1871,7 @@ class DiscoveredLicenseListView(
"filter_fieldname": "license_expression_spdx",
},
"detection_count",
+ "is_license_clue",
{
"field_name": "compliance_alert",
"filter_fieldname": "compliance_alert",
From 519e6b019d4a8efa6d3dad1fc8b5464f225b2745 Mon Sep 17 00:00:00 2001
From: Ayan Sinha Mahapatra
Date: Wed, 16 Jul 2025 20:28:33 +0530
Subject: [PATCH 14/14] Show license detection issues using `--todo` option
Signed-off-by: Ayan Sinha Mahapatra
---
scanpipe/filters.py | 2 +
.../0074_discovered_license_models.py | 35 ++++
scanpipe/models.py | 45 ++++-
scanpipe/pipelines/scan_single_package.py | 3 +
scanpipe/pipes/__init__.py | 27 ++-
scanpipe/pipes/input.py | 1 +
scanpipe/pipes/scancode.py | 56 +++++++
.../scanpipe/license_detection_list.html | 8 +
.../panels/license_detections_summary.html | 12 ++
.../tabset/tab_license_detections.html | 18 ++
.../data/asgiref/asgiref-3.3.0.spdx.json | 42 ++---
.../data/asgiref/asgiref-3.3.0_fixtures.json | 158 +++++++++++-------
.../asgiref-3.3.0_scanpipe_output.json | 134 ++++++++++-----
.../asgiref/asgiref-3.3.0_toolkit_scan.json | 62 +++----
.../asgiref-3.3.0_walk_test_fixtures.json | 158 +++++++++++-------
.../data/cyclonedx/asgiref-3.3.0.cdx.json | 36 ++--
.../openpdf-parent-1.3.11_scan_package.json | 18 +-
.../scancode/is-npm-1.0.0_scan_package.json | 24 ++-
.../is-npm-1.0.0_scan_package_summary.json | 4 +-
.../data/scancode/is-npm-1.0.0_summary.json | 4 +-
.../multiple-is-npm-1.0.0_scan_package.json | 37 +++-
...ple-is-npm-1.0.0_scan_package_summary.json | 4 +-
.../scancode/package_assembly_codebase.json | 16 +-
scanpipe/tests/pipes/test_output.py | 2 +-
scanpipe/tests/test_models.py | 2 +-
scanpipe/views.py | 7 +-
26 files changed, 654 insertions(+), 261 deletions(-)
diff --git a/scanpipe/filters.py b/scanpipe/filters.py
index 6a826c02a8..91da843543 100644
--- a/scanpipe/filters.py
+++ b/scanpipe/filters.py
@@ -857,6 +857,7 @@ class LicenseFilterSet(FilterSetUtilsMixin, django_filters.FilterSet):
choices=[(EMPTY_VAR, "None")] + CodebaseResource.Compliance.choices,
)
is_license_clue = StrictBooleanFilter()
+ needs_review = StrictBooleanFilter()
class Meta:
model = DiscoveredLicense
@@ -868,6 +869,7 @@ class Meta:
"license_expression_spdx",
"compliance_alert",
"is_license_clue",
+ "needs_review",
]
diff --git a/scanpipe/migrations/0074_discovered_license_models.py b/scanpipe/migrations/0074_discovered_license_models.py
index 5aa0ad5bea..f6e29d02e5 100644
--- a/scanpipe/migrations/0074_discovered_license_models.py
+++ b/scanpipe/migrations/0074_discovered_license_models.py
@@ -102,6 +102,20 @@ class Migration(migrations.Migration):
help_text='True if this is not a proper license detection which should be considered in the license_expression for the parent resource/package. A license match is considered as a clue if it could be a possiblefalse positives or the matched rule is tagged as a clue explicitly.',
),
),
+ (
+ "from_package",
+ models.BooleanField(
+ default=False,
+ help_text='True if this was discovered in a extracted license statement and False if this was discovered in a file.',
+ ),
+ ),
+ (
+ "needs_review",
+ models.BooleanField(
+ default=False,
+ help_text='True if this was license detection needs to be reviewed as there might be a license detection issue.',
+ ),
+ ),
(
"project",
models.ForeignKey(
@@ -111,6 +125,15 @@ class Migration(migrations.Migration):
to="scanpipe.project",
),
),
+ (
+ "review_comments",
+ models.JSONField(
+ blank=True,
+ default=list,
+ help_text='A list of review comments for license detection issues which needs review. These descriptive comments are based on ambigous detection types and could also offers helpful suggestions on how to review/report these detection issues.',
+ verbose_name='Review Comments',
+ ),
+ ),
],
options={
"ordering": ["detection_count", "identifier"],
@@ -130,6 +153,18 @@ class Migration(migrations.Migration):
fields=["detection_count"],
name="scanpipe_di_detecti_d87ff1_idx",
),
+ models.Index(
+ fields=['is_license_clue'],
+ name='scanpipe_di_is_lice_f4922a_idx'
+ ),
+ models.Index(
+ fields=['from_package'],
+ name='scanpipe_di_from_pa_6485b2_idx'
+ ),
+ models.Index(
+ fields=['needs_review'],
+ name='scanpipe_di_needs_r_5cff82_idx'
+ ),
],
},
bases=(
diff --git a/scanpipe/models.py b/scanpipe/models.py
index 2f7e6238ae..da726c4b8c 100644
--- a/scanpipe/models.py
+++ b/scanpipe/models.py
@@ -4146,6 +4146,12 @@ class DiscoveredLicenseQuerySet(
ComplianceAlertQuerySetMixin,
ProjectRelatedQuerySet,
):
+ def needs_review(self):
+ return self.filter(needs_review=True)
+
+ def does_not_need_review(self):
+ return self.filter(needs_review=False)
+
def order_by_count_and_expression(self):
"""Order by detection count and license expression (identifer) fields."""
return self.order_by("-detection_count", "identifier")
@@ -4214,9 +4220,13 @@ class DiscoveredLicense(
license_expression_field = "license_expression"
- # If this license was discovered in a extracted license statement
- # this is True, and False if this was discovered in a file.
- from_package = None
+ from_package = models.BooleanField(
+ default=False,
+ help_text=_(
+ "True if this was discovered in a extracted license statement "
+ "and False if this was discovered in a file."
+ ),
+ )
is_license_clue = models.BooleanField(
default=False,
@@ -4246,6 +4256,26 @@ class DiscoveredLicense(
),
)
+ needs_review = models.BooleanField(
+ default=False,
+ help_text=_(
+ "True if this was license detection needs to be reviewed "
+ "as there might be a license detection issue."
+ ),
+ )
+
+ review_comments = models.JSONField(
+ _("Review Comments"),
+ default=list,
+ blank=True,
+ help_text=_(
+ "A list of review comments for license detection issues which "
+ "needs review. These descriptive comments are based on ambigous "
+ "detection types and could also offers helpful suggestions on "
+ "how to review/report these detection issues."
+ ),
+ )
+
objects = DiscoveredLicenseQuerySet.as_manager()
class Meta:
@@ -4255,6 +4285,9 @@ class Meta:
models.Index(fields=["license_expression"]),
models.Index(fields=["license_expression_spdx"]),
models.Index(fields=["detection_count"]),
+ models.Index(fields=["is_license_clue"]),
+ models.Index(fields=["from_package"]),
+ models.Index(fields=["needs_review"]),
]
constraints = [
models.UniqueConstraint(
@@ -4268,7 +4301,7 @@ def __str__(self):
return self.identifier
@classmethod
- def create_from_data(cls, project, detection_data):
+ def create_from_data(cls, project, detection_data, from_package=False):
"""
Create and returns a DiscoveredLicense for a `project` from the
`detection_data`. If one of the values of the required fields is not
@@ -4302,7 +4335,9 @@ def create_from_data(cls, project, detection_data):
if field_name in cls.model_fields() and value not in EMPTY_VALUES
}
- discovered_license = cls(project=project, **cleaned_data)
+ discovered_license = cls(
+ project=project, from_package=from_package, **cleaned_data
+ )
# Using save_error=False to not capture potential errors at this level but
# rather in the CodebaseResource.create_and_add_license_data method so
# resource data can be injected in the ProjectMessage record.
diff --git a/scanpipe/pipelines/scan_single_package.py b/scanpipe/pipelines/scan_single_package.py
index c8753b90de..605ef0ea5d 100644
--- a/scanpipe/pipelines/scan_single_package.py
+++ b/scanpipe/pipelines/scan_single_package.py
@@ -61,11 +61,14 @@ def steps(cls):
"info": True,
"license": True,
"license_text": True,
+ "license_diagnostics": True,
+ "license_text_diagnostics": True,
"license_references": True,
"package": True,
"url": True,
"classify": True,
"summary": True,
+ "todo": True,
}
def get_package_input(self):
diff --git a/scanpipe/pipes/__init__.py b/scanpipe/pipes/__init__.py
index 91fc2c2069..59d4039b1c 100644
--- a/scanpipe/pipes/__init__.py
+++ b/scanpipe/pipes/__init__.py
@@ -329,6 +329,7 @@ def update_or_create_license_detection(
from_package=False,
count_detection=True,
is_license_clue=False,
+ check_todo=False,
):
"""
Get, update or create a DiscoveredLicense object then return it.
@@ -355,8 +356,9 @@ def update_or_create_license_detection(
license_detection.update_from_data(detection_data)
else:
license_detection = DiscoveredLicense.create_from_data(
- project,
- detection_data,
+ project=project,
+ detection_data=detection_data,
+ from_package=from_package,
)
if not license_detection:
@@ -377,7 +379,9 @@ def update_or_create_license_detection(
count_detection=count_detection,
)
- license_detection.from_package = from_package
+ if check_todo:
+ scancode.check_license_detection_for_issues(license_detection)
+
return license_detection
@@ -399,6 +403,23 @@ def _clean_license_detection_data(detection_data):
return detection_data
+def update_license_detection_with_issue(project, todo_issue):
+ detection_data = todo_issue.get("detection")
+ if "identifier" not in detection_data:
+ return
+
+ detection_identifier = detection_data.get("identifier")
+ license_detection = project.discoveredlicenses.get_or_none(
+ identifier=detection_identifier,
+ )
+ if license_detection:
+ review_comments = todo_issue.get("review_comments").values()
+ license_detection.update(
+ needs_review=True,
+ review_comments=list(review_comments),
+ )
+
+
def get_dependencies(project, dependency_data):
"""
Given a `dependency_data` mapping, get a list of DiscoveredDependency objects
diff --git a/scanpipe/pipes/input.py b/scanpipe/pipes/input.py
index e88f1edfa4..58ec2e5c96 100644
--- a/scanpipe/pipes/input.py
+++ b/scanpipe/pipes/input.py
@@ -108,6 +108,7 @@ def load_inventory_from_toolkit_scan(project, input_location):
scancode.create_discovered_dependencies(
project, scanned_codebase, strip_datafile_path_root=True
)
+ scancode.load_todo_issues(project, scanned_codebase)
def load_inventory_from_scanpipe(project, scan_data, extra_data_prefix=None):
diff --git a/scanpipe/pipes/scancode.py b/scanpipe/pipes/scancode.py
index 7f9bd4e521..8f169311d2 100644
--- a/scanpipe/pipes/scancode.py
+++ b/scanpipe/pipes/scancode.py
@@ -43,12 +43,16 @@
from licensedcode.detection import FileRegion
from licensedcode.detection import LicenseDetectionFromResult
from licensedcode.detection import LicenseMatchFromResult
+from licensedcode.detection import UniqueDetection
+from licensedcode.detection import get_ambiguous_license_detections_by_type
from packagedcode import get_package_handler
from packagedcode import models as packagedcode_models
from scancode import Scanner
from scancode import api as scancode_api
from scancode import cli as scancode_cli
from scancode.cli import run_scan as scancode_run_scan
+from summarycode.todo import ReviewComments
+from summarycode.todo import get_review_comments
from aboutcode.pipeline import LoopProgress
from scanpipe import pipes
@@ -489,6 +493,7 @@ def collect_and_create_license_detections(project):
project=project,
detection_data=detection_data,
resource_path=resource.path,
+ check_todo=True,
)
for clue_data in resource.license_clues:
@@ -497,6 +502,7 @@ def collect_and_create_license_detections(project):
detection_data=clue_data,
resource_path=resource.path,
is_license_clue=True,
+ check_todo=True,
)
for resource in project.codebaseresources.has_package_data():
@@ -511,6 +517,7 @@ def collect_and_create_license_detections(project):
detection_data=detection,
resource_path=resource.path,
from_package=True,
+ check_todo=True,
)
for detection in package_data.other_license_detections:
@@ -519,6 +526,7 @@ def collect_and_create_license_detections(project):
detection_data=detection,
resource_path=resource.path,
from_package=True,
+ check_todo=True,
)
@@ -1022,6 +1030,54 @@ def create_discovered_licenses(project, scanned_codebase):
pipes.update_or_create_license_detection(project, detection_data)
+def load_todo_issues(project, scanned_codebase):
+ if hasattr(scanned_codebase.attributes, "todo"):
+ for todo_issue in scanned_codebase.attributes.todo:
+ pipes.update_license_detection_with_issue(project, todo_issue)
+
+ license_clues = project.discoveredlicenses.filter(
+ is_license_clue=True,
+ )
+ license_clues.update(
+ needs_review=True,
+ review_comments=[ReviewComments.LICENSE_CLUES.value],
+ )
+
+
+def check_license_detection_for_issues(discovered_license):
+ file_regions = [
+ FileRegion(
+ path=file_region.get("path"),
+ start_line=file_region.get("start_line"),
+ end_line=file_region.get("end_line"),
+ )
+ for file_region in discovered_license.file_regions
+ ]
+ matches = [
+ LicenseMatchFromResult.from_dict(license_match)
+ for license_match in discovered_license.matches
+ ]
+ unique_detection = UniqueDetection(
+ identifier=discovered_license.identifier,
+ license_expression=discovered_license.license_expression,
+ license_expression_spdx=discovered_license.license_expression_spdx,
+ detection_count=discovered_license.detection_count,
+ detection_log=discovered_license.detection_log,
+ matches=matches,
+ file_regions=file_regions,
+ )
+ detections_by_issue_type = get_ambiguous_license_detections_by_type(
+ unique_license_detections=[unique_detection],
+ )
+ if detections_by_issue_type:
+ issue_type = next(iter(detections_by_issue_type))
+ review_comments = get_review_comments(detection_log=[issue_type])
+ discovered_license.update(
+ needs_review=True,
+ review_comments=list(review_comments.values()),
+ )
+
+
def set_codebase_resource_for_package(codebase_resource, discovered_package):
"""
Assign the `discovered_package` to the `codebase_resource` and set its
diff --git a/scanpipe/templates/scanpipe/license_detection_list.html b/scanpipe/templates/scanpipe/license_detection_list.html
index 7ae9141f53..6ea52f5196 100644
--- a/scanpipe/templates/scanpipe/license_detection_list.html
+++ b/scanpipe/templates/scanpipe/license_detection_list.html
@@ -24,6 +24,11 @@
{# CAUTION: Avoid relying on get_absolute_url to prevent unnecessary query triggers #}
{{ license_detection.identifier }}
+ {% if license_detection.needs_review %}
+
+
+
+ {% endif %}
{% if license_detection.has_compliance_alert %}
@@ -42,6 +47,9 @@
|
{{ license_detection.is_license_clue }}
|
+
+ {{ license_detection.needs_review }}
+ |
{% if display_compliance_alert %}
diff --git a/scanpipe/templates/scanpipe/panels/license_detections_summary.html b/scanpipe/templates/scanpipe/panels/license_detections_summary.html
index d9e8b5654d..d31b5e41ab 100644
--- a/scanpipe/templates/scanpipe/panels/license_detections_summary.html
+++ b/scanpipe/templates/scanpipe/panels/license_detections_summary.html
@@ -18,6 +18,12 @@
See all license detections
{{ total_counts.all|intcomma }}
+ {% if total_counts.needs_review %}
+
+
+ {{ total_counts.needs_review|intcomma }}
+
+ {% endif %}
{% if total_counts.with_compliance_error %}
@@ -30,6 +36,12 @@
See all license clues
{{ clue_counts.all|intcomma }}
+ {% if clue_counts.needs_review %}
+
+
+ {{ clue_counts.needs_review|intcomma }}
+
+ {% endif %}
{% if clue_counts.with_compliance_error %}
diff --git a/scanpipe/templates/scanpipe/tabset/tab_license_detections.html b/scanpipe/templates/scanpipe/tabset/tab_license_detections.html
index 6903978b9b..bff482ff43 100644
--- a/scanpipe/templates/scanpipe/tabset/tab_license_detections.html
+++ b/scanpipe/templates/scanpipe/tabset/tab_license_detections.html
@@ -72,6 +72,24 @@
|
{% endif %}
+ {% if tab_data.fields.review_comments.value %}
+
+
+
+ | Review Comments |
+
+
+
+ {% for comment in tab_data.fields.review_comments.value %}
+
+ |
+ {{ comment }}
+ |
+
+ {% endfor %}
+
+
+ {% endif %}
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 07e04fd069..86bb3ba6f6 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/1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "documentNamespace": "https://scancode.io/spdxdocs/804c3391-e6f9-415f-bb7a-cb6653853a46",
"creationInfo": {
"created": "2000-01-01T01:02:03Z",
"creators": [
@@ -14,7 +14,7 @@
"packages": [
{
"name": "asgiref",
- "SPDXID": "SPDXRef-scancodeio-discoveredpackage-b4e16c8a-f564-4379-9de9-ea2aaba08d94",
+ "SPDXID": "SPDXRef-scancodeio-discoveredpackage-9d0bdc32-1117-407a-9908-08d3558dc739",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "BSD-3-Clause",
"copyrightText": "NOASSERTION",
@@ -33,7 +33,7 @@
},
{
"name": "asgiref",
- "SPDXID": "SPDXRef-scancodeio-discoveredpackage-80e083f1-7d05-432e-96f8-e6dfd9e494f0",
+ "SPDXID": "SPDXRef-scancodeio-discoveredpackage-7969de5e-5589-4441-bffa-a60e12b43280",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "BSD-3-Clause",
"copyrightText": "NOASSERTION",
@@ -52,7 +52,7 @@
},
{
"name": "pytest",
- "SPDXID": "SPDXRef-scancodeio-discovereddependency-05f9bf8f-4da8-488e-9f48-6e183c4b813b",
+ "SPDXID": "SPDXRef-scancodeio-discovereddependency-4cff8bf8-197c-4698-a43a-5c793586c780",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION",
@@ -68,7 +68,7 @@
},
{
"name": "pytest",
- "SPDXID": "SPDXRef-scancodeio-discovereddependency-43988fc2-bc0e-4c81-b083-7c5f21a7be50",
+ "SPDXID": "SPDXRef-scancodeio-discovereddependency-4c5c1313-3850-4f81-ac27-8d496080d667",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION",
@@ -84,7 +84,7 @@
},
{
"name": "pytest-asyncio",
- "SPDXID": "SPDXRef-scancodeio-discovereddependency-ea25292c-05af-4982-9596-866c5de9d8cd",
+ "SPDXID": "SPDXRef-scancodeio-discovereddependency-f983278c-22f1-43e1-ba2b-a020d659531b",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION",
@@ -100,7 +100,7 @@
},
{
"name": "pytest-asyncio",
- "SPDXID": "SPDXRef-scancodeio-discovereddependency-a0b6b6e7-5e75-4b69-9742-b04fe8a594a3",
+ "SPDXID": "SPDXRef-scancodeio-discovereddependency-98aeddb5-b81a-43d4-ac56-dc873a589fdf",
"downloadLocation": "NOASSERTION",
"licenseConcluded": "NOASSERTION",
"copyrightText": "NOASSERTION",
@@ -116,33 +116,33 @@
}
],
"documentDescribes": [
- "SPDXRef-scancodeio-discoveredpackage-b4e16c8a-f564-4379-9de9-ea2aaba08d94",
- "SPDXRef-scancodeio-discoveredpackage-80e083f1-7d05-432e-96f8-e6dfd9e494f0",
- "SPDXRef-scancodeio-discovereddependency-05f9bf8f-4da8-488e-9f48-6e183c4b813b",
- "SPDXRef-scancodeio-discovereddependency-43988fc2-bc0e-4c81-b083-7c5f21a7be50",
- "SPDXRef-scancodeio-discovereddependency-ea25292c-05af-4982-9596-866c5de9d8cd",
- "SPDXRef-scancodeio-discovereddependency-a0b6b6e7-5e75-4b69-9742-b04fe8a594a3"
+ "SPDXRef-scancodeio-discoveredpackage-9d0bdc32-1117-407a-9908-08d3558dc739",
+ "SPDXRef-scancodeio-discoveredpackage-7969de5e-5589-4441-bffa-a60e12b43280",
+ "SPDXRef-scancodeio-discovereddependency-4cff8bf8-197c-4698-a43a-5c793586c780",
+ "SPDXRef-scancodeio-discovereddependency-4c5c1313-3850-4f81-ac27-8d496080d667",
+ "SPDXRef-scancodeio-discovereddependency-f983278c-22f1-43e1-ba2b-a020d659531b",
+ "SPDXRef-scancodeio-discovereddependency-98aeddb5-b81a-43d4-ac56-dc873a589fdf"
],
"files": [],
"relationships": [
{
- "spdxElementId": "SPDXRef-scancodeio-discovereddependency-05f9bf8f-4da8-488e-9f48-6e183c4b813b",
- "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-b4e16c8a-f564-4379-9de9-ea2aaba08d94",
+ "spdxElementId": "SPDXRef-scancodeio-discovereddependency-4cff8bf8-197c-4698-a43a-5c793586c780",
+ "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-9d0bdc32-1117-407a-9908-08d3558dc739",
"relationshipType": "DEPENDENCY_OF"
},
{
- "spdxElementId": "SPDXRef-scancodeio-discovereddependency-43988fc2-bc0e-4c81-b083-7c5f21a7be50",
- "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-80e083f1-7d05-432e-96f8-e6dfd9e494f0",
+ "spdxElementId": "SPDXRef-scancodeio-discovereddependency-4c5c1313-3850-4f81-ac27-8d496080d667",
+ "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-7969de5e-5589-4441-bffa-a60e12b43280",
"relationshipType": "DEPENDENCY_OF"
},
{
- "spdxElementId": "SPDXRef-scancodeio-discovereddependency-ea25292c-05af-4982-9596-866c5de9d8cd",
- "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-b4e16c8a-f564-4379-9de9-ea2aaba08d94",
+ "spdxElementId": "SPDXRef-scancodeio-discovereddependency-f983278c-22f1-43e1-ba2b-a020d659531b",
+ "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-9d0bdc32-1117-407a-9908-08d3558dc739",
"relationshipType": "DEPENDENCY_OF"
},
{
- "spdxElementId": "SPDXRef-scancodeio-discovereddependency-a0b6b6e7-5e75-4b69-9742-b04fe8a594a3",
- "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-80e083f1-7d05-432e-96f8-e6dfd9e494f0",
+ "spdxElementId": "SPDXRef-scancodeio-discovereddependency-98aeddb5-b81a-43d4-ac56-dc873a589fdf",
+ "relatedSpdxElement": "SPDXRef-scancodeio-discoveredpackage-7969de5e-5589-4441-bffa-a60e12b43280",
"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 91d9a866b7..12d2e50319 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": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "pk": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"fields": {
"extra_data": {},
- "created_date": "2025-06-30T19:56:37.439Z",
+ "created_date": "2025-07-16T15:27:02.698Z",
"name": "asgiref",
- "slug": "asgiref-1cdd3f3a",
- "work_directory": "/tmp/tmpw3r_lrtn/projects/asgiref-1cdd3f3a",
+ "slug": "asgiref-804c3391",
+ "work_directory": "/tmp/tmp7oqqjl0j/projects/asgiref-804c3391",
"is_archived": false,
"notes": "",
"settings": {},
@@ -16,17 +16,17 @@
},
{
"model": "scanpipe.run",
- "pk": "5bd1dcf6-b369-45a6-a2dc-dfe05f9a25cf",
+ "pk": "6188f85f-da57-473f-84e0-e75723714e2d",
"fields": {
"task_id": null,
"task_start_date": null,
"task_end_date": null,
"task_exitcode": null,
"task_output": "",
- "log": "2025-06-30 19:56:37.442 Pipeline [scan_codebase] starting\n2025-06-30 19:56:37.443 Step [download_missing_inputs] starting\n2025-06-30 19:56:37.444 Step [download_missing_inputs] completed in 0 seconds\n2025-06-30 19:56:37.445 Step [copy_inputs_to_codebase_directory] starting\n2025-06-30 19:56:37.446 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2025-06-30 19:56:37.446 Step [extract_archives] starting\n2025-06-30 19:56:37.502 Step [extract_archives] completed in 0 seconds\n2025-06-30 19:56:37.504 Step [collect_and_create_codebase_resources] starting\n2025-06-30 19:56:37.705 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2025-06-30 19:56:37.707 Step [flag_empty_files] starting\n2025-06-30 19:56:37.709 Step [flag_empty_files] completed in 0 seconds\n2025-06-30 19:56:37.710 Step [flag_ignored_resources] starting\n2025-06-30 19:56:37.716 Step [flag_ignored_resources] completed in 0 seconds\n2025-06-30 19:56:37.717 Step [scan_for_application_packages] starting\n2025-06-30 19:56:37.718 Collecting package data from resources:\n2025-06-30 19:56:37.800 Progress: 11% (2/18) ETA: 1 seconds\n2025-06-30 19:56:37.831 Progress: 22% (4/18)\n2025-06-30 19:56:37.834 Progress: 33% (6/18)\n2025-06-30 19:56:37.836 Progress: 44% (8/18)\n2025-06-30 19:56:37.837 Progress: 55% (10/18)\n2025-06-30 19:56:37.839 Progress: 66% (12/18)\n2025-06-30 19:56:37.844 Progress: 77% (14/18)\n2025-06-30 19:56:37.862 Progress: 88% (16/18)\n2025-06-30 19:56:41.912 Progress: 100% (18/18)\n2025-06-30 19:56:41.974 Assembling collected package data:\n2025-06-30 19:56:41.975 Progress: 0%\n2025-06-30 19:56:42.044 Step [scan_for_application_packages] completed in 4 seconds\n2025-06-30 19:56:42.045 Step [scan_for_files] starting\n2025-06-30 19:57:51.517 Progress: 12% (2/16) ETA: 509 seconds (8.5 minutes)\n2025-06-30 19:57:51.803 Progress: 25% (4/16) ETA: 209 seconds (3.5 minutes)\n2025-06-30 19:57:51.819 Progress: 37% (6/16) ETA: 119 seconds (2.0 minutes)\n2025-06-30 19:57:51.852 Progress: 50% (8/16) ETA: 70 seconds (1.2 minutes)\n2025-06-30 19:57:51.875 Progress: 62% (10/16) ETA: 43 seconds\n2025-06-30 19:57:51.899 Progress: 75% (12/16) ETA: 23 seconds\n2025-06-30 19:57:51.927 Progress: 87% (14/16) ETA: 10 seconds\n2025-06-30 19:57:52.377 Progress: 100% (16/16)\n2025-06-30 19:57:52.765 Step [scan_for_files] completed in 71 seconds (1.2 minutes)\n2025-06-30 19:57:52.767 Pipeline completed in 75 seconds (1.3 minutes)\n",
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "log": "2025-07-16 15:27:02.700 Pipeline [scan_codebase] starting\n2025-07-16 15:27:02.701 Step [download_missing_inputs] starting\n2025-07-16 15:27:02.702 Step [download_missing_inputs] completed in 0 seconds\n2025-07-16 15:27:02.703 Step [copy_inputs_to_codebase_directory] starting\n2025-07-16 15:27:02.703 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2025-07-16 15:27:02.704 Step [extract_archives] starting\n2025-07-16 15:27:02.756 Step [extract_archives] completed in 0 seconds\n2025-07-16 15:27:02.758 Step [collect_and_create_codebase_resources] starting\n2025-07-16 15:27:02.929 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2025-07-16 15:27:02.930 Step [flag_empty_files] starting\n2025-07-16 15:27:02.932 Step [flag_empty_files] completed in 0 seconds\n2025-07-16 15:27:02.933 Step [flag_ignored_resources] starting\n2025-07-16 15:27:02.935 Step [flag_ignored_resources] completed in 0 seconds\n2025-07-16 15:27:02.936 Step [scan_for_application_packages] starting\n2025-07-16 15:27:02.937 Collecting package data from resources:\n2025-07-16 15:27:02.978 Progress: 11% (2/18)\n2025-07-16 15:27:03.005 Progress: 22% (4/18)\n2025-07-16 15:27:03.014 Progress: 33% (6/18)\n2025-07-16 15:27:03.017 Progress: 44% (8/18)\n2025-07-16 15:27:03.019 Progress: 55% (10/18)\n2025-07-16 15:27:03.020 Progress: 66% (12/18)\n2025-07-16 15:27:03.021 Progress: 77% (14/18)\n2025-07-16 15:27:03.022 Progress: 88% (16/18)\n2025-07-16 15:27:06.312 Progress: 100% (18/18)\n2025-07-16 15:27:06.372 Assembling collected package data:\n2025-07-16 15:27:06.373 Progress: 0%\n2025-07-16 15:27:09.130 Step [scan_for_application_packages] completed in 6 seconds\n2025-07-16 15:27:09.131 Step [scan_for_files] starting\n2025-07-16 15:27:09.467 Progress: 12% (2/16) ETA: 2 seconds\n2025-07-16 15:27:09.475 Progress: 25% (4/16) ETA: 1 seconds\n2025-07-16 15:27:09.484 Progress: 37% (6/16) ETA: 1 seconds\n2025-07-16 15:27:09.700 Progress: 50% (8/16) ETA: 1 seconds\n2025-07-16 15:27:09.877 Progress: 62% (10/16)\n2025-07-16 15:27:09.933 Progress: 75% (12/16)\n2025-07-16 15:27:09.958 Progress: 87% (14/16)\n2025-07-16 15:27:10.158 Progress: 100% (16/16)\n2025-07-16 15:27:10.204 Step [scan_for_files] completed in 1 seconds\n2025-07-16 15:27:10.206 Step [collect_and_create_license_detections] starting\n2025-07-16 15:27:10.221 Step [collect_and_create_license_detections] completed in 0 seconds\n2025-07-16 15:27:10.222 Pipeline completed in 8 seconds\n",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"pipeline_name": "scan_codebase",
- "created_date": "2025-06-30T19:56:37.441Z",
+ "created_date": "2025-07-16T15:27:02.699Z",
"scancodeio_version": "",
"description": "Scan a codebase for application packages, licenses, and copyrights.",
"current_step": "",
@@ -43,7 +43,7 @@
"sha256": "a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -353,7 +353,7 @@
"sha256": "",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -398,7 +398,7 @@
"sha256": "",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -443,7 +443,7 @@
"sha256": "",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -488,7 +488,7 @@
"sha256": "6e89108c2cf0c0446174188f76f60465ae1c1f14f83427807df40d52a27cb2c8",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -533,12 +533,35 @@
"sha256": "b846415d1b514e9c1dff14a22deb906d794bc546ca6129f950a18cd091e2a669",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "detected_license_expression": "",
- "detected_license_expression_spdx": "",
- "license_detections": [],
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "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",
+ "license_expression_spdx": "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": null,
+ "percentage_of_license_text": 95.11,
"copyrights": [
{
"end_line": 1,
@@ -556,7 +579,7 @@
"authors": [],
"emails": [],
"urls": [],
- "compliance_alert": "",
+ "compliance_alert": "error",
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -590,7 +613,7 @@
"sha256": "70f98f4eb9f6068b192b5464fcdf69e29a8ff09962bfce84bbb052baeee44f33",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -900,7 +923,7 @@
"sha256": "11546323af45e6a5639bf620a9c4d73e74c0bf705f494af4595007b923f75e8a",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -945,7 +968,7 @@
"sha256": "2c1983592aa38f0bfb0afacc73ddc5b46ce10e8e89ceaa9fed1e5fc6361b608d",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -990,7 +1013,7 @@
"sha256": "30f49b9094bff904a42caeec32515715fe625a56dc48bd7c0e3d9988c0ad4bd7",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1035,7 +1058,7 @@
"sha256": "fa4651a3b79201a4dc44a4096cd49ec8f427e912ea0ee05c666357b413a8afe7",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1080,7 +1103,7 @@
"sha256": "ee0fcf4a8e6fa9df8a4643bb48e82892d496afce44b6c8b8aea2721755545e1c",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1125,7 +1148,7 @@
"sha256": "3151f66c476208c3154cb6c4fb557a2a253bab82f0ab33fb3c8b9f7976be9e33",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1170,7 +1193,7 @@
"sha256": "ddd445b778c097fc75c2bf69ad964cbadd3bd6999d1dd2306d39d401855e8e3e",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1215,7 +1238,7 @@
"sha256": "ddbc8d455eceb68fc583c67e7c4ad0277c867fb39095c51ec5b37f70342e8334",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1260,12 +1283,35 @@
"sha256": "126c3e3a8a75a517d2739612304607804cf5f34da63fa25d03a6f11f7edb6f2f",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "detected_license_expression": "",
- "detected_license_expression_spdx": "",
- "license_detections": [],
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "detected_license_expression": "apache-2.0",
+ "detected_license_expression_spdx": "Apache-2.0",
+ "license_detections": [
+ {
+ "matches": [
+ {
+ "score": 100.0,
+ "matcher": "2-aho",
+ "end_line": 2,
+ "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/apache-2.0_174.RULE",
+ "from_file": null,
+ "start_line": 2,
+ "matched_text": "# under the Apache 2.0 license. You may see the original project at",
+ "match_coverage": 100.0,
+ "matched_length": 6,
+ "rule_relevance": 100,
+ "rule_identifier": "apache-2.0_174.RULE",
+ "license_expression": "apache-2.0",
+ "license_expression_spdx": "Apache-2.0"
+ }
+ ],
+ "identifier": "apache_2_0-5a90b5fa-5d10-5a98-d2a7-ef089c46a900",
+ "license_expression": "apache-2.0",
+ "license_expression_spdx": "Apache-2.0"
+ }
+ ],
"license_clues": [],
- "percentage_of_license_text": null,
+ "percentage_of_license_text": 1.22,
"copyrights": [],
"holders": [],
"authors": [],
@@ -1287,7 +1333,7 @@
"start_line": 83
}
],
- "compliance_alert": "",
+ "compliance_alert": "error",
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -1321,7 +1367,7 @@
"sha256": "f8bd1ea3fb8afddabb10f8efd66796d41446cad51168ef4d3c44b19c973d0ad0",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1366,7 +1412,7 @@
"sha256": "885267fee0fea687875a02ceb929ca095312d47aaa57e20e4ce382f397caaf4d",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1412,7 +1458,7 @@
"version": "3.3.0",
"qualifiers": "",
"subpath": "",
- "uuid": "b4e16c8a-f564-4379-9de9-ea2aaba08d94",
+ "uuid": "9d0bdc32-1117-407a-9908-08d3558dc739",
"md5": "",
"sha1": "",
"sha256": "",
@@ -1422,8 +1468,8 @@
"Documentation": "https://asgi.readthedocs.io/",
"Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions"
},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "compliance_alert": "",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "compliance_alert": "error",
"affected_by_vulnerabilities": [],
"filename": "",
"primary_language": "Python",
@@ -1513,7 +1559,7 @@
],
"missing_resources": [],
"modified_resources": [],
- "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd",
"keywords": [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
@@ -1546,7 +1592,7 @@
"version": "3.3.0",
"qualifiers": "",
"subpath": "",
- "uuid": "80e083f1-7d05-432e-96f8-e6dfd9e494f0",
+ "uuid": "7969de5e-5589-4441-bffa-a60e12b43280",
"md5": "",
"sha1": "",
"sha256": "",
@@ -1556,8 +1602,8 @@
"Documentation": "https://asgi.readthedocs.io/",
"Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions"
},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "compliance_alert": "",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "compliance_alert": "error",
"affected_by_vulnerabilities": [],
"filename": "",
"primary_language": "Python",
@@ -1647,7 +1693,7 @@
],
"missing_resources": [],
"modified_resources": [],
- "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
"keywords": [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
@@ -1693,10 +1739,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "05f9bf8f-4da8-488e-9f48-6e183c4b813b",
+ "uuid": "4cff8bf8-197c-4698-a43a-5c793586c780",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest?uuid=7adc83d4-42ba-42eb-acf2-6a7be8295ba4",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest?uuid=55081a17-fcd9-4032-9ef3-fca2f63bd943",
"for_package": 1,
"resolved_to_package": null,
"datafile_resource": 1,
@@ -1719,10 +1765,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "ea25292c-05af-4982-9596-866c5de9d8cd",
+ "uuid": "f983278c-22f1-43e1-ba2b-a020d659531b",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=194690bd-fe7e-49a7-880f-4e543f60deb8",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=4a12f26f-dc2c-42af-80d0-f719add6c4f5",
"for_package": 1,
"resolved_to_package": null,
"datafile_resource": 1,
@@ -1745,10 +1791,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "43988fc2-bc0e-4c81-b083-7c5f21a7be50",
+ "uuid": "4c5c1313-3850-4f81-ac27-8d496080d667",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest?uuid=2f480940-dae0-455c-9ecc-3a558e082a8f",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest?uuid=ea00e9bf-8060-43e7-9ee4-4617f438636d",
"for_package": 2,
"resolved_to_package": null,
"datafile_resource": 7,
@@ -1771,10 +1817,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "a0b6b6e7-5e75-4b69-9742-b04fe8a594a3",
+ "uuid": "98aeddb5-b81a-43d4-ac56-dc873a589fdf",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=60082b5f-bb24-4225-8fd9-0d7868dc6d2e",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=6ec16aca-ca98-4200-b1f9-021d8cd9b833",
"for_package": 2,
"resolved_to_package": null,
"datafile_resource": 7,
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 0ff39cbfad..036360b7a2 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": "v35.0.0-7-gbe98fc4e",
+ "tool_version": "v35.1.0-17-gde96a5af",
"other_tools": [
"pkg:pypi/scancode-toolkit@32.4.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": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "created_date": "2025-06-30T19:56:37.439Z",
+ "uuid": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "created_date": "2025-07-16T15:27:02.698Z",
"notes": "",
"settings": {},
"input_sources": [
{
- "uuid": "1240025f-b37e-473e-bdd6-77391b367f2a",
+ "uuid": "25a5874c-6913-4542-a301-8678a189c461",
"filename": "asgiref-3.3.0-py3-none-any.whl",
"download_url": "",
"is_uploaded": true,
@@ -30,15 +30,15 @@
"description": "Scan a codebase for application packages, licenses, and copyrights.",
"selected_groups": null,
"selected_steps": null,
- "uuid": "5bd1dcf6-b369-45a6-a2dc-dfe05f9a25cf",
- "created_date": "2025-06-30T19:56:37.441763Z",
+ "uuid": "6188f85f-da57-473f-84e0-e75723714e2d",
+ "created_date": "2025-07-16T15:27:02.699851Z",
"scancodeio_version": "",
"task_id": null,
"task_start_date": null,
"task_end_date": null,
"task_exitcode": null,
"task_output": "",
- "log": "2025-06-30 19:56:37.442 Pipeline [scan_codebase] starting\n2025-06-30 19:56:37.443 Step [download_missing_inputs] starting\n2025-06-30 19:56:37.444 Step [download_missing_inputs] completed in 0 seconds\n2025-06-30 19:56:37.445 Step [copy_inputs_to_codebase_directory] starting\n2025-06-30 19:56:37.446 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2025-06-30 19:56:37.446 Step [extract_archives] starting\n2025-06-30 19:56:37.502 Step [extract_archives] completed in 0 seconds\n2025-06-30 19:56:37.504 Step [collect_and_create_codebase_resources] starting\n2025-06-30 19:56:37.705 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2025-06-30 19:56:37.707 Step [flag_empty_files] starting\n2025-06-30 19:56:37.709 Step [flag_empty_files] completed in 0 seconds\n2025-06-30 19:56:37.710 Step [flag_ignored_resources] starting\n2025-06-30 19:56:37.716 Step [flag_ignored_resources] completed in 0 seconds\n2025-06-30 19:56:37.717 Step [scan_for_application_packages] starting\n2025-06-30 19:56:37.718 Collecting package data from resources:\n2025-06-30 19:56:37.800 Progress: 11% (2/18) ETA: 1 seconds\n2025-06-30 19:56:37.831 Progress: 22% (4/18)\n2025-06-30 19:56:37.834 Progress: 33% (6/18)\n2025-06-30 19:56:37.836 Progress: 44% (8/18)\n2025-06-30 19:56:37.837 Progress: 55% (10/18)\n2025-06-30 19:56:37.839 Progress: 66% (12/18)\n2025-06-30 19:56:37.844 Progress: 77% (14/18)\n2025-06-30 19:56:37.862 Progress: 88% (16/18)\n2025-06-30 19:56:41.912 Progress: 100% (18/18)\n2025-06-30 19:56:41.974 Assembling collected package data:\n2025-06-30 19:56:41.975 Progress: 0%\n2025-06-30 19:56:42.044 Step [scan_for_application_packages] completed in 4 seconds\n2025-06-30 19:56:42.045 Step [scan_for_files] starting\n2025-06-30 19:57:51.517 Progress: 12% (2/16) ETA: 509 seconds (8.5 minutes)\n2025-06-30 19:57:51.803 Progress: 25% (4/16) ETA: 209 seconds (3.5 minutes)\n2025-06-30 19:57:51.819 Progress: 37% (6/16) ETA: 119 seconds (2.0 minutes)\n2025-06-30 19:57:51.852 Progress: 50% (8/16) ETA: 70 seconds (1.2 minutes)\n2025-06-30 19:57:51.875 Progress: 62% (10/16) ETA: 43 seconds\n2025-06-30 19:57:51.899 Progress: 75% (12/16) ETA: 23 seconds\n2025-06-30 19:57:51.927 Progress: 87% (14/16) ETA: 10 seconds\n2025-06-30 19:57:52.377 Progress: 100% (16/16)\n2025-06-30 19:57:52.765 Step [scan_for_files] completed in 71 seconds (1.2 minutes)\n2025-06-30 19:57:52.767 Pipeline completed in 75 seconds (1.3 minutes)\n",
+ "log": "2025-07-16 15:27:02.700 Pipeline [scan_codebase] starting\n2025-07-16 15:27:02.701 Step [download_missing_inputs] starting\n2025-07-16 15:27:02.702 Step [download_missing_inputs] completed in 0 seconds\n2025-07-16 15:27:02.703 Step [copy_inputs_to_codebase_directory] starting\n2025-07-16 15:27:02.703 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2025-07-16 15:27:02.704 Step [extract_archives] starting\n2025-07-16 15:27:02.756 Step [extract_archives] completed in 0 seconds\n2025-07-16 15:27:02.758 Step [collect_and_create_codebase_resources] starting\n2025-07-16 15:27:02.929 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2025-07-16 15:27:02.930 Step [flag_empty_files] starting\n2025-07-16 15:27:02.932 Step [flag_empty_files] completed in 0 seconds\n2025-07-16 15:27:02.933 Step [flag_ignored_resources] starting\n2025-07-16 15:27:02.935 Step [flag_ignored_resources] completed in 0 seconds\n2025-07-16 15:27:02.936 Step [scan_for_application_packages] starting\n2025-07-16 15:27:02.937 Collecting package data from resources:\n2025-07-16 15:27:02.978 Progress: 11% (2/18)\n2025-07-16 15:27:03.005 Progress: 22% (4/18)\n2025-07-16 15:27:03.014 Progress: 33% (6/18)\n2025-07-16 15:27:03.017 Progress: 44% (8/18)\n2025-07-16 15:27:03.019 Progress: 55% (10/18)\n2025-07-16 15:27:03.020 Progress: 66% (12/18)\n2025-07-16 15:27:03.021 Progress: 77% (14/18)\n2025-07-16 15:27:03.022 Progress: 88% (16/18)\n2025-07-16 15:27:06.312 Progress: 100% (18/18)\n2025-07-16 15:27:06.372 Assembling collected package data:\n2025-07-16 15:27:06.373 Progress: 0%\n2025-07-16 15:27:09.130 Step [scan_for_application_packages] completed in 6 seconds\n2025-07-16 15:27:09.131 Step [scan_for_files] starting\n2025-07-16 15:27:09.467 Progress: 12% (2/16) ETA: 2 seconds\n2025-07-16 15:27:09.475 Progress: 25% (4/16) ETA: 1 seconds\n2025-07-16 15:27:09.484 Progress: 37% (6/16) ETA: 1 seconds\n2025-07-16 15:27:09.700 Progress: 50% (8/16) ETA: 1 seconds\n2025-07-16 15:27:09.877 Progress: 62% (10/16)\n2025-07-16 15:27:09.933 Progress: 75% (12/16)\n2025-07-16 15:27:09.958 Progress: 87% (14/16)\n2025-07-16 15:27:10.158 Progress: 100% (16/16)\n2025-07-16 15:27:10.204 Step [scan_for_files] completed in 1 seconds\n2025-07-16 15:27:10.206 Step [collect_and_create_license_detections] starting\n2025-07-16 15:27:10.221 Step [collect_and_create_license_detections] completed in 0 seconds\n2025-07-16 15:27:10.222 Pipeline completed in 8 seconds\n",
"execution_time": null
}
],
@@ -150,7 +150,7 @@
"other_license_expression_spdx": "",
"other_license_detections": [],
"extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n",
- "compliance_alert": "",
+ "compliance_alert": "error",
"notice_text": "",
"source_packages": [],
"extra_data": {
@@ -158,7 +158,7 @@
"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=4bb66559-05cb-4015-9f0a-4b08353b6b52",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd",
"is_private": false,
"is_virtual": false,
"datasource_ids": [
@@ -275,7 +275,7 @@
"other_license_expression_spdx": "",
"other_license_detections": [],
"extracted_license_statement": "license: BSD\nclassifiers:\n - 'License :: OSI Approved :: BSD License'\n",
- "compliance_alert": "",
+ "compliance_alert": "error",
"notice_text": "",
"source_packages": [],
"extra_data": {
@@ -283,7 +283,7 @@
"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=71afaea0-f335-42cb-9fba-23706d270790",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
"is_private": false,
"is_virtual": false,
"datasource_ids": [
@@ -307,8 +307,8 @@
"is_optional": true,
"is_pinned": false,
"is_direct": true,
- "dependency_uid": "pkg:pypi/pytest?uuid=7adc83d4-42ba-42eb-acf2-6a7be8295ba4",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52",
+ "dependency_uid": "pkg:pypi/pytest?uuid=55081a17-fcd9-4032-9ef3-fca2f63bd943",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd",
"resolved_to_package_uid": null,
"datafile_path": "asgiref-3.3.0-py3-none-any.whl",
"datasource_id": "pypi_wheel",
@@ -323,8 +323,8 @@
"is_optional": true,
"is_pinned": false,
"is_direct": true,
- "dependency_uid": "pkg:pypi/pytest?uuid=2f480940-dae0-455c-9ecc-3a558e082a8f",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790",
+ "dependency_uid": "pkg:pypi/pytest?uuid=ea00e9bf-8060-43e7-9ee4-4617f438636d",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
"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",
@@ -339,8 +339,8 @@
"is_optional": true,
"is_pinned": false,
"is_direct": true,
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=194690bd-fe7e-49a7-880f-4e543f60deb8",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=4a12f26f-dc2c-42af-80d0-f719add6c4f5",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd",
"resolved_to_package_uid": null,
"datafile_path": "asgiref-3.3.0-py3-none-any.whl",
"datasource_id": "pypi_wheel",
@@ -355,8 +355,8 @@
"is_optional": true,
"is_pinned": false,
"is_direct": true,
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=60082b5f-bb24-4225-8fd9-0d7868dc6d2e",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=6ec16aca-ca98-4200-b1f9-021d8cd9b833",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
"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",
@@ -371,7 +371,7 @@
"name": "asgiref-3.3.0-py3-none-any.whl",
"status": "application-package",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52"
+ "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd"
],
"tag": "",
"extension": ".whl",
@@ -798,7 +798,7 @@
"name": "LICENSE",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": "",
@@ -806,12 +806,35 @@
"mime_type": "text/plain",
"file_type": "ASCII text",
"programming_language": "",
- "detected_license_expression": "",
- "detected_license_expression_spdx": "",
- "license_detections": [],
+ "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",
+ "license_expression_spdx": "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": null,
- "compliance_alert": "",
+ "percentage_of_license_text": 95.11,
+ "compliance_alert": "error",
"copyrights": [
{
"end_line": 1,
@@ -852,7 +875,7 @@
"name": "METADATA",
"status": "application-package",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": "",
@@ -1159,7 +1182,7 @@
"name": "RECORD",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": "",
@@ -1201,7 +1224,7 @@
"name": "top_level.txt",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".txt",
@@ -1243,7 +1266,7 @@
"name": "WHEEL",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": "",
@@ -1285,7 +1308,7 @@
"name": "compatibility.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1327,7 +1350,7 @@
"name": "current_thread_executor.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1369,7 +1392,7 @@
"name": "__init__.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1411,7 +1434,7 @@
"name": "local.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1453,7 +1476,7 @@
"name": "server.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1495,7 +1518,7 @@
"name": "sync.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1537,7 +1560,7 @@
"name": "testing.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1579,7 +1602,7 @@
"name": "timeout.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
@@ -1587,12 +1610,35 @@
"mime_type": "text/x-script.python",
"file_type": "Python script, ASCII text executable",
"programming_language": "Python",
- "detected_license_expression": "",
- "detected_license_expression_spdx": "",
- "license_detections": [],
+ "detected_license_expression": "apache-2.0",
+ "detected_license_expression_spdx": "Apache-2.0",
+ "license_detections": [
+ {
+ "matches": [
+ {
+ "score": 100.0,
+ "matcher": "2-aho",
+ "end_line": 2,
+ "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/apache-2.0_174.RULE",
+ "from_file": null,
+ "start_line": 2,
+ "matched_text": "# under the Apache 2.0 license. You may see the original project at",
+ "match_coverage": 100.0,
+ "matched_length": 6,
+ "rule_relevance": 100,
+ "rule_identifier": "apache-2.0_174.RULE",
+ "license_expression": "apache-2.0",
+ "license_expression_spdx": "Apache-2.0"
+ }
+ ],
+ "identifier": "apache_2_0-5a90b5fa-5d10-5a98-d2a7-ef089c46a900",
+ "license_expression": "apache-2.0",
+ "license_expression_spdx": "Apache-2.0"
+ }
+ ],
"license_clues": [],
- "percentage_of_license_text": null,
- "compliance_alert": "",
+ "percentage_of_license_text": 1.22,
+ "compliance_alert": "error",
"copyrights": [],
"holders": [],
"authors": [],
@@ -1637,7 +1683,7 @@
"name": "wsgi.py",
"status": "scanned",
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
],
"tag": "",
"extension": ".py",
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 5981ab7ad6..c15f607f50 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
@@ -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": "2025-06-30T195752.768874",
- "end_timestamp": "2025-06-30T195756.929632",
+ "start_timestamp": "2025-07-16T152710.223094",
+ "end_timestamp": "2025-07-16T152711.545101",
"output_format_version": "4.1.0",
- "duration": 4.160773515701294,
+ "duration": 1.322021245956421,
"message": null,
"errors": [],
"warnings": [],
@@ -21,8 +21,8 @@
"system_environment": {
"operating_system": "linux",
"cpu_architecture": "64",
- "platform": "Linux-5.15.0-141-generic-x86_64-with-glibc2.35",
- "platform_version": "#151-Ubuntu SMP Sun May 18 21:35:19 UTC 2025",
+ "platform": "Linux-5.15.0-143-generic-x86_64-with-glibc2.35",
+ "platform_version": "#153-Ubuntu SMP Fri Jun 13 19:10:45 UTC 2025",
"python_version": "3.10.12 (main, May 27 2025, 17:12:29) [GCC 11.4.0]"
},
"spdx_license_list_version": "3.26",
@@ -140,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=e8949b32-8d37-482a-8f0a-1e0fe8d3dac2",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=1688f96b-4f7c-4f59-9221-532b427b4560",
"datafile_paths": [
"codebase/asgiref-3.3.0-py3-none-any.whl"
],
@@ -258,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=b9e196d1-7cc1-4d20-a6f8-845e5e596041",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4",
"datafile_paths": [
"codebase/asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA"
],
@@ -279,8 +279,8 @@
"is_direct": true,
"resolved_package": {},
"extra_data": {},
- "dependency_uid": "pkg:pypi/pytest?uuid=f4533087-433f-431a-9ce8-e47e4d051fdc",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e8949b32-8d37-482a-8f0a-1e0fe8d3dac2",
+ "dependency_uid": "pkg:pypi/pytest?uuid=b152065e-125b-4bd1-8d60-f2de45b0ea14",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=1688f96b-4f7c-4f59-9221-532b427b4560",
"datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl",
"datasource_id": "pypi_wheel"
},
@@ -294,8 +294,8 @@
"is_direct": true,
"resolved_package": {},
"extra_data": {},
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=62bb86cc-68d1-432a-ae89-5f733b45ecc3",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e8949b32-8d37-482a-8f0a-1e0fe8d3dac2",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=e5c4c0c5-4671-44c5-b8c1-68d9acb07d8e",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=1688f96b-4f7c-4f59-9221-532b427b4560",
"datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl",
"datasource_id": "pypi_wheel"
},
@@ -309,8 +309,8 @@
"is_direct": true,
"resolved_package": {},
"extra_data": {},
- "dependency_uid": "pkg:pypi/pytest?uuid=6b229106-c7bd-4511-bbb3-e7e47d4eb237",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041",
+ "dependency_uid": "pkg:pypi/pytest?uuid=3b443d57-63ce-4383-afe9-71ce4d1efbc6",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4",
"datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA",
"datasource_id": "pypi_wheel_metadata"
},
@@ -324,8 +324,8 @@
"is_direct": true,
"resolved_package": {},
"extra_data": {},
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=6fafad63-6d5e-40e0-8851-5e0eec53b71e",
- "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=a7c13ec9-3218-4464-8844-2565c4b0a5ac",
+ "for_package_uid": "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4",
"datafile_path": "codebase/asgiref-3.3.0-py3-none-any.whl-extract/asgiref-3.3.0.dist-info/METADATA",
"datasource_id": "pypi_wheel_metadata"
}
@@ -464,7 +464,7 @@
"base_name": "asgiref-3.3.0-py3-none-any",
"extension": ".whl",
"size": 19948,
- "date": "2025-06-30",
+ "date": "2025-07-16",
"sha1": "c03f67211a311b13d1294ac8af7cb139ee34c4f9",
"md5": "5bce1df6dedc53a41a9a6b40d7b1699e",
"sha256": "a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e",
@@ -745,7 +745,7 @@
}
],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=e8949b32-8d37-482a-8f0a-1e0fe8d3dac2"
+ "pkg:pypi/asgiref@3.3.0?uuid=1688f96b-4f7c-4f59-9221-532b427b4560"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -855,7 +855,7 @@
"is_script": false,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -893,7 +893,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -931,7 +931,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -969,7 +969,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1007,7 +1007,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1045,7 +1045,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1083,7 +1083,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1121,7 +1121,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": "apache-2.0",
"detected_license_expression_spdx": "Apache-2.0",
@@ -1181,7 +1181,7 @@
"is_script": true,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1255,7 +1255,7 @@
"is_script": false,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": "bsd-new",
"detected_license_expression_spdx": "BSD-3-Clause",
@@ -1592,7 +1592,7 @@
}
],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": "bsd-new",
"detected_license_expression_spdx": "BSD-3-Clause",
@@ -1679,7 +1679,7 @@
"is_script": false,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1717,7 +1717,7 @@
"is_script": false,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"detected_license_expression": null,
"detected_license_expression_spdx": null,
@@ -1755,7 +1755,7 @@
"is_script": false,
"package_data": [],
"for_packages": [
- "pkg:pypi/asgiref@3.3.0?uuid=b9e196d1-7cc1-4d20-a6f8-845e5e596041"
+ "pkg:pypi/asgiref@3.3.0?uuid=f91c7642-bbbc-4735-a558-274d192826f4"
],
"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 85f1ac3688..5d9a6b79e7 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": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "pk": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"fields": {
"extra_data": {},
- "created_date": "2025-06-30T19:56:37.439Z",
+ "created_date": "2025-07-16T15:27:02.698Z",
"name": "asgiref",
- "slug": "asgiref-1cdd3f3a",
- "work_directory": "/tmp/tmpw3r_lrtn/projects/asgiref-1cdd3f3a",
+ "slug": "asgiref-804c3391",
+ "work_directory": "/tmp/tmp7oqqjl0j/projects/asgiref-804c3391",
"is_archived": false,
"notes": "",
"settings": {},
@@ -16,17 +16,17 @@
},
{
"model": "scanpipe.run",
- "pk": "5bd1dcf6-b369-45a6-a2dc-dfe05f9a25cf",
+ "pk": "6188f85f-da57-473f-84e0-e75723714e2d",
"fields": {
"task_id": null,
"task_start_date": null,
"task_end_date": null,
"task_exitcode": null,
"task_output": "",
- "log": "2025-06-30 19:56:37.442 Pipeline [scan_codebase] starting\n2025-06-30 19:56:37.443 Step [download_missing_inputs] starting\n2025-06-30 19:56:37.444 Step [download_missing_inputs] completed in 0 seconds\n2025-06-30 19:56:37.445 Step [copy_inputs_to_codebase_directory] starting\n2025-06-30 19:56:37.446 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2025-06-30 19:56:37.446 Step [extract_archives] starting\n2025-06-30 19:56:37.502 Step [extract_archives] completed in 0 seconds\n2025-06-30 19:56:37.504 Step [collect_and_create_codebase_resources] starting\n2025-06-30 19:56:37.705 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2025-06-30 19:56:37.707 Step [flag_empty_files] starting\n2025-06-30 19:56:37.709 Step [flag_empty_files] completed in 0 seconds\n2025-06-30 19:56:37.710 Step [flag_ignored_resources] starting\n2025-06-30 19:56:37.716 Step [flag_ignored_resources] completed in 0 seconds\n2025-06-30 19:56:37.717 Step [scan_for_application_packages] starting\n2025-06-30 19:56:37.718 Collecting package data from resources:\n2025-06-30 19:56:37.800 Progress: 11% (2/18) ETA: 1 seconds\n2025-06-30 19:56:37.831 Progress: 22% (4/18)\n2025-06-30 19:56:37.834 Progress: 33% (6/18)\n2025-06-30 19:56:37.836 Progress: 44% (8/18)\n2025-06-30 19:56:37.837 Progress: 55% (10/18)\n2025-06-30 19:56:37.839 Progress: 66% (12/18)\n2025-06-30 19:56:37.844 Progress: 77% (14/18)\n2025-06-30 19:56:37.862 Progress: 88% (16/18)\n2025-06-30 19:56:41.912 Progress: 100% (18/18)\n2025-06-30 19:56:41.974 Assembling collected package data:\n2025-06-30 19:56:41.975 Progress: 0%\n2025-06-30 19:56:42.044 Step [scan_for_application_packages] completed in 4 seconds\n2025-06-30 19:56:42.045 Step [scan_for_files] starting\n2025-06-30 19:57:51.517 Progress: 12% (2/16) ETA: 509 seconds (8.5 minutes)\n2025-06-30 19:57:51.803 Progress: 25% (4/16) ETA: 209 seconds (3.5 minutes)\n2025-06-30 19:57:51.819 Progress: 37% (6/16) ETA: 119 seconds (2.0 minutes)\n2025-06-30 19:57:51.852 Progress: 50% (8/16) ETA: 70 seconds (1.2 minutes)\n2025-06-30 19:57:51.875 Progress: 62% (10/16) ETA: 43 seconds\n2025-06-30 19:57:51.899 Progress: 75% (12/16) ETA: 23 seconds\n2025-06-30 19:57:51.927 Progress: 87% (14/16) ETA: 10 seconds\n2025-06-30 19:57:52.377 Progress: 100% (16/16)\n2025-06-30 19:57:52.765 Step [scan_for_files] completed in 71 seconds (1.2 minutes)\n2025-06-30 19:57:52.767 Pipeline completed in 75 seconds (1.3 minutes)\n",
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "log": "2025-07-16 15:27:02.700 Pipeline [scan_codebase] starting\n2025-07-16 15:27:02.701 Step [download_missing_inputs] starting\n2025-07-16 15:27:02.702 Step [download_missing_inputs] completed in 0 seconds\n2025-07-16 15:27:02.703 Step [copy_inputs_to_codebase_directory] starting\n2025-07-16 15:27:02.703 Step [copy_inputs_to_codebase_directory] completed in 0 seconds\n2025-07-16 15:27:02.704 Step [extract_archives] starting\n2025-07-16 15:27:02.756 Step [extract_archives] completed in 0 seconds\n2025-07-16 15:27:02.758 Step [collect_and_create_codebase_resources] starting\n2025-07-16 15:27:02.929 Step [collect_and_create_codebase_resources] completed in 0 seconds\n2025-07-16 15:27:02.930 Step [flag_empty_files] starting\n2025-07-16 15:27:02.932 Step [flag_empty_files] completed in 0 seconds\n2025-07-16 15:27:02.933 Step [flag_ignored_resources] starting\n2025-07-16 15:27:02.935 Step [flag_ignored_resources] completed in 0 seconds\n2025-07-16 15:27:02.936 Step [scan_for_application_packages] starting\n2025-07-16 15:27:02.937 Collecting package data from resources:\n2025-07-16 15:27:02.978 Progress: 11% (2/18)\n2025-07-16 15:27:03.005 Progress: 22% (4/18)\n2025-07-16 15:27:03.014 Progress: 33% (6/18)\n2025-07-16 15:27:03.017 Progress: 44% (8/18)\n2025-07-16 15:27:03.019 Progress: 55% (10/18)\n2025-07-16 15:27:03.020 Progress: 66% (12/18)\n2025-07-16 15:27:03.021 Progress: 77% (14/18)\n2025-07-16 15:27:03.022 Progress: 88% (16/18)\n2025-07-16 15:27:06.312 Progress: 100% (18/18)\n2025-07-16 15:27:06.372 Assembling collected package data:\n2025-07-16 15:27:06.373 Progress: 0%\n2025-07-16 15:27:09.130 Step [scan_for_application_packages] completed in 6 seconds\n2025-07-16 15:27:09.131 Step [scan_for_files] starting\n2025-07-16 15:27:09.467 Progress: 12% (2/16) ETA: 2 seconds\n2025-07-16 15:27:09.475 Progress: 25% (4/16) ETA: 1 seconds\n2025-07-16 15:27:09.484 Progress: 37% (6/16) ETA: 1 seconds\n2025-07-16 15:27:09.700 Progress: 50% (8/16) ETA: 1 seconds\n2025-07-16 15:27:09.877 Progress: 62% (10/16)\n2025-07-16 15:27:09.933 Progress: 75% (12/16)\n2025-07-16 15:27:09.958 Progress: 87% (14/16)\n2025-07-16 15:27:10.158 Progress: 100% (16/16)\n2025-07-16 15:27:10.204 Step [scan_for_files] completed in 1 seconds\n2025-07-16 15:27:10.206 Step [collect_and_create_license_detections] starting\n2025-07-16 15:27:10.221 Step [collect_and_create_license_detections] completed in 0 seconds\n2025-07-16 15:27:10.222 Pipeline completed in 8 seconds\n",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"pipeline_name": "scan_codebase",
- "created_date": "2025-06-30T19:56:37.441Z",
+ "created_date": "2025-07-16T15:27:02.699Z",
"scancodeio_version": "",
"description": "Scan a codebase for application packages, licenses, and copyrights.",
"current_step": "",
@@ -43,7 +43,7 @@
"sha256": "a5098bc870b80e7b872bff60bb363c7f2c2c89078759f6c47b53ff8c525a152e",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -353,7 +353,7 @@
"sha256": "",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -398,7 +398,7 @@
"sha256": "",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -443,7 +443,7 @@
"sha256": "",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -488,7 +488,7 @@
"sha256": "6e89108c2cf0c0446174188f76f60465ae1c1f14f83427807df40d52a27cb2c8",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -533,12 +533,35 @@
"sha256": "b846415d1b514e9c1dff14a22deb906d794bc546ca6129f950a18cd091e2a669",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "detected_license_expression": "",
- "detected_license_expression_spdx": "",
- "license_detections": [],
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "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",
+ "license_expression_spdx": "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": null,
+ "percentage_of_license_text": 95.11,
"copyrights": [
{
"end_line": 1,
@@ -556,7 +579,7 @@
"authors": [],
"emails": [],
"urls": [],
- "compliance_alert": "",
+ "compliance_alert": "error",
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -590,7 +613,7 @@
"sha256": "70f98f4eb9f6068b192b5464fcdf69e29a8ff09962bfce84bbb052baeee44f33",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -900,7 +923,7 @@
"sha256": "11546323af45e6a5639bf620a9c4d73e74c0bf705f494af4595007b923f75e8a",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -945,7 +968,7 @@
"sha256": "2c1983592aa38f0bfb0afacc73ddc5b46ce10e8e89ceaa9fed1e5fc6361b608d",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -990,7 +1013,7 @@
"sha256": "30f49b9094bff904a42caeec32515715fe625a56dc48bd7c0e3d9988c0ad4bd7",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1035,7 +1058,7 @@
"sha256": "fa4651a3b79201a4dc44a4096cd49ec8f427e912ea0ee05c666357b413a8afe7",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1080,7 +1103,7 @@
"sha256": "ee0fcf4a8e6fa9df8a4643bb48e82892d496afce44b6c8b8aea2721755545e1c",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1125,7 +1148,7 @@
"sha256": "3151f66c476208c3154cb6c4fb557a2a253bab82f0ab33fb3c8b9f7976be9e33",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1170,7 +1193,7 @@
"sha256": "ddd445b778c097fc75c2bf69ad964cbadd3bd6999d1dd2306d39d401855e8e3e",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1215,7 +1238,7 @@
"sha256": "ddbc8d455eceb68fc583c67e7c4ad0277c867fb39095c51ec5b37f70342e8334",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1260,12 +1283,35 @@
"sha256": "126c3e3a8a75a517d2739612304607804cf5f34da63fa25d03a6f11f7edb6f2f",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "detected_license_expression": "",
- "detected_license_expression_spdx": "",
- "license_detections": [],
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "detected_license_expression": "apache-2.0",
+ "detected_license_expression_spdx": "Apache-2.0",
+ "license_detections": [
+ {
+ "matches": [
+ {
+ "score": 100.0,
+ "matcher": "2-aho",
+ "end_line": 2,
+ "rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/apache-2.0_174.RULE",
+ "from_file": null,
+ "start_line": 2,
+ "matched_text": "# under the Apache 2.0 license. You may see the original project at",
+ "match_coverage": 100.0,
+ "matched_length": 6,
+ "rule_relevance": 100,
+ "rule_identifier": "apache-2.0_174.RULE",
+ "license_expression": "apache-2.0",
+ "license_expression_spdx": "Apache-2.0"
+ }
+ ],
+ "identifier": "apache_2_0-5a90b5fa-5d10-5a98-d2a7-ef089c46a900",
+ "license_expression": "apache-2.0",
+ "license_expression_spdx": "Apache-2.0"
+ }
+ ],
"license_clues": [],
- "percentage_of_license_text": null,
+ "percentage_of_license_text": 1.22,
"copyrights": [],
"holders": [],
"authors": [],
@@ -1287,7 +1333,7 @@
"start_line": 83
}
],
- "compliance_alert": "",
+ "compliance_alert": "error",
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -1321,7 +1367,7 @@
"sha256": "f8bd1ea3fb8afddabb10f8efd66796d41446cad51168ef4d3c44b19c973d0ad0",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1366,7 +1412,7 @@
"sha256": "885267fee0fea687875a02ceb929ca095312d47aaa57e20e4ce382f397caaf4d",
"sha512": "",
"extra_data": {},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"detected_license_expression": "",
"detected_license_expression_spdx": "",
"license_detections": [],
@@ -1412,7 +1458,7 @@
"version": "3.3.0",
"qualifiers": "",
"subpath": "",
- "uuid": "b4e16c8a-f564-4379-9de9-ea2aaba08d94",
+ "uuid": "9d0bdc32-1117-407a-9908-08d3558dc739",
"md5": "",
"sha1": "",
"sha256": "",
@@ -1422,8 +1468,8 @@
"Documentation": "https://asgi.readthedocs.io/",
"Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions"
},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "compliance_alert": "",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "compliance_alert": "error",
"affected_by_vulnerabilities": [],
"filename": "",
"primary_language": "Python",
@@ -1513,7 +1559,7 @@
],
"missing_resources": [],
"modified_resources": [],
- "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd",
"keywords": [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
@@ -1546,7 +1592,7 @@
"version": "3.3.0",
"qualifiers": "",
"subpath": "",
- "uuid": "80e083f1-7d05-432e-96f8-e6dfd9e494f0",
+ "uuid": "7969de5e-5589-4441-bffa-a60e12b43280",
"md5": "",
"sha1": "",
"sha256": "",
@@ -1556,8 +1602,8 @@
"Documentation": "https://asgi.readthedocs.io/",
"Further Documentation": "https://docs.djangoproject.com/en/stable/topics/async/#async-adapter-functions"
},
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "compliance_alert": "",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "compliance_alert": "error",
"affected_by_vulnerabilities": [],
"filename": "",
"primary_language": "Python",
@@ -1647,7 +1693,7 @@
],
"missing_resources": [],
"modified_resources": [],
- "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790",
+ "package_uid": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
"keywords": [
"Development Status :: 5 - Production/Stable",
"Environment :: Web Environment",
@@ -1693,10 +1739,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "05f9bf8f-4da8-488e-9f48-6e183c4b813b",
+ "uuid": "4cff8bf8-197c-4698-a43a-5c793586c780",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest?uuid=7adc83d4-42ba-42eb-acf2-6a7be8295ba4",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest?uuid=55081a17-fcd9-4032-9ef3-fca2f63bd943",
"for_package": 1,
"resolved_to_package": null,
"datafile_resource": 1,
@@ -1719,10 +1765,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "ea25292c-05af-4982-9596-866c5de9d8cd",
+ "uuid": "f983278c-22f1-43e1-ba2b-a020d659531b",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=194690bd-fe7e-49a7-880f-4e543f60deb8",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=4a12f26f-dc2c-42af-80d0-f719add6c4f5",
"for_package": 1,
"resolved_to_package": null,
"datafile_resource": 1,
@@ -1745,10 +1791,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "43988fc2-bc0e-4c81-b083-7c5f21a7be50",
+ "uuid": "4c5c1313-3850-4f81-ac27-8d496080d667",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest?uuid=2f480940-dae0-455c-9ecc-3a558e082a8f",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest?uuid=ea00e9bf-8060-43e7-9ee4-4617f438636d",
"for_package": 2,
"resolved_to_package": null,
"datafile_resource": 7,
@@ -1771,10 +1817,10 @@
"version": "",
"qualifiers": "",
"subpath": "",
- "uuid": "a0b6b6e7-5e75-4b69-9742-b04fe8a594a3",
+ "uuid": "98aeddb5-b81a-43d4-ac56-dc873a589fdf",
"affected_by_vulnerabilities": [],
- "project": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
- "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=60082b5f-bb24-4225-8fd9-0d7868dc6d2e",
+ "project": "804c3391-e6f9-415f-bb7a-cb6653853a46",
+ "dependency_uid": "pkg:pypi/pytest-asyncio?uuid=6ec16aca-ca98-4200-b1f9-021d8cd9b833",
"for_package": 2,
"resolved_to_package": null,
"datafile_resource": 7,
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 65d6d6c530..d354df7e99 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": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd",
+ "bom-ref": "804c3391-e6f9-415f-bb7a-cb6653853a46",
"name": "asgiref",
"type": "library"
},
@@ -26,9 +26,16 @@
},
"components": [
{
- "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52",
+ "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
"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": {
+ "licenses": [
+ {
+ "expression": "Apache-2.0 AND LicenseRef-test"
+ }
+ ]
+ },
"externalReferences": [
{
"type": "bom",
@@ -56,7 +63,7 @@
},
{
"name": "aboutcode:package_uid",
- "value": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52"
+ "value": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
},
{
"name": "aboutcode:primary_language",
@@ -68,16 +75,9 @@
"version": "3.3.0"
},
{
- "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790",
+ "bom-ref": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd",
"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": {
- "licenses": [
- {
- "expression": "Apache-2.0 AND LicenseRef-test"
- }
- ]
- },
"externalReferences": [
{
"type": "bom",
@@ -105,7 +105,7 @@
},
{
"name": "aboutcode:package_uid",
- "value": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "value": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd"
},
{
"name": "aboutcode:primary_language",
@@ -120,23 +120,23 @@
"dependencies": [
{
"dependsOn": [
- "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52",
- "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663",
+ "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd"
],
- "ref": "1cdd3f3a-eea9-4c9c-b78e-9fa6bcde9cfd"
+ "ref": "804c3391-e6f9-415f-bb7a-cb6653853a46"
},
{
- "ref": "pkg:pypi/asgiref@3.3.0?uuid=4bb66559-05cb-4015-9f0a-4b08353b6b52"
+ "ref": "pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
},
{
- "ref": "pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "ref": "pkg:pypi/asgiref@3.3.0?uuid=e62e0385-a279-4d5a-b2a5-7f0cfb21d7bd"
}
],
"vulnerabilities": [
{
"affects": [
{
- "ref": "urn:cdx:pkg:pypi/asgiref@3.3.0?uuid=71afaea0-f335-42cb-9fba-23706d270790"
+ "ref": "urn:cdx:pkg:pypi/asgiref@3.3.0?uuid=078ee2a1-aa92-4f80-8032-8af0b3c26663"
}
],
"bom-ref": "BomRef",
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 f79ab96468..eab30481fb 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
@@ -8,11 +8,14 @@
"--info": true,
"--license": true,
"--license-text": true,
+ "--license-diagnostics": true,
+ "--license-text-diagnostics": true,
"--license-references": true,
"--package": true,
"--url": true,
"--classify": true,
- "--summary": true
+ "--summary": true,
+ "--todo": 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": "4.1.0",
@@ -52,6 +55,7 @@
],
"other_languages": []
},
+ "todo": [],
"packages": [
{
"type": "maven",
@@ -313,6 +317,7 @@
"license_expression": "lgpl-3.0",
"license_expression_spdx": "LGPL-3.0-only",
"detection_count": 1,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "lgpl-3.0",
@@ -336,6 +341,7 @@
"license_expression": "mpl-2.0",
"license_expression_spdx": "MPL-2.0",
"detection_count": 1,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "mpl-2.0",
@@ -359,6 +365,7 @@
"license_expression": "mpl-2.0 OR lgpl-3.0",
"license_expression_spdx": "MPL-2.0 OR LGPL-3.0-only",
"detection_count": 1,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "mpl-2.0 OR lgpl-3.0",
@@ -373,7 +380,8 @@
"rule_relevance": 95,
"rule_identifier": "mpl-2.0_or_lgpl-3.0_1.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mpl-2.0_or_lgpl-3.0_1.RULE",
- "matched_text": " \n \n GNU General Lesser Public License (LGPL) version 3.0\n http://www.gnu.org/licenses/lgpl.html\n repo\n \n \n Mozilla Public License Version 2.0\n http://www.mozilla.org/MPL/2.0/\n repo\n \n "
+ "matched_text": " \n \n GNU General Lesser Public License (LGPL) version 3.0\n http://www.gnu.org/licenses/lgpl.html\n repo\n \n \n Mozilla Public License Version 2.0\n http://www.mozilla.org/MPL/2.0/\n repo\n \n ",
+ "matched_text_diagnostics": "licenses>\n \n GNU General Lesser Public License (LGPL) version 3.0\n http://www.gnu.org/licenses/lgpl.html\n repo\n \n \n Mozilla Public License Version 2.0\n http://www.mozilla.org/MPL/2.0/\n repo\n \n "
}
]
}
@@ -582,6 +590,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -622,6 +631,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -861,9 +871,11 @@
"rule_relevance": 95,
"rule_identifier": "mpl-2.0_or_lgpl-3.0_1.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mpl-2.0_or_lgpl-3.0_1.RULE",
- "matched_text": " \n \n GNU General Lesser Public License (LGPL) version 3.0\n http://www.gnu.org/licenses/lgpl.html\n repo\n \n \n Mozilla Public License Version 2.0\n http://www.mozilla.org/MPL/2.0/\n repo\n \n "
+ "matched_text": " \n \n GNU General Lesser Public License (LGPL) version 3.0\n http://www.gnu.org/licenses/lgpl.html\n repo\n \n \n Mozilla Public License Version 2.0\n http://www.mozilla.org/MPL/2.0/\n repo\n \n ",
+ "matched_text_diagnostics": "licenses>\n \n GNU General Lesser Public License (LGPL) version 3.0\n http://www.gnu.org/licenses/lgpl.html\n repo\n \n \n Mozilla Public License Version 2.0\n http://www.mozilla.org/MPL/2.0/\n repo\n \n "
}
],
+ "detection_log": [],
"identifier": "mpl_2_0_or_lgpl_3_0-7b07902d-2b7f-9c7e-aa21-3ae2142743ba"
}
],
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 638f95e236..6636558fc7 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
@@ -8,11 +8,14 @@
"--info": true,
"--license": true,
"--license-text": true,
+ "--license-diagnostics": true,
+ "--license-text-diagnostics": true,
"--license-references": true,
"--package": true,
"--url": true,
"--classify": true,
- "--summary": true
+ "--summary": true,
+ "--todo": 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": "4.1.0",
@@ -52,6 +55,7 @@
],
"other_languages": []
},
+ "todo": [],
"packages": [
{
"type": "npm",
@@ -165,6 +169,7 @@
"license_expression": "mit",
"license_expression_spdx": "MIT",
"detection_count": 2,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "mit",
@@ -179,7 +184,8 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": " \"license\": \"MIT\","
+ "matched_text": " \"license\": \"MIT\",",
+ "matched_text_diagnostics": "license\": \"MIT\","
}
]
},
@@ -188,6 +194,7 @@
"license_expression": "mit",
"license_expression_spdx": "MIT",
"detection_count": 1,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "mit",
@@ -327,6 +334,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -365,6 +373,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -403,6 +412,7 @@
"is_archive": false,
"is_media": false,
"is_source": true,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -443,6 +453,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -570,9 +581,11 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": " \"license\": \"MIT\","
+ "matched_text": " \"license\": \"MIT\",",
+ "matched_text_diagnostics": "license\": \"MIT\","
}
],
+ "detection_log": [],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee"
}
],
@@ -621,6 +634,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": true,
@@ -651,9 +665,11 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": "## License\n\nMIT \u00a9 [Sindre Sorhus](http://sindresorhus.com)"
+ "matched_text": "## License\n\nMIT \u00a9 [Sindre Sorhus](http://sindresorhus.com)",
+ "matched_text_diagnostics": "License\n\nMIT \u00a9 ["
}
],
+ "detection_log": [],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee"
}
],
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 1b1c0d16d1..1edcaf9391 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
@@ -82,10 +82,12 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"license_expression": "mit",
- "license_expression_spdx": "MIT"
+ "license_expression_spdx": "MIT",
+ "matched_text_diagnostics": "License\n\nMIT \u00a9 ["
}
],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee",
+ "detection_log": [],
"license_expression": "mit",
"license_expression_spdx": "MIT"
}
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 be5a2ab12c..70d60653e5 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
@@ -85,10 +85,12 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"license_expression": "mit",
- "license_expression_spdx": "MIT"
+ "license_expression_spdx": "MIT",
+ "matched_text_diagnostics": "License\n\nMIT \u00a9 ["
}
],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee",
+ "detection_log": [],
"license_expression": "mit",
"license_expression_spdx": "MIT"
}
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 793a069583..498915297f 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
@@ -8,11 +8,14 @@
"--info": true,
"--license": true,
"--license-text": true,
+ "--license-diagnostics": true,
+ "--license-text-diagnostics": true,
"--license-references": true,
"--package": true,
"--url": true,
"--classify": true,
- "--summary": true
+ "--summary": true,
+ "--todo": 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": "4.1.0",
@@ -52,6 +55,7 @@
],
"other_languages": []
},
+ "todo": [],
"packages": [
{
"type": "npm",
@@ -268,6 +272,7 @@
"license_expression": "mit",
"license_expression_spdx": "MIT",
"detection_count": 4,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "mit",
@@ -282,7 +287,8 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": " \"license\": \"MIT\","
+ "matched_text": " \"license\": \"MIT\",",
+ "matched_text_diagnostics": "license\": \"MIT\","
}
]
},
@@ -291,6 +297,7 @@
"license_expression": "mit",
"license_expression_spdx": "MIT",
"detection_count": 2,
+ "detection_log": [],
"reference_matches": [
{
"license_expression": "mit",
@@ -430,6 +437,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -468,6 +476,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -506,6 +515,7 @@
"is_archive": false,
"is_media": false,
"is_source": true,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -546,6 +556,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -584,6 +595,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -622,6 +634,7 @@
"is_archive": false,
"is_media": false,
"is_source": true,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -662,6 +675,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -789,9 +803,11 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": " \"license\": \"MIT\","
+ "matched_text": " \"license\": \"MIT\",",
+ "matched_text_diagnostics": "license\": \"MIT\","
}
],
+ "detection_log": [],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee"
}
],
@@ -840,6 +856,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": true,
@@ -870,9 +887,11 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": "## License\n\nMIT \u00a9 [Sindre Sorhus](http://sindresorhus.com)"
+ "matched_text": "## License\n\nMIT \u00a9 [Sindre Sorhus](http://sindresorhus.com)",
+ "matched_text_diagnostics": "License\n\nMIT \u00a9 ["
}
],
+ "detection_log": [],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee"
}
],
@@ -936,6 +955,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": false,
@@ -1063,9 +1083,11 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": " \"license\": \"MIT\","
+ "matched_text": " \"license\": \"MIT\",",
+ "matched_text_diagnostics": "license\": \"MIT\","
}
],
+ "detection_log": [],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee"
}
],
@@ -1114,6 +1136,7 @@
"is_archive": false,
"is_media": false,
"is_source": false,
+ "for_todo": [],
"is_legal": false,
"is_manifest": false,
"is_readme": true,
@@ -1144,9 +1167,11 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"rule_url": "https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/rules/mit_30.RULE",
- "matched_text": "## License\n\nMIT \u00a9 [Sindre Sorhus](http://sindresorhus.com)"
+ "matched_text": "## License\n\nMIT \u00a9 [Sindre Sorhus](http://sindresorhus.com)",
+ "matched_text_diagnostics": "License\n\nMIT \u00a9 ["
}
],
+ "detection_log": [],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee"
}
],
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 b056d8fb41..ffa3eb1f1f 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
@@ -106,10 +106,12 @@
"rule_relevance": 100,
"rule_identifier": "mit_30.RULE",
"license_expression": "mit",
- "license_expression_spdx": "MIT"
+ "license_expression_spdx": "MIT",
+ "matched_text_diagnostics": "License\n\nMIT \u00a9 ["
}
],
"identifier": "mit-3fce6ea2-8abd-6c6b-3ede-a37af7c6efee",
+ "detection_log": [],
"license_expression": "mit",
"license_expression_spdx": "MIT"
}
diff --git a/scanpipe/tests/data/scancode/package_assembly_codebase.json b/scanpipe/tests/data/scancode/package_assembly_codebase.json
index 11b9135e92..ce0266a650 100644
--- a/scanpipe/tests/data/scancode/package_assembly_codebase.json
+++ b/scanpipe/tests/data/scancode/package_assembly_codebase.json
@@ -8,10 +8,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": "2025-06-30T195757.062637",
- "end_timestamp": "2025-06-30T195757.374873",
+ "start_timestamp": "2025-07-16T152711.658601",
+ "end_timestamp": "2025-07-16T152711.886384",
"output_format_version": "4.1.0",
- "duration": 0.31224966049194336,
+ "duration": 0.2277970314025879,
"message": null,
"errors": [],
"warnings": [],
@@ -19,8 +19,8 @@
"system_environment": {
"operating_system": "linux",
"cpu_architecture": "64",
- "platform": "Linux-5.15.0-141-generic-x86_64-with-glibc2.35",
- "platform_version": "#151-Ubuntu SMP Sun May 18 21:35:19 UTC 2025",
+ "platform": "Linux-5.15.0-143-generic-x86_64-with-glibc2.35",
+ "platform_version": "#153-Ubuntu SMP Fri Jun 13 19:10:45 UTC 2025",
"python_version": "3.10.12 (main, May 27 2025, 17:12:29) [GCC 11.4.0]"
},
"spdx_license_list_version": "3.26",
@@ -91,7 +91,7 @@
"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=46bc67bc-2555-4267-847b-97bb17199aa3",
+ "package_uid": "pkg:npm/test@0.1.0?uuid=ea1e6923-1857-4092-9a5a-37dad26b5e52",
"datafile_paths": [
"package_assembly_codebase.tar.gz-extract/test/get_package_resources/package.json"
],
@@ -278,7 +278,7 @@
}
],
"for_packages": [
- "pkg:npm/test@0.1.0?uuid=46bc67bc-2555-4267-847b-97bb17199aa3"
+ "pkg:npm/test@0.1.0?uuid=ea1e6923-1857-4092-9a5a-37dad26b5e52"
],
"files_count": 0,
"dirs_count": 0,
@@ -308,7 +308,7 @@
"is_script": false,
"package_data": [],
"for_packages": [
- "pkg:npm/test@0.1.0?uuid=46bc67bc-2555-4267-847b-97bb17199aa3"
+ "pkg:npm/test@0.1.0?uuid=ea1e6923-1857-4092-9a5a-37dad26b5e52"
],
"files_count": 0,
"dirs_count": 0,
diff --git a/scanpipe/tests/pipes/test_output.py b/scanpipe/tests/pipes/test_output.py
index 5cf3538659..d272c0025d 100644
--- a/scanpipe/tests/pipes/test_output.py
+++ b/scanpipe/tests/pipes/test_output.py
@@ -338,7 +338,7 @@ def test_scanpipe_pipes_outputs_to_cyclonedx(self, regen=FIXTURES_REGEN):
project = Project.objects.get(name="asgiref")
package = project.discoveredpackages.get(
- uuid="80e083f1-7d05-432e-96f8-e6dfd9e494f0"
+ uuid="7969de5e-5589-4441-bffa-a60e12b43280"
)
package.other_license_expression_spdx = "Apache-2.0 AND LicenseRef-test"
diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py
index 7aa5cf6280..8e28fb8296 100644
--- a/scanpipe/tests/test_models.py
+++ b/scanpipe/tests/test_models.py
@@ -2647,7 +2647,7 @@ def test_scanpipe_model_codebase_resource_compliance_alert_queryset_mixin(self):
self.project1, path="missing", compliance_alert=severities.MISSING
)
- qs = CodebaseResource.objects.order_by("path")
+ qs = self.project1.codebaseresources.order_by("path")
self.assertQuerySetEqual(qs.compliance_issues(severities.ERROR), [error])
self.assertQuerySetEqual(
qs.compliance_issues(severities.WARNING), [error, warning]
diff --git a/scanpipe/views.py b/scanpipe/views.py
index 4f47eee11b..8722114f0d 100644
--- a/scanpipe/views.py
+++ b/scanpipe/views.py
@@ -360,6 +360,8 @@ def get_field_value(self, field_name, render_func=None):
"emails",
"datafile_paths",
"datasource_ids",
+ "detection_log",
+ "review_comments",
]
if isinstance(field_value, list | dict):
@@ -1140,6 +1142,7 @@ def get_license_detection_summary(project, limit=10):
"with_compliance_error": (
proper_license_detections.has_compliance_alert().count()
),
+ "needs_review": proper_license_detections.needs_review().count(),
"all": proper_license_detections.count(),
}
@@ -1150,6 +1153,7 @@ def get_license_detection_summary(project, limit=10):
if license_clues.exists():
clue_counts = {
"with_compliance_error": (license_clues.has_compliance_alert().count()),
+ "needs_review": license_clues.needs_review().count(),
"all": license_clues.count(),
}
@@ -1872,6 +1876,7 @@ class DiscoveredLicenseListView(
},
"detection_count",
"is_license_clue",
+ "needs_review",
{
"field_name": "compliance_alert",
"filter_fieldname": "compliance_alert",
@@ -2483,7 +2488,7 @@ class DiscoveredLicenseDetailsView(
"icon_class": "fa-solid fa-info-circle",
},
"detection": {
- "fields": ["matches", "detection_log", "file_regions"],
+ "fields": ["matches", "detection_log", "review_comments", "file_regions"],
"icon_class": "fa-solid fa-search",
"template": "scanpipe/tabset/tab_license_detections.html",
},
|