From 173db430bbf769f265c2a6c93a7a0b9414f5d136 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 26 Jun 2024 13:20:39 +0530 Subject: [PATCH 01/50] Add ScoreCard config into settings.py developed functions to check for availability nexB#598 Signed-off-by: 404-geek --- scancodeio/settings.py | 4 +++ scanpipe/pipes/ScoreCode.py | 59 +++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 scanpipe/pipes/ScoreCode.py diff --git a/scancodeio/settings.py b/scancodeio/settings.py index 112de2def..2b0b3e60e 100644 --- a/scancodeio/settings.py +++ b/scancodeio/settings.py @@ -410,3 +410,7 @@ MATCHCODEIO_USER = env.str("MATCHCODEIO_USER", default="") MATCHCODEIO_PASSWORD = env.str("MATCHCODEIO_PASSWORD", default="") MATCHCODEIO_API_KEY = env.str("MATCHCODEIO_API_KEY", default="") + +# OpenSSF ScoreCard Integration + +SCORECARD_URL = env.str('SCORECARD_URL', default="") \ No newline at end of file diff --git a/scanpipe/pipes/ScoreCode.py b/scanpipe/pipes/ScoreCode.py new file mode 100644 index 000000000..c7c7a933f --- /dev/null +++ b/scanpipe/pipes/ScoreCode.py @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# http://nexb.com and https://github.com/nexB/scancode.io +# The ScanCode.io software is licensed under the Apache License version 2.0. +# Data generated with ScanCode.io is provided as-is without warranties. +# ScanCode is a trademark of nexB Inc. +# +# You may not use this software except in compliance with the License. +# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# Data Generated with ScanCode.io is provided on an "AS IS" BASIS, WITHOUT WARRANTIES +# OR CONDITIONS OF ANY KIND, either express or implied. No content created from +# ScanCode.io should be considered or used as legal advice. Consult an Attorney +# for any legal advice. +# +# ScanCode.io is a free software code scanning tool from nexB Inc. and others. +# Visit https://github.com/nexB/scancode.io for support and download. + +import logging + +from django.conf import settings + +import requests + +label = "ScoreCode" +logger = logging.getLogger(__name__) +session = requests.Session() + + +# Only SCORECARD_URL can be provided through setting +SCORECARD_API_URL = None +SCORECARD_URL = settings.SCORECARD_URL +if SCORECARD_URL: + SCORECARD_API_URL = f'{SCORECARD_URL.rstrip("/")}/projects/' + +def is_configured(): + """Return True if the required Scorecard settings have been set.""" + if SCORECARD_API_URL: + return True + return False + + +def is_available(): + """Return True if the configured Scorecard server is available.""" + if not is_configured(): + return False + + try: + response = session.head(SCORECARD_API_URL) + response.raise_for_status() + except requests.exceptions.RequestException as request_exception: + logger.debug(f"{label} is_available() error: {request_exception}") + return False + + return response.status_code == requests.codes.ok \ No newline at end of file From 272b99cfdc42f9b3ba64f908a996e7048caeeda5 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 26 Jun 2024 16:02:28 +0530 Subject: [PATCH 02/50] code style fix nexB#598 Signed-off-by: 404-geek --- scanpipe/pipes/ScoreCode.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanpipe/pipes/ScoreCode.py b/scanpipe/pipes/ScoreCode.py index c7c7a933f..bf0f333bd 100644 --- a/scanpipe/pipes/ScoreCode.py +++ b/scanpipe/pipes/ScoreCode.py @@ -37,6 +37,7 @@ if SCORECARD_URL: SCORECARD_API_URL = f'{SCORECARD_URL.rstrip("/")}/projects/' + def is_configured(): """Return True if the required Scorecard settings have been set.""" if SCORECARD_API_URL: @@ -56,4 +57,4 @@ def is_available(): logger.debug(f"{label} is_available() error: {request_exception}") return False - return response.status_code == requests.codes.ok \ No newline at end of file + return response.status_code == requests.codes.ok From bc445c144dd7f1ee74170676700f13b9a90c8918 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 26 Jun 2024 16:33:09 +0530 Subject: [PATCH 03/50] settings.py code style fix nexB#598 Signed-off-by: 404-geek --- scancodeio/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scancodeio/settings.py b/scancodeio/settings.py index 25945ecfa..24f6ea50c 100644 --- a/scancodeio/settings.py +++ b/scancodeio/settings.py @@ -417,4 +417,4 @@ # OpenSSF ScoreCard Integration -SCORECARD_URL = env.str('SCORECARD_URL', default="") \ No newline at end of file +SCORECARD_URL = env.str('SCORECARD_URL', default="") From f241b3b20faeddf50a91dfad40f7c6e5e6fd2a03 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 27 Jun 2024 16:19:29 +0530 Subject: [PATCH 04/50] mixin import and models declaration nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/scanpipe/models.py b/scanpipe/models.py index 06b55c4a6..c6a0a0ab8 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -78,6 +78,7 @@ from packageurl import normalize_qualifiers from packageurl.contrib.django.models import PackageURLMixin from packageurl.contrib.django.models import PackageURLQuerySetMixin +from ossf_scorecard.contrib.models import Package_score_Mixin from rest_framework.authtoken.models import Token from rq.command import send_stop_job_command from rq.exceptions import NoSuchJobError @@ -3693,6 +3694,21 @@ def as_spdx(self): external_refs=external_refs, ) +class PackageScore(UUIDPKModel, Package_score_Mixin): + + def __str__(self): + return self.score or str(self.uuid) + + discovered_package = models.ForeignKey( + DiscoveredPackage, + related_name="declared_dependencies", + help_text=_("The package that declares this dependency."), + on_delete=models.CASCADE, + editable=False, + blank=True, + null=True, + ) + class WebhookSubscription(UUIDPKModel, ProjectRelatedModel): target_url = models.URLField(_("Target URL"), max_length=1024) From 605a5cf5b94e2baeaaeed4a3646033f0cea63f72 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 27 Jun 2024 16:57:25 +0530 Subject: [PATCH 05/50] transforming scorecard data into object for saving nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/scanpipe/models.py b/scanpipe/models.py index c6a0a0ab8..e73d1ba95 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3709,6 +3709,45 @@ def __str__(self): null=True, ) + @classmethod + def create_from_data( + cls, + DiscoveredPackage, + scorecard_data, + scoring_tool=None + ): + """ + Create and returns a DiscoveredDependency for a `project` from the + `dependency_data`. + + If `strip_datafile_path_root` is True, then `create_from_data()` will + strip the root path segment from the `datafile_path` of + `dependency_data` before looking up the corresponding CodebaseResource + for `datafile_path`. This is used in the case where Dependency data is + imported from a scancode-toolkit scan, where the root path segments are + not stripped for `datafile_path`. + """ + scorecard_data = scorecard_data.copy() + required_fields = ["purl", "dependency_uid"] + missing_values = [ + field_name + for field_name in required_fields + if not dependency_data.get(field_name) + ] + + + + cleaned_data = { + field_name: value + for field_name, value in dependency_data.items() + if field_name in cls.model_fields() and value not in EMPTY_VALUES + } + + return cls.objects.create( + discovered_package=DiscoveredPackage, + scoring_tool=scoring_tool, + ) + class WebhookSubscription(UUIDPKModel, ProjectRelatedModel): target_url = models.URLField(_("Target URL"), max_length=1024) From 3833dca0739312f61d615bf7fd9a45879de2f2e0 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 1 Jul 2024 13:35:27 +0530 Subject: [PATCH 06/50] added test cases for saving scorecard data into models and modified saving logic nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 50 +++++---- scanpipe/tests/__init__.py | 206 ++++++++++++++++++++++++++++++++++ scanpipe/tests/test_models.py | 12 ++ 3 files changed, 244 insertions(+), 24 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index e73d1ba95..902acc11c 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -29,6 +29,7 @@ from collections import Counter from collections import defaultdict from contextlib import suppress +from datetime import datetime from itertools import groupby from operator import itemgetter from pathlib import Path @@ -78,7 +79,8 @@ from packageurl import normalize_qualifiers from packageurl.contrib.django.models import PackageURLMixin from packageurl.contrib.django.models import PackageURLQuerySetMixin -from ossf_scorecard.contrib.models import Package_score_Mixin +from ossf_scorecard.contrib.django.models import Package_score_Mixin +from ossf_scorecard.contrib.django.utils import fetch_documentation_url from rest_framework.authtoken.models import Token from rq.command import send_stop_job_command from rq.exceptions import NoSuchJobError @@ -3694,6 +3696,7 @@ def as_spdx(self): external_refs=external_refs, ) + class PackageScore(UUIDPKModel, Package_score_Mixin): def __str__(self): @@ -3701,8 +3704,8 @@ def __str__(self): discovered_package = models.ForeignKey( DiscoveredPackage, - related_name="declared_dependencies", - help_text=_("The package that declares this dependency."), + related_name="discovered_packages_score", + help_text=_("The package for which the score is given"), on_delete=models.CASCADE, editable=False, blank=True, @@ -3717,37 +3720,36 @@ def create_from_data( scoring_tool=None ): """ - Create and returns a DiscoveredDependency for a `project` from the - `dependency_data`. - - If `strip_datafile_path_root` is True, then `create_from_data()` will - strip the root path segment from the `datafile_path` of - `dependency_data` before looking up the corresponding CodebaseResource - for `datafile_path`. This is used in the case where Dependency data is - imported from a scancode-toolkit scan, where the root path segments are - not stripped for `datafile_path`. + Create ScoreCard Object from ScoreCard Json """ scorecard_data = scorecard_data.copy() - required_fields = ["purl", "dependency_uid"] - missing_values = [ - field_name - for field_name in required_fields - if not dependency_data.get(field_name) - ] + final_data = {'score': str(scorecard_data.get('score')), + 'scoring_tool_version': scorecard_data.get('scorecard').get('version'), + 'scoring_tool_documentation_url': fetch_documentation_url( + scorecard_data.get('checks')[0].get('documentation').get('url') + )} + date_str = scorecard_data.get('date', None) + if date_str: - cleaned_data = { - field_name: value - for field_name, value in dependency_data.items() - if field_name in cls.model_fields() and value not in EMPTY_VALUES - } + naive_datetime = datetime.strptime(date_str, '%Y-%m-%d') - return cls.objects.create( + score_date = timezone.make_aware(naive_datetime, timezone.get_current_timezone()) + else: + score_date = timezone.now() + + final_data['score_date'] = score_date + + scorecard_object = cls.objects.create( + **final_data, discovered_package=DiscoveredPackage, scoring_tool=scoring_tool, ) + scorecard_object.save() + return scorecard_object + class WebhookSubscription(UUIDPKModel, ProjectRelatedModel): target_url = models.URLField(_("Target URL"), max_length=1024) diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index 42ad5e464..b9242cd7a 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -262,3 +262,209 @@ def make_dependency(project, **extra): "license_key": "mpl-2.0", }, } + + +scorecard_data = { + "date": "2024-06-17", + "repo": { + "name": "github.com/pallets/flask", + "commit": "d718ecf6d3dfc4656d262154c59672437c1ea075" + }, + "scorecard": { + "version": "v5.0.0-rc2-63-g5d08c1cc", + "commit": "5d08c1cc11c1e45c2ab2a88adac0a18464f0216b" + }, + "score": 6.7, + "checks": [ + { + "name": "Code-Review", + "score": 1, + "reason": "Found 2/11 approved changesets -- score normalized to 1", + "details": None, + "documentation": { + "short": "Determines if the project requires human code review before pull requests (aka merge requests) are merged.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#code-review" + } + }, + { + "name": "Maintained", + "score": 10, + "reason": "30 commit(s) and 17 issue activity found in the last 90 days -- score normalized to 10", + "details": None, + "documentation": { + "short": "Determines if the project is \"actively maintained\".", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#maintained" + } + }, + { + "name": "CII-Best-Practices", + "score": 0, + "reason": "no effort to earn an OpenSSF best practices badge detected", + "details": None, + "documentation": { + "short": "Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#cii-best-practices" + } + }, + { + "name": "License", + "score": 10, + "reason": "license file detected", + "details": [ + "Info: project has a license file: LICENSE.txt:0", + "Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE.txt:0" + ], + "documentation": { + "short": "Determines if the project has defined a license.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license" + } + }, + { + "name": "Dangerous-Workflow", + "score": 10, + "reason": "no dangerous workflow patterns detected", + "details": None, + "documentation": { + "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#dangerous-workflow" + } + }, + { + "name": "Signed-Releases", + "score": 10, + "reason": "5 out of the last 5 releases have a total of 5 signed artifacts.", + "details": [ + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/160813583", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/149637381", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/146388022", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/128454404", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/122480844" + ], + "documentation": { + "short": "Determines if the project cryptographically signs release artifacts.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#signed-releases" + } + }, + { + "name": "Token-Permissions", + "score": 0, + "reason": "detected GitHub workflow tokens with excessive permissions", + "details": [ + "Info: jobLevel 'actions' permission set to 'read': .github/workflows/publish.yaml:32", + "Warn: no topLevel permission defined: .github/workflows/publish.yaml:1", + "Warn: no topLevel permission defined: .github/workflows/tests.yaml:1", + "Info: no jobLevel write permissions found" + ], + "documentation": { + "short": "Determines if the project's workflows follow the principle of least privilege.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#token-permissions" + } + }, + { + "name": "Binary-Artifacts", + "score": 10, + "reason": "no binaries found in the repo", + "details": None, + "documentation": { + "short": "Determines if the project has generated executable (binary) artifacts in the source repository.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#binary-artifacts" + } + }, + { + "name": "Branch-Protection", + "score": -1, + "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", + "details": None, + "documentation": { + "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#branch-protection" + } + }, + { + "name": "Pinned-Dependencies", + "score": 4, + "reason": "dependency not pinned by hash detected -- score normalized to 4", + "details": [ + "Info: Possibly incomplete results: error parsing shell code: invalid parameter name: .github/workflows/tests.yaml:44", + "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:5", + "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:6", + "Warn: pipCommand not pinned by hash: .github/workflows/publish.yaml:19", + "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:44", + "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:60", + "Info: 10 out of 10 GitHub-owned GitHubAction dependencies pinned", + "Info: 3 out of 3 third-party GitHubAction dependencies pinned", + "Info: 0 out of 5 pipCommand dependencies pinned" + ], + "documentation": { + "short": "Determines if the project has declared and pinned the dependencies of its build process.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies" + } + }, + { + "name": "Fuzzing", + "score": 10, + "reason": "project is fuzzed", + "details": [ + "Info: OSSFuzz integration found" + ], + "documentation": { + "short": "Determines if the project uses fuzzing.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#fuzzing" + } + }, + { + "name": "Packaging", + "score": 10, + "reason": "packaging workflow detected", + "details": [ + "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yaml:55" + ], + "documentation": { + "short": "Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging" + } + }, + { + "name": "Security-Policy", + "score": 9, + "reason": "security policy file detected", + "details": [ + "Info: security policy file detected: github.com/pallets/.github/SECURITY.md:1", + "Info: Found linked content: github.com/pallets/.github/SECURITY.md:1", + "Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy", + "Info: Found text in security policy: github.com/pallets/.github/SECURITY.md:1" + ], + "documentation": { + "short": "Determines if the project has published a security policy.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#security-policy" + } + }, + { + "name": "Vulnerabilities", + "score": 6, + "reason": "4 existing vulnerabilities detected", + "details": [ + "Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95", + "Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj", + "Warn: Project is vulnerable to: GHSA-2g68-c3qc-8985", + "Warn: Project is vulnerable to: GHSA-hrfv-mqp8-q5rw / PYSEC-2023-221" + ], + "documentation": { + "short": "Determines if the project has open, known unfixed vulnerabilities.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#vulnerabilities" + } + }, + { + "name": "SAST", + "score": 0, + "reason": "SAST tool is not run on all commits -- score normalized to 0", + "details": [ + "Warn: 0 commits out of 22 are checked with a SAST tool" + ], + "documentation": { + "short": "Determines if the project uses static code analysis.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#sast" + } + } + ] +} \ No newline at end of file diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index d7c89bd44..f61d48775 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -59,6 +59,7 @@ from scanpipe.models import DiscoveredPackage from scanpipe.models import Project from scanpipe.models import ProjectMessage +from scanpipe.models import PackageScore from scanpipe.models import Run from scanpipe.models import RunInProgressError from scanpipe.models import RunNotAllowedToStart @@ -76,6 +77,7 @@ from scanpipe.tests import make_resource_file from scanpipe.tests import mocked_now from scanpipe.tests import package_data1 +from scanpipe.tests import scorecard_data from scanpipe.tests import package_data2 from scanpipe.tests.pipelines.do_nothing import DoNothing @@ -2277,6 +2279,16 @@ def test_scanpipe_codebase_resource_queryset_elfs(self): self.assertTrue("e" in paths) self.assertTrue("a" in paths) + def test_scorecard_models(self): + + package = DiscoveredPackage.create_from_data(self.project1, package_data1) + + package_score = PackageScore.create_from_data(package, scorecard_data, scoring_tool="OSSF") + + self.assertIsNotNone(package_score) + self.assertEqual(package_score.scoring_tool, "OSSF") + self.assertEqual(package_score.score, "6.7") + class ScanPipeModelsTransactionTest(TransactionTestCase): """ From 5502b5fb2164d84cbffaea829589b2298faea960 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Tue, 2 Jul 2024 00:19:27 +0530 Subject: [PATCH 07/50] added score checks mixin to models nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 47 +++++++++++++++++++++++++++++++++-- scanpipe/tests/test_models.py | 6 +++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index a9005fc59..1c433cb97 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -80,6 +80,7 @@ from packageurl import normalize_qualifiers from packageurl.contrib.django.models import PackageURLMixin from packageurl.contrib.django.models import PackageURLQuerySetMixin +from ossf_scorecard.contrib.django.models import scorecard_checks_Mixin from ossf_scorecard.contrib.django.models import Package_score_Mixin from ossf_scorecard.contrib.django.utils import fetch_documentation_url from rest_framework.authtoken.models import Token @@ -3786,6 +3787,7 @@ def __str__(self): ) @classmethod + @transaction.atomic() def create_from_data( cls, DiscoveredPackage, @@ -3820,8 +3822,50 @@ def create_from_data( scoring_tool=scoring_tool, ) - scorecard_object.save() + # Create associated scorecard_checks + checks_data = scorecard_data.get('checks', []) + + ScorecardCheck.objects.bulk_create([ + ScorecardCheck( + check_name=check_data.get('name'), + check_score=check_data.get('score'), + reason=check_data.get('reason'), + details=check_data.get('details', []), + for_package_score=scorecard_object + ) for check_data in checks_data + ]) + return scorecard_object + + +class ScorecardCheck(UUIDPKModel, scorecard_checks_Mixin): + + def __str__(self): + return self.check_score or str(self.uuid) + + for_package_score = models.ForeignKey( + PackageScore, + related_name="discovered_packages_score_checks", + help_text=_("The checks for which the score is given"), + on_delete=models.CASCADE, + editable=False, + blank=True, + null=True, + ) + + @classmethod + def create_from_data(cls, package_score, check_data): + """ + Create a ScorecardCheck instance from provided data. + """ + final_data = { + 'check_name': check_data.get('name'), + 'check_score': check_data.get('score'), + 'reason': check_data.get('reason'), + 'details': check_data.get('details', []), + 'for_package_score': package_score, + } + return cls.objects.create(**final_data) def normalize_package_url_data(purl_mapping, ignore_nulls=False): """ @@ -3842,7 +3886,6 @@ def normalize_package_url_data(purl_mapping, ignore_nulls=False): return normalized_purl_mapping - class WebhookSubscription(UUIDPKModel, ProjectRelatedModel): target_url = models.URLField(_("Target URL"), max_length=1024) created_date = models.DateTimeField(auto_now_add=True, editable=False) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 37f4b1d10..fe1d943f3 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2302,6 +2302,12 @@ def test_scorecard_models(self): self.assertEqual(package_score.scoring_tool, "OSSF") self.assertEqual(package_score.score, "6.7") + checks = package_score.discovered_packages_score_checks.all() + self.assertEqual(checks.count(), 14) + self.assertEqual(checks[0].check_name, 'Code-Review') + self.assertEqual(checks[0].check_score, '1') + + class ScanPipeModelsTransactionTest(TransactionTestCase): """ From 103fca087334094bd34c42e87fa2d7dcb347c224 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 3 Jul 2024 20:24:49 +0530 Subject: [PATCH 08/50] empty details in score response handled nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 1c433cb97..61a68271a 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3825,12 +3825,13 @@ def create_from_data( # Create associated scorecard_checks checks_data = scorecard_data.get('checks', []) + ScorecardCheck.objects.bulk_create([ ScorecardCheck( check_name=check_data.get('name'), check_score=check_data.get('score'), reason=check_data.get('reason'), - details=check_data.get('details', []), + details=check_data.get('details') or [], for_package_score=scorecard_object ) for check_data in checks_data ]) From 952e6a6158dfb208f24e98dbaa210e70699f0f1d Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 3 Jul 2024 22:57:46 +0530 Subject: [PATCH 09/50] changed class names to camel case for models and modified the tests nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 12 ++++++------ scanpipe/tests/test_models.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 61a68271a..c13f3690b 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -80,9 +80,9 @@ from packageurl import normalize_qualifiers from packageurl.contrib.django.models import PackageURLMixin from packageurl.contrib.django.models import PackageURLQuerySetMixin -from ossf_scorecard.contrib.django.models import scorecard_checks_Mixin -from ossf_scorecard.contrib.django.models import Package_score_Mixin -from ossf_scorecard.contrib.django.utils import fetch_documentation_url +from ossf_scorecard.contrib.django.models import ScorecardChecksMixin +from ossf_scorecard.contrib.django.models import PackageScoreMixin +from ossf_scorecard.contrib.django.utils import FetchDocumentationUrl from rest_framework.authtoken.models import Token from rq.command import send_stop_job_command from rq.exceptions import NoSuchJobError @@ -3771,7 +3771,7 @@ def as_spdx(self): -class PackageScore(UUIDPKModel, Package_score_Mixin): +class PackageScore(UUIDPKModel, PackageScoreMixin): def __str__(self): return self.score or str(self.uuid) @@ -3801,7 +3801,7 @@ def create_from_data( final_data = {'score': str(scorecard_data.get('score')), 'scoring_tool_version': scorecard_data.get('scorecard').get('version'), - 'scoring_tool_documentation_url': fetch_documentation_url( + 'scoring_tool_documentation_url': FetchDocumentationUrl( scorecard_data.get('checks')[0].get('documentation').get('url') )} @@ -3839,7 +3839,7 @@ def create_from_data( return scorecard_object -class ScorecardCheck(UUIDPKModel, scorecard_checks_Mixin): +class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): def __str__(self): return self.check_score or str(self.uuid) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index fe1d943f3..5c5f09f6a 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2296,14 +2296,14 @@ def test_scorecard_models(self): package = DiscoveredPackage.create_from_data(self.project1, package_data1) - package_score = PackageScore.create_from_data(package, scorecard_data, scoring_tool="OSSF") + package_score = PackageScore.create_from_data(package, scorecard_data, PackageScore.ScoringTool.OSSF) self.assertIsNotNone(package_score) - self.assertEqual(package_score.scoring_tool, "OSSF") + self.assertEqual(package_score.scoring_tool, PackageScore.ScoringTool.OSSF) self.assertEqual(package_score.score, "6.7") checks = package_score.discovered_packages_score_checks.all() - self.assertEqual(checks.count(), 14) + self.assertEqual(checks.count(), 15) self.assertEqual(checks[0].check_name, 'Code-Review') self.assertEqual(checks[0].check_score, '1') From 3ba3db57be59263b611f43d27637ea541c47d0b9 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 4 Jul 2024 00:22:55 +0530 Subject: [PATCH 10/50] code formatted nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 67 +++--- scanpipe/tests/__init__.py | 398 +++++++++++++++++----------------- scanpipe/tests/test_models.py | 11 +- 3 files changed, 236 insertions(+), 240 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index c13f3690b..ac74ddbd0 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3770,7 +3770,6 @@ def as_spdx(self): ) - class PackageScore(UUIDPKModel, PackageScoreMixin): def __str__(self): @@ -3788,33 +3787,32 @@ def __str__(self): @classmethod @transaction.atomic() - def create_from_data( - cls, - DiscoveredPackage, - scorecard_data, - scoring_tool=None - ): + def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): """ Create ScoreCard Object from ScoreCard Json """ scorecard_data = scorecard_data.copy() - final_data = {'score': str(scorecard_data.get('score')), - 'scoring_tool_version': scorecard_data.get('scorecard').get('version'), - 'scoring_tool_documentation_url': FetchDocumentationUrl( - scorecard_data.get('checks')[0].get('documentation').get('url') - )} + final_data = { + "score": str(scorecard_data.get("score")), + "scoring_tool_version": scorecard_data.get("scorecard").get("version"), + "scoring_tool_documentation_url": FetchDocumentationUrl( + scorecard_data.get("checks")[0].get("documentation").get("url") + ), + } - date_str = scorecard_data.get('date', None) + date_str = scorecard_data.get("date", None) if date_str: - naive_datetime = datetime.strptime(date_str, '%Y-%m-%d') + naive_datetime = datetime.strptime(date_str, "%Y-%m-%d") - score_date = timezone.make_aware(naive_datetime, timezone.get_current_timezone()) + score_date = timezone.make_aware( + naive_datetime, timezone.get_current_timezone() + ) else: score_date = timezone.now() - final_data['score_date'] = score_date + final_data["score_date"] = score_date scorecard_object = cls.objects.create( **final_data, @@ -3823,18 +3821,20 @@ def create_from_data( ) # Create associated scorecard_checks - checks_data = scorecard_data.get('checks', []) + checks_data = scorecard_data.get("checks", []) - - ScorecardCheck.objects.bulk_create([ - ScorecardCheck( - check_name=check_data.get('name'), - check_score=check_data.get('score'), - reason=check_data.get('reason'), - details=check_data.get('details') or [], - for_package_score=scorecard_object - ) for check_data in checks_data - ]) + ScorecardCheck.objects.bulk_create( + [ + ScorecardCheck( + check_name=check_data.get("name"), + check_score=check_data.get("score"), + reason=check_data.get("reason"), + details=check_data.get("details") or [], + for_package_score=scorecard_object, + ) + for check_data in checks_data + ] + ) return scorecard_object @@ -3860,14 +3860,15 @@ def create_from_data(cls, package_score, check_data): Create a ScorecardCheck instance from provided data. """ final_data = { - 'check_name': check_data.get('name'), - 'check_score': check_data.get('score'), - 'reason': check_data.get('reason'), - 'details': check_data.get('details', []), - 'for_package_score': package_score, + "check_name": check_data.get("name"), + "check_score": check_data.get("score"), + "reason": check_data.get("reason"), + "details": check_data.get("details", []), + "for_package_score": package_score, } return cls.objects.create(**final_data) - + + def normalize_package_url_data(purl_mapping, ignore_nulls=False): """ Normalize a mapping of purl data so database queries with diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index b9242cd7a..bb8864be6 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -265,206 +265,202 @@ def make_dependency(project, **extra): scorecard_data = { - "date": "2024-06-17", - "repo": { - "name": "github.com/pallets/flask", - "commit": "d718ecf6d3dfc4656d262154c59672437c1ea075" - }, - "scorecard": { - "version": "v5.0.0-rc2-63-g5d08c1cc", - "commit": "5d08c1cc11c1e45c2ab2a88adac0a18464f0216b" - }, - "score": 6.7, - "checks": [ - { - "name": "Code-Review", - "score": 1, - "reason": "Found 2/11 approved changesets -- score normalized to 1", - "details": None, - "documentation": { - "short": "Determines if the project requires human code review before pull requests (aka merge requests) are merged.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#code-review" - } - }, - { - "name": "Maintained", - "score": 10, - "reason": "30 commit(s) and 17 issue activity found in the last 90 days -- score normalized to 10", - "details": None, - "documentation": { - "short": "Determines if the project is \"actively maintained\".", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#maintained" - } - }, - { - "name": "CII-Best-Practices", - "score": 0, - "reason": "no effort to earn an OpenSSF best practices badge detected", - "details": None, - "documentation": { - "short": "Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#cii-best-practices" - } - }, - { - "name": "License", - "score": 10, - "reason": "license file detected", - "details": [ - "Info: project has a license file: LICENSE.txt:0", - "Info: FSF or OSI recognized license: BSD 3-Clause \"New\" or \"Revised\" License: LICENSE.txt:0" - ], - "documentation": { - "short": "Determines if the project has defined a license.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license" - } - }, - { - "name": "Dangerous-Workflow", - "score": 10, - "reason": "no dangerous workflow patterns detected", - "details": None, - "documentation": { - "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#dangerous-workflow" - } - }, - { - "name": "Signed-Releases", - "score": 10, - "reason": "5 out of the last 5 releases have a total of 5 signed artifacts.", - "details": [ - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/160813583", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/149637381", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/146388022", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/128454404", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/122480844" - ], - "documentation": { - "short": "Determines if the project cryptographically signs release artifacts.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#signed-releases" - } - }, - { - "name": "Token-Permissions", - "score": 0, - "reason": "detected GitHub workflow tokens with excessive permissions", - "details": [ - "Info: jobLevel 'actions' permission set to 'read': .github/workflows/publish.yaml:32", - "Warn: no topLevel permission defined: .github/workflows/publish.yaml:1", - "Warn: no topLevel permission defined: .github/workflows/tests.yaml:1", - "Info: no jobLevel write permissions found" - ], - "documentation": { - "short": "Determines if the project's workflows follow the principle of least privilege.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#token-permissions" - } - }, - { - "name": "Binary-Artifacts", - "score": 10, - "reason": "no binaries found in the repo", - "details": None, - "documentation": { - "short": "Determines if the project has generated executable (binary) artifacts in the source repository.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#binary-artifacts" - } - }, - { - "name": "Branch-Protection", - "score": -1, - "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", - "details": None, - "documentation": { - "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#branch-protection" - } - }, - { - "name": "Pinned-Dependencies", - "score": 4, - "reason": "dependency not pinned by hash detected -- score normalized to 4", - "details": [ - "Info: Possibly incomplete results: error parsing shell code: invalid parameter name: .github/workflows/tests.yaml:44", - "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:5", - "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:6", - "Warn: pipCommand not pinned by hash: .github/workflows/publish.yaml:19", - "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:44", - "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:60", - "Info: 10 out of 10 GitHub-owned GitHubAction dependencies pinned", - "Info: 3 out of 3 third-party GitHubAction dependencies pinned", - "Info: 0 out of 5 pipCommand dependencies pinned" - ], - "documentation": { - "short": "Determines if the project has declared and pinned the dependencies of its build process.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies" - } - }, - { - "name": "Fuzzing", - "score": 10, - "reason": "project is fuzzed", - "details": [ - "Info: OSSFuzz integration found" - ], - "documentation": { - "short": "Determines if the project uses fuzzing.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#fuzzing" - } - }, - { - "name": "Packaging", - "score": 10, - "reason": "packaging workflow detected", - "details": [ - "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yaml:55" - ], - "documentation": { - "short": "Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging" - } - }, - { - "name": "Security-Policy", - "score": 9, - "reason": "security policy file detected", - "details": [ - "Info: security policy file detected: github.com/pallets/.github/SECURITY.md:1", - "Info: Found linked content: github.com/pallets/.github/SECURITY.md:1", - "Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy", - "Info: Found text in security policy: github.com/pallets/.github/SECURITY.md:1" - ], - "documentation": { - "short": "Determines if the project has published a security policy.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#security-policy" - } + "date": "2024-06-17", + "repo": { + "name": "github.com/pallets/flask", + "commit": "d718ecf6d3dfc4656d262154c59672437c1ea075", }, - { - "name": "Vulnerabilities", - "score": 6, - "reason": "4 existing vulnerabilities detected", - "details": [ - "Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95", - "Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj", - "Warn: Project is vulnerable to: GHSA-2g68-c3qc-8985", - "Warn: Project is vulnerable to: GHSA-hrfv-mqp8-q5rw / PYSEC-2023-221" - ], - "documentation": { - "short": "Determines if the project has open, known unfixed vulnerabilities.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#vulnerabilities" - } + "scorecard": { + "version": "v5.0.0-rc2-63-g5d08c1cc", + "commit": "5d08c1cc11c1e45c2ab2a88adac0a18464f0216b", }, - { - "name": "SAST", - "score": 0, - "reason": "SAST tool is not run on all commits -- score normalized to 0", - "details": [ - "Warn: 0 commits out of 22 are checked with a SAST tool" - ], - "documentation": { - "short": "Determines if the project uses static code analysis.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#sast" - } - } - ] -} \ No newline at end of file + "score": 6.7, + "checks": [ + { + "name": "Code-Review", + "score": 1, + "reason": "Found 2/11 approved changesets -- score normalized to 1", + "details": None, + "documentation": { + "short": "Determines if the project requires human code review before pull requests (aka merge requests) are merged.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#code-review", + }, + }, + { + "name": "Maintained", + "score": 10, + "reason": "30 commit(s) and 17 issue activity found in the last 90 days -- score normalized to 10", + "details": None, + "documentation": { + "short": 'Determines if the project is "actively maintained".', + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#maintained", + }, + }, + { + "name": "CII-Best-Practices", + "score": 0, + "reason": "no effort to earn an OpenSSF best practices badge detected", + "details": None, + "documentation": { + "short": "Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#cii-best-practices", + }, + }, + { + "name": "License", + "score": 10, + "reason": "license file detected", + "details": [ + "Info: project has a license file: LICENSE.txt:0", + 'Info: FSF or OSI recognized license: BSD 3-Clause "New" or "Revised" License: LICENSE.txt:0', + ], + "documentation": { + "short": "Determines if the project has defined a license.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license", + }, + }, + { + "name": "Dangerous-Workflow", + "score": 10, + "reason": "no dangerous workflow patterns detected", + "details": None, + "documentation": { + "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#dangerous-workflow", + }, + }, + { + "name": "Signed-Releases", + "score": 10, + "reason": "5 out of the last 5 releases have a total of 5 signed artifacts.", + "details": [ + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/160813583", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/149637381", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/146388022", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/128454404", + "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/122480844", + ], + "documentation": { + "short": "Determines if the project cryptographically signs release artifacts.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#signed-releases", + }, + }, + { + "name": "Token-Permissions", + "score": 0, + "reason": "detected GitHub workflow tokens with excessive permissions", + "details": [ + "Info: jobLevel 'actions' permission set to 'read': .github/workflows/publish.yaml:32", + "Warn: no topLevel permission defined: .github/workflows/publish.yaml:1", + "Warn: no topLevel permission defined: .github/workflows/tests.yaml:1", + "Info: no jobLevel write permissions found", + ], + "documentation": { + "short": "Determines if the project's workflows follow the principle of least privilege.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#token-permissions", + }, + }, + { + "name": "Binary-Artifacts", + "score": 10, + "reason": "no binaries found in the repo", + "details": None, + "documentation": { + "short": "Determines if the project has generated executable (binary) artifacts in the source repository.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#binary-artifacts", + }, + }, + { + "name": "Branch-Protection", + "score": -1, + "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", + "details": None, + "documentation": { + "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#branch-protection", + }, + }, + { + "name": "Pinned-Dependencies", + "score": 4, + "reason": "dependency not pinned by hash detected -- score normalized to 4", + "details": [ + "Info: Possibly incomplete results: error parsing shell code: invalid parameter name: .github/workflows/tests.yaml:44", + "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:5", + "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:6", + "Warn: pipCommand not pinned by hash: .github/workflows/publish.yaml:19", + "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:44", + "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:60", + "Info: 10 out of 10 GitHub-owned GitHubAction dependencies pinned", + "Info: 3 out of 3 third-party GitHubAction dependencies pinned", + "Info: 0 out of 5 pipCommand dependencies pinned", + ], + "documentation": { + "short": "Determines if the project has declared and pinned the dependencies of its build process.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies", + }, + }, + { + "name": "Fuzzing", + "score": 10, + "reason": "project is fuzzed", + "details": ["Info: OSSFuzz integration found"], + "documentation": { + "short": "Determines if the project uses fuzzing.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#fuzzing", + }, + }, + { + "name": "Packaging", + "score": 10, + "reason": "packaging workflow detected", + "details": [ + "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yaml:55" + ], + "documentation": { + "short": "Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging", + }, + }, + { + "name": "Security-Policy", + "score": 9, + "reason": "security policy file detected", + "details": [ + "Info: security policy file detected: github.com/pallets/.github/SECURITY.md:1", + "Info: Found linked content: github.com/pallets/.github/SECURITY.md:1", + "Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy", + "Info: Found text in security policy: github.com/pallets/.github/SECURITY.md:1", + ], + "documentation": { + "short": "Determines if the project has published a security policy.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#security-policy", + }, + }, + { + "name": "Vulnerabilities", + "score": 6, + "reason": "4 existing vulnerabilities detected", + "details": [ + "Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95", + "Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj", + "Warn: Project is vulnerable to: GHSA-2g68-c3qc-8985", + "Warn: Project is vulnerable to: GHSA-hrfv-mqp8-q5rw / PYSEC-2023-221", + ], + "documentation": { + "short": "Determines if the project has open, known unfixed vulnerabilities.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#vulnerabilities", + }, + }, + { + "name": "SAST", + "score": 0, + "reason": "SAST tool is not run on all commits -- score normalized to 0", + "details": ["Warn: 0 commits out of 22 are checked with a SAST tool"], + "documentation": { + "short": "Determines if the project uses static code analysis.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#sast", + }, + }, + ], +} diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 5c5f09f6a..141a3354b 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2293,10 +2293,10 @@ def test_scanpipe_codebase_resource_queryset_elfs(self): self.assertTrue("a" in paths) def test_scorecard_models(self): - package = DiscoveredPackage.create_from_data(self.project1, package_data1) - - package_score = PackageScore.create_from_data(package, scorecard_data, PackageScore.ScoringTool.OSSF) + package_score = PackageScore.create_from_data( + package, scorecard_data, PackageScore.ScoringTool.OSSF + ) self.assertIsNotNone(package_score) self.assertEqual(package_score.scoring_tool, PackageScore.ScoringTool.OSSF) @@ -2304,9 +2304,8 @@ def test_scorecard_models(self): checks = package_score.discovered_packages_score_checks.all() self.assertEqual(checks.count(), 15) - self.assertEqual(checks[0].check_name, 'Code-Review') - self.assertEqual(checks[0].check_score, '1') - + self.assertEqual(checks[0].check_name, "Code-Review") + self.assertEqual(checks[0].check_score, "1") class ScanPipeModelsTransactionTest(TransactionTestCase): From 2f2b84699af9a616d2774148a7b9eb305173fd8d Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 4 Jul 2024 01:54:28 +0530 Subject: [PATCH 11/50] code formatted nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 6 +- scanpipe/tests/__init__.py | 135 ++++++++++++++++++++++------------ scanpipe/tests/test_models.py | 4 +- 3 files changed, 95 insertions(+), 50 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index ac74ddbd0..56737c0a3 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -74,15 +74,15 @@ from licensedcode.cache import build_spdx_license_expression from licensedcode.cache import get_licensing from matchcode_toolkit.fingerprinting import IGNORED_DIRECTORY_FINGERPRINTS +from ossf_scorecard.contrib.django.models import PackageScoreMixin +from ossf_scorecard.contrib.django.models import ScorecardChecksMixin +from ossf_scorecard.contrib.django.utils import FetchDocumentationUrl from packagedcode.models import build_package_uid from packagedcode.utils import get_base_purl from packageurl import PackageURL from packageurl import normalize_qualifiers from packageurl.contrib.django.models import PackageURLMixin from packageurl.contrib.django.models import PackageURLQuerySetMixin -from ossf_scorecard.contrib.django.models import ScorecardChecksMixin -from ossf_scorecard.contrib.django.models import PackageScoreMixin -from ossf_scorecard.contrib.django.utils import FetchDocumentationUrl from rest_framework.authtoken.models import Token from rq.command import send_stop_job_command from rq.exceptions import NoSuchJobError diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index bb8864be6..b828c3824 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -263,7 +263,6 @@ def make_dependency(project, **extra): }, } - scorecard_data = { "date": "2024-06-17", "repo": { @@ -282,18 +281,22 @@ def make_dependency(project, **extra): "reason": "Found 2/11 approved changesets -- score normalized to 1", "details": None, "documentation": { - "short": "Determines if the project requires human code review before pull requests (aka merge requests) are merged.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#code-review", + "short": "Determines if the project requires human code review before " + "pull requests (aka merge requests) are merged.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a" + "88adac0a18464f0216b/docs/checks.md#code-review", }, }, { "name": "Maintained", "score": 10, - "reason": "30 commit(s) and 17 issue activity found in the last 90 days -- score normalized to 10", + "reason": "30 commit(s) and 17 issue activity found in the last 90 days " + "-- score normalized to 10", "details": None, "documentation": { "short": 'Determines if the project is "actively maintained".', - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#maintained", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" + "adac0a18464f0216b/docs/checks.md#maintained", }, }, { @@ -302,8 +305,10 @@ def make_dependency(project, **extra): "reason": "no effort to earn an OpenSSF best practices badge detected", "details": None, "documentation": { - "short": "Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#cii-best-practices", + "short": "Determines if the project has an OpenSSF (formerly CII) Best " + "Practices Badge.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" + "adac0a18464f0216b/docs/checks.md#cii-best-practices", }, }, { @@ -312,11 +317,13 @@ def make_dependency(project, **extra): "reason": "license file detected", "details": [ "Info: project has a license file: LICENSE.txt:0", - 'Info: FSF or OSI recognized license: BSD 3-Clause "New" or "Revised" License: LICENSE.txt:0', + 'Info: FSF or OSI recognized license: BSD 3-Clause "New" or "Revised"' + ' License: LICENSE.txt:0', ], "documentation": { "short": "Determines if the project has defined a license.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c" + "1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license", }, }, { @@ -325,24 +332,34 @@ def make_dependency(project, **extra): "reason": "no dangerous workflow patterns detected", "details": None, "documentation": { - "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#dangerous-workflow", + "short": "Determines if the project's GitHub Action workflows avoid " + "dangerous patterns.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88a" + "dac0a18464f0216b/docs/checks.md#dangerous-workflow", }, }, { "name": "Signed-Releases", "score": 10, - "reason": "5 out of the last 5 releases have a total of 5 signed artifacts.", + "reason": "5 out of the last 5 releases have a total of 5 signed " + "artifacts.", "details": [ - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/160813583", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/149637381", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/146388022", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/128454404", - "Info: provenance for release artifact: multiple.intoto.jsonl: https://api.github.com/repos/pallets/flask/releases/assets/122480844", + "Info: provenance for release artifact: multiple.intoto.jsonl:" + " https://api.github.com/repos/pallets/flask/releases/assets/160813583", + "Info: provenance for release artifact: multiple.intoto.jsonl:" + " https://api.github.com/repos/pallets/flask/releases/assets/149637381", + "Info: provenance for release artifact: multiple.intoto.jsonl:" + " https://api.github.com/repos/pallets/flask/releases/assets/146388022", + "Info: provenance for release artifact: multiple.intoto.jsonl:" + " https://api.github.com/repos/pallets/flask/releases/assets/128454404", + "Info: provenance for release artifact: multiple.intoto.jsonl:" + " https://api.github.com/repos/pallets/flask/releases/assets/122480844", ], "documentation": { - "short": "Determines if the project cryptographically signs release artifacts.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#signed-releases", + "short": "Determines if the project cryptographically signs release art" + "ifacts.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" + "adac0a18464f0216b/docs/checks.md#signed-releases", }, }, { @@ -350,14 +367,18 @@ def make_dependency(project, **extra): "score": 0, "reason": "detected GitHub workflow tokens with excessive permissions", "details": [ - "Info: jobLevel 'actions' permission set to 'read': .github/workflows/publish.yaml:32", - "Warn: no topLevel permission defined: .github/workflows/publish.yaml:1", + "Info: jobLevel 'actions' permission set to 'read': .github/workflows/" + "publish.yaml:32", + "Warn: no topLevel permission defined: .github/workflows/publish" + ".yaml:1", "Warn: no topLevel permission defined: .github/workflows/tests.yaml:1", "Info: no jobLevel write permissions found", ], "documentation": { - "short": "Determines if the project's workflows follow the principle of least privilege.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#token-permissions", + "short": "Determines if the project's workflows follow the princip" + "le of least privilege.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a8" + "8adac0a18464f0216b/docs/checks.md#token-permissions", }, }, { @@ -366,18 +387,24 @@ def make_dependency(project, **extra): "reason": "no binaries found in the repo", "details": None, "documentation": { - "short": "Determines if the project has generated executable (binary) artifacts in the source repository.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#binary-artifacts", + "short": "Determines if the project has generated executable (bin" + "ary) artifacts in the source repository.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" + "2a88adac0a18464f0216b/docs/checks.md#binary-artifacts", }, }, { "name": "Branch-Protection", "score": -1, - "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", + "reason": "internal error: error during branchesHandler.setup: intern" + "al error: githubv4.Query: " + "Resource not accessible by integration", "details": None, "documentation": { - "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#branch-protection", + "short": "Determines if the default and release branches are prote" + "cted with GitHub's branch protection settings.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" + "2a88adac0a18464f0216b/docs/checks.md#branch-protection", }, }, { @@ -385,10 +412,14 @@ def make_dependency(project, **extra): "score": 4, "reason": "dependency not pinned by hash detected -- score normalized to 4", "details": [ - "Info: Possibly incomplete results: error parsing shell code: invalid parameter name: .github/workflows/tests.yaml:44", - "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:5", - "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command.sh:6", - "Warn: pipCommand not pinned by hash: .github/workflows/publish.yaml:19", + "Info: Possibly incomplete results: error parsing shell code: inv" + "alid parameter name: .github/workflows/tests.yaml:44", + "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command" + ".sh:5", + "Warn: pipCommand not pinned by hash: .devcontainer/on-create-comm" + "and.sh:6", + "Warn: pipCommand not pinned by hash: .github/workflows/publish.yaml" + ":19", "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:44", "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:60", "Info: 10 out of 10 GitHub-owned GitHubAction dependencies pinned", @@ -396,8 +427,10 @@ def make_dependency(project, **extra): "Info: 0 out of 5 pipCommand dependencies pinned", ], "documentation": { - "short": "Determines if the project has declared and pinned the dependencies of its build process.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies", + "short": "Determines if the project has declared and pinned the depen" + "dencies of its build process.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" + "2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies", }, }, { @@ -407,7 +440,8 @@ def make_dependency(project, **extra): "details": ["Info: OSSFuzz integration found"], "documentation": { "short": "Determines if the project uses fuzzing.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#fuzzing", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a" + "88adac0a18464f0216b/docs/checks.md#fuzzing", }, }, { @@ -415,11 +449,15 @@ def make_dependency(project, **extra): "score": 10, "reason": "packaging workflow detected", "details": [ - "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yaml:55" + "Info: Project packages its releases by way of GitHub Actions.: .git" + "hub/workflows/publish.yaml:55" ], "documentation": { - "short": "Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging", + "short": "Determines if the project is published as a package that othe" + "rs can easily download, install, " + "easily update, and uninstall.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e" + "45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging", }, }, { @@ -427,14 +465,18 @@ def make_dependency(project, **extra): "score": 9, "reason": "security policy file detected", "details": [ - "Info: security policy file detected: github.com/pallets/.github/SECURITY.md:1", + "Info: security policy file detected: github.com/pallets/.github/S" + "ECURITY.md:1", "Info: Found linked content: github.com/pallets/.github/SECURITY.md:1", - "Warn: One or no descriptive hints of disclosure, vulnerability, and/or timelines in security policy", - "Info: Found text in security policy: github.com/pallets/.github/SECURITY.md:1", + "Warn: One or no descriptive hints of disclosure, vulnerability," + " and/or timelines in security policy", + "Info: Found text in security policy: github.com/pallets/" + ".github/SECURITY.md:1", ], "documentation": { "short": "Determines if the project has published a security policy.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#security-policy", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2" + "ab2a88adac0a18464f0216b/docs/checks.md#security-policy", }, }, { @@ -448,8 +490,10 @@ def make_dependency(project, **extra): "Warn: Project is vulnerable to: GHSA-hrfv-mqp8-q5rw / PYSEC-2023-221", ], "documentation": { - "short": "Determines if the project has open, known unfixed vulnerabilities.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#vulnerabilities", + "short": "Determines if the project has open, known unfixed vulnera" + "bilities.", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2" + "a88adac0a18464f0216b/docs/checks.md#vulnerabilities", }, }, { @@ -459,7 +503,8 @@ def make_dependency(project, **extra): "details": ["Warn: 0 commits out of 22 are checked with a SAST tool"], "documentation": { "short": "Determines if the project uses static code analysis.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88adac0a18464f0216b/docs/checks.md#sast", + "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2a" + "b2a88adac0a18464f0216b/docs/checks.md#sast", }, }, ], diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 141a3354b..ad9751261 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -58,9 +58,9 @@ from scanpipe.models import CodebaseResource from scanpipe.models import DiscoveredDependency from scanpipe.models import DiscoveredPackage +from scanpipe.models import PackageScore from scanpipe.models import Project from scanpipe.models import ProjectMessage -from scanpipe.models import PackageScore from scanpipe.models import Run from scanpipe.models import RunInProgressError from scanpipe.models import RunNotAllowedToStart @@ -79,8 +79,8 @@ from scanpipe.tests import make_resource_file from scanpipe.tests import mocked_now from scanpipe.tests import package_data1 -from scanpipe.tests import scorecard_data from scanpipe.tests import package_data2 +from scanpipe.tests import scorecard_data from scanpipe.tests.pipelines.do_nothing import DoNothing scanpipe_app = apps.get_app_config("scanpipe") From 39a056d2df4b7ed82f7fb40dc3d50159a97aabb4 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 4 Jul 2024 01:58:10 +0530 Subject: [PATCH 12/50] code formatted nexB#1283 Signed-off-by: 404-geek --- scanpipe/tests/__init__.py | 62 +++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index b828c3824..9c67c440d 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -282,21 +282,21 @@ def make_dependency(project, **extra): "details": None, "documentation": { "short": "Determines if the project requires human code review before " - "pull requests (aka merge requests) are merged.", + "pull requests (aka merge requests) are merged.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a" - "88adac0a18464f0216b/docs/checks.md#code-review", + "88adac0a18464f0216b/docs/checks.md#code-review", }, }, { "name": "Maintained", "score": 10, "reason": "30 commit(s) and 17 issue activity found in the last 90 days " - "-- score normalized to 10", + "-- score normalized to 10", "details": None, "documentation": { "short": 'Determines if the project is "actively maintained".', "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" - "adac0a18464f0216b/docs/checks.md#maintained", + "adac0a18464f0216b/docs/checks.md#maintained", }, }, { @@ -306,9 +306,9 @@ def make_dependency(project, **extra): "details": None, "documentation": { "short": "Determines if the project has an OpenSSF (formerly CII) Best " - "Practices Badge.", + "Practices Badge.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" - "adac0a18464f0216b/docs/checks.md#cii-best-practices", + "adac0a18464f0216b/docs/checks.md#cii-best-practices", }, }, { @@ -318,12 +318,12 @@ def make_dependency(project, **extra): "details": [ "Info: project has a license file: LICENSE.txt:0", 'Info: FSF or OSI recognized license: BSD 3-Clause "New" or "Revised"' - ' License: LICENSE.txt:0', + " License: LICENSE.txt:0", ], "documentation": { "short": "Determines if the project has defined a license.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c" - "1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license", + "1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license", }, }, { @@ -333,16 +333,16 @@ def make_dependency(project, **extra): "details": None, "documentation": { "short": "Determines if the project's GitHub Action workflows avoid " - "dangerous patterns.", + "dangerous patterns.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88a" - "dac0a18464f0216b/docs/checks.md#dangerous-workflow", + "dac0a18464f0216b/docs/checks.md#dangerous-workflow", }, }, { "name": "Signed-Releases", "score": 10, "reason": "5 out of the last 5 releases have a total of 5 signed " - "artifacts.", + "artifacts.", "details": [ "Info: provenance for release artifact: multiple.intoto.jsonl:" " https://api.github.com/repos/pallets/flask/releases/assets/160813583", @@ -357,9 +357,9 @@ def make_dependency(project, **extra): ], "documentation": { "short": "Determines if the project cryptographically signs release art" - "ifacts.", + "ifacts.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" - "adac0a18464f0216b/docs/checks.md#signed-releases", + "adac0a18464f0216b/docs/checks.md#signed-releases", }, }, { @@ -376,9 +376,9 @@ def make_dependency(project, **extra): ], "documentation": { "short": "Determines if the project's workflows follow the princip" - "le of least privilege.", + "le of least privilege.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a8" - "8adac0a18464f0216b/docs/checks.md#token-permissions", + "8adac0a18464f0216b/docs/checks.md#token-permissions", }, }, { @@ -388,23 +388,23 @@ def make_dependency(project, **extra): "details": None, "documentation": { "short": "Determines if the project has generated executable (bin" - "ary) artifacts in the source repository.", + "ary) artifacts in the source repository.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" - "2a88adac0a18464f0216b/docs/checks.md#binary-artifacts", + "2a88adac0a18464f0216b/docs/checks.md#binary-artifacts", }, }, { "name": "Branch-Protection", "score": -1, "reason": "internal error: error during branchesHandler.setup: intern" - "al error: githubv4.Query: " - "Resource not accessible by integration", + "al error: githubv4.Query: " + "Resource not accessible by integration", "details": None, "documentation": { "short": "Determines if the default and release branches are prote" - "cted with GitHub's branch protection settings.", + "cted with GitHub's branch protection settings.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" - "2a88adac0a18464f0216b/docs/checks.md#branch-protection", + "2a88adac0a18464f0216b/docs/checks.md#branch-protection", }, }, { @@ -428,9 +428,9 @@ def make_dependency(project, **extra): ], "documentation": { "short": "Determines if the project has declared and pinned the depen" - "dencies of its build process.", + "dencies of its build process.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" - "2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies", + "2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies", }, }, { @@ -441,7 +441,7 @@ def make_dependency(project, **extra): "documentation": { "short": "Determines if the project uses fuzzing.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a" - "88adac0a18464f0216b/docs/checks.md#fuzzing", + "88adac0a18464f0216b/docs/checks.md#fuzzing", }, }, { @@ -454,10 +454,10 @@ def make_dependency(project, **extra): ], "documentation": { "short": "Determines if the project is published as a package that othe" - "rs can easily download, install, " - "easily update, and uninstall.", + "rs can easily download, install, " + "easily update, and uninstall.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e" - "45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging", + "45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging", }, }, { @@ -476,7 +476,7 @@ def make_dependency(project, **extra): "documentation": { "short": "Determines if the project has published a security policy.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2" - "ab2a88adac0a18464f0216b/docs/checks.md#security-policy", + "ab2a88adac0a18464f0216b/docs/checks.md#security-policy", }, }, { @@ -491,9 +491,9 @@ def make_dependency(project, **extra): ], "documentation": { "short": "Determines if the project has open, known unfixed vulnera" - "bilities.", + "bilities.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2" - "a88adac0a18464f0216b/docs/checks.md#vulnerabilities", + "a88adac0a18464f0216b/docs/checks.md#vulnerabilities", }, }, { @@ -504,7 +504,7 @@ def make_dependency(project, **extra): "documentation": { "short": "Determines if the project uses static code analysis.", "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2a" - "b2a88adac0a18464f0216b/docs/checks.md#sast", + "b2a88adac0a18464f0216b/docs/checks.md#sast", }, }, ], From e5f3e7a1507a0cf7a798a79c39b4cdd682a9aca2 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 4 Jul 2024 02:09:20 +0530 Subject: [PATCH 13/50] docstrings formatted nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 56737c0a3..940a3108c 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3788,9 +3788,7 @@ def __str__(self): @classmethod @transaction.atomic() def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): - """ - Create ScoreCard Object from ScoreCard Json - """ + """Create ScoreCard Object from ScoreCard Json""" scorecard_data = scorecard_data.copy() final_data = { @@ -3856,9 +3854,7 @@ def __str__(self): @classmethod def create_from_data(cls, package_score, check_data): - """ - Create a ScorecardCheck instance from provided data. - """ + """Create a ScorecardCheck instance from provided data.""" final_data = { "check_name": check_data.get("name"), "check_score": check_data.get("score"), From c2f5c4d3a75e7989bc0064af2a1420ee1a132b57 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 4 Jul 2024 17:02:11 +0530 Subject: [PATCH 14/50] created basic fetch and availability functions for scorecode pipeline nexB#598 Signed-off-by: 404-geek --- scancodeio/settings.py | 2 +- .../pipelines/get_scorecard_info_packages.py | 59 ++++++++++++++++++ scanpipe/pipes/{ScoreCode.py => scorecode.py} | 62 +++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 scanpipe/pipelines/get_scorecard_info_packages.py rename scanpipe/pipes/{ScoreCode.py => scorecode.py} (58%) diff --git a/scancodeio/settings.py b/scancodeio/settings.py index 24f6ea50c..cd1197f07 100644 --- a/scancodeio/settings.py +++ b/scancodeio/settings.py @@ -417,4 +417,4 @@ # OpenSSF ScoreCard Integration -SCORECARD_URL = env.str('SCORECARD_URL', default="") +SCORECARD_URL = env.str("SCORECARD_URL", default="") diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py new file mode 100644 index 000000000..d240cb6ed --- /dev/null +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# http://nexb.com and https://github.com/nexB/scancode.io +# The ScanCode.io software is licensed under the Apache License version 2.0. +# Data generated with ScanCode.io is provided as-is without warranties. +# ScanCode is a trademark of nexB Inc. +# +# You may not use this software except in compliance with the License. +# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0 +# Unless required by applicable law or agreed to in writing, software distributed +# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# +# Data Generated with ScanCode.io is provided on an "AS IS" BASIS, WITHOUT WARRANTIES +# OR CONDITIONS OF ANY KIND, either express or implied. No content created from +# ScanCode.io should be considered or used as legal advice. Consult an Attorney +# for any legal advice. +# +# ScanCode.io is a free software code scanning tool from nexB Inc. and others. +# Visit https://github.com/nexB/scancode.io for support and download. + +from scanpipe.pipelines import Pipeline +from scanpipe.pipes import scorecode + + +class FetchScoreCodeInfo(Pipeline): + """ + Fetch scorecode information for packages and dependencies. + + scorecode data is stored on each package and dependency instance. + """ + + download_inputs = False + is_addon = True + + @classmethod + def steps(cls): + return ( + cls.check_scorecode_service_availability, + cls.lookup_packages_scorecode_info, + cls.lookup_dependencies_scorecode_info, + ) + + def check_scorecode_service_availability(self): + """Check if the scorecode service is configured and available.""" + if not scorecode.is_configured(): + raise Exception("scorecode service is not configured.") + + if not scorecode.is_available(): + raise Exception("scorecode service is not available.") + + def lookup_packages_scorecode_info(self): + """Fetch scorecode information for each of the project's discovered packages.""" + packages = self.project.discoveredpackages.all() + scorecode.fetch_scorecode_info( + packages=packages, + logger=self.log, + ) diff --git a/scanpipe/pipes/ScoreCode.py b/scanpipe/pipes/scorecode.py similarity index 58% rename from scanpipe/pipes/ScoreCode.py rename to scanpipe/pipes/scorecode.py index bf0f333bd..e3ccd45f5 100644 --- a/scanpipe/pipes/ScoreCode.py +++ b/scanpipe/pipes/scorecode.py @@ -21,10 +21,13 @@ # Visit https://github.com/nexB/scancode.io for support and download. import logging +from collections import namedtuple +from urllib.parse import urlparse from django.conf import settings import requests +from ossf_scorecard.scorecard import GetScorecard label = "ScoreCode" logger = logging.getLogger(__name__) @@ -58,3 +61,62 @@ def is_available(): return False return response.status_code == requests.codes.ok + + +def fetch_scorecard_info(packages, logger): + """ + Fetch scorecard information for the given packages. + + Args: + packages (QuerySet): A queryset of package instances. + logger (Logger): A logger instance to log messages. + """ + + for package in packages: + url = package.vcs_url + repo_data = extract_repo_info(url) + + if repo_data: + + scorecard_data = GetScorecard( + platform=repo_data.platform, org=repo_data.org, repo=repo_data.repo + ) + + logger.info(f"Fetching scorecard data for package: {scorecard_data}") + + +def extract_repo_info(url): + """ + Extract platform, org, and repo from a given GitHub or GitLab URL. + + Args: + url (str): The URL to parse. + + Returns: + RepoData: Named tuple containing 'platform', 'org', and 'repo' if the URL is + valid, else None. + """ + RepoData = namedtuple("RepoData", ["platform", "org", "repo"]) + + parsed_url = urlparse(url) + hostname = parsed_url.hostname + + if not hostname: + return None + + if "github.com" in hostname: + platform = "github" + elif "gitlab.com" in hostname: + platform = "gitlab" + else: + return None + + path_parts = parsed_url.path.strip("/").split("/") + + if len(path_parts) < 2: + return None + + org = path_parts[0] + repo = path_parts[1] + + return RepoData(platform=platform, org=org, repo=repo) From 0dbc92fdf49af599935ce7dce77ec41da0d1cc18 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 7 Jul 2024 23:16:05 +0530 Subject: [PATCH 15/50] modified doc strings and models and imported ScoreCode package in setup.cfg nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 106 ++++++++++++++++++++++++++++++---- scanpipe/pipes/scorecode.py | 19 ++++-- scanpipe/tests/test_models.py | 19 ++++++ 3 files changed, 128 insertions(+), 16 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index d9f5e0dfb..57501fb31 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -29,6 +29,7 @@ from collections import Counter from collections import defaultdict from contextlib import suppress +from datetime import datetime from itertools import groupby from operator import itemgetter from pathlib import Path @@ -73,6 +74,8 @@ from licensedcode.cache import build_spdx_license_expression from licensedcode.cache import get_licensing from matchcode_toolkit.fingerprinting import IGNORED_DIRECTORY_FINGERPRINTS +from ossf_scorecard.contrib.django.models import PackageScoreMixin +from ossf_scorecard.contrib.django.models import ScorecardChecksMixin from packagedcode.models import build_package_uid from packagedcode.utils import get_base_purl from packageurl import PackageURL @@ -1775,9 +1778,6 @@ class Run(UUIDPKModel, ProjectRelatedModel, AbstractTaskFieldsModel): selected_groups = models.JSONField( null=True, blank=True, validators=[validate_none_or_list] ) - selected_steps = models.JSONField( - null=True, blank=True, validators=[validate_none_or_list] - ) objects = RunQuerySet.as_manager() @@ -2908,13 +2908,6 @@ def with_resources_count(self): ) return self.annotate(resources_count=count_subquery) - def only_purl_fields(self): - """ - Only select and return the UUID and PURL fields. - Minimum requirements to render a Package link in the UI. - """ - return self.only("uuid", *PURL_FIELDS) - class AbstractPackage(models.Model): """These fields should be kept in line with `packagedcode.models.PackageData`.""" @@ -3776,6 +3769,99 @@ def as_spdx(self): ) +class PackageScore(UUIDPKModel, PackageScoreMixin): + + def __str__(self): + return self.score or str(self.uuid) + + discovered_package = models.ForeignKey( + DiscoveredPackage, + related_name="discovered_packages_score", + help_text=_("The package for which the score is given"), + on_delete=models.CASCADE, + editable=False, + blank=True, + null=True, + ) + + @classmethod + @transaction.atomic() + def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): + """Create ScoreCard Object from ScoreCard Object""" + final_data = { + "score": scorecard_data.score, + "scoring_tool_version": scorecard_data.scoring_tool_version, + "scoring_tool_documentation_url": ( + scorecard_data.scoring_tool_documentation_url + ), + } + + date_str = scorecard_data.score_date + if date_str: + + naive_datetime = datetime.strptime(date_str, "%Y-%m-%d") + + score_date = timezone.make_aware( + naive_datetime, timezone.get_current_timezone() + ) + else: + score_date = timezone.now() + + final_data["score_date"] = score_date + + scorecard_object = cls.objects.create( + **final_data, + discovered_package=DiscoveredPackage, + scoring_tool=scoring_tool, + ) + + # Create associated scorecard_checks + checks_data = scorecard_data.checks + + ScorecardCheck.objects.bulk_create( + [ + ScorecardCheck( + check_name=check_data.check_name, + check_score=check_data.check_score, + reason=check_data.reason or "", + details=check_data.details or [], + for_package_score=scorecard_object, + ) + for check_data in checks_data + ] + ) + + return scorecard_object + + +class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): + + def __str__(self): + return self.check_score or str(self.uuid) + + for_package_score = models.ForeignKey( + PackageScore, + related_name="discovered_packages_score_checks", + help_text=_("The checks for which the score is given"), + on_delete=models.CASCADE, + editable=False, + blank=True, + null=True, + ) + + @classmethod + def create_from_data(cls, package_score, check_data): + """Create a ScorecardCheck instance from provided data.""" + final_data = { + "check_name": check_data.get("name"), + "check_score": check_data.get("score"), + "reason": check_data.get("reason"), + "details": check_data.get("details", []), + "for_package_score": package_score, + } + return cls.objects.create(**final_data) + + def normalize_package_url_data(purl_mapping, ignore_nulls=False): """ Normalize a mapping of purl data so database queries with diff --git a/scanpipe/pipes/scorecode.py b/scanpipe/pipes/scorecode.py index e3ccd45f5..fcee80bdf 100644 --- a/scanpipe/pipes/scorecode.py +++ b/scanpipe/pipes/scorecode.py @@ -65,13 +65,18 @@ def is_available(): def fetch_scorecard_info(packages, logger): """ - Fetch scorecard information for the given packages. + Extract platform, org, and repo from a given GitHub or GitLab URL. - Args: - packages (QuerySet): A queryset of package instances. - logger (Logger): A logger instance to log messages. - """ + Args + ---- + url (str): The URL to parse. + Returns + ------- + RepoData: Named tuple containing 'platform', 'org', and 'repo' if the URL is + valid, else None. + + """ for package in packages: url = package.vcs_url repo_data = extract_repo_info(url) @@ -92,9 +97,11 @@ def extract_repo_info(url): Args: url (str): The URL to parse. - Returns: + Returns + ------- RepoData: Named tuple containing 'platform', 'org', and 'repo' if the URL is valid, else None. + """ RepoData = namedtuple("RepoData", ["platform", "org", "repo"]) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index dc1f2c935..0a00a30ac 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -48,6 +48,7 @@ from django.test.utils import CaptureQueriesContext from django.utils import timezone +from ossf_scorecard.contrib.models import PackageScoreMixin from packagedcode.models import PackageData from packageurl import PackageURL from requests.exceptions import RequestException @@ -58,6 +59,7 @@ from scanpipe.models import CodebaseResource from scanpipe.models import DiscoveredDependency from scanpipe.models import DiscoveredPackage +from scanpipe.models import PackageScore from scanpipe.models import Project from scanpipe.models import ProjectMessage from scanpipe.models import Run @@ -79,6 +81,7 @@ from scanpipe.tests import mocked_now from scanpipe.tests import package_data1 from scanpipe.tests import package_data2 +from scanpipe.tests import scorecard_data from scanpipe.tests.pipelines.do_nothing import DoNothing scanpipe_app = apps.get_app_config("scanpipe") @@ -2290,6 +2293,22 @@ def test_scanpipe_codebase_resource_queryset_elfs(self): self.assertTrue("e" in paths) self.assertTrue("a" in paths) + def test_scorecard_models(self): + package = DiscoveredPackage.create_from_data(self.project1, package_data1) + scorecard_obj = PackageScoreMixin.from_data(scorecard_data) + package_score = PackageScore.create_from_data( + package, scorecard_obj, PackageScore.ScoringTool.OSSF + ) + + self.assertIsNotNone(package_score) + self.assertEqual(package_score.scoring_tool, PackageScore.ScoringTool.OSSF) + self.assertEqual(package_score.score, "6.7") + + checks = package_score.discovered_packages_score_checks.all() + self.assertEqual(checks.count(), 15) + self.assertEqual(checks[0].check_name, "Code-Review") + self.assertEqual(checks[0].check_score, "1") + class ScanPipeModelsTransactionTest(TransactionTestCase): """ From d652f426c1934f0acf9ad05de8a52c3fd7477ec8 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 8 Jul 2024 00:05:40 +0530 Subject: [PATCH 16/50] setup.cfg nexB#1283 Signed-off-by: 404-geek --- setup.cfg | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setup.cfg b/setup.cfg index 7353c7867..985b10aeb 100644 --- a/setup.cfg +++ b/setup.cfg @@ -97,6 +97,8 @@ install_requires = fontawesomefree==6.5.1 # MatchCode-toolkit matchcode-toolkit==5.1.0 + # ScoreCode + ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@6bfa54b0dc75b835ccebb69cb2ceed71942b307c # Univers univers==30.11.0 # Markdown @@ -126,6 +128,7 @@ dev = bumpver==2023.1129 twine==5.1.0 + [options.entry_points] console_scripts = scanpipe = scancodeio:command_line From 563991b69c876068069717076d567f0af0d76408 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 11 Jul 2024 23:30:00 +0530 Subject: [PATCH 17/50] reinstated deleted code during rebase nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scanpipe/models.py b/scanpipe/models.py index 21b7d9bb1..5412a2142 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -1775,6 +1775,9 @@ class Run(UUIDPKModel, ProjectRelatedModel, AbstractTaskFieldsModel): scancodeio_version = models.CharField(max_length=100, blank=True) description = models.TextField(blank=True) current_step = models.CharField(max_length=256, blank=True) + selected_steps = models.JSONField( + null=True, blank=True, validators=[validate_none_or_list] + ) selected_groups = models.JSONField( null=True, blank=True, validators=[validate_none_or_list] ) @@ -2908,6 +2911,12 @@ def with_resources_count(self): ) return self.annotate(resources_count=count_subquery) + def only_purl_fields(self): + """ + Only select and return the UUID and PURL fields. + Minimum requirements to render a Package link in the UI. + """ + return self.only("uuid", *PURL_FIELDS) class AbstractPackage(models.Model): """These fields should be kept in line with `packagedcode.models.PackageData`.""" From 4632dfc8f877ca6075172df82677b7602c8cc27c Mon Sep 17 00:00:00 2001 From: 404-geek Date: Thu, 11 Jul 2024 23:39:53 +0530 Subject: [PATCH 18/50] code formatting nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scanpipe/models.py b/scanpipe/models.py index 5412a2142..e24ea0e1e 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -2918,6 +2918,7 @@ def only_purl_fields(self): """ return self.only("uuid", *PURL_FIELDS) + class AbstractPackage(models.Model): """These fields should be kept in line with `packagedcode.models.PackageData`.""" From 923c8340511bf12414f07911a3ed7473be2661e3 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 12 Jul 2024 01:17:26 +0530 Subject: [PATCH 19/50] database migrations for scorecard nexB#1283 Signed-off-by: 404-geek --- .../0064_packagescore_scorecardcheck.py | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 scanpipe/migrations/0064_packagescore_scorecardcheck.py diff --git a/scanpipe/migrations/0064_packagescore_scorecardcheck.py b/scanpipe/migrations/0064_packagescore_scorecardcheck.py new file mode 100644 index 000000000..f9c9b2131 --- /dev/null +++ b/scanpipe/migrations/0064_packagescore_scorecardcheck.py @@ -0,0 +1,151 @@ +# Generated by Django 5.0.6 on 2024-07-11 18:26 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("scanpipe", "0063_run_selected_steps"), + ] + + operations = [ + migrations.CreateModel( + name="PackageScore", + fields=[ + ( + "scoring_tool", + models.CharField( + blank=True, + choices=[("ossf-scorecard", "Ossf"), ("others", "Others")], + help_text="Defines the source of a score or any other scoring metricsFor example: ossf-scorecard for scorecard data", + max_length=100, + ), + ), + ( + "scoring_tool_version", + models.CharField( + blank=True, + help_text="Defines the version of the scoring tool used for scanning thepackageFor Eg : 4.6 current version of OSSF - scorecard", + max_length=50, + ), + ), + ( + "score", + models.CharField( + blank=True, + help_text="Score of the package which is scanned", + max_length=50, + ), + ), + ( + "scoring_tool_documentation_url", + models.CharField( + blank=True, + help_text="Documentation URL of the scoring tool used", + max_length=100, + ), + ), + ( + "score_date", + models.DateTimeField( + blank=True, + editable=False, + help_text="Date when the scoring was calculated on the package", + null=True, + ), + ), + ( + "uuid", + models.UUIDField( + db_index=True, + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + verbose_name="UUID", + ), + ), + ( + "discovered_package", + models.ForeignKey( + blank=True, + editable=False, + help_text="The package for which the score is given", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="discovered_packages_score", + to="scanpipe.discoveredpackage", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.CreateModel( + name="ScorecardCheck", + fields=[ + ( + "check_name", + models.CharField( + blank=True, + help_text="Defines the name of check corresponding to the OSSF scoreFor example: Code-Review or CII-Best-PracticesThese are the some of the checks which are performed on a scanned package", + max_length=100, + ), + ), + ( + "check_score", + models.CharField( + blank=True, + help_text="Defines the score of the check for the package scannedFor Eg : 9 is a score given for Code-Review", + max_length=50, + ), + ), + ( + "reason", + models.CharField( + blank=True, + help_text="Gives a reason why a score was given for a specific checkFor eg, : Found 9/10 approved changesets -- score normalized to 9", + max_length=300, + ), + ), + ( + "details", + models.JSONField( + blank=True, + default=list, + help_text="A list of details/errors regarding the score", + ), + ), + ( + "uuid", + models.UUIDField( + db_index=True, + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + verbose_name="UUID", + ), + ), + ( + "for_package_score", + models.ForeignKey( + blank=True, + editable=False, + help_text="The checks for which the score is given", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="discovered_packages_score_checks", + to="scanpipe.packagescore", + ), + ), + ], + options={ + "abstract": False, + }, + ), + ] From 94bfcd0b69951740cac1ac16ac02150603af8f12 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 14 Jul 2024 01:25:18 +0530 Subject: [PATCH 20/50] updated the scanpipe only fields nexB#1283 Signed-off-by: 404-geek --- scanpipe/tests/test_models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index d8b0d8bbf..7b1194e79 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2201,6 +2201,7 @@ def test_scanpipe_package_model_integrity_with_toolkit_package_model(self): "resolved_from_dependencies", "parent_packages", "children_packages", + "discovered_packages_score", ] package_data_only_field = ["datasource_id", "dependencies"] From d129f730dac4c3b6c0950469d276500f6e9659ca Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 14 Jul 2024 01:35:53 +0530 Subject: [PATCH 21/50] changed scorecode commit hash for latest pull nexB#1283 Signed-off-by: 404-geek --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index dc2d3fa61..1e13bfacf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -98,7 +98,7 @@ install_requires = # MatchCode-toolkit matchcode-toolkit==5.1.0 # ScoreCode - ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@6bfa54b0dc75b835ccebb69cb2ceed71942b307c + ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@c0ec90bb33148c881acd13db72893a28b3ce62e1 # Univers univers==30.11.0 # Markdown From 259f00492bc58c2f0be9b2ba1ec91564c556b944 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 15 Jul 2024 20:55:09 +0530 Subject: [PATCH 22/50] update pipeline code and changed scorecode hash commit nexB#1283 Signed-off-by: 404-geek --- .../pipelines/get_scorecard_info_packages.py | 10 +- scanpipe/pipes/scorecode.py | 129 ------------------ setup.cfg | 2 +- 3 files changed, 6 insertions(+), 135 deletions(-) delete mode 100644 scanpipe/pipes/scorecode.py diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index d240cb6ed..e4827db06 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -21,7 +21,7 @@ # Visit https://github.com/nexB/scancode.io for support and download. from scanpipe.pipelines import Pipeline -from scanpipe.pipes import scorecode +from ossf_scorecard import scorecard class FetchScoreCodeInfo(Pipeline): @@ -39,21 +39,21 @@ def steps(cls): return ( cls.check_scorecode_service_availability, cls.lookup_packages_scorecode_info, - cls.lookup_dependencies_scorecode_info, + # cls.lookup_dependencies_scorecode_info, ) def check_scorecode_service_availability(self): """Check if the scorecode service is configured and available.""" - if not scorecode.is_configured(): + if not scorecard.is_configured(): raise Exception("scorecode service is not configured.") - if not scorecode.is_available(): + if not scorecard.is_available(): raise Exception("scorecode service is not available.") def lookup_packages_scorecode_info(self): """Fetch scorecode information for each of the project's discovered packages.""" packages = self.project.discoveredpackages.all() - scorecode.fetch_scorecode_info( + scorecard.fetch_scorecard_info( packages=packages, logger=self.log, ) diff --git a/scanpipe/pipes/scorecode.py b/scanpipe/pipes/scorecode.py deleted file mode 100644 index fcee80bdf..000000000 --- a/scanpipe/pipes/scorecode.py +++ /dev/null @@ -1,129 +0,0 @@ -# SPDX-License-Identifier: Apache-2.0 -# -# http://nexb.com and https://github.com/nexB/scancode.io -# The ScanCode.io software is licensed under the Apache License version 2.0. -# Data generated with ScanCode.io is provided as-is without warranties. -# ScanCode is a trademark of nexB Inc. -# -# You may not use this software except in compliance with the License. -# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0 -# Unless required by applicable law or agreed to in writing, software distributed -# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, either express or implied. See the License for the -# specific language governing permissions and limitations under the License. -# -# Data Generated with ScanCode.io is provided on an "AS IS" BASIS, WITHOUT WARRANTIES -# OR CONDITIONS OF ANY KIND, either express or implied. No content created from -# ScanCode.io should be considered or used as legal advice. Consult an Attorney -# for any legal advice. -# -# ScanCode.io is a free software code scanning tool from nexB Inc. and others. -# Visit https://github.com/nexB/scancode.io for support and download. - -import logging -from collections import namedtuple -from urllib.parse import urlparse - -from django.conf import settings - -import requests -from ossf_scorecard.scorecard import GetScorecard - -label = "ScoreCode" -logger = logging.getLogger(__name__) -session = requests.Session() - - -# Only SCORECARD_URL can be provided through setting -SCORECARD_API_URL = None -SCORECARD_URL = settings.SCORECARD_URL -if SCORECARD_URL: - SCORECARD_API_URL = f'{SCORECARD_URL.rstrip("/")}/projects/' - - -def is_configured(): - """Return True if the required Scorecard settings have been set.""" - if SCORECARD_API_URL: - return True - return False - - -def is_available(): - """Return True if the configured Scorecard server is available.""" - if not is_configured(): - return False - - try: - response = session.head(SCORECARD_API_URL) - response.raise_for_status() - except requests.exceptions.RequestException as request_exception: - logger.debug(f"{label} is_available() error: {request_exception}") - return False - - return response.status_code == requests.codes.ok - - -def fetch_scorecard_info(packages, logger): - """ - Extract platform, org, and repo from a given GitHub or GitLab URL. - - Args - ---- - url (str): The URL to parse. - - Returns - ------- - RepoData: Named tuple containing 'platform', 'org', and 'repo' if the URL is - valid, else None. - - """ - for package in packages: - url = package.vcs_url - repo_data = extract_repo_info(url) - - if repo_data: - - scorecard_data = GetScorecard( - platform=repo_data.platform, org=repo_data.org, repo=repo_data.repo - ) - - logger.info(f"Fetching scorecard data for package: {scorecard_data}") - - -def extract_repo_info(url): - """ - Extract platform, org, and repo from a given GitHub or GitLab URL. - - Args: - url (str): The URL to parse. - - Returns - ------- - RepoData: Named tuple containing 'platform', 'org', and 'repo' if the URL is - valid, else None. - - """ - RepoData = namedtuple("RepoData", ["platform", "org", "repo"]) - - parsed_url = urlparse(url) - hostname = parsed_url.hostname - - if not hostname: - return None - - if "github.com" in hostname: - platform = "github" - elif "gitlab.com" in hostname: - platform = "gitlab" - else: - return None - - path_parts = parsed_url.path.strip("/").split("/") - - if len(path_parts) < 2: - return None - - org = path_parts[0] - repo = path_parts[1] - - return RepoData(platform=platform, org=org, repo=repo) diff --git a/setup.cfg b/setup.cfg index 1e13bfacf..7456362ff 100644 --- a/setup.cfg +++ b/setup.cfg @@ -98,7 +98,7 @@ install_requires = # MatchCode-toolkit matchcode-toolkit==5.1.0 # ScoreCode - ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@c0ec90bb33148c881acd13db72893a28b3ce62e1 + ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@1fa09b5ecdcc7813600e69bce38d42ed53cb364d # Univers univers==30.11.0 # Markdown From ccd75aea1c3752bb73e907d0c17162bd1c1e1596 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 15 Jul 2024 20:58:14 +0530 Subject: [PATCH 23/50] changed imports structure nexB#1283 Signed-off-by: 404-geek --- scanpipe/pipelines/get_scorecard_info_packages.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index e4827db06..63349e1c7 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -20,9 +20,10 @@ # ScanCode.io is a free software code scanning tool from nexB Inc. and others. # Visit https://github.com/nexB/scancode.io for support and download. -from scanpipe.pipelines import Pipeline from ossf_scorecard import scorecard +from scanpipe.pipelines import Pipeline + class FetchScoreCodeInfo(Pipeline): """ From 29da2903a837aff18b6c676561dcb511e043bc38 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 26 Jul 2024 00:25:48 +0530 Subject: [PATCH 24/50] modified lookup and save logic nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 3 --- .../pipelines/get_scorecard_info_packages.py | 18 ++++++++++++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 0dabc4e32..9085307fa 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3843,7 +3843,6 @@ def as_spdx(self): class PackageScore(UUIDPKModel, PackageScoreMixin): - def __str__(self): return self.score or str(self.uuid) @@ -3871,7 +3870,6 @@ def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): date_str = scorecard_data.score_date if date_str: - naive_datetime = datetime.strptime(date_str, "%Y-%m-%d") score_date = timezone.make_aware( @@ -3908,7 +3906,6 @@ def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): - def __str__(self): return self.check_score or str(self.uuid) diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index 63349e1c7..fcc1986d0 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -22,6 +22,7 @@ from ossf_scorecard import scorecard +from scanpipe.models import PackageScore from scanpipe.pipelines import Pipeline @@ -39,8 +40,7 @@ class FetchScoreCodeInfo(Pipeline): def steps(cls): return ( cls.check_scorecode_service_availability, - cls.lookup_packages_scorecode_info, - # cls.lookup_dependencies_scorecode_info, + cls.lookup_save_packages_scorecode_info, ) def check_scorecode_service_availability(self): @@ -51,10 +51,20 @@ def check_scorecode_service_availability(self): if not scorecard.is_available(): raise Exception("scorecode service is not available.") - def lookup_packages_scorecode_info(self): + def lookup_save_packages_scorecode_info(self): """Fetch scorecode information for each of the project's discovered packages.""" packages = self.project.discoveredpackages.all() - scorecard.fetch_scorecard_info( + scorecard_packages_data = scorecard.fetch_scorecard_info( packages=packages, logger=self.log, ) + + if scorecard_packages_data: + scorecard.save_scorecard_info( + package_scorecard_data=scorecard_packages_data, + cls=PackageScore, + logger=self.log, + ) + + else: + raise Exception("No Data Found for the packages") From 9d72734a89b47dbb7cc0ae6b2cb2a44716842abe Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sat, 27 Jul 2024 15:46:54 +0530 Subject: [PATCH 25/50] merged migrations due to conflicts nexB#1283 Signed-off-by: 404-geek --- scanpipe/migrations/0072_merge_20240725_1903.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 scanpipe/migrations/0072_merge_20240725_1903.py diff --git a/scanpipe/migrations/0072_merge_20240725_1903.py b/scanpipe/migrations/0072_merge_20240725_1903.py new file mode 100644 index 000000000..ea708e374 --- /dev/null +++ b/scanpipe/migrations/0072_merge_20240725_1903.py @@ -0,0 +1,14 @@ +# Generated by Django 5.0.7 on 2024-07-25 19:03 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('scanpipe', '0066_alter_webhooksubscription_options_and_more'), + ('scanpipe', '0071_remove_discoveredpackage_scores_and_more'), + ] + + operations = [ + ] From 301122e98c89bef2ff76dd5db70332dd7f9a65af Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sat, 27 Jul 2024 15:52:20 +0530 Subject: [PATCH 26/50] updated migrations nexB#1283 Signed-off-by: 404-geek --- .../0064_packagescore_scorecardcheck.py | 151 ------------------ .../0067_packagescore_scorecardcheck.py | 44 +++++ .../migrations/0072_merge_20240725_1903.py | 14 -- 3 files changed, 44 insertions(+), 165 deletions(-) delete mode 100644 scanpipe/migrations/0064_packagescore_scorecardcheck.py create mode 100644 scanpipe/migrations/0067_packagescore_scorecardcheck.py delete mode 100644 scanpipe/migrations/0072_merge_20240725_1903.py diff --git a/scanpipe/migrations/0064_packagescore_scorecardcheck.py b/scanpipe/migrations/0064_packagescore_scorecardcheck.py deleted file mode 100644 index f9c9b2131..000000000 --- a/scanpipe/migrations/0064_packagescore_scorecardcheck.py +++ /dev/null @@ -1,151 +0,0 @@ -# Generated by Django 5.0.6 on 2024-07-11 18:26 - -import django.db.models.deletion -import uuid -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("scanpipe", "0063_run_selected_steps"), - ] - - operations = [ - migrations.CreateModel( - name="PackageScore", - fields=[ - ( - "scoring_tool", - models.CharField( - blank=True, - choices=[("ossf-scorecard", "Ossf"), ("others", "Others")], - help_text="Defines the source of a score or any other scoring metricsFor example: ossf-scorecard for scorecard data", - max_length=100, - ), - ), - ( - "scoring_tool_version", - models.CharField( - blank=True, - help_text="Defines the version of the scoring tool used for scanning thepackageFor Eg : 4.6 current version of OSSF - scorecard", - max_length=50, - ), - ), - ( - "score", - models.CharField( - blank=True, - help_text="Score of the package which is scanned", - max_length=50, - ), - ), - ( - "scoring_tool_documentation_url", - models.CharField( - blank=True, - help_text="Documentation URL of the scoring tool used", - max_length=100, - ), - ), - ( - "score_date", - models.DateTimeField( - blank=True, - editable=False, - help_text="Date when the scoring was calculated on the package", - null=True, - ), - ), - ( - "uuid", - models.UUIDField( - db_index=True, - default=uuid.uuid4, - editable=False, - primary_key=True, - serialize=False, - verbose_name="UUID", - ), - ), - ( - "discovered_package", - models.ForeignKey( - blank=True, - editable=False, - help_text="The package for which the score is given", - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="discovered_packages_score", - to="scanpipe.discoveredpackage", - ), - ), - ], - options={ - "abstract": False, - }, - ), - migrations.CreateModel( - name="ScorecardCheck", - fields=[ - ( - "check_name", - models.CharField( - blank=True, - help_text="Defines the name of check corresponding to the OSSF scoreFor example: Code-Review or CII-Best-PracticesThese are the some of the checks which are performed on a scanned package", - max_length=100, - ), - ), - ( - "check_score", - models.CharField( - blank=True, - help_text="Defines the score of the check for the package scannedFor Eg : 9 is a score given for Code-Review", - max_length=50, - ), - ), - ( - "reason", - models.CharField( - blank=True, - help_text="Gives a reason why a score was given for a specific checkFor eg, : Found 9/10 approved changesets -- score normalized to 9", - max_length=300, - ), - ), - ( - "details", - models.JSONField( - blank=True, - default=list, - help_text="A list of details/errors regarding the score", - ), - ), - ( - "uuid", - models.UUIDField( - db_index=True, - default=uuid.uuid4, - editable=False, - primary_key=True, - serialize=False, - verbose_name="UUID", - ), - ), - ( - "for_package_score", - models.ForeignKey( - blank=True, - editable=False, - help_text="The checks for which the score is given", - null=True, - on_delete=django.db.models.deletion.CASCADE, - related_name="discovered_packages_score_checks", - to="scanpipe.packagescore", - ), - ), - ], - options={ - "abstract": False, - }, - ), - ] diff --git a/scanpipe/migrations/0067_packagescore_scorecardcheck.py b/scanpipe/migrations/0067_packagescore_scorecardcheck.py new file mode 100644 index 000000000..f06a3741c --- /dev/null +++ b/scanpipe/migrations/0067_packagescore_scorecardcheck.py @@ -0,0 +1,44 @@ +# Generated by Django 5.0.7 on 2024-07-27 10:20 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('scanpipe', '0066_alter_webhooksubscription_options_and_more'), + ] + + operations = [ + migrations.CreateModel( + name='PackageScore', + fields=[ + ('scoring_tool', models.CharField(blank=True, choices=[('ossf-scorecard', 'Ossf'), ('others', 'Others')], help_text='Defines the source of a score or any other scoring metricsFor example: ossf-scorecard for scorecard data', max_length=100)), + ('scoring_tool_version', models.CharField(blank=True, help_text='Defines the version of the scoring tool used for scanning thepackageFor Eg : 4.6 current version of OSSF - scorecard', max_length=50)), + ('score', models.CharField(blank=True, help_text='Score of the package which is scanned', max_length=50)), + ('scoring_tool_documentation_url', models.CharField(blank=True, help_text='Documentation URL of the scoring tool used', max_length=100)), + ('score_date', models.DateTimeField(blank=True, editable=False, help_text='Date when the scoring was calculated on the package', null=True)), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), + ('discovered_package', models.ForeignKey(blank=True, editable=False, help_text='The package for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score', to='scanpipe.discoveredpackage')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ScorecardCheck', + fields=[ + ('check_name', models.CharField(blank=True, help_text='Defines the name of check corresponding to the OSSF scoreFor example: Code-Review or CII-Best-PracticesThese are the some of the checks which are performed on a scanned package', max_length=100)), + ('check_score', models.CharField(blank=True, help_text='Defines the score of the check for the package scannedFor Eg : 9 is a score given for Code-Review', max_length=50)), + ('reason', models.CharField(blank=True, help_text='Gives a reason why a score was given for a specific checkFor eg, : Found 9/10 approved changesets -- score normalized to 9', max_length=300)), + ('details', models.JSONField(blank=True, default=list, help_text='A list of details/errors regarding the score')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), + ('for_package_score', models.ForeignKey(blank=True, editable=False, help_text='The checks for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score_checks', to='scanpipe.packagescore')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/scanpipe/migrations/0072_merge_20240725_1903.py b/scanpipe/migrations/0072_merge_20240725_1903.py deleted file mode 100644 index ea708e374..000000000 --- a/scanpipe/migrations/0072_merge_20240725_1903.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 5.0.7 on 2024-07-25 19:03 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('scanpipe', '0066_alter_webhooksubscription_options_and_more'), - ('scanpipe', '0071_remove_discoveredpackage_scores_and_more'), - ] - - operations = [ - ] From 5812d9725dbf2e4c21c5e54eca29c67f64228e6a Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sat, 27 Jul 2024 16:44:35 +0530 Subject: [PATCH 27/50] updated doc string for get_scorecard_info_packages.py nexB#1283 Signed-off-by: 404-geek --- scanpipe/pipelines/get_scorecard_info_packages.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index fcc1986d0..3ca0e81ab 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -28,7 +28,19 @@ class FetchScoreCodeInfo(Pipeline): """ - Fetch scorecode information for packages and dependencies. + Pipeline to fetch ScoreCode information for packages and dependencies. + + This pipeline retrieves ScoreCode data for each package and dependency + in the project and stores it in the corresponding package and dependency + instances. + + Attributes: + download_inputs (bool): Indicates whether inputs should be downloaded. + is_addon (bool): Indicates whether this pipeline is an add-on. + + Methods: + steps(cls): + Defines the steps for the pipeline. scorecode data is stored on each package and dependency instance. """ From df5041682d6aa69156c4ec08be20ba96aa8cec5f Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 28 Jul 2024 21:14:52 +0530 Subject: [PATCH 28/50] Added scorecard pipeline to SCIO with intergration test nexB#1283 Signed-off-by: 404-geek --- scancodeio/settings.py | 4 --- .../pipelines/get_scorecard_info_packages.py | 29 +++++++++------ scanpipe/tests/test_pipelines.py | 35 +++++++++++++++++++ setup.cfg | 3 +- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/scancodeio/settings.py b/scancodeio/settings.py index a7e4301e5..0a75b96fa 100644 --- a/scancodeio/settings.py +++ b/scancodeio/settings.py @@ -418,7 +418,3 @@ MATCHCODEIO_USER = env.str("MATCHCODEIO_USER", default="") MATCHCODEIO_PASSWORD = env.str("MATCHCODEIO_PASSWORD", default="") MATCHCODEIO_API_KEY = env.str("MATCHCODEIO_API_KEY", default="") - -# OpenSSF ScoreCard Integration - -SCORECARD_URL = env.str("SCORECARD_URL", default="") diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index 3ca0e81ab..cb05f23d9 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -28,21 +28,28 @@ class FetchScoreCodeInfo(Pipeline): """ - Pipeline to fetch ScoreCode information for packages and dependencies. + Pipeline to fetch ScoreCode information for packages and dependencies. - This pipeline retrieves ScoreCode data for each package and dependency - in the project and stores it in the corresponding package and dependency - instances. + This pipeline retrieves ScoreCode data for each package in the project and + stores it in the corresponding package instances - Attributes: - download_inputs (bool): Indicates whether inputs should be downloaded. - is_addon (bool): Indicates whether this pipeline is an add-on. + Attributes + ---------- + download_inputs (bool): Indicates whether inputs should be downloaded. + is_addon (bool): Indicates whether this pipeline is an add-on. - Methods: - steps(cls): - Defines the steps for the pipeline. + Methods + ------- + steps(cls): + Defines the steps for the pipeline. + + check_scorecode_service_availability(self): + Checks if the ScoreCode service is configured and available. + + lookup_save_packages_scorecode_info(self): + Fetches ScoreCode information for each discovered package in the project + and saves the information to the respective package instances. - scorecode data is stored on each package and dependency instance. """ download_inputs = False diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index 90d260b8e..2d7612716 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -1233,6 +1233,41 @@ def test_scanpipe_find_vulnerabilities_pipeline_integration( expected = vulnerability_data[0]["affected_by_vulnerabilities"] self.assertEqual(expected, package1.affected_by_vulnerabilities) + @mock.patch("ossf_scorecard.scorecard.is_available") + @mock.patch("ossf_scorecard.scorecard.is_configured") + def test_scanpipe_get_scorecard_info_packages_integration( + self, mock_is_configured, mock_is_available + ): + pipeline_name = "get_scorecard_info_packages" + project1 = Project.objects.create(name="Analysis") + package1 = DiscoveredPackage.create_from_data(project1, package_data1) + package1.vcs_url = "https://github.com/nexB/scancode-toolkit" + package1.save() + + run = project1.add_pipeline(pipeline_name) + pipeline = run.make_pipeline_instance() + mock_is_configured.return_value = False + mock_is_available.return_value = False + exitcode, out = pipeline.execute() + self.assertEqual(1, exitcode, msg=out) + self.assertIn("scorecode service is not configured.", out) + + run = project1.add_pipeline(pipeline_name) + pipeline = run.make_pipeline_instance() + mock_is_configured.return_value = True + mock_is_available.return_value = True + + exitcode, out = pipeline.execute() + self.assertEqual(0, exitcode, msg=out) + + package1.refresh_from_db() + self.assertIsNotNone( + package1.discovered_packages_score.filter(scoring_tool="OSSF")[0].score, + msg=out, + ) + + self.assertEqual("https://github.com/nexB/scancode-toolkit", package1.vcs_url) + def test_scanpipe_resolve_dependencies_pipeline_integration(self): pipeline_name = "resolve_dependencies" project1 = Project.objects.create(name="Analysis") diff --git a/setup.cfg b/setup.cfg index 02f6815f7..b05c61663 100644 --- a/setup.cfg +++ b/setup.cfg @@ -99,7 +99,7 @@ install_requires = # MatchCode-toolkit matchcode-toolkit==5.1.0 # ScoreCode - ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@1fa09b5ecdcc7813600e69bce38d42ed53cb364d + ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@0ab078f18d83684c3a920095bcec8664d44cf028 # Univers univers==30.11.0 # Markdown @@ -139,6 +139,7 @@ scancodeio_pipelines = collect_symbols_tree_sitter = scanpipe.pipelines.collect_symbols_tree_sitter:CollectSymbolsTreeSitter enrich_with_purldb = scanpipe.pipelines.enrich_with_purldb:EnrichWithPurlDB find_vulnerabilities = scanpipe.pipelines.find_vulnerabilities:FindVulnerabilities + get_scorecard_info_packages = scanpipe.pipelines.get_scorecard_info_packages:FetchScoreCodeInfo inspect_elf_binaries = scanpipe.pipelines.inspect_elf_binaries:InspectELFBinaries inspect_packages = scanpipe.pipelines.inspect_packages:InspectPackages load_inventory = scanpipe.pipelines.load_inventory:LoadInventory From fc4945edeef31d6c0c95b22001b26bedf1be1239 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Tue, 20 Aug 2024 22:16:30 +0530 Subject: [PATCH 29/50] moved the data to be regenerated if reqiured nexB#1283 Signed-off-by: 404-geek --- scanpipe/tests/__init__.py | 251 +----- .../data/scorecode/scorecard_response.json | 800 ++++++++++++++++++ scanpipe/tests/test_models.py | 4 +- 3 files changed, 807 insertions(+), 248 deletions(-) create mode 100644 scanpipe/tests/data/scorecode/scorecard_response.json diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index c40ed2d24..9425f8876 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -20,6 +20,7 @@ # ScanCode.io is a free software code scanning tool from nexB Inc. and others. # Visit https://github.com/nexB/scancode.io for support and download. +import json import os from datetime import datetime from unittest import mock @@ -265,249 +266,7 @@ def make_dependency(project, **extra): }, } -scorecard_data = { - "date": "2024-06-17", - "repo": { - "name": "github.com/pallets/flask", - "commit": "d718ecf6d3dfc4656d262154c59672437c1ea075", - }, - "scorecard": { - "version": "v5.0.0-rc2-63-g5d08c1cc", - "commit": "5d08c1cc11c1e45c2ab2a88adac0a18464f0216b", - }, - "score": 6.7, - "checks": [ - { - "name": "Code-Review", - "score": 1, - "reason": "Found 2/11 approved changesets -- score normalized to 1", - "details": None, - "documentation": { - "short": "Determines if the project requires human code review before " - "pull requests (aka merge requests) are merged.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a" - "88adac0a18464f0216b/docs/checks.md#code-review", - }, - }, - { - "name": "Maintained", - "score": 10, - "reason": "30 commit(s) and 17 issue activity found in the last 90 days " - "-- score normalized to 10", - "details": None, - "documentation": { - "short": 'Determines if the project is "actively maintained".', - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" - "adac0a18464f0216b/docs/checks.md#maintained", - }, - }, - { - "name": "CII-Best-Practices", - "score": 0, - "reason": "no effort to earn an OpenSSF best practices badge detected", - "details": None, - "documentation": { - "short": "Determines if the project has an OpenSSF (formerly CII) Best " - "Practices Badge.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" - "adac0a18464f0216b/docs/checks.md#cii-best-practices", - }, - }, - { - "name": "License", - "score": 10, - "reason": "license file detected", - "details": [ - "Info: project has a license file: LICENSE.txt:0", - 'Info: FSF or OSI recognized license: BSD 3-Clause "New" or "Revised"' - " License: LICENSE.txt:0", - ], - "documentation": { - "short": "Determines if the project has defined a license.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c" - "1e45c2ab2a88adac0a18464f0216b/docs/checks.md#license", - }, - }, - { - "name": "Dangerous-Workflow", - "score": 10, - "reason": "no dangerous workflow patterns detected", - "details": None, - "documentation": { - "short": "Determines if the project's GitHub Action workflows avoid " - "dangerous patterns.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88a" - "dac0a18464f0216b/docs/checks.md#dangerous-workflow", - }, - }, - { - "name": "Signed-Releases", - "score": 10, - "reason": "5 out of the last 5 releases have a total of 5 signed " - "artifacts.", - "details": [ - "Info: provenance for release artifact: multiple.intoto.jsonl:" - " https://api.github.com/repos/pallets/flask/releases/assets/160813583", - "Info: provenance for release artifact: multiple.intoto.jsonl:" - " https://api.github.com/repos/pallets/flask/releases/assets/149637381", - "Info: provenance for release artifact: multiple.intoto.jsonl:" - " https://api.github.com/repos/pallets/flask/releases/assets/146388022", - "Info: provenance for release artifact: multiple.intoto.jsonl:" - " https://api.github.com/repos/pallets/flask/releases/assets/128454404", - "Info: provenance for release artifact: multiple.intoto.jsonl:" - " https://api.github.com/repos/pallets/flask/releases/assets/122480844", - ], - "documentation": { - "short": "Determines if the project cryptographically signs release art" - "ifacts.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a88" - "adac0a18464f0216b/docs/checks.md#signed-releases", - }, - }, - { - "name": "Token-Permissions", - "score": 0, - "reason": "detected GitHub workflow tokens with excessive permissions", - "details": [ - "Info: jobLevel 'actions' permission set to 'read': .github/workflows/" - "publish.yaml:32", - "Warn: no topLevel permission defined: .github/workflows/publish" - ".yaml:1", - "Warn: no topLevel permission defined: .github/workflows/tests.yaml:1", - "Info: no jobLevel write permissions found", - ], - "documentation": { - "short": "Determines if the project's workflows follow the princip" - "le of least privilege.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a8" - "8adac0a18464f0216b/docs/checks.md#token-permissions", - }, - }, - { - "name": "Binary-Artifacts", - "score": 10, - "reason": "no binaries found in the repo", - "details": None, - "documentation": { - "short": "Determines if the project has generated executable (bin" - "ary) artifacts in the source repository.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" - "2a88adac0a18464f0216b/docs/checks.md#binary-artifacts", - }, - }, - { - "name": "Branch-Protection", - "score": -1, - "reason": "internal error: error during branchesHandler.setup: intern" - "al error: githubv4.Query: " - "Resource not accessible by integration", - "details": None, - "documentation": { - "short": "Determines if the default and release branches are prote" - "cted with GitHub's branch protection settings.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" - "2a88adac0a18464f0216b/docs/checks.md#branch-protection", - }, - }, - { - "name": "Pinned-Dependencies", - "score": 4, - "reason": "dependency not pinned by hash detected -- score normalized to 4", - "details": [ - "Info: Possibly incomplete results: error parsing shell code: inv" - "alid parameter name: .github/workflows/tests.yaml:44", - "Warn: pipCommand not pinned by hash: .devcontainer/on-create-command" - ".sh:5", - "Warn: pipCommand not pinned by hash: .devcontainer/on-create-comm" - "and.sh:6", - "Warn: pipCommand not pinned by hash: .github/workflows/publish.yaml" - ":19", - "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:44", - "Warn: pipCommand not pinned by hash: .github/workflows/tests.yaml:60", - "Info: 10 out of 10 GitHub-owned GitHubAction dependencies pinned", - "Info: 3 out of 3 third-party GitHubAction dependencies pinned", - "Info: 0 out of 5 pipCommand dependencies pinned", - ], - "documentation": { - "short": "Determines if the project has declared and pinned the depen" - "dencies of its build process.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab" - "2a88adac0a18464f0216b/docs/checks.md#pinned-dependencies", - }, - }, - { - "name": "Fuzzing", - "score": 10, - "reason": "project is fuzzed", - "details": ["Info: OSSFuzz integration found"], - "documentation": { - "short": "Determines if the project uses fuzzing.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2a" - "88adac0a18464f0216b/docs/checks.md#fuzzing", - }, - }, - { - "name": "Packaging", - "score": 10, - "reason": "packaging workflow detected", - "details": [ - "Info: Project packages its releases by way of GitHub Actions.: .git" - "hub/workflows/publish.yaml:55" - ], - "documentation": { - "short": "Determines if the project is published as a package that othe" - "rs can easily download, install, " - "easily update, and uninstall.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e" - "45c2ab2a88adac0a18464f0216b/docs/checks.md#packaging", - }, - }, - { - "name": "Security-Policy", - "score": 9, - "reason": "security policy file detected", - "details": [ - "Info: security policy file detected: github.com/pallets/.github/S" - "ECURITY.md:1", - "Info: Found linked content: github.com/pallets/.github/SECURITY.md:1", - "Warn: One or no descriptive hints of disclosure, vulnerability," - " and/or timelines in security policy", - "Info: Found text in security policy: github.com/pallets/" - ".github/SECURITY.md:1", - ], - "documentation": { - "short": "Determines if the project has published a security policy.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2" - "ab2a88adac0a18464f0216b/docs/checks.md#security-policy", - }, - }, - { - "name": "Vulnerabilities", - "score": 6, - "reason": "4 existing vulnerabilities detected", - "details": [ - "Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95", - "Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj", - "Warn: Project is vulnerable to: GHSA-2g68-c3qc-8985", - "Warn: Project is vulnerable to: GHSA-hrfv-mqp8-q5rw / PYSEC-2023-221", - ], - "documentation": { - "short": "Determines if the project has open, known unfixed vulnera" - "bilities.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2ab2" - "a88adac0a18464f0216b/docs/checks.md#vulnerabilities", - }, - }, - { - "name": "SAST", - "score": 0, - "reason": "SAST tool is not run on all commits -- score normalized to 0", - "details": ["Warn: 0 commits out of 22 are checked with a SAST tool"], - "documentation": { - "short": "Determines if the project uses static code analysis.", - "url": "https://github.com/ossf/scorecard/blob/5d08c1cc11c1e45c2a" - "b2a88adac0a18464f0216b/docs/checks.md#sast", - }, - }, - ], -} +scorecard_data = None + +with open("data/scorecode/scorecard_response.json") as file: + scorecard_data = json.load(file) diff --git a/scanpipe/tests/data/scorecode/scorecard_response.json b/scanpipe/tests/data/scorecode/scorecard_response.json new file mode 100644 index 000000000..d6f951c1d --- /dev/null +++ b/scanpipe/tests/data/scorecode/scorecard_response.json @@ -0,0 +1,800 @@ +{ + "date": "2024-07-22", + "repo": { + "name": "github.com/nexB/scancode-toolkit", + "commit": "dd675aacae1b24a838f5520da77534326b17c5e9" + }, + "scorecard": { + "version": "v5.0.0-4-g093669b6", + "commit": "093669b630d2f32dc44f8b5a0c6778daba135c1b" + }, + "score": 4.4, + "checks": [ + { + "name": "Code-Review", + "score": 7, + "reason": "Found 7/9 approved changesets -- score normalized to 7", + "details": null, + "documentation": { + "short": "Determines if the project requires human code review before pull requests (aka merge requests) are merged.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#code-review" + } + }, + { + "name": "Maintained", + "score": 10, + "reason": "30 commit(s) and 22 issue activity found in the last 90 days -- score normalized to 10", + "details": null, + "documentation": { + "short": "Determines if the project is \"actively maintained\".", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#maintained" + } + }, + { + "name": "CII-Best-Practices", + "score": 0, + "reason": "no effort to earn an OpenSSF best practices badge detected", + "details": null, + "documentation": { + "short": "Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#cii-best-practices" + } + }, + { + "name": "Branch-Protection", + "score": -1, + "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", + "details": null, + "documentation": { + "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#branch-protection" + } + }, + { + "name": "Signed-Releases", + "score": 0, + "reason": "Project has not signed or included provenance with any releases.", + "details": [ + "Warn: release artifact v32.2.1 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/163419040", + "Warn: release artifact v32.2.0 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/161475747", + "Warn: release artifact v32.1.0 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/147940455", + "Warn: release artifact v32.0.8 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/124587514", + "Warn: release artifact v32.0.7 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/122941689", + "Warn: release artifact v32.2.1 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/163419040", + "Warn: release artifact v32.2.0 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/161475747", + "Warn: release artifact v32.1.0 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/147940455", + "Warn: release artifact v32.0.8 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/124587514", + "Warn: release artifact v32.0.7 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/122941689" + ], + "documentation": { + "short": "Determines if the project cryptographically signs release artifacts.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#signed-releases" + } + }, + { + "name": "License", + "score": 9, + "reason": "license file detected", + "details": [ + "Info: project has a license file: apache-2.0.LICENSE:0", + "Warn: project license file does not contain an FSF or OSI license." + ], + "documentation": { + "short": "Determines if the project has defined a license.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#license" + } + }, + { + "name": "Security-Policy", + "score": 0, + "reason": "security policy file not detected", + "details": [ + "Warn: no security policy file detected", + "Warn: no security file to analyze", + "Warn: no security file to analyze", + "Warn: no security file to analyze" + ], + "documentation": { + "short": "Determines if the project has published a security policy.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#security-policy" + } + }, + { + "name": "Dangerous-Workflow", + "score": 10, + "reason": "no dangerous workflow patterns detected", + "details": null, + "documentation": { + "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#dangerous-workflow" + } + }, + { + "name": "Token-Permissions", + "score": 10, + "reason": "GitHub workflow tokens follow principle of least privilege", + "details": [ + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:356", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:59", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:91", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:125", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:159", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:193", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:224", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:270", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:397", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:25", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:315", + "Warn: jobLevel 'contents' permission set to 'write': .github/workflows/scancode-release.yml:434", + "Info: topLevel 'contents' permission set to 'read': .github/workflows/about-files-ci.yml:6", + "Info: topLevel 'contents' permission set to 'read': .github/workflows/docs-ci.yml:6", + "Info: found token with 'none' permissions: .github/workflows/scancode-release.yml:1" + ], + "documentation": { + "short": "Determines if the project's workflows follow the principle of least privilege.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#token-permissions" + } + }, + { + "name": "Packaging", + "score": 10, + "reason": "packaging workflow detected", + "details": [ + "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/scancode-release.yml:561" + ], + "documentation": { + "short": "Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#packaging" + } + }, + { + "name": "Fuzzing", + "score": 0, + "reason": "project is not fuzzed", + "details": [ + "Warn: no fuzzer integrations found" + ], + "documentation": { + "short": "Determines if the project uses fuzzing.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#fuzzing" + } + }, + { + "name": "SAST", + "score": 0, + "reason": "SAST tool is not run on all commits -- score normalized to 0", + "details": [ + "Warn: 0 commits out of 30 are checked with a SAST tool" + ], + "documentation": { + "short": "Determines if the project uses static code analysis.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#sast" + } + }, + { + "name": "Binary-Artifacts", + "score": 0, + "reason": "binaries present in source code", + "details": [ + "Warn: binary detected: tests/cluecode/data/copyrights/binary_lib-php_embed_lib.lib:1", + "Warn: binary detected: tests/cluecode/data/copyrights/copyright_php_lib-php_embed_lib.lib:1", + "Warn: binary detected: tests/cluecode/data/copyrights/dll-9_msvci_dll.dll:1", + "Warn: binary detected: tests/cluecode/data/copyrights/dll-9_msvci_dll2.dll:1", + "Warn: binary detected: tests/cluecode/data/copyrights/no_class_file_1-PersistentArrayHolder_class.class:1", + "Warn: binary detected: tests/cluecode/data/copyrights/no_class_file_2-PersistentElementHolder_class.class:1", + "Warn: binary detected: tests/cluecode/data/copyrights/no_class_file_3-PersistentIndexedElementHolder_class.class:1", + "Warn: binary detected: tests/cluecode/data/copyrights/no_class_file_4-PersistentListElementHolder_class.class:1", + "Warn: binary detected: tests/cluecode/data/copyrights/win-archive.lib:1", + "Warn: binary detected: tests/cluecode/data/copyrights/windows.dll:1", + "Warn: binary detected: tests/cluecode/data/finder/binaries/gapi32.dll:1", + "Warn: binary detected: tests/cluecode/data/finder/url/XMLConstants.class:1", + "Warn: binary detected: tests/licensedcode/data/datadriven/external/fossology-tests/No_license_found/ConfigRuleSet.class:1", + "Warn: binary detected: tests/licensedcode/data/datadriven/lic1/do-not_detect-licenses-in-archive.jar:1", + "Warn: binary detected: tests/licensedcode/data/datadriven/lic2/basename.elf:1", + "Warn: binary detected: tests/licensedcode/data/datadriven/lic3/long-s3cli-0.0.53-linux-amd64.go:1", + "Warn: binary detected: tests/licensedcode/data/datadriven/lic4/NamespaceNode.class:1", + "Warn: binary detected: tests/licensedcode/data/index/do-not-cache-full-paths/_codecs_jp.cpython-38-x86_64-linux-gnu-slim-v2.so:1", + "Warn: binary detected: tests/licensedcode/data/matched_text/binary_text/gosu:1", + "Warn: binary detected: tests/licensedcode/data/matched_text/ffmpeg/ffmpeg:1", + "Warn: binary detected: tests/licensedcode/data/matched_text/ffmpeg/ffmpeg.exe:1", + "Warn: binary detected: tests/licensedcode/data/matched_text/ffmpeg/libavsample.lib:1", + "Warn: binary detected: tests/licensedcode/data/perf/ath_pci.ko:1", + "Warn: binary detected: tests/licensedcode/data/perf/eeepc_acpi.ko:1", + "Warn: binary detected: tests/licensedcode/data/positions/ath_pci.ko:1", + "Warn: binary detected: tests/licensedcode/data/positions/eeepc_acpi.ko:1", + "Warn: binary detected: tests/licensedcode/data/positions/wlan_xauth.ko:1", + "Warn: binary detected: tests/licensedcode/data/query/ath_pci.ko:1", + "Warn: binary detected: tests/licensedcode/data/query/eeepc_acpi.ko:1", + "Warn: binary detected: tests/licensedcode/data/query/wlan_xauth.ko:1", + "Warn: binary detected: tests/packagedcode/data/archives/adduser_3.112ubuntu1_all.deb:1", + "Warn: binary detected: tests/packagedcode/data/archives/alfandega-2.2-2.rh80.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/archives/simple.jar:1", + "Warn: binary detected: tests/packagedcode/data/archives/small.iso:1", + "Warn: binary detected: tests/packagedcode/data/maven_misc/extracted-jar/hsqldb-2.4.0.jar-extract/org/hsqldb/Database.class:1", + "Warn: binary detected: tests/packagedcode/data/pypi/archive/atomicwrites-1.2.1-py2.py3-none-any.whl:1", + "Warn: binary detected: tests/packagedcode/data/pyrpm/Eterm-0.9.3-5mdv2007.0.rpm:1", + "Warn: binary detected: tests/packagedcode/data/recon/pypi/atomicwrites/atomicwrites-1.2.1-py2.py3-none-any.whl:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/FaxMail-2.3-12mdv2007.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/NEC-MultiWriter_1700C-1.0-1.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/alfandega-2.0-1.7.3.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/alfandega-2.2-2.rh80.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/alfandega-2.2-2.rh80.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/apache-commons-io-2.4-12.el7.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/berry-mkdiscicons-0.07-b1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/berry-service-0.05-b1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/broken.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/cndrvcups-common-2.00-2.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/cndrvcups-lipslx-2.00-2.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/elfinfo-1.0-1.fc9.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/firefox-3.5.6-b1.nosrc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.2b1-1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.2b1-49607cl.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4-0.b2.rhfc1.dag.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-10.fc12.ppc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-10.fc12.x86_64.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-114.1.ppc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-5.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-7.el4.asp101.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-7.el5.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-8mdv2007.1.sparc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2-9.fc11.ppc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fping-2.4b2to-20080101.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/fxload-2002_04_11-212.1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/kimera-1.40+-b1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/libproxy-bin-0.3.0-4.el6_3.x86_64.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/libsqueeze0.2_0-0.2.3-8mdv2010.0.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/m4ri-20081028-5.fc12.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/m4ri-devel-20081028-5.fc12.ppc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/mdcp-0.1.2-2.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/mdcp-0.1.2-2.i686.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/mdcp-0.1.2-2.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/mdv-rpm-summary-0.9.3-1mdv2010.0.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/mvlutils-2.8.4-7.0.2.0801061.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/necsul-1.2.0-2.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/necsul-devel-1.2.0-2.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/necsul-suse-1.2.0-2.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/necsul-suse-devel-1.2.0-2.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-CGI-3.42-8.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Class-MethodMaker-1.06-1.7.3.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Class-MethodMaker-1.06-1.8.0.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Class-MethodMaker-1.06-1.8.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Compress-Zlib-1.16-1.7.3.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Compress-Zlib-1.16-1.8.0.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Compress-Zlib-1.16-1.8.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Crypt-IDEA-1.08-2.fc10.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Crypt-IDEA-1.08-2.fc10.x86_64.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-IO-Interface-0.97-3.7.3.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-IO-Interface-0.97-3.8.0.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-IO-Interface-0.97-3.8.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Net-IP-1.15-1.7.3.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Net-IP-1.15-1.8.0.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Net-IP-1.15-1.8.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Term-ProgressBar-2.00-1.7.3.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Term-ProgressBar-2.00-1.8.0.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Term-ProgressBar-2.00-1.8.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Term-ReadKey-2.20-1.7.3.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Term-ReadKey-2.20-1.8.0.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/perl-Term-ReadKey-2.20-1.8.0.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/ping-0.17-30994cl.ppc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/ping-0.17-30994cl.sparc.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/ping-ss020927-54702cl.i386.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/python-glc-0.7.1-1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/renamed.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/rpm_trailing.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/setup-2.5.49-b1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/svgalib-1.9.25-b1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/xsetup-0.28-b1.src.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/header/zziplib-0.11.15-3sf.i586.rpm:1", + "Warn: binary detected: tests/packagedcode/data/rpm/package/alfandega-2.0-1.7.3.noarch.rpm:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/Microsoft.Practices.EnterpriseLibrary.Caching.dll:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/Moq.Silverlight.dll:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/Windows.AI.winmd:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/_ctypes_test.pyd:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/chcp.com:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/clfs.sys.mui:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/crypt32.dll.mun:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/euc-jp.so:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/file.exe:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/libiconv2.dll:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/libintl3.dll:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/stdole2.tlb:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/tbs.sys:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/tre4.dll:1", + "Warn: binary detected: tests/packagedcode/data/win_pe/zlib1.dll:1", + "Warn: binary detected: tests/scancode/data/rpm/fping-2.4-0.b2.rhfc1.dag.i386.rpm:1", + "Warn: binary detected: tests/textcode/data/archive/simple.jar:1", + "Warn: binary detected: tests/textcode/data/strings/basic/main.o:1", + "Warn: binary detected: tests/textcode/data/strings/bin/amd64_exec:1", + "Warn: binary detected: tests/textcode/data/strings/bin/c_count.exe:1", + "Warn: binary detected: tests/textcode/data/strings/bin/cygmagic-1.dll:1", + "Warn: binary detected: tests/textcode/data/strings/bin/file_stripped:1", + "Warn: binary detected: tests/textcode/data/strings/bin/ia32_exec:1", + "Warn: binary detected: tests/textcode/data/strings/bin/ia64_exec:1", + "Warn: binary detected: tests/textcode/data/strings/bin/malformed_stringtable:1", + "Warn: binary detected: tests/textcode/data/strings/bin/mips32_exec:1", + "Warn: binary detected: tests/textcode/data/strings/bin/mips64_exec:1", + "Warn: binary detected: tests/textcode/data/strings/bin/msvci70.dll:1", + "Warn: binary detected: tests/textcode/data/strings/bin/php4embed.lib:1", + "Warn: binary detected: tests/textcode/data/strings/bin/pyexpat.lib:1", + "Warn: binary detected: tests/textcode/data/strings/bin/rlog.exe:1", + "Warn: binary detected: tests/textcode/data/strings/bin/shash.i686:1", + "Warn: binary detected: tests/textcode/data/strings/bin/shash.x86_64:1", + "Warn: binary detected: tests/textcode/data/strings/bin/ssdeep.i686:1", + "Warn: binary detected: tests/textcode/data/strings/bin/ssdeep.x86_64:1", + "Warn: binary detected: tests/textcode/data/strings/bin/sspi_protocol.dll:1", + "Warn: binary detected: tests/textcode/data/strings/bin/zlib.lib:1", + "Warn: binary detected: tests/textcode/data/strings/elf/shash.i686:1", + "Warn: binary detected: tests/textcode/data/strings/obj/test.o:1", + "Warn: binary detected: tests/textcode/data/strings/pe/7-zip-pe-with-unicode.dll:1", + "Warn: binary detected: tests/textcode/data/strings/wip-short_strings/false:1", + "Warn: binary detected: tests/textcode/data/strings/with-lf/strings.exe:1" + ], + "documentation": { + "short": "Determines if the project has generated executable (binary) artifacts in the source repository.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#binary-artifacts" + } + }, + { + "name": "Pinned-Dependencies", + "score": 0, + "reason": "dependency not pinned by hash detected -- score normalized to 0", + "details": [ + "Info: Possibly incomplete results: error parsing shell code: a command can only contain words and redirects; encountered ): tests/cluecode/data/authors/expat-ltmain.sh:0", + "Info: Possibly incomplete results: error parsing shell code: a command can only contain words and redirects; encountered ): tests/cluecode/data/ics/expat-conftools/ltmain.sh:0", + "Info: Possibly incomplete results: error parsing shell code: invalid parameter name: tests/licensedcode/data/datadriven/lic2/apache_and_apache-2.0_and_public-domain.txt:0", + "Info: Possibly incomplete results: error parsing shell code: \"for\" must be followed by a literal: tests/licensedcode/data/datadriven/lic3/no_license_22.txt:0", + "Info: Possibly incomplete results: error parsing shell code: if statement must end with \"fi\": tests/packagedcode/data/bashlex/ltmain.sh:0", + "Info: Possibly incomplete results: error parsing shell code: unclosed here-document 'EOF': tests/packagedcode/data/bashlex/stripheredoc.sh:0", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/about-files-ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/about-files-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/about-files-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/about-files-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs-ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/docs-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/docs-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:106: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:109: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:117: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:174: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:177: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:185: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:288: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:291: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:296: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:333: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:336: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:341: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:374: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:377: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:382: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:455: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:461: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:467: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:473: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:479: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:485: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:491: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:497: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:503: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:509: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:515: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:521: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:527: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:533: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:539: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:545: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: third-party GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:555: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:51: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:140: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:143: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:151: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:205: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:208: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:216: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:242: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:245: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:250: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:415: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:418: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:423: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:580: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:585: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: third-party GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:595: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:83: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: containerImage not pinned by hash: Dockerfile:10: pin your Docker image by updating python:3.8-slim-buster to python:3.8-slim-buster@sha256:8799b0564103a9f36cfb8a8e1c562e11a9a6f2e3bb214e2adc23982b36a04511", + "Warn: pipCommand not pinned by hash: .github/workflows/docs-ci.yml:28", + "Warn: pipCommand not pinned by hash: .github/workflows/scancode-release.yml:260", + "Warn: pipCommand not pinned by hash: .github/workflows/scancode-release.yml:263", + "Info: 0 out of 55 GitHub-owned GitHubAction dependencies pinned", + "Info: 0 out of 2 third-party GitHubAction dependencies pinned", + "Info: 0 out of 1 containerImage dependencies pinned", + "Info: 0 out of 3 pipCommand dependencies pinned" + ], + "documentation": { + "short": "Determines if the project has declared and pinned the dependencies of its build process.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#pinned-dependencies" + } + }, + { + "name": "Vulnerabilities", + "score": 0, + "reason": "369 existing vulnerabilities detected", + "details": [ + "Warn: Project is vulnerable to: GHSA-248v-346w-9cwc", + "Warn: Project is vulnerable to: GHSA-v3c5-jqr6-7qm8 / PYSEC-2022-42991", + "Warn: Project is vulnerable to: GHSA-jjg7-2v4v-x38h / PYSEC-2024-60", + "Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj", + "Warn: Project is vulnerable to: GHSA-mrwq-x4v8-fh7p / PYSEC-2023-117", + "Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56", + "Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf", + "Warn: Project is vulnerable to: GHSA-jfmj-5v4g-7637", + "Warn: Project is vulnerable to: RUSTSEC-2020-0159", + "Warn: Project is vulnerable to: GHSA-wcg3-cvx6-7396 / RUSTSEC-2020-0071", + "Warn: Project is vulnerable to: GHSA-rc23-xxgq-x27g / RUSTSEC-2022-0054", + "Warn: Project is vulnerable to: GHSA-3hhc-qp5v-9p2j", + "Warn: Project is vulnerable to: GHSA-579w-22j4-4749", + "Warn: Project is vulnerable to: GHSA-9rf5-jm6f-2fmm", + "Warn: Project is vulnerable to: GHSA-hqf9-rc9j-5fmj", + "Warn: Project is vulnerable to: GHSA-r8fh-hq2p-7qhq", + "Warn: Project is vulnerable to: GHSA-xrr6-3pc4-m447", + "Warn: Project is vulnerable to: GHSA-j6gc-792m-qgm2", + "Warn: Project is vulnerable to: GHSA-j96r-xvjq-r9pg", + "Warn: Project is vulnerable to: GHSA-pj73-v5mw-pm9j", + "Warn: Project is vulnerable to: GHSA-2gw2-8q9w-cw8p", + "Warn: Project is vulnerable to: GHSA-34hf-g744-jw64", + "Warn: Project is vulnerable to: GHSA-r5hc-9xx5-97rw", + "Warn: Project is vulnerable to: GHSA-jppv-gw3r-w3q8", + "Warn: Project is vulnerable to: GHSA-5cm2-9h8c-rvfx", + "Warn: Project is vulnerable to: GHSA-8mq4-9jjh-9xrc", + "Warn: Project is vulnerable to: GHSA-gj4p-3wh3-2rmf", + "Warn: Project is vulnerable to: GHSA-xfhh-rx56-rxcr", + "Warn: Project is vulnerable to: GHSA-wxc4-f4m6-wwqv / GO-2020-0036", + "Warn: Project is vulnerable to: GHSA-r88r-gmrh-7j83 / GO-2021-0061", + "Warn: Project is vulnerable to: GHSA-6q6q-88xp-6f2r / GO-2022-0956", + "Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95", + "Warn: Project is vulnerable to: GHSA-275c-w5mq-v5m2", + "Warn: Project is vulnerable to: GHSA-2hvc-hwg3-hpvw", + "Warn: Project is vulnerable to: GHSA-2rp8-hff9-c5wr", + "Warn: Project is vulnerable to: GHSA-2wcj-qr76-9768", + "Warn: Project is vulnerable to: GHSA-3cr5-2446-8pg3", + "Warn: Project is vulnerable to: GHSA-4rrv-8gcp-24v8", + "Warn: Project is vulnerable to: GHSA-547m-23x7-cxg5", + "Warn: Project is vulnerable to: GHSA-83g7-8fch-p37m", + "Warn: Project is vulnerable to: GHSA-8fp7-jwv2-49x9", + "Warn: Project is vulnerable to: GHSA-8wfh-qxxv-3q8c / PYSEC-2023-122", + "Warn: Project is vulnerable to: GHSA-9q9v-qgwx-84mr / PYSEC-2023-126", + "Warn: Project is vulnerable to: GHSA-c6ph-m8cw-rfqh", + "Warn: Project is vulnerable to: GHSA-chj7-w3f6-cvfj", + "Warn: Project is vulnerable to: GHSA-cv2j-922j-hr56 / PYSEC-2023-125", + "Warn: Project is vulnerable to: GHSA-fh54-3vhg-mpc2", + "Warn: Project is vulnerable to: GHSA-g57v-2687-jx33", + "Warn: Project is vulnerable to: GHSA-gcjf-29m9-888q / PYSEC-2022-43063", + "Warn: Project is vulnerable to: GHSA-hh7p-hvm3-rg88 / PYSEC-2023-124", + "Warn: Project is vulnerable to: GHSA-j5h9-9r39-43q5", + "Warn: Project is vulnerable to: GHSA-jm68-fpmr-8j2g", + "Warn: Project is vulnerable to: GHSA-jwrc-3v3f-5cq5", + "Warn: Project is vulnerable to: GHSA-mr78-v55p-7777", + "Warn: Project is vulnerable to: GHSA-mrmm-qmrj-xgp6", + "Warn: Project is vulnerable to: GHSA-qppw-c37g-xwcc", + "Warn: Project is vulnerable to: GHSA-qqv2-35q8-p2g2", + "Warn: Project is vulnerable to: GHSA-rf7p-79xq-8xwm", + "Warn: Project is vulnerable to: GHSA-rg9q-m8hv-xxr6", + "Warn: Project is vulnerable to: GHSA-rr46-m366-gm44 / PYSEC-2023-123", + "Warn: Project is vulnerable to: GHSA-rx2r-q96c-w5cc", + "Warn: Project is vulnerable to: GHSA-v9pg-qw6x-w5r2", + "Warn: Project is vulnerable to: GHSA-x3q9-c788-j7c8", + "Warn: Project is vulnerable to: GHSA-xjpw-hx47-rccv", + "Warn: Project is vulnerable to: GHSA-xgfm-fjx6-62mj", + "Warn: Project is vulnerable to: GHSA-crqg-jrpj-fc84", + "Warn: Project is vulnerable to: GHSA-27xj-rqx5-2255", + "Warn: Project is vulnerable to: GHSA-288c-cq4h-88gq", + "Warn: Project is vulnerable to: GHSA-4gq5-ch57-c2mg", + "Warn: Project is vulnerable to: GHSA-4w82-r329-3q67", + "Warn: Project is vulnerable to: GHSA-57j2-w4cx-62h2", + "Warn: Project is vulnerable to: GHSA-58pp-9c76-5625", + "Warn: Project is vulnerable to: GHSA-5949-rw7g-wx7w", + "Warn: Project is vulnerable to: GHSA-5p34-5m6p-p58g", + "Warn: Project is vulnerable to: GHSA-5r5r-6hpj-8gg9", + "Warn: Project is vulnerable to: GHSA-5ww9-j83m-q7qx", + "Warn: Project is vulnerable to: GHSA-645p-88qh-w398", + "Warn: Project is vulnerable to: GHSA-6fpp-rgj9-8rwc", + "Warn: Project is vulnerable to: GHSA-6wqp-v4v6-c87c", + "Warn: Project is vulnerable to: GHSA-758m-v56v-grj4", + "Warn: Project is vulnerable to: GHSA-85cw-hj65-qqv9", + "Warn: Project is vulnerable to: GHSA-89qr-369f-5m5x", + "Warn: Project is vulnerable to: GHSA-8c4j-34r4-xr8g", + "Warn: Project is vulnerable to: GHSA-8w26-6f25-cm9x", + "Warn: Project is vulnerable to: GHSA-95cm-88f5-f2c7", + "Warn: Project is vulnerable to: GHSA-9gph-22xh-8x98", + "Warn: Project is vulnerable to: GHSA-9m6f-7xcq-8vf8", + "Warn: Project is vulnerable to: GHSA-9mxf-g3x6-wv74", + "Warn: Project is vulnerable to: GHSA-9vvp-fxw6-jcxr", + "Warn: Project is vulnerable to: GHSA-c265-37vj-cwcc", + "Warn: Project is vulnerable to: GHSA-c2q3-4qrh-fm48", + "Warn: Project is vulnerable to: GHSA-c8hm-7hpq-7jhg", + "Warn: Project is vulnerable to: GHSA-cf6r-3wgc-h863", + "Warn: Project is vulnerable to: GHSA-cggj-fvv3-cqwv", + "Warn: Project is vulnerable to: GHSA-cjjf-94ff-43w7", + "Warn: Project is vulnerable to: GHSA-cmfg-87vq-g5g4", + "Warn: Project is vulnerable to: GHSA-cvm9-fjm9-3572", + "Warn: Project is vulnerable to: GHSA-f3j5-rmmp-3fc5", + "Warn: Project is vulnerable to: GHSA-f9hv-mg5h-xcw9", + "Warn: Project is vulnerable to: GHSA-f9xh-2qgp-cq57", + "Warn: Project is vulnerable to: GHSA-fmmc-742q-jg75", + "Warn: Project is vulnerable to: GHSA-fqwf-pjwf-7vqv", + "Warn: Project is vulnerable to: GHSA-gjmw-vf9h-g25v", + "Warn: Project is vulnerable to: GHSA-gwp4-hfv6-p7hw", + "Warn: Project is vulnerable to: GHSA-gww7-p5w4-wrfv", + "Warn: Project is vulnerable to: GHSA-h3cw-g4mq-c5x2", + "Warn: Project is vulnerable to: GHSA-h4rc-386g-6m85", + "Warn: Project is vulnerable to: GHSA-h822-r4r5-v8jg", + "Warn: Project is vulnerable to: GHSA-j823-4qch-3rgm", + "Warn: Project is vulnerable to: GHSA-jjjh-jjxp-wpff", + "Warn: Project is vulnerable to: GHSA-m6x4-97wx-4q27", + "Warn: Project is vulnerable to: GHSA-mc6h-4qgp-37qh", + "Warn: Project is vulnerable to: GHSA-mph4-vhrx-mv67", + "Warn: Project is vulnerable to: GHSA-mx7p-6679-8g3q", + "Warn: Project is vulnerable to: GHSA-mx9v-gmh4-mgqw", + "Warn: Project is vulnerable to: GHSA-p43x-xfjf-5jhr", + "Warn: Project is vulnerable to: GHSA-q93h-jc49-78gg", + "Warn: Project is vulnerable to: GHSA-qjw2-hr98-qgfh", + "Warn: Project is vulnerable to: GHSA-qmqc-x3r4-6v39", + "Warn: Project is vulnerable to: GHSA-qr7j-h6gg-jmgc", + "Warn: Project is vulnerable to: GHSA-r3gr-cxrf-hg25", + "Warn: Project is vulnerable to: GHSA-r695-7vr9-jgc2", + "Warn: Project is vulnerable to: GHSA-rf6r-2c4q-2vwg", + "Warn: Project is vulnerable to: GHSA-rgv9-q543-rqg4", + "Warn: Project is vulnerable to: GHSA-rpr3-cw39-3pxh", + "Warn: Project is vulnerable to: GHSA-v3xw-c963-f5hc", + "Warn: Project is vulnerable to: GHSA-v585-23hc-c647", + "Warn: Project is vulnerable to: GHSA-vfqx-33qm-g869", + "Warn: Project is vulnerable to: GHSA-wh8g-3j2c-rqj5", + "Warn: Project is vulnerable to: GHSA-x2w5-5m2g-7h5m", + "Warn: Project is vulnerable to: GHSA-gwrp-pvrq-jmwv", + "Warn: Project is vulnerable to: GHSA-fmj2-7wx8-qj4v", + "Warn: Project is vulnerable to: GHSA-36p3-wjmg-h94x", + "Warn: Project is vulnerable to: GHSA-hh26-6xwr-ggv7", + "Warn: Project is vulnerable to: GHSA-g5mm-vmx4-3rg7", + "Warn: Project is vulnerable to: GHSA-3rmv-2pg5-xvqj", + "Warn: Project is vulnerable to: GHSA-4487-x383-qpph", + "Warn: Project is vulnerable to: GHSA-f26x-pr96-vw86", + "Warn: Project is vulnerable to: GHSA-ffvq-7w96-97p7", + "Warn: Project is vulnerable to: GHSA-g8hw-794c-4j9g", + "Warn: Project is vulnerable to: GHSA-p5hg-3xm3-gcjg", + "Warn: Project is vulnerable to: GHSA-rcpf-vj53-7h2m", + "Warn: Project is vulnerable to: GHSA-558x-2xjg-6232", + "Warn: Project is vulnerable to: GHSA-564r-hj7v-mcr5", + "Warn: Project is vulnerable to: GHSA-wxqc-pxw9-g2p8", + "Warn: Project is vulnerable to: GHSA-9339-86wc-4qgf", + "Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw", + "Warn: Project is vulnerable to: GHSA-7r3h-m5j6-3q42", + "Warn: Project is vulnerable to: GHSA-25mq-v84q-4j7r", + "Warn: Project is vulnerable to: GHSA-cwmx-hcrq-mhc3", + "Warn: Project is vulnerable to: GHSA-f2wf-25xc-69c9", + "Warn: Project is vulnerable to: GHSA-q559-8m2m-g699", + "Warn: Project is vulnerable to: GHSA-w248-ffj2-4v5q", + "Warn: Project is vulnerable to: GHSA-337x-4q8g-prc5", + "Warn: Project is vulnerable to: GHSA-6565-fg86-6jcx / PYSEC-2015-8", + "Warn: Project is vulnerable to: GHSA-68w8-qjq3-2gfm / PYSEC-2021-98", + "Warn: Project is vulnerable to: GHSA-6g95-x6cj-mg4v / PYSEC-2015-7", + "Warn: Project is vulnerable to: GHSA-6wcr-wcqm-3mfh / PYSEC-2015-11", + "Warn: Project is vulnerable to: GHSA-7fq8-4pv5-5w5c / PYSEC-2015-9", + "Warn: Project is vulnerable to: GHSA-7qfw-j7hp-v45g / PYSEC-2015-4", + "Warn: Project is vulnerable to: GHSA-c8c8-9472-w52h / PYSEC-2016-2", + "Warn: Project is vulnerable to: GHSA-crhm-qpjc-cm64 / PYSEC-2016-3", + "Warn: Project is vulnerable to: GHSA-fp6p-5xvw-m74f / PYSEC-2016-16", + "Warn: Project is vulnerable to: GHSA-gv98-g628-m9x5 / PYSEC-2015-5", + "Warn: Project is vulnerable to: GHSA-h582-2pch-3xv3 / PYSEC-2015-20", + "Warn: Project is vulnerable to: GHSA-hmr4-m2h5-33qx", + "Warn: Project is vulnerable to: GHSA-j3j3-jrfh-cm2w / PYSEC-2015-18", + "Warn: Project is vulnerable to: GHSA-jhjg-w2cp-5j44 / PYSEC-2015-6", + "Warn: Project is vulnerable to: GHSA-pgxh-wfw4-jx2v / PYSEC-2015-22", + "Warn: Project is vulnerable to: GHSA-pw27-w7w4-9qc7 / PYSEC-2016-15", + "Warn: Project is vulnerable to: GHSA-q5qw-4364-5hhm / PYSEC-2015-10", + "Warn: Project is vulnerable to: GHSA-v6rh-hp5x-86rv", + "Warn: Project is vulnerable to: GHSA-vfq6-hq5r-27r6 / PYSEC-2019-16", + "Warn: Project is vulnerable to: GHSA-wh4h-v3f2-r2pp", + "Warn: Project is vulnerable to: GHSA-x38m-486c-2wr9 / PYSEC-2015-23", + "Warn: Project is vulnerable to: GHSA-xxj9-f6rv-m3x4", + "Warn: Project is vulnerable to: PYSEC-2016-18", + "Warn: Project is vulnerable to: GHSA-hjf3-r7gw-9rwg / PYSEC-2012-14", + "Warn: Project is vulnerable to: GHSA-6528-wvf6-f6qg / PYSEC-2018-97", + "Warn: Project is vulnerable to: GHSA-cq27-v7xp-c356 / PYSEC-2017-94", + "Warn: Project is vulnerable to: GHSA-v367-p58w-98h5 / PYSEC-2012-16", + "Warn: Project is vulnerable to: GHSA-x377-f64p-hf5j / PYSEC-2013-29", + "Warn: Project is vulnerable to: GHSA-r9jw-mwhq-wp62 / PYSEC-2017-24", + "Warn: Project is vulnerable to: GHSA-652x-xj99-gmcc / PYSEC-2014-14", + "Warn: Project is vulnerable to: GHSA-cfj3-7x9c-4p3h / PYSEC-2014-13", + "Warn: Project is vulnerable to: GHSA-pg2w-x9wp-vw92 / PYSEC-2015-17", + "Warn: Project is vulnerable to: GHSA-x84v-xcm2-53pg / PYSEC-2018-28", + "Warn: Project is vulnerable to: GHSA-537h-rv9q-vvph / PYSEC-2020-99", + "Warn: Project is vulnerable to: GHSA-xrx6-fmxq-rjj2 / PYSEC-2020-100", + "Warn: Project is vulnerable to: GHSA-9772-cwx9-r4cj", + "Warn: Project is vulnerable to: GHSA-hj5v-574p-mj7c / PYSEC-2020-92", + "Warn: Project is vulnerable to: GHSA-w596-4wvx-j9j6 / PYSEC-2022-42969", + "Warn: Project is vulnerable to: GHSA-6757-jp84-gxfx", + "Warn: Project is vulnerable to: GHSA-8q59-q68h-6hv4 / PYSEC-2021-142", + "Warn: Project is vulnerable to: GHSA-rprw-h62v-c2w7 / PYSEC-2018-49", + "Warn: Project is vulnerable to: GHSA-43fp-rhv2-5gv8 / PYSEC-2022-42986", + "Warn: Project is vulnerable to: GHSA-xqr8-7jwr-rhp7 / PYSEC-2023-135", + "Warn: Project is vulnerable to: GHSA-9w8r-397f-prfh / PYSEC-2021-140", + "Warn: Project is vulnerable to: GHSA-pq64-v7f5-gqh8 / PYSEC-2021-141", + "Warn: Project is vulnerable to: GHSA-g4mx-q9vg-27p4 / PYSEC-2023-212", + "Warn: Project is vulnerable to: GHSA-r64q-w8jr-g9qp / PYSEC-2019-132", + "Warn: Project is vulnerable to: GHSA-v845-jxx5-vc9f / PYSEC-2023-192", + "Warn: Project is vulnerable to: GHSA-wqvq-5m8c-6g24 / PYSEC-2020-148", + "Warn: Project is vulnerable to: GHSA-q2q7-5pp4-w6pg / PYSEC-2021-108", + "Warn: Project is vulnerable to: GHSA-qwmp-2cf2-g9g6 / PYSEC-2022-43017", + "Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5", + "Warn: Project is vulnerable to: GHSA-r9hx-vwmv-q579 / PYSEC-2022-43012", + "Warn: Project is vulnerable to: GHSA-h4m5-qpfp-3mpv / PYSEC-2021-421", + "Warn: Project is vulnerable to: GHSA-55x5-fj6c-h6m8", + "Warn: Project is vulnerable to: GHSA-jq4v-f5q6-mjqq / PYSEC-2021-19", + "Warn: Project is vulnerable to: GHSA-pgww-xf46-h92r / PYSEC-2020-62", + "Warn: Project is vulnerable to: GHSA-wrxv-2j5q-m38w / PYSEC-2022-230", + "Warn: Project is vulnerable to: GHSA-xp26-p53h-6h2p / PYSEC-2018-12", + "Warn: Project is vulnerable to: GHSA-j8r2-6x86-q33q / PYSEC-2023-74", + "Warn: Project is vulnerable to: GHSA-4g8v-vg43-wpgf", + "Warn: Project is vulnerable to: GHSA-7wjx-3g7j-8584", + "Warn: Project is vulnerable to: GHSA-8727-m6gj-mc37", + "Warn: Project is vulnerable to: GHSA-8xww-x3g3-6jcv", + "Warn: Project is vulnerable to: GHSA-hjg4-8q5f-x6fm", + "Warn: Project is vulnerable to: GHSA-jp5v-5gx4-jmj9", + "Warn: Project is vulnerable to: GHSA-p84v-45xj-wwqj", + "Warn: Project is vulnerable to: GHSA-rmj8-8hhh-gv5h / GHSA-wh98-p28r-vrc9", + "Warn: Project is vulnerable to: GHSA-65cv-r6x7-79hv", + "Warn: Project is vulnerable to: GHSA-86g5-2wh3-gc9j", + "Warn: Project is vulnerable to: GHSA-cfjv-5498-mph5", + "Warn: Project is vulnerable to: GHSA-ch3h-j2vf-95pv", + "Warn: Project is vulnerable to: GHSA-m63j-wh5w-c252", + "Warn: Project is vulnerable to: GHSA-xq5j-gw7f-jgj8", + "Warn: Project is vulnerable to: GHSA-q2qw-rmrh-vv42", + "Warn: Project is vulnerable to: GHSA-8hc4-xxm3-5ppp", + "Warn: Project is vulnerable to: GHSA-2p68-f74v-9wc6", + "Warn: Project is vulnerable to: GHSA-23c2-gwp5-pxw9", + "Warn: Project is vulnerable to: GHSA-6c3j-c64m-qhgq", + "Warn: Project is vulnerable to: GHSA-gxr4-xjj5-5px2", + "Warn: Project is vulnerable to: GHSA-jpcq-cgw6-v4j6", + "Warn: Project is vulnerable to: GHSA-228g-948r-83gx", + "Warn: Project is vulnerable to: GHSA-486f-hjj9-9vhh", + "Warn: Project is vulnerable to: GHSA-c3gv-9cxf-6f57", + "Warn: Project is vulnerable to: GHSA-g4xq-jx4w-4cjv", + "Warn: Project is vulnerable to: GHSA-x7rv-cr6v-4vm4", + "Warn: Project is vulnerable to: GHSA-242x-7cm6-4w8j", + "Warn: Project is vulnerable to: GHSA-286v-pcf5-25rc", + "Warn: Project is vulnerable to: GHSA-2qc6-mcvw-92cw", + "Warn: Project is vulnerable to: GHSA-2rr5-8q37-2w7h", + "Warn: Project is vulnerable to: GHSA-4hm9-844j-jmxp", + "Warn: Project is vulnerable to: GHSA-59gp-qqm7-cw4j", + "Warn: Project is vulnerable to: GHSA-6qvp-r6r3-9p7h", + "Warn: Project is vulnerable to: GHSA-7553-jr98-vx47", + "Warn: Project is vulnerable to: GHSA-7rrm-v45f-jp64", + "Warn: Project is vulnerable to: GHSA-882p-jqgm-f45g", + "Warn: Project is vulnerable to: GHSA-cf46-6xxh-pc75", + "Warn: Project is vulnerable to: GHSA-cgx6-hpwq-fhv5", + "Warn: Project is vulnerable to: GHSA-cr5j-953j-xw5p", + "Warn: Project is vulnerable to: GHSA-crjr-9rc5-ghw8", + "Warn: Project is vulnerable to: GHSA-fq42-c5rg-92c2", + "Warn: Project is vulnerable to: GHSA-gx8x-g87m-h5q6", + "Warn: Project is vulnerable to: GHSA-jc36-42cf-vqwj", + "Warn: Project is vulnerable to: GHSA-jw9f-hh49-cvp9", + "Warn: Project is vulnerable to: GHSA-pxvg-2qj5-37jq", + "Warn: Project is vulnerable to: GHSA-qxcg-xjjg-66mj", + "Warn: Project is vulnerable to: GHSA-r58r-74gx-6wx3", + "Warn: Project is vulnerable to: GHSA-r95h-9x8f-r3f7", + "Warn: Project is vulnerable to: GHSA-v4f8-2847-rwm7", + "Warn: Project is vulnerable to: GHSA-v6gp-9mmm-c6p5", + "Warn: Project is vulnerable to: GHSA-vcc3-rw6f-jv97", + "Warn: Project is vulnerable to: GHSA-vmfx-gcfq-wvm2", + "Warn: Project is vulnerable to: GHSA-vr8q-g5c7-m54m", + "Warn: Project is vulnerable to: GHSA-xc9x-jj77-9p9j", + "Warn: Project is vulnerable to: GHSA-xh29-r2w5-wx8m", + "Warn: Project is vulnerable to: GHSA-xxx9-3xcr-gjj3", + "Warn: Project is vulnerable to: GHSA-33vf-4xgg-9r58 / GHSA-84j7-475p-hp8v", + "Warn: Project is vulnerable to: GHSA-48w2-rm65-62xx", + "Warn: Project is vulnerable to: GHSA-68xg-gqqm-vgj8", + "Warn: Project is vulnerable to: GHSA-7xx3-m584-x994", + "Warn: Project is vulnerable to: GHSA-c2f4-cvqm-65w2", + "Warn: Project is vulnerable to: GHSA-h99w-9q5r-gjq9", + "Warn: Project is vulnerable to: GHSA-q28m-8xjw-8vr5", + "Warn: Project is vulnerable to: GHSA-w64w-qqph-5gxm", + "Warn: Project is vulnerable to: GHSA-x7jg-6pwg-fx5h", + "Warn: Project is vulnerable to: GHSA-22f2-v57c-j9cx", + "Warn: Project is vulnerable to: GHSA-3h57-hmj3-gj3p", + "Warn: Project is vulnerable to: GHSA-54rr-7fvw-6x8f", + "Warn: Project is vulnerable to: GHSA-5f9h-9pjv-v6j7", + "Warn: Project is vulnerable to: GHSA-5r2p-j47h-mhpg", + "Warn: Project is vulnerable to: GHSA-65f5-mfpf-vfhj", + "Warn: Project is vulnerable to: GHSA-93pm-5p5f-3ghx", + "Warn: Project is vulnerable to: GHSA-c6qg-cjj8-47qp", + "Warn: Project is vulnerable to: GHSA-hrqr-hxpp-chr3", + "Warn: Project is vulnerable to: GHSA-hxqx-xwvh-44m2", + "Warn: Project is vulnerable to: GHSA-j6w9-fv6q-3q52", + "Warn: Project is vulnerable to: GHSA-rqv2-275x-2jq5", + "Warn: Project is vulnerable to: GHSA-wq4h-7r42-5hrr", + "Warn: Project is vulnerable to: GHSA-xj5v-6v4g-jfw6", + "Warn: Project is vulnerable to: GHSA-5x79-w82f-gw8w", + "Warn: Project is vulnerable to: GHSA-9h9g-93gc-623h", + "Warn: Project is vulnerable to: GHSA-mcvf-2q2m-x72m", + "Warn: Project is vulnerable to: GHSA-pg8v-g4xq-hww9", + "Warn: Project is vulnerable to: GHSA-px3r-jm9g-c8w8", + "Warn: Project is vulnerable to: GHSA-rrfc-7g8p-99q8", + "Warn: Project is vulnerable to: GHSA-pr3h-jjhj-573x", + "Warn: Project is vulnerable to: GHSA-g6wq-qcwm-j5g2", + "Warn: Project is vulnerable to: GHSA-jxhc-q857-3j6g", + "Warn: Project is vulnerable to: GHSA-3xg8-cc8f-9wv2", + "Warn: Project is vulnerable to: GHSA-cxf7-qrc5-9446", + "Warn: Project is vulnerable to: GHSA-5c5f-7vfq-3732", + "Warn: Project is vulnerable to: GHSA-3x8r-x6xp-q4vm", + "Warn: Project is vulnerable to: GHSA-592j-995h-p23j", + "Warn: Project is vulnerable to: GHSA-ggxm-pgc9-g7fp", + "Warn: Project is vulnerable to: GHSA-q3wr-qw3g-3p4h", + "Warn: Project is vulnerable to: GHSA-gc3j-vvwf-4rp8", + "Warn: Project is vulnerable to: GHSA-r8xx-8vm8-x6wj", + "Warn: Project is vulnerable to: GHSA-r9mq-m72x-257g", + "Warn: Project is vulnerable to: GHSA-9hmq-fm33-x4xx", + "Warn: Project is vulnerable to: GHSA-4xqq-m2hx-25v8", + "Warn: Project is vulnerable to: GHSA-8cr8-4vfw-mr7h", + "Warn: Project is vulnerable to: GHSA-vg3r-rm7w-2xgh", + "Warn: Project is vulnerable to: GHSA-3qc2-v3hp-6cv8", + "Warn: Project is vulnerable to: GHSA-grh7-935j-hg6w", + "Warn: Project is vulnerable to: GHSA-jrfj-98qg-qjgv", + "Warn: Project is vulnerable to: GHSA-2x8x-jmrp-phxw", + "Warn: Project is vulnerable to: GHSA-qp49-3pvw-x4m5", + "Warn: Project is vulnerable to: GHSA-jphg-qwrw-7w9g", + "Warn: Project is vulnerable to: GHSA-8c56-cpmw-89x7", + "Warn: Project is vulnerable to: GHSA-x2fm-93ww-ggvx", + "Warn: Project is vulnerable to: GHSA-mm33-5vfq-3mm3", + "Warn: Project is vulnerable to: GHSA-xp5h-f8jf-rc8q", + "Warn: Project is vulnerable to: GHSA-hq7p-j377-6v63", + "Warn: Project is vulnerable to: GHSA-8h22-8cf7-hq6g", + "Warn: Project is vulnerable to: GHSA-cr5q-6q9f-rq6q", + "Warn: Project is vulnerable to: GHSA-w749-p3v6-hccq", + "Warn: Project is vulnerable to: GHSA-frgf-8jr5-j2jv", + "Warn: Project is vulnerable to: GHSA-fwhr-88qx-h9g7", + "Warn: Project is vulnerable to: GHSA-qphc-hf5q-v8fc", + "Warn: Project is vulnerable to: GHSA-3vfw-7rcp-3xgm", + "Warn: Project is vulnerable to: GHSA-7g65-ghrg-hpf5", + "Warn: Project is vulnerable to: GHSA-92w9-2pqw-rhjj", + "Warn: Project is vulnerable to: GHSA-fcqf-h4h4-695m", + "Warn: Project is vulnerable to: GHSA-ffpv-c4hm-3x6v", + "Warn: Project is vulnerable to: GHSA-hgpp-pp89-4fgf", + "Warn: Project is vulnerable to: GHSA-j838-vfpq-fmf2", + "Warn: Project is vulnerable to: GHSA-jmgw-6vjg-jjwg", + "Warn: Project is vulnerable to: GHSA-q34c-48gc-m9g8", + "Warn: Project is vulnerable to: GHSA-q58j-fmvf-9rq6", + "Warn: Project is vulnerable to: GHSA-q759-hwvc-m3jg", + "Warn: Project is vulnerable to: GHSA-v5jg-558j-q67c", + "Warn: Project is vulnerable to: GHSA-v9v4-7jp6-8c73", + "Warn: Project is vulnerable to: GHSA-xrr4-p6fq-hjg7", + "Warn: Project is vulnerable to: GHSA-9fh3-vh3h-q4g3", + "Warn: Project is vulnerable to: GHSA-h835-75hw-pj89", + "Warn: Project is vulnerable to: GHSA-xgr2-v94m-rc9g", + "Warn: Project is vulnerable to: GHSA-6wj9-77wq-jq7p", + "Warn: Project is vulnerable to: GHSA-fr52-4hqw-p27f", + "Warn: Project is vulnerable to: GHSA-pf6m-fxpq-fg8v", + "Warn: Project is vulnerable to: GHSA-h77x-m5q8-c29h", + "Warn: Project is vulnerable to: GHSA-v6j3-7jrw-hq2p", + "Warn: Project is vulnerable to: GHSA-v882-ccj6-jc48", + "Warn: Project is vulnerable to: GHSA-xc85-32mf-xpv8", + "Warn: Project is vulnerable to: GHSA-48wp-p9qv-4j64", + "Warn: Project is vulnerable to: GHSA-4qw4-jpp4-8gvp", + "Warn: Project is vulnerable to: GHSA-636f-xm5j-pj9m", + "Warn: Project is vulnerable to: GHSA-7vh7-fw88-wj87", + "Warn: Project is vulnerable to: GHSA-fmx4-26r3-wxpf", + "Warn: Project is vulnerable to: GHSA-8c8q-2xw3-j869", + "Warn: Project is vulnerable to: GHSA-5g4r-2qhx-vqfm", + "Warn: Project is vulnerable to: GHSA-2qrg-x229-3v8q", + "Warn: Project is vulnerable to: GHSA-65fg-84f6-3jq3", + "Warn: Project is vulnerable to: GHSA-f7vh-qwp3-x37m", + "Warn: Project is vulnerable to: GHSA-fp5r-v3w9-4333", + "Warn: Project is vulnerable to: GHSA-w9p3-5cr8-m3jj" + ], + "documentation": { + "short": "Determines if the project has open, known unfixed vulnerabilities.", + "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#vulnerabilities" + } + } + ] +} \ No newline at end of file diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index ce5f51c56..0496b39a6 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2455,7 +2455,7 @@ def test_scorecard_models(self): self.assertEqual(checks.count(), 15) self.assertEqual(checks[0].check_name, "Code-Review") self.assertEqual(checks[0].check_score, "1") - + def test_scanpipe_model_codebase_resource_compliance_alert_queryset_mixin(self): severities = CodebaseResource.Compliance make_resource_file(self.project1, path="none") @@ -2478,7 +2478,7 @@ def test_scanpipe_model_codebase_resource_compliance_alert_queryset_mixin(self): self.assertQuerySetEqual( qs.compliance_issues(severities.MISSING), [error, missing, warning] ) - + class ScanPipeModelsTransactionTest(TransactionTestCase): """ From c00b3b383612ebb18ca9a6cf06c85f8bc8ce1230 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 21 Aug 2024 00:06:11 +0530 Subject: [PATCH 30/50] updated urls for testing nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 12 +++++++++++- scanpipe/tests/__init__.py | 5 ++++- scanpipe/tests/test_models.py | 4 ++-- scanpipe/tests/test_pipelines.py | 4 ++-- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 8115300d9..ec19d1851 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3928,12 +3928,22 @@ def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): } date_str = scorecard_data.score_date + + formats = ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%SZ"] + if date_str: - naive_datetime = datetime.strptime(date_str, "%Y-%m-%d") + naive_datetime = None + + for fmt in formats: + try: + naive_datetime = datetime.strptime(date_str, fmt) + except ValueError: + continue score_date = timezone.make_aware( naive_datetime, timezone.get_current_timezone() ) + else: score_date = timezone.now() diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index 9425f8876..169bf6f8a 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -23,6 +23,7 @@ import json import os from datetime import datetime +from pathlib import Path from unittest import mock from django.apps import apps @@ -268,5 +269,7 @@ def make_dependency(project, **extra): scorecard_data = None -with open("data/scorecode/scorecard_response.json") as file: +data = Path(__file__).parent / "data" + +with open(f"{data}/scorecode/scorecard_response.json") as file: scorecard_data = json.load(file) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 0496b39a6..4f841c85b 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2449,12 +2449,12 @@ def test_scorecard_models(self): self.assertIsNotNone(package_score) self.assertEqual(package_score.scoring_tool, PackageScore.ScoringTool.OSSF) - self.assertEqual(package_score.score, "6.7") + self.assertEqual(package_score.score, "4.4") checks = package_score.discovered_packages_score_checks.all() self.assertEqual(checks.count(), 15) self.assertEqual(checks[0].check_name, "Code-Review") - self.assertEqual(checks[0].check_score, "1") + self.assertEqual(checks[0].check_score, "7") def test_scanpipe_model_codebase_resource_compliance_alert_queryset_mixin(self): severities = CodebaseResource.Compliance diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index c9cff25a9..ed8cd8414 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -1245,7 +1245,7 @@ def test_scanpipe_get_scorecard_info_packages_integration( pipeline_name = "get_scorecard_info_packages" project1 = Project.objects.create(name="Analysis") package1 = DiscoveredPackage.create_from_data(project1, package_data1) - package1.vcs_url = "https://github.com/nexB/scancode-toolkit" + package1.vcs_url = "https://github.com/ossf/scorecard" package1.save() run = project1.add_pipeline(pipeline_name) @@ -1270,7 +1270,7 @@ def test_scanpipe_get_scorecard_info_packages_integration( msg=out, ) - self.assertEqual("https://github.com/nexB/scancode-toolkit", package1.vcs_url) + self.assertEqual("https://github.com/ossf/scorecard", package1.vcs_url) def test_scanpipe_resolve_dependencies_pipeline_integration(self): pipeline_name = "resolve_dependencies" From b97ff7a0e1686e952a5979ad0615c7f6163ebe55 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Wed, 21 Aug 2024 00:13:37 +0530 Subject: [PATCH 31/50] added merged migration file nexB#1283 Signed-off-by: 404-geek --- scanpipe/migrations/0068_merge_20240820_1656.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 scanpipe/migrations/0068_merge_20240820_1656.py diff --git a/scanpipe/migrations/0068_merge_20240820_1656.py b/scanpipe/migrations/0068_merge_20240820_1656.py new file mode 100644 index 000000000..1cb9f2f47 --- /dev/null +++ b/scanpipe/migrations/0068_merge_20240820_1656.py @@ -0,0 +1,14 @@ +# Generated by Django 5.0.7 on 2024-08-20 16:56 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('scanpipe', '0067_discoveredpackage_notes'), + ('scanpipe', '0067_packagescore_scorecardcheck'), + ] + + operations = [ + ] From 496945b315c3a45523a850ddd48ecaca08252995 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 23 Aug 2024 01:02:14 +0530 Subject: [PATCH 32/50] Changed docstring and renamed functions according to suggestions nexB#1283 Signed-off-by: 404-geek --- .../migrations/0068_merge_20240820_1656.py | 14 ---------- ...py => 0068_packagescore_scorecardcheck.py} | 4 +-- scanpipe/models.py | 22 ++++++--------- .../pipelines/get_scorecard_info_packages.py | 28 ++++--------------- setup.cfg | 2 +- 5 files changed, 17 insertions(+), 53 deletions(-) delete mode 100644 scanpipe/migrations/0068_merge_20240820_1656.py rename scanpipe/migrations/{0067_packagescore_scorecardcheck.py => 0068_packagescore_scorecardcheck.py} (96%) diff --git a/scanpipe/migrations/0068_merge_20240820_1656.py b/scanpipe/migrations/0068_merge_20240820_1656.py deleted file mode 100644 index 1cb9f2f47..000000000 --- a/scanpipe/migrations/0068_merge_20240820_1656.py +++ /dev/null @@ -1,14 +0,0 @@ -# Generated by Django 5.0.7 on 2024-08-20 16:56 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('scanpipe', '0067_discoveredpackage_notes'), - ('scanpipe', '0067_packagescore_scorecardcheck'), - ] - - operations = [ - ] diff --git a/scanpipe/migrations/0067_packagescore_scorecardcheck.py b/scanpipe/migrations/0068_packagescore_scorecardcheck.py similarity index 96% rename from scanpipe/migrations/0067_packagescore_scorecardcheck.py rename to scanpipe/migrations/0068_packagescore_scorecardcheck.py index f06a3741c..c8fcfb185 100644 --- a/scanpipe/migrations/0067_packagescore_scorecardcheck.py +++ b/scanpipe/migrations/0068_packagescore_scorecardcheck.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.7 on 2024-07-27 10:20 +# Generated by Django 5.0.7 on 2024-08-21 06:45 import django.db.models.deletion import uuid @@ -8,7 +8,7 @@ class Migration(migrations.Migration): dependencies = [ - ('scanpipe', '0066_alter_webhooksubscription_options_and_more'), + ('scanpipe', '0067_discoveredpackage_notes'), ] operations = [ diff --git a/scanpipe/models.py b/scanpipe/models.py index ec19d1851..91c5503ae 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3918,7 +3918,7 @@ def __str__(self): @classmethod @transaction.atomic() def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): - """Create ScoreCard Object from ScoreCard Object""" + """Create ScoreCard object from scorecard data and discovered package""" final_data = { "score": scorecard_data.score, "scoring_tool_version": scorecard_data.scoring_tool_version, @@ -3958,18 +3958,14 @@ def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): # Create associated scorecard_checks checks_data = scorecard_data.checks - ScorecardCheck.objects.bulk_create( - [ - ScorecardCheck( - check_name=check_data.check_name, - check_score=check_data.check_score, - reason=check_data.reason or "", - details=check_data.details or [], - for_package_score=scorecard_object, - ) - for check_data in checks_data - ] - ) + for check_data in checks_data: + ScorecardCheck.objects.create( + check_name=check_data.check_name, + check_score=check_data.check_score, + reason=check_data.reason or "", + details=check_data.details or [], + for_package_score=scorecard_object, + ) return scorecard_object diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index cb05f23d9..3dcc2a0e6 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -28,28 +28,10 @@ class FetchScoreCodeInfo(Pipeline): """ - Pipeline to fetch ScoreCode information for packages and dependencies. - - This pipeline retrieves ScoreCode data for each package in the project and - stores it in the corresponding package instances - - Attributes - ---------- - download_inputs (bool): Indicates whether inputs should be downloaded. - is_addon (bool): Indicates whether this pipeline is an add-on. - - Methods - ------- - steps(cls): - Defines the steps for the pipeline. - - check_scorecode_service_availability(self): - Checks if the ScoreCode service is configured and available. - - lookup_save_packages_scorecode_info(self): - Fetches ScoreCode information for each discovered package in the project - and saves the information to the respective package instances. + Fetch ScoreCode information for packages and dependencies. + This pipeline retrieves ScoreCode data for each package in the project + and stores it in the corresponding package instances. """ download_inputs = False @@ -70,7 +52,7 @@ def check_scorecode_service_availability(self): if not scorecard.is_available(): raise Exception("scorecode service is not available.") - def lookup_save_packages_scorecode_info(self): + def fetch_packages_scorecode_info(self): """Fetch scorecode information for each of the project's discovered packages.""" packages = self.project.discoveredpackages.all() scorecard_packages_data = scorecard.fetch_scorecard_info( @@ -86,4 +68,4 @@ def lookup_save_packages_scorecode_info(self): ) else: - raise Exception("No Data Found for the packages") + raise Exception("No data found for the packages") diff --git a/setup.cfg b/setup.cfg index 8feffd693..e569ad4e4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -139,7 +139,7 @@ scancodeio_pipelines = collect_symbols_tree_sitter = scanpipe.pipelines.collect_symbols_tree_sitter:CollectSymbolsTreeSitter enrich_with_purldb = scanpipe.pipelines.enrich_with_purldb:EnrichWithPurlDB find_vulnerabilities = scanpipe.pipelines.find_vulnerabilities:FindVulnerabilities - get_scorecard_info_packages = scanpipe.pipelines.get_scorecard_info_packages:FetchScoreCodeInfo + fetch_scorecode_info = scanpipe.pipelines.get_scorecard_info_packages:FetchScoreCodeInfo inspect_elf_binaries = scanpipe.pipelines.inspect_elf_binaries:InspectELFBinaries inspect_packages = scanpipe.pipelines.inspect_packages:InspectPackages load_inventory = scanpipe.pipelines.load_inventory:LoadInventory From f86d5bbbdefa6d38823c81e071e5ef84ce884135 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 23 Aug 2024 01:09:22 +0530 Subject: [PATCH 33/50] class name changes in steps of pipeline nexB#1283 Signed-off-by: 404-geek --- scanpipe/pipelines/get_scorecard_info_packages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index 3dcc2a0e6..de2f72df7 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -41,7 +41,7 @@ class FetchScoreCodeInfo(Pipeline): def steps(cls): return ( cls.check_scorecode_service_availability, - cls.lookup_save_packages_scorecode_info, + cls.fetch_packages_scorecode_info, ) def check_scorecode_service_availability(self): From 36e955ac2a893398bbca0f2d875f2b2dd82c743a Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 23 Aug 2024 01:25:41 +0530 Subject: [PATCH 34/50] pipeline name updated nexB#1283 Signed-off-by: 404-geek --- scanpipe/tests/test_pipelines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index ed8cd8414..b17b55d1c 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -1242,7 +1242,7 @@ def test_scanpipe_find_vulnerabilities_pipeline_integration( def test_scanpipe_get_scorecard_info_packages_integration( self, mock_is_configured, mock_is_available ): - pipeline_name = "get_scorecard_info_packages" + pipeline_name = "fetch_scorecode_info" project1 = Project.objects.create(name="Analysis") package1 = DiscoveredPackage.create_from_data(project1, package_data1) package1.vcs_url = "https://github.com/ossf/scorecard" From 43886a30334c5aff59600611e17323b2dd690453 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sat, 21 Sep 2024 22:28:25 -0400 Subject: [PATCH 35/50] update pipeline code and steps nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 37 +++++++++++-------- .../pipelines/get_scorecard_info_packages.py | 24 ++++++------ 2 files changed, 33 insertions(+), 28 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 91c5503ae..de19d5459 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3917,7 +3917,8 @@ def __str__(self): @classmethod @transaction.atomic() - def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): + def create_from_scorecard_data(cls, discovered_package, scorecard_data, + scoring_tool=None): """Create ScoreCard object from scorecard data and discovered package""" final_data = { "score": scorecard_data.score, @@ -3951,24 +3952,30 @@ def create_from_data(cls, DiscoveredPackage, scorecard_data, scoring_tool=None): scorecard_object = cls.objects.create( **final_data, - discovered_package=DiscoveredPackage, + discovered_package=discovered_package, scoring_tool=scoring_tool, ) - # Create associated scorecard_checks - checks_data = scorecard_data.checks - - for check_data in checks_data: + for check in scorecard_data.checks: ScorecardCheck.objects.create( - check_name=check_data.check_name, - check_score=check_data.check_score, - reason=check_data.reason or "", - details=check_data.details or [], + check_name=check.check_name, + check_score=check.check_score, + reason=check.reason or "", + details=check.details or [], for_package_score=scorecard_object, ) return scorecard_object + @classmethod + def create_from_package_and_scorecard(cls, scorecard_data, package): + score_object = cls.create_from_data( + discovered_package=package, + scorecard_data=scorecard_data, + scoring_tool="ossf_scorecard", + ) + score_object.save() + class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): def __str__(self): @@ -3985,13 +3992,13 @@ def __str__(self): ) @classmethod - def create_from_data(cls, package_score, check_data): + def create_from_data(cls, package_score, check): """Create a ScorecardCheck instance from provided data.""" final_data = { - "check_name": check_data.get("name"), - "check_score": check_data.get("score"), - "reason": check_data.get("reason"), - "details": check_data.get("details", []), + "check_name": check.get("name"), + "check_score": check.get("score"), + "reason": check.get("reason"), + "details": check.get("details", []), "for_package_score": package_score, } return cls.objects.create(**final_data) diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index de2f72df7..a4ec985f5 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -54,18 +54,16 @@ def check_scorecode_service_availability(self): def fetch_packages_scorecode_info(self): """Fetch scorecode information for each of the project's discovered packages.""" - packages = self.project.discoveredpackages.all() - scorecard_packages_data = scorecard.fetch_scorecard_info( - packages=packages, - logger=self.log, - ) + for package in self.project.discoveredpackages.all(): + + scorecard_data = scorecard.fetch_scorecard_info(package=package) - if scorecard_packages_data: - scorecard.save_scorecard_info( - package_scorecard_data=scorecard_packages_data, - cls=PackageScore, - logger=self.log, - ) + if scorecard_data: + PackageScore.create_from_package_and_scorecard( + scorecard_data=scorecard_data, + package=package, + ) - else: - raise Exception("No data found for the packages") + else: + #We Want to create error instead of exception + raise Exception("No data found for the package") From 3d4d6ea195f50995c87a58d8345027c92166bfad Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 1 Nov 2024 18:46:38 -0400 Subject: [PATCH 36/50] update pipeline steps to work with scorecode 0.0.2 release nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 36 +++++++++---------- .../pipelines/get_scorecard_info_packages.py | 19 +++++----- scanpipe/tests/test_models.py | 14 ++++---- scanpipe/tests/test_pipelines.py | 16 ++++----- setup.cfg | 2 +- 5 files changed, 41 insertions(+), 46 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index de19d5459..e56516886 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -75,8 +75,6 @@ from licensedcode.cache import build_spdx_license_expression from licensedcode.cache import get_licensing from matchcode_toolkit.fingerprinting import IGNORED_DIRECTORY_FINGERPRINTS -from ossf_scorecard.contrib.django.models import PackageScoreMixin -from ossf_scorecard.contrib.django.models import ScorecardChecksMixin from packagedcode.models import build_package_uid from packagedcode.utils import get_base_purl from packageurl import PackageURL @@ -89,6 +87,8 @@ from rq.exceptions import NoSuchJobError from rq.job import Job from rq.job import JobStatus +from scorecode.contrib.django.models import PackageScoreMixin +from scorecode.contrib.django.models import ScorecardChecksMixin from taggit.managers import TaggableManager from taggit.models import GenericUUIDTaggedItemBase from taggit.models import TaggedItemBase @@ -3901,7 +3901,7 @@ def as_spdx(self): ) -class PackageScore(UUIDPKModel, PackageScoreMixin): +class DiscoveredPackageScore(UUIDPKModel, PackageScoreMixin): def __str__(self): return self.score or str(self.uuid) @@ -3917,8 +3917,9 @@ def __str__(self): @classmethod @transaction.atomic() - def create_from_scorecard_data(cls, discovered_package, scorecard_data, - scoring_tool=None): + def create_from_scorecard_data( + cls, discovered_package, scorecard_data, scoring_tool=None + ): """Create ScoreCard object from scorecard data and discovered package""" final_data = { "score": scorecard_data.score, @@ -3957,24 +3958,18 @@ def create_from_scorecard_data(cls, discovered_package, scorecard_data, ) for check in scorecard_data.checks: - ScorecardCheck.objects.create( - check_name=check.check_name, - check_score=check.check_score, - reason=check.reason or "", - details=check.details or [], - for_package_score=scorecard_object, - ) + ScorecardCheck.create_from_data(package_score=scorecard_object, check=check) return scorecard_object @classmethod def create_from_package_and_scorecard(cls, scorecard_data, package): - score_object = cls.create_from_data( + score_object = cls.create_from_scorecard_data( discovered_package=package, scorecard_data=scorecard_data, - scoring_tool="ossf_scorecard", + scoring_tool="ossf-scorecard", ) - score_object.save() + return score_object class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): @@ -3982,7 +3977,7 @@ def __str__(self): return self.check_score or str(self.uuid) for_package_score = models.ForeignKey( - PackageScore, + DiscoveredPackageScore, related_name="discovered_packages_score_checks", help_text=_("The checks for which the score is given"), on_delete=models.CASCADE, @@ -3995,12 +3990,13 @@ def __str__(self): def create_from_data(cls, package_score, check): """Create a ScorecardCheck instance from provided data.""" final_data = { - "check_name": check.get("name"), - "check_score": check.get("score"), - "reason": check.get("reason"), - "details": check.get("details", []), + "check_name": check.check_name, + "check_score": check.check_score, + "reason": check.reason or "", + "details": check.details if check.details is not None else [], "for_package_score": package_score, } + return cls.objects.create(**final_data) diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/get_scorecard_info_packages.py index a4ec985f5..21049fc99 100644 --- a/scanpipe/pipelines/get_scorecard_info_packages.py +++ b/scanpipe/pipelines/get_scorecard_info_packages.py @@ -20,9 +20,10 @@ # ScanCode.io is a free software code scanning tool from nexB Inc. and others. # Visit https://github.com/nexB/scancode.io for support and download. -from ossf_scorecard import scorecard -from scanpipe.models import PackageScore +from scorecode import ossf_scorecard + +from scanpipe.models import DiscoveredPackageScore from scanpipe.pipelines import Pipeline @@ -46,24 +47,22 @@ def steps(cls): def check_scorecode_service_availability(self): """Check if the scorecode service is configured and available.""" - if not scorecard.is_configured(): - raise Exception("scorecode service is not configured.") - - if not scorecard.is_available(): + if not ossf_scorecard.is_available(): raise Exception("scorecode service is not available.") def fetch_packages_scorecode_info(self): """Fetch scorecode information for each of the project's discovered packages.""" for package in self.project.discoveredpackages.all(): - - scorecard_data = scorecard.fetch_scorecard_info(package=package) + scorecard_data = ossf_scorecard.fetch_scorecard_info( + package=package, logger=None + ) if scorecard_data: - PackageScore.create_from_package_and_scorecard( + DiscoveredPackageScore.create_from_package_and_scorecard( scorecard_data=scorecard_data, package=package, ) else: - #We Want to create error instead of exception + # We Want to create error instead of exception raise Exception("No data found for the package") diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 4f841c85b..148b84c35 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -49,18 +49,18 @@ from django.urls import reverse from django.utils import timezone -from ossf_scorecard.contrib.models import PackageScoreMixin from packagedcode.models import PackageData from packageurl import PackageURL from requests.exceptions import RequestException from rq.job import JobStatus +from scorecode.models import PackageScore from scancodeio import __version__ as scancodeio_version from scanpipe.models import CodebaseRelation from scanpipe.models import CodebaseResource from scanpipe.models import DiscoveredDependency from scanpipe.models import DiscoveredPackage -from scanpipe.models import PackageScore +from scanpipe.models import DiscoveredPackageScore from scanpipe.models import Project from scanpipe.models import ProjectMessage from scanpipe.models import Run @@ -2442,13 +2442,15 @@ def test_scanpipe_codebase_resource_queryset_elfs(self): def test_scorecard_models(self): package = DiscoveredPackage.create_from_data(self.project1, package_data1) - scorecard_obj = PackageScoreMixin.from_data(scorecard_data) - package_score = PackageScore.create_from_data( - package, scorecard_obj, PackageScore.ScoringTool.OSSF + scorecard_obj = PackageScore.from_data(scorecard_data) + package_score = DiscoveredPackageScore.create_from_package_and_scorecard( + package=package, scorecard_data=scorecard_obj ) self.assertIsNotNone(package_score) - self.assertEqual(package_score.scoring_tool, PackageScore.ScoringTool.OSSF) + self.assertEqual( + package_score.scoring_tool, DiscoveredPackageScore.ScoringTool.OSSF + ) self.assertEqual(package_score.score, "4.4") checks = package_score.discovered_packages_score_checks.all() diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index b17b55d1c..01e731923 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -1237,11 +1237,8 @@ def test_scanpipe_find_vulnerabilities_pipeline_integration( expected = vulnerability_data[0]["affected_by_vulnerabilities"] self.assertEqual(expected, package1.affected_by_vulnerabilities) - @mock.patch("ossf_scorecard.scorecard.is_available") - @mock.patch("ossf_scorecard.scorecard.is_configured") - def test_scanpipe_get_scorecard_info_packages_integration( - self, mock_is_configured, mock_is_available - ): + @mock.patch("scorecode.ossf_scorecard.is_available") + def test_scanpipe_get_scorecard_info_packages_integration(self, mock_is_available): pipeline_name = "fetch_scorecode_info" project1 = Project.objects.create(name="Analysis") package1 = DiscoveredPackage.create_from_data(project1, package_data1) @@ -1250,15 +1247,14 @@ def test_scanpipe_get_scorecard_info_packages_integration( run = project1.add_pipeline(pipeline_name) pipeline = run.make_pipeline_instance() - mock_is_configured.return_value = False mock_is_available.return_value = False exitcode, out = pipeline.execute() self.assertEqual(1, exitcode, msg=out) - self.assertIn("scorecode service is not configured.", out) + self.assertIn("scorecode service is not available.", out) run = project1.add_pipeline(pipeline_name) pipeline = run.make_pipeline_instance() - mock_is_configured.return_value = True + # mock_is_configured.return_value = True mock_is_available.return_value = True exitcode, out = pipeline.execute() @@ -1266,7 +1262,9 @@ def test_scanpipe_get_scorecard_info_packages_integration( package1.refresh_from_db() self.assertIsNotNone( - package1.discovered_packages_score.filter(scoring_tool="OSSF")[0].score, + package1.discovered_packages_score.filter(scoring_tool="ossf-scorecard")[ + 0 + ].score, msg=out, ) diff --git a/setup.cfg b/setup.cfg index 8d8246926..e3c43fec3 100644 --- a/setup.cfg +++ b/setup.cfg @@ -99,7 +99,7 @@ install_requires = # MatchCode-toolkit matchcode-toolkit==5.1.0 # ScoreCode - ScoreCode[full] @ git+https://github.com/nexB/ScoreCode.git@0ab078f18d83684c3a920095bcec8664d44cf028 + scorecode==0.0.2 # Univers univers==30.12.1 # Markdown From b9229a584c8c2eeb730f59296d11505e097ad396 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 1 Nov 2024 18:53:21 -0400 Subject: [PATCH 37/50] update migration nexB#1283 Signed-off-by: 404-geek --- ...eck.py => 0068_discoveredpackagescore_scorecardcheck.py} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename scanpipe/migrations/{0068_packagescore_scorecardcheck.py => 0068_discoveredpackagescore_scorecardcheck.py} (94%) diff --git a/scanpipe/migrations/0068_packagescore_scorecardcheck.py b/scanpipe/migrations/0068_discoveredpackagescore_scorecardcheck.py similarity index 94% rename from scanpipe/migrations/0068_packagescore_scorecardcheck.py rename to scanpipe/migrations/0068_discoveredpackagescore_scorecardcheck.py index c8fcfb185..25ebe5817 100644 --- a/scanpipe/migrations/0068_packagescore_scorecardcheck.py +++ b/scanpipe/migrations/0068_discoveredpackagescore_scorecardcheck.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.7 on 2024-08-21 06:45 +# Generated by Django 5.1.1 on 2024-11-01 22:51 import django.db.models.deletion import uuid @@ -13,7 +13,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( - name='PackageScore', + name='DiscoveredPackageScore', fields=[ ('scoring_tool', models.CharField(blank=True, choices=[('ossf-scorecard', 'Ossf'), ('others', 'Others')], help_text='Defines the source of a score or any other scoring metricsFor example: ossf-scorecard for scorecard data', max_length=100)), ('scoring_tool_version', models.CharField(blank=True, help_text='Defines the version of the scoring tool used for scanning thepackageFor Eg : 4.6 current version of OSSF - scorecard', max_length=50)), @@ -35,7 +35,7 @@ class Migration(migrations.Migration): ('reason', models.CharField(blank=True, help_text='Gives a reason why a score was given for a specific checkFor eg, : Found 9/10 approved changesets -- score normalized to 9', max_length=300)), ('details', models.JSONField(blank=True, default=list, help_text='A list of details/errors regarding the score')), ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), - ('for_package_score', models.ForeignKey(blank=True, editable=False, help_text='The checks for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score_checks', to='scanpipe.packagescore')), + ('for_package_score', models.ForeignKey(blank=True, editable=False, help_text='The checks for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score_checks', to='scanpipe.discoveredpackagescore')), ], options={ 'abstract': False, From ee2ea145384cde78cd18a138f3eaf8f807f0c3bf Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 1 Nov 2024 18:59:22 -0400 Subject: [PATCH 38/50] update migration nexB#1283 Signed-off-by: 404-geek --- ...check.py => 0069_discoveredpackagescore_scorecardcheck.py} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename scanpipe/migrations/{0068_discoveredpackagescore_scorecardcheck.py => 0069_discoveredpackagescore_scorecardcheck.py} (96%) diff --git a/scanpipe/migrations/0068_discoveredpackagescore_scorecardcheck.py b/scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py similarity index 96% rename from scanpipe/migrations/0068_discoveredpackagescore_scorecardcheck.py rename to scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py index 25ebe5817..34a41d14b 100644 --- a/scanpipe/migrations/0068_discoveredpackagescore_scorecardcheck.py +++ b/scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.1 on 2024-11-01 22:51 +# Generated by Django 5.1.1 on 2024-11-01 22:58 import django.db.models.deletion import uuid @@ -8,7 +8,7 @@ class Migration(migrations.Migration): dependencies = [ - ('scanpipe', '0067_discoveredpackage_notes'), + ('scanpipe', '0068_rename_discovered_dependencies_attribute'), ] operations = [ From bd5b9b3e8a13f9aa96791567dadae809fdf36cf7 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sat, 2 Nov 2024 23:59:07 -0400 Subject: [PATCH 39/50] rename pipeline name with data parsing function nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 41 +++++++++---------- ...fo_packages.py => fetch_scorecode_info.py} | 0 2 files changed, 19 insertions(+), 22 deletions(-) rename scanpipe/pipelines/{get_scorecard_info_packages.py => fetch_scorecode_info.py} (100%) diff --git a/scanpipe/models.py b/scanpipe/models.py index 0d0fb4d05..9ede1be78 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3920,6 +3920,24 @@ def __str__(self): null=True, ) + def parse_score_date(date_str, formats=None): + """Parse a date string into a timezone-aware datetime object, + or return None if parsing fails.""" + if not formats: + formats = ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%SZ"] + + if date_str: + for fmt in formats: + try: + naive_datetime = datetime.strptime(date_str, fmt) + return timezone.make_aware(naive_datetime, + timezone.get_current_timezone()) + except ValueError: + continue + + # Return None if date_str is None or parsing fails + return None + @classmethod @transaction.atomic() def create_from_scorecard_data( @@ -3932,30 +3950,9 @@ def create_from_scorecard_data( "scoring_tool_documentation_url": ( scorecard_data.scoring_tool_documentation_url ), + "score_date": cls.parse_score_date(scorecard_data.score_date), } - date_str = scorecard_data.score_date - - formats = ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%SZ"] - - if date_str: - naive_datetime = None - - for fmt in formats: - try: - naive_datetime = datetime.strptime(date_str, fmt) - except ValueError: - continue - - score_date = timezone.make_aware( - naive_datetime, timezone.get_current_timezone() - ) - - else: - score_date = timezone.now() - - final_data["score_date"] = score_date - scorecard_object = cls.objects.create( **final_data, discovered_package=discovered_package, diff --git a/scanpipe/pipelines/get_scorecard_info_packages.py b/scanpipe/pipelines/fetch_scorecode_info.py similarity index 100% rename from scanpipe/pipelines/get_scorecard_info_packages.py rename to scanpipe/pipelines/fetch_scorecode_info.py From 2b4629e8b2a5fefe693eecf9b711423937726fe6 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 3 Nov 2024 00:03:31 -0400 Subject: [PATCH 40/50] code valid nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 9ede1be78..b7c73d78a 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3921,8 +3921,10 @@ def __str__(self): ) def parse_score_date(date_str, formats=None): - """Parse a date string into a timezone-aware datetime object, - or return None if parsing fails.""" + """ + Parse a date string into a timezone-aware datetime object, + or return None if parsing fails. + """ if not formats: formats = ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%SZ"] @@ -3930,8 +3932,9 @@ def parse_score_date(date_str, formats=None): for fmt in formats: try: naive_datetime = datetime.strptime(date_str, fmt) - return timezone.make_aware(naive_datetime, - timezone.get_current_timezone()) + return timezone.make_aware( + naive_datetime, timezone.get_current_timezone() + ) except ValueError: continue From 99ee48d7227207e3b36907e611cf8e60eb993bec Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 3 Nov 2024 00:05:31 -0400 Subject: [PATCH 41/50] update setup.cfg nexB#1283 Signed-off-by: 404-geek --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index fc1d46869..3af6543ac 100644 --- a/setup.cfg +++ b/setup.cfg @@ -142,7 +142,7 @@ scancodeio_pipelines = collect_symbols_tree_sitter = scanpipe.pipelines.collect_symbols_tree_sitter:CollectSymbolsTreeSitter enrich_with_purldb = scanpipe.pipelines.enrich_with_purldb:EnrichWithPurlDB find_vulnerabilities = scanpipe.pipelines.find_vulnerabilities:FindVulnerabilities - fetch_scorecode_info = scanpipe.pipelines.get_scorecard_info_packages:FetchScoreCodeInfo + fetch_scorecode_info = scanpipe.pipelines.fetch_scorecode_info:FetchScoreCodeInfo inspect_elf_binaries = scanpipe.pipelines.inspect_elf_binaries:InspectELFBinaries inspect_packages = scanpipe.pipelines.inspect_packages:InspectPackages load_inventory = scanpipe.pipelines.load_inventory:LoadInventory From 80153f8858d48ea980e10a7c00d8f06f2c79e729 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 3 Nov 2024 21:30:48 -0500 Subject: [PATCH 42/50] optimize code while saving score checks nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index b7c73d78a..f0d9e19e7 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -3994,15 +3994,13 @@ def __str__(self): @classmethod def create_from_data(cls, package_score, check): """Create a ScorecardCheck instance from provided data.""" - final_data = { - "check_name": check.check_name, - "check_score": check.check_score, - "reason": check.reason or "", - "details": check.details if check.details is not None else [], - "for_package_score": package_score, - } - - return cls.objects.create(**final_data) + return cls.objects.create( + check_name=check.check_name, + check_score=check.check_score, + reason=check.reason or "", + details=check.details or [], + for_package_score=package_score, + ) def normalize_package_url_data(purl_mapping, ignore_nulls=False): From 113a557775c8954ceb1c79d7c1f316d3e94f12f3 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 2 Dec 2024 20:53:19 -0500 Subject: [PATCH 43/50] update test cases and regen scorecard data logic nexB#1283 Signed-off-by: 404-geek --- ...9_discoveredpackagescore_scorecardcheck.py | 44 -- .../data/scorecode/scorecard_response.json | 485 +++++++++--------- scanpipe/tests/regen_test_data.py | 31 ++ scanpipe/tests/test_models.py | 13 +- 4 files changed, 288 insertions(+), 285 deletions(-) delete mode 100644 scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py diff --git a/scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py b/scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py deleted file mode 100644 index 34a41d14b..000000000 --- a/scanpipe/migrations/0069_discoveredpackagescore_scorecardcheck.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.1.1 on 2024-11-01 22:58 - -import django.db.models.deletion -import uuid -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('scanpipe', '0068_rename_discovered_dependencies_attribute'), - ] - - operations = [ - migrations.CreateModel( - name='DiscoveredPackageScore', - fields=[ - ('scoring_tool', models.CharField(blank=True, choices=[('ossf-scorecard', 'Ossf'), ('others', 'Others')], help_text='Defines the source of a score or any other scoring metricsFor example: ossf-scorecard for scorecard data', max_length=100)), - ('scoring_tool_version', models.CharField(blank=True, help_text='Defines the version of the scoring tool used for scanning thepackageFor Eg : 4.6 current version of OSSF - scorecard', max_length=50)), - ('score', models.CharField(blank=True, help_text='Score of the package which is scanned', max_length=50)), - ('scoring_tool_documentation_url', models.CharField(blank=True, help_text='Documentation URL of the scoring tool used', max_length=100)), - ('score_date', models.DateTimeField(blank=True, editable=False, help_text='Date when the scoring was calculated on the package', null=True)), - ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), - ('discovered_package', models.ForeignKey(blank=True, editable=False, help_text='The package for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score', to='scanpipe.discoveredpackage')), - ], - options={ - 'abstract': False, - }, - ), - migrations.CreateModel( - name='ScorecardCheck', - fields=[ - ('check_name', models.CharField(blank=True, help_text='Defines the name of check corresponding to the OSSF scoreFor example: Code-Review or CII-Best-PracticesThese are the some of the checks which are performed on a scanned package', max_length=100)), - ('check_score', models.CharField(blank=True, help_text='Defines the score of the check for the package scannedFor Eg : 9 is a score given for Code-Review', max_length=50)), - ('reason', models.CharField(blank=True, help_text='Gives a reason why a score was given for a specific checkFor eg, : Found 9/10 approved changesets -- score normalized to 9', max_length=300)), - ('details', models.JSONField(blank=True, default=list, help_text='A list of details/errors regarding the score')), - ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), - ('for_package_score', models.ForeignKey(blank=True, editable=False, help_text='The checks for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score_checks', to='scanpipe.discoveredpackagescore')), - ], - options={ - 'abstract': False, - }, - ), - ] diff --git a/scanpipe/tests/data/scorecode/scorecard_response.json b/scanpipe/tests/data/scorecode/scorecard_response.json index d6f951c1d..d6d7f4461 100644 --- a/scanpipe/tests/data/scorecode/scorecard_response.json +++ b/scanpipe/tests/data/scorecode/scorecard_response.json @@ -1,33 +1,33 @@ { - "date": "2024-07-22", + "date": "2024-11-25", "repo": { "name": "github.com/nexB/scancode-toolkit", - "commit": "dd675aacae1b24a838f5520da77534326b17c5e9" + "commit": "65e1c2db473c0b0891dec0d0c369209cdd7cb0f5" }, "scorecard": { - "version": "v5.0.0-4-g093669b6", - "commit": "093669b630d2f32dc44f8b5a0c6778daba135c1b" + "version": "v5.0.0-94-g51f31c98", + "commit": "51f31c9882b6e5998e0df571096147a99842092b" }, - "score": 4.4, + "score": 4.2, "checks": [ { "name": "Code-Review", - "score": 7, - "reason": "Found 7/9 approved changesets -- score normalized to 7", + "score": 5, + "reason": "Found 8/14 approved changesets -- score normalized to 5", "details": null, "documentation": { "short": "Determines if the project requires human code review before pull requests (aka merge requests) are merged.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#code-review" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#code-review" } }, { "name": "Maintained", "score": 10, - "reason": "30 commit(s) and 22 issue activity found in the last 90 days -- score normalized to 10", + "reason": "30 commit(s) and 21 issue activity found in the last 90 days -- score normalized to 10", "details": null, "documentation": { "short": "Determines if the project is \"actively maintained\".", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#maintained" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#maintained" } }, { @@ -37,51 +37,7 @@ "details": null, "documentation": { "short": "Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#cii-best-practices" - } - }, - { - "name": "Branch-Protection", - "score": -1, - "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", - "details": null, - "documentation": { - "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#branch-protection" - } - }, - { - "name": "Signed-Releases", - "score": 0, - "reason": "Project has not signed or included provenance with any releases.", - "details": [ - "Warn: release artifact v32.2.1 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/163419040", - "Warn: release artifact v32.2.0 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/161475747", - "Warn: release artifact v32.1.0 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/147940455", - "Warn: release artifact v32.0.8 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/124587514", - "Warn: release artifact v32.0.7 not signed: https://api.github.com/repos/nexB/scancode-toolkit/releases/122941689", - "Warn: release artifact v32.2.1 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/163419040", - "Warn: release artifact v32.2.0 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/161475747", - "Warn: release artifact v32.1.0 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/147940455", - "Warn: release artifact v32.0.8 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/124587514", - "Warn: release artifact v32.0.7 does not have provenance: https://api.github.com/repos/nexB/scancode-toolkit/releases/122941689" - ], - "documentation": { - "short": "Determines if the project cryptographically signs release artifacts.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#signed-releases" - } - }, - { - "name": "License", - "score": 9, - "reason": "license file detected", - "details": [ - "Info: project has a license file: apache-2.0.LICENSE:0", - "Warn: project license file does not contain an FSF or OSI license." - ], - "documentation": { - "short": "Determines if the project has defined a license.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#license" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#cii-best-practices" } }, { @@ -96,17 +52,7 @@ ], "documentation": { "short": "Determines if the project has published a security policy.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#security-policy" - } - }, - { - "name": "Dangerous-Workflow", - "score": 10, - "reason": "no dangerous workflow patterns detected", - "details": null, - "documentation": { - "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#dangerous-workflow" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#security-policy" } }, { @@ -114,25 +60,48 @@ "score": 10, "reason": "GitHub workflow tokens follow principle of least privilege", "details": [ - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:356", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:319", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:360", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:401", "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:59", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:91", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:125", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:159", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:193", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:224", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:270", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:397", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:126", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:161", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:196", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:228", "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:25", - "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:315", - "Warn: jobLevel 'contents' permission set to 'write': .github/workflows/scancode-release.yml:434", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:91", + "Info: jobLevel 'contents' permission set to 'read': .github/workflows/scancode-release.yml:274", + "Warn: jobLevel 'contents' permission set to 'write': .github/workflows/scancode-release.yml:438", "Info: topLevel 'contents' permission set to 'read': .github/workflows/about-files-ci.yml:6", "Info: topLevel 'contents' permission set to 'read': .github/workflows/docs-ci.yml:6", "Info: found token with 'none' permissions: .github/workflows/scancode-release.yml:1" ], "documentation": { "short": "Determines if the project's workflows follow the principle of least privilege.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#token-permissions" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#token-permissions" + } + }, + { + "name": "Dangerous-Workflow", + "score": 10, + "reason": "no dangerous workflow patterns detected", + "details": null, + "documentation": { + "short": "Determines if the project's GitHub Action workflows avoid dangerous patterns.", + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#dangerous-workflow" + } + }, + { + "name": "License", + "score": 9, + "reason": "license file detected", + "details": [ + "Info: project has a license file: apache-2.0.LICENSE:0", + "Warn: project license file does not contain an FSF or OSI license." + ], + "documentation": { + "short": "Determines if the project has defined a license.", + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#license" } }, { @@ -140,11 +109,42 @@ "score": 10, "reason": "packaging workflow detected", "details": [ - "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/scancode-release.yml:561" + "Info: Project packages its releases by way of GitHub Actions.: .github/workflows/scancode-release.yml:547" ], "documentation": { "short": "Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#packaging" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#packaging" + } + }, + { + "name": "Branch-Protection", + "score": -1, + "reason": "internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration", + "details": null, + "documentation": { + "short": "Determines if the default and release branches are protected with GitHub's branch protection settings.", + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#branch-protection" + } + }, + { + "name": "Signed-Releases", + "score": 0, + "reason": "Project has not signed or included provenance with any releases.", + "details": [ + "Warn: release artifact v32.3.0 not signed: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/180932258", + "Warn: release artifact v32.2.1 not signed: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/163419040", + "Warn: release artifact v32.2.0 not signed: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/161475747", + "Warn: release artifact v32.1.0 not signed: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/147940455", + "Warn: release artifact v32.0.8 not signed: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/124587514", + "Warn: release artifact v32.3.0 does not have provenance: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/180932258", + "Warn: release artifact v32.2.1 does not have provenance: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/163419040", + "Warn: release artifact v32.2.0 does not have provenance: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/161475747", + "Warn: release artifact v32.1.0 does not have provenance: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/147940455", + "Warn: release artifact v32.0.8 does not have provenance: https://api.github.com/repos/aboutcode-org/scancode-toolkit/releases/124587514" + ], + "documentation": { + "short": "Determines if the project cryptographically signs release artifacts.", + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#signed-releases" } }, { @@ -156,7 +156,7 @@ ], "documentation": { "short": "Determines if the project uses fuzzing.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#fuzzing" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#fuzzing" } }, { @@ -164,11 +164,11 @@ "score": 0, "reason": "SAST tool is not run on all commits -- score normalized to 0", "details": [ - "Warn: 0 commits out of 30 are checked with a SAST tool" + "Warn: 0 commits out of 28 are checked with a SAST tool" ], "documentation": { "short": "Determines if the project uses static code analysis.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#sast" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#sast" } }, { @@ -331,7 +331,7 @@ ], "documentation": { "short": "Determines if the project has generated executable (binary) artifacts in the source repository.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#binary-artifacts" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#binary-artifacts" } }, { @@ -345,93 +345,94 @@ "Info: Possibly incomplete results: error parsing shell code: \"for\" must be followed by a literal: tests/licensedcode/data/datadriven/lic3/no_license_22.txt:0", "Info: Possibly incomplete results: error parsing shell code: if statement must end with \"fi\": tests/packagedcode/data/bashlex/ltmain.sh:0", "Info: Possibly incomplete results: error parsing shell code: unclosed here-document 'EOF': tests/packagedcode/data/bashlex/stripheredoc.sh:0", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/about-files-ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/about-files-ci.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/about-files-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/about-files-ci.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs-ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/docs-ci.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/docs-ci.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:106: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:109: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:117: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:174: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:177: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:185: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:288: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:291: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:296: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:333: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:336: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:341: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:374: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:377: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:382: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:455: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:461: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:467: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:473: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:479: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:485: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:491: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:497: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:503: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:509: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:515: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:521: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:527: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:533: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:539: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:545: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: third-party GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:555: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:51: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:140: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:143: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:151: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:205: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:208: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:216: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:242: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:245: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:250: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:415: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:418: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:423: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:580: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:585: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: third-party GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:595: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:83: update your workflow using https://app.stepsecurity.io/secureworkflow/nexB/scancode-toolkit/scancode-release.yml/develop?enable=pin", - "Warn: containerImage not pinned by hash: Dockerfile:10: pin your Docker image by updating python:3.8-slim-buster to python:3.8-slim-buster@sha256:8799b0564103a9f36cfb8a8e1c562e11a9a6f2e3bb214e2adc23982b36a04511", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/about-files-ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/about-files-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/about-files-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/about-files-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs-ci.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/docs-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/docs-ci.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:246: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:249: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:254: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:292: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:295: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:300: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:337: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:340: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:345: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:459: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:465: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:471: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:477: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:483: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:489: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:495: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:501: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:507: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:513: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:519: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:525: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:531: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: third-party GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:541: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:566: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:571: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: third-party GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:581: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:43: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:51: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:106: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:110: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:118: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:176: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:180: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:188: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:378: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:381: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:386: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:419: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:422: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:427: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:72: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:75: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:83: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:141: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:145: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:153: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:208: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:212: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/scancode-release.yml:220: update your workflow using https://app.stepsecurity.io/secureworkflow/aboutcode-org/scancode-toolkit/scancode-release.yml/develop?enable=pin", + "Warn: containerImage not pinned by hash: Dockerfile:10: pin your Docker image by updating python:3.12-slim-bookworm to python:3.12-slim-bookworm@sha256:2a6386ad2db20e7f55073f69a98d6da2cf9f168e05e7487d2670baeb9b7601c5", "Warn: pipCommand not pinned by hash: .github/workflows/docs-ci.yml:28", - "Warn: pipCommand not pinned by hash: .github/workflows/scancode-release.yml:260", - "Warn: pipCommand not pinned by hash: .github/workflows/scancode-release.yml:263", - "Info: 0 out of 55 GitHub-owned GitHubAction dependencies pinned", + "Warn: pipCommand not pinned by hash: .github/workflows/scancode-release.yml:264", + "Warn: pipCommand not pinned by hash: .github/workflows/scancode-release.yml:267", + "Info: 0 out of 52 GitHub-owned GitHubAction dependencies pinned", "Info: 0 out of 2 third-party GitHubAction dependencies pinned", "Info: 0 out of 1 containerImage dependencies pinned", "Info: 0 out of 3 pipCommand dependencies pinned" ], "documentation": { "short": "Determines if the project has declared and pinned the dependencies of its build process.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#pinned-dependencies" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#pinned-dependencies" } }, { "name": "Vulnerabilities", "score": 0, - "reason": "369 existing vulnerabilities detected", + "reason": "383 existing vulnerabilities detected", "details": [ + "Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6", + "Warn: Project is vulnerable to: PYSEC-2022-42969 / GHSA-w596-4wvx-j9j6", + "Warn: Project is vulnerable to: GHSA-g7vv-2v7x-gj9p", "Warn: Project is vulnerable to: GHSA-248v-346w-9cwc", - "Warn: Project is vulnerable to: GHSA-v3c5-jqr6-7qm8 / PYSEC-2022-42991", - "Warn: Project is vulnerable to: GHSA-jjg7-2v4v-x38h / PYSEC-2024-60", + "Warn: Project is vulnerable to: GHSA-h4gh-qq45-vh27", + "Warn: Project is vulnerable to: PYSEC-2022-42991 / GHSA-v3c5-jqr6-7qm8", + "Warn: Project is vulnerable to: PYSEC-2024-60 / GHSA-jjg7-2v4v-x38h", "Warn: Project is vulnerable to: GHSA-h75v-3vvj-5mfj", - "Warn: Project is vulnerable to: GHSA-mrwq-x4v8-fh7p / PYSEC-2023-117", + "Warn: Project is vulnerable to: PYSEC-2023-117 / GHSA-mrwq-x4v8-fh7p", "Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56", "Warn: Project is vulnerable to: GHSA-34jh-p97f-mpxf", "Warn: Project is vulnerable to: GHSA-jfmj-5v4g-7637", "Warn: Project is vulnerable to: RUSTSEC-2020-0159", - "Warn: Project is vulnerable to: GHSA-wcg3-cvx6-7396 / RUSTSEC-2020-0071", - "Warn: Project is vulnerable to: GHSA-rc23-xxgq-x27g / RUSTSEC-2022-0054", + "Warn: Project is vulnerable to: RUSTSEC-2020-0071 / GHSA-wcg3-cvx6-7396", + "Warn: Project is vulnerable to: RUSTSEC-2022-0054 / GHSA-rc23-xxgq-x27g", "Warn: Project is vulnerable to: GHSA-3hhc-qp5v-9p2j", "Warn: Project is vulnerable to: GHSA-579w-22j4-4749", "Warn: Project is vulnerable to: GHSA-9rf5-jm6f-2fmm", @@ -449,42 +450,24 @@ "Warn: Project is vulnerable to: GHSA-8mq4-9jjh-9xrc", "Warn: Project is vulnerable to: GHSA-gj4p-3wh3-2rmf", "Warn: Project is vulnerable to: GHSA-xfhh-rx56-rxcr", - "Warn: Project is vulnerable to: GHSA-wxc4-f4m6-wwqv / GO-2020-0036", - "Warn: Project is vulnerable to: GHSA-r88r-gmrh-7j83 / GO-2021-0061", - "Warn: Project is vulnerable to: GHSA-6q6q-88xp-6f2r / GO-2022-0956", + "Warn: Project is vulnerable to: GO-2020-0036 / GHSA-wxc4-f4m6-wwqv", + "Warn: Project is vulnerable to: GO-2021-0061 / GHSA-r88r-gmrh-7j83", + "Warn: Project is vulnerable to: GO-2022-0956 / GHSA-6q6q-88xp-6f2r", "Warn: Project is vulnerable to: GHSA-h5c8-rqwp-cp95", - "Warn: Project is vulnerable to: GHSA-275c-w5mq-v5m2", "Warn: Project is vulnerable to: GHSA-2hvc-hwg3-hpvw", "Warn: Project is vulnerable to: GHSA-2rp8-hff9-c5wr", - "Warn: Project is vulnerable to: GHSA-2wcj-qr76-9768", - "Warn: Project is vulnerable to: GHSA-3cr5-2446-8pg3", - "Warn: Project is vulnerable to: GHSA-4rrv-8gcp-24v8", - "Warn: Project is vulnerable to: GHSA-547m-23x7-cxg5", "Warn: Project is vulnerable to: GHSA-83g7-8fch-p37m", - "Warn: Project is vulnerable to: GHSA-8fp7-jwv2-49x9", - "Warn: Project is vulnerable to: GHSA-8wfh-qxxv-3q8c / PYSEC-2023-122", - "Warn: Project is vulnerable to: GHSA-9q9v-qgwx-84mr / PYSEC-2023-126", - "Warn: Project is vulnerable to: GHSA-c6ph-m8cw-rfqh", + "Warn: Project is vulnerable to: PYSEC-2023-122 / GHSA-8wfh-qxxv-3q8c", + "Warn: Project is vulnerable to: PYSEC-2023-126 / GHSA-9q9v-qgwx-84mr", "Warn: Project is vulnerable to: GHSA-chj7-w3f6-cvfj", - "Warn: Project is vulnerable to: GHSA-cv2j-922j-hr56 / PYSEC-2023-125", + "Warn: Project is vulnerable to: PYSEC-2023-125 / GHSA-cv2j-922j-hr56", "Warn: Project is vulnerable to: GHSA-fh54-3vhg-mpc2", - "Warn: Project is vulnerable to: GHSA-g57v-2687-jx33", - "Warn: Project is vulnerable to: GHSA-gcjf-29m9-888q / PYSEC-2022-43063", - "Warn: Project is vulnerable to: GHSA-hh7p-hvm3-rg88 / PYSEC-2023-124", - "Warn: Project is vulnerable to: GHSA-j5h9-9r39-43q5", - "Warn: Project is vulnerable to: GHSA-jm68-fpmr-8j2g", + "Warn: Project is vulnerable to: PYSEC-2023-124 / GHSA-hh7p-hvm3-rg88", "Warn: Project is vulnerable to: GHSA-jwrc-3v3f-5cq5", - "Warn: Project is vulnerable to: GHSA-mr78-v55p-7777", "Warn: Project is vulnerable to: GHSA-mrmm-qmrj-xgp6", - "Warn: Project is vulnerable to: GHSA-qppw-c37g-xwcc", "Warn: Project is vulnerable to: GHSA-qqv2-35q8-p2g2", - "Warn: Project is vulnerable to: GHSA-rf7p-79xq-8xwm", - "Warn: Project is vulnerable to: GHSA-rg9q-m8hv-xxr6", - "Warn: Project is vulnerable to: GHSA-rr46-m366-gm44 / PYSEC-2023-123", - "Warn: Project is vulnerable to: GHSA-rx2r-q96c-w5cc", - "Warn: Project is vulnerable to: GHSA-v9pg-qw6x-w5r2", - "Warn: Project is vulnerable to: GHSA-x3q9-c788-j7c8", - "Warn: Project is vulnerable to: GHSA-xjpw-hx47-rccv", + "Warn: Project is vulnerable to: PYSEC-2023-123 / GHSA-rr46-m366-gm44", + "Warn: Project is vulnerable to: PYSEC-2022-43063", "Warn: Project is vulnerable to: GHSA-xgfm-fjx6-62mj", "Warn: Project is vulnerable to: GHSA-crqg-jrpj-fc84", "Warn: Project is vulnerable to: GHSA-27xj-rqx5-2255", @@ -551,10 +534,12 @@ "Warn: Project is vulnerable to: GHSA-vfqx-33qm-g869", "Warn: Project is vulnerable to: GHSA-wh8g-3j2c-rqj5", "Warn: Project is vulnerable to: GHSA-x2w5-5m2g-7h5m", + "Warn: Project is vulnerable to: GHSA-78wr-2p64-hpwj", "Warn: Project is vulnerable to: GHSA-gwrp-pvrq-jmwv", "Warn: Project is vulnerable to: GHSA-fmj2-7wx8-qj4v", "Warn: Project is vulnerable to: GHSA-36p3-wjmg-h94x", "Warn: Project is vulnerable to: GHSA-hh26-6xwr-ggv7", + "Warn: Project is vulnerable to: GHSA-4gc7-5j7h-4qph", "Warn: Project is vulnerable to: GHSA-g5mm-vmx4-3rg7", "Warn: Project is vulnerable to: GHSA-3rmv-2pg5-xvqj", "Warn: Project is vulnerable to: GHSA-4487-x383-qpph", @@ -565,76 +550,93 @@ "Warn: Project is vulnerable to: GHSA-rcpf-vj53-7h2m", "Warn: Project is vulnerable to: GHSA-558x-2xjg-6232", "Warn: Project is vulnerable to: GHSA-564r-hj7v-mcr5", + "Warn: Project is vulnerable to: GHSA-9cmq-m9j5-mvww", "Warn: Project is vulnerable to: GHSA-wxqc-pxw9-g2p8", "Warn: Project is vulnerable to: GHSA-9339-86wc-4qgf", + "Warn: Project is vulnerable to: GHSA-h592-38cm-4ggp", + "Warn: Project is vulnerable to: GHSA-qxxx-2pp7-5hmx", + "Warn: Project is vulnerable to: GHSA-rfx6-vp9g-rh7v", + "Warn: Project is vulnerable to: GHSA-w3f4-3q6j-rh82", "Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw", "Warn: Project is vulnerable to: GHSA-7r3h-m5j6-3q42", + "Warn: Project is vulnerable to: GHSA-8g4q-xg66-9fp4", "Warn: Project is vulnerable to: GHSA-25mq-v84q-4j7r", "Warn: Project is vulnerable to: GHSA-cwmx-hcrq-mhc3", "Warn: Project is vulnerable to: GHSA-f2wf-25xc-69c9", "Warn: Project is vulnerable to: GHSA-q559-8m2m-g699", "Warn: Project is vulnerable to: GHSA-w248-ffj2-4v5q", - "Warn: Project is vulnerable to: GHSA-337x-4q8g-prc5", - "Warn: Project is vulnerable to: GHSA-6565-fg86-6jcx / PYSEC-2015-8", - "Warn: Project is vulnerable to: GHSA-68w8-qjq3-2gfm / PYSEC-2021-98", - "Warn: Project is vulnerable to: GHSA-6g95-x6cj-mg4v / PYSEC-2015-7", - "Warn: Project is vulnerable to: GHSA-6wcr-wcqm-3mfh / PYSEC-2015-11", - "Warn: Project is vulnerable to: GHSA-7fq8-4pv5-5w5c / PYSEC-2015-9", - "Warn: Project is vulnerable to: GHSA-7qfw-j7hp-v45g / PYSEC-2015-4", - "Warn: Project is vulnerable to: GHSA-c8c8-9472-w52h / PYSEC-2016-2", - "Warn: Project is vulnerable to: GHSA-crhm-qpjc-cm64 / PYSEC-2016-3", - "Warn: Project is vulnerable to: GHSA-fp6p-5xvw-m74f / PYSEC-2016-16", - "Warn: Project is vulnerable to: GHSA-gv98-g628-m9x5 / PYSEC-2015-5", - "Warn: Project is vulnerable to: GHSA-h582-2pch-3xv3 / PYSEC-2015-20", + "Warn: Project is vulnerable to: GHSA-qq5c-677p-737q", + "Warn: Project is vulnerable to: PYSEC-2015-8 / GHSA-6565-fg86-6jcx", + "Warn: Project is vulnerable to: PYSEC-2021-98 / GHSA-68w8-qjq3-2gfm", + "Warn: Project is vulnerable to: PYSEC-2015-7 / GHSA-6g95-x6cj-mg4v", + "Warn: Project is vulnerable to: PYSEC-2015-11 / GHSA-6wcr-wcqm-3mfh", + "Warn: Project is vulnerable to: PYSEC-2015-9 / GHSA-7fq8-4pv5-5w5c", + "Warn: Project is vulnerable to: PYSEC-2015-4 / GHSA-7qfw-j7hp-v45g", + "Warn: Project is vulnerable to: GHSA-2x8x-jmrp-phxw / GHSA-8x94-hmjh-97hq", + "Warn: Project is vulnerable to: PYSEC-2016-2 / GHSA-c8c8-9472-w52h", + "Warn: Project is vulnerable to: PYSEC-2016-3 / GHSA-crhm-qpjc-cm64", + "Warn: Project is vulnerable to: PYSEC-2016-16 / GHSA-fp6p-5xvw-m74f", + "Warn: Project is vulnerable to: PYSEC-2015-5 / GHSA-gv98-g628-m9x5", + "Warn: Project is vulnerable to: PYSEC-2015-20 / GHSA-h582-2pch-3xv3", "Warn: Project is vulnerable to: GHSA-hmr4-m2h5-33qx", - "Warn: Project is vulnerable to: GHSA-j3j3-jrfh-cm2w / PYSEC-2015-18", - "Warn: Project is vulnerable to: GHSA-jhjg-w2cp-5j44 / PYSEC-2015-6", - "Warn: Project is vulnerable to: GHSA-pgxh-wfw4-jx2v / PYSEC-2015-22", - "Warn: Project is vulnerable to: GHSA-pw27-w7w4-9qc7 / PYSEC-2016-15", - "Warn: Project is vulnerable to: GHSA-q5qw-4364-5hhm / PYSEC-2015-10", - "Warn: Project is vulnerable to: GHSA-v6rh-hp5x-86rv", - "Warn: Project is vulnerable to: GHSA-vfq6-hq5r-27r6 / PYSEC-2019-16", - "Warn: Project is vulnerable to: GHSA-wh4h-v3f2-r2pp", - "Warn: Project is vulnerable to: GHSA-x38m-486c-2wr9 / PYSEC-2015-23", - "Warn: Project is vulnerable to: GHSA-xxj9-f6rv-m3x4", + "Warn: Project is vulnerable to: PYSEC-2015-18 / GHSA-j3j3-jrfh-cm2w", + "Warn: Project is vulnerable to: PYSEC-2015-6 / GHSA-jhjg-w2cp-5j44", + "Warn: Project is vulnerable to: PYSEC-2015-22 / GHSA-pgxh-wfw4-jx2v", + "Warn: Project is vulnerable to: PYSEC-2016-15 / GHSA-pw27-w7w4-9qc7", + "Warn: Project is vulnerable to: PYSEC-2015-10 / GHSA-q5qw-4364-5hhm", + "Warn: Project is vulnerable to: GHSA-rrqc-c2jx-6jgv", + "Warn: Project is vulnerable to: PYSEC-2019-16 / GHSA-vfq6-hq5r-27r6", + "Warn: Project is vulnerable to: PYSEC-2015-23 / GHSA-x38m-486c-2wr9", "Warn: Project is vulnerable to: PYSEC-2016-18", - "Warn: Project is vulnerable to: GHSA-hjf3-r7gw-9rwg / PYSEC-2012-14", - "Warn: Project is vulnerable to: GHSA-6528-wvf6-f6qg / PYSEC-2018-97", - "Warn: Project is vulnerable to: GHSA-cq27-v7xp-c356 / PYSEC-2017-94", - "Warn: Project is vulnerable to: GHSA-v367-p58w-98h5 / PYSEC-2012-16", - "Warn: Project is vulnerable to: GHSA-x377-f64p-hf5j / PYSEC-2013-29", - "Warn: Project is vulnerable to: GHSA-r9jw-mwhq-wp62 / PYSEC-2017-24", - "Warn: Project is vulnerable to: GHSA-652x-xj99-gmcc / PYSEC-2014-14", - "Warn: Project is vulnerable to: GHSA-cfj3-7x9c-4p3h / PYSEC-2014-13", - "Warn: Project is vulnerable to: GHSA-pg2w-x9wp-vw92 / PYSEC-2015-17", - "Warn: Project is vulnerable to: GHSA-x84v-xcm2-53pg / PYSEC-2018-28", - "Warn: Project is vulnerable to: GHSA-537h-rv9q-vvph / PYSEC-2020-99", - "Warn: Project is vulnerable to: GHSA-xrx6-fmxq-rjj2 / PYSEC-2020-100", + "Warn: Project is vulnerable to: PYSEC-2012-14 / GHSA-hjf3-r7gw-9rwg", + "Warn: Project is vulnerable to: PYSEC-2018-97 / GHSA-6528-wvf6-f6qg", + "Warn: Project is vulnerable to: PYSEC-2017-94 / GHSA-cq27-v7xp-c356", + "Warn: Project is vulnerable to: PYSEC-2012-16 / GHSA-v367-p58w-98h5", + "Warn: Project is vulnerable to: PYSEC-2013-29 / GHSA-x377-f64p-hf5j", + "Warn: Project is vulnerable to: PYSEC-2017-24 / GHSA-r9jw-mwhq-wp62", + "Warn: Project is vulnerable to: PYSEC-2014-14 / GHSA-652x-xj99-gmcc", + "Warn: Project is vulnerable to: PYSEC-2014-13 / GHSA-cfj3-7x9c-4p3h", + "Warn: Project is vulnerable to: PYSEC-2015-17 / GHSA-pg2w-x9wp-vw92", + "Warn: Project is vulnerable to: PYSEC-2018-28 / GHSA-x84v-xcm2-53pg", + "Warn: Project is vulnerable to: PYSEC-2020-99 / GHSA-537h-rv9q-vvph", + "Warn: Project is vulnerable to: PYSEC-2020-100 / GHSA-xrx6-fmxq-rjj2", "Warn: Project is vulnerable to: GHSA-9772-cwx9-r4cj", - "Warn: Project is vulnerable to: GHSA-hj5v-574p-mj7c / PYSEC-2020-92", - "Warn: Project is vulnerable to: GHSA-w596-4wvx-j9j6 / PYSEC-2022-42969", - "Warn: Project is vulnerable to: GHSA-6757-jp84-gxfx", - "Warn: Project is vulnerable to: GHSA-8q59-q68h-6hv4 / PYSEC-2021-142", - "Warn: Project is vulnerable to: GHSA-rprw-h62v-c2w7 / PYSEC-2018-49", - "Warn: Project is vulnerable to: GHSA-43fp-rhv2-5gv8 / PYSEC-2022-42986", - "Warn: Project is vulnerable to: GHSA-xqr8-7jwr-rhp7 / PYSEC-2023-135", - "Warn: Project is vulnerable to: GHSA-9w8r-397f-prfh / PYSEC-2021-140", - "Warn: Project is vulnerable to: GHSA-pq64-v7f5-gqh8 / PYSEC-2021-141", - "Warn: Project is vulnerable to: GHSA-g4mx-q9vg-27p4 / PYSEC-2023-212", - "Warn: Project is vulnerable to: GHSA-r64q-w8jr-g9qp / PYSEC-2019-132", - "Warn: Project is vulnerable to: GHSA-v845-jxx5-vc9f / PYSEC-2023-192", - "Warn: Project is vulnerable to: GHSA-wqvq-5m8c-6g24 / PYSEC-2020-148", - "Warn: Project is vulnerable to: GHSA-q2q7-5pp4-w6pg / PYSEC-2021-108", - "Warn: Project is vulnerable to: GHSA-qwmp-2cf2-g9g6 / PYSEC-2022-43017", + "Warn: Project is vulnerable to: PYSEC-2020-92 / GHSA-hj5v-574p-mj7c", + "Warn: Project is vulnerable to: PYSEC-2021-142 / GHSA-8q59-q68h-6hv4", + "Warn: Project is vulnerable to: PYSEC-2018-49 / GHSA-rprw-h62v-c2w7", + "Warn: Project is vulnerable to: PYSEC-2022-42986 / GHSA-43fp-rhv2-5gv8", + "Warn: Project is vulnerable to: PYSEC-2023-135 / GHSA-xqr8-7jwr-rhp7", + "Warn: Project is vulnerable to: PYSEC-2021-140 / GHSA-9w8r-397f-prfh", + "Warn: Project is vulnerable to: PYSEC-2021-141 / GHSA-pq64-v7f5-gqh8", + "Warn: Project is vulnerable to: PYSEC-2023-212 / GHSA-g4mx-q9vg-27p4", + "Warn: Project is vulnerable to: PYSEC-2019-132 / GHSA-r64q-w8jr-g9qp", + "Warn: Project is vulnerable to: PYSEC-2023-192 / GHSA-v845-jxx5-vc9f", + "Warn: Project is vulnerable to: PYSEC-2020-148 / GHSA-wqvq-5m8c-6g24", + "Warn: Project is vulnerable to: PYSEC-2021-108 / GHSA-q2q7-5pp4-w6pg", + "Warn: Project is vulnerable to: PYSEC-2022-43017 / GHSA-qwmp-2cf2-g9g6", "Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5", - "Warn: Project is vulnerable to: GHSA-r9hx-vwmv-q579 / PYSEC-2022-43012", - "Warn: Project is vulnerable to: GHSA-h4m5-qpfp-3mpv / PYSEC-2021-421", + "Warn: Project is vulnerable to: PYSEC-2022-43012 / GHSA-r9hx-vwmv-q579", + "Warn: Project is vulnerable to: PYSEC-2021-421 / GHSA-h4m5-qpfp-3mpv", + "Warn: Project is vulnerable to: PYSEC-2023-120 / GHSA-45c4-8wx5-qw6w", + "Warn: Project is vulnerable to: PYSEC-2024-24 / GHSA-5h86-8mv2-jq9f", + "Warn: Project is vulnerable to: GHSA-5m98-qgg9-wh84", + "Warn: Project is vulnerable to: GHSA-7gpw-8wmc-pm8g", + "Warn: Project is vulnerable to: GHSA-8495-4g3g-x7pr", + "Warn: Project is vulnerable to: PYSEC-2024-26 / GHSA-8qpw-xqxj-h4r2", + "Warn: Project is vulnerable to: PYSEC-2023-246 / GHSA-gfw2-4jvh-wgfg", + "Warn: Project is vulnerable to: GHSA-jwhx-xcg6-8xhj", + "Warn: Project is vulnerable to: GHSA-pjjw-qhg8-p2p9", + "Warn: Project is vulnerable to: PYSEC-2023-250 / GHSA-q3qx-c6g2-7pw2", + "Warn: Project is vulnerable to: PYSEC-2023-251 / GHSA-qvrw-v9rv-5rjx", + "Warn: Project is vulnerable to: PYSEC-2021-76 / GHSA-v6wp-4m6f-gcjg", + "Warn: Project is vulnerable to: PYSEC-2023-247 / GHSA-xx9p-xxvh-7g8j", "Warn: Project is vulnerable to: GHSA-55x5-fj6c-h6m8", - "Warn: Project is vulnerable to: GHSA-jq4v-f5q6-mjqq / PYSEC-2021-19", - "Warn: Project is vulnerable to: GHSA-pgww-xf46-h92r / PYSEC-2020-62", - "Warn: Project is vulnerable to: GHSA-wrxv-2j5q-m38w / PYSEC-2022-230", - "Warn: Project is vulnerable to: GHSA-xp26-p53h-6h2p / PYSEC-2018-12", - "Warn: Project is vulnerable to: GHSA-j8r2-6x86-q33q / PYSEC-2023-74", + "Warn: Project is vulnerable to: PYSEC-2021-19 / GHSA-jq4v-f5q6-mjqq", + "Warn: Project is vulnerable to: PYSEC-2020-62 / GHSA-pgww-xf46-h92r", + "Warn: Project is vulnerable to: PYSEC-2022-230 / GHSA-wrxv-2j5q-m38w", + "Warn: Project is vulnerable to: PYSEC-2018-12 / GHSA-xp26-p53h-6h2p", + "Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q", + "Warn: Project is vulnerable to: GHSA-h47h-mwp9-c6q6", "Warn: Project is vulnerable to: GHSA-4g8v-vg43-wpgf", "Warn: Project is vulnerable to: GHSA-7wjx-3g7j-8584", "Warn: Project is vulnerable to: GHSA-8727-m6gj-mc37", @@ -642,7 +644,9 @@ "Warn: Project is vulnerable to: GHSA-hjg4-8q5f-x6fm", "Warn: Project is vulnerable to: GHSA-jp5v-5gx4-jmj9", "Warn: Project is vulnerable to: GHSA-p84v-45xj-wwqj", + "Warn: Project is vulnerable to: GHSA-vfg9-r3fq-jvx4", "Warn: Project is vulnerable to: GHSA-rmj8-8hhh-gv5h / GHSA-wh98-p28r-vrc9", + "Warn: Project is vulnerable to: GHSA-x76w-6vjr-8xgj", "Warn: Project is vulnerable to: GHSA-65cv-r6x7-79hv", "Warn: Project is vulnerable to: GHSA-86g5-2wh3-gc9j", "Warn: Project is vulnerable to: GHSA-cfjv-5498-mph5", @@ -695,6 +699,7 @@ "Warn: Project is vulnerable to: GHSA-48w2-rm65-62xx", "Warn: Project is vulnerable to: GHSA-68xg-gqqm-vgj8", "Warn: Project is vulnerable to: GHSA-7xx3-m584-x994", + "Warn: Project is vulnerable to: GHSA-9hf4-67fc-4vf4", "Warn: Project is vulnerable to: GHSA-c2f4-cvqm-65w2", "Warn: Project is vulnerable to: GHSA-h99w-9q5r-gjq9", "Warn: Project is vulnerable to: GHSA-q28m-8xjw-8vr5", @@ -724,28 +729,34 @@ "Warn: Project is vulnerable to: GHSA-g6wq-qcwm-j5g2", "Warn: Project is vulnerable to: GHSA-jxhc-q857-3j6g", "Warn: Project is vulnerable to: GHSA-3xg8-cc8f-9wv2", + "Warn: Project is vulnerable to: GHSA-2m96-52r3-2f3g", "Warn: Project is vulnerable to: GHSA-cxf7-qrc5-9446", "Warn: Project is vulnerable to: GHSA-5c5f-7vfq-3732", "Warn: Project is vulnerable to: GHSA-3x8r-x6xp-q4vm", - "Warn: Project is vulnerable to: GHSA-592j-995h-p23j", "Warn: Project is vulnerable to: GHSA-ggxm-pgc9-g7fp", "Warn: Project is vulnerable to: GHSA-q3wr-qw3g-3p4h", "Warn: Project is vulnerable to: GHSA-gc3j-vvwf-4rp8", "Warn: Project is vulnerable to: GHSA-r8xx-8vm8-x6wj", "Warn: Project is vulnerable to: GHSA-r9mq-m72x-257g", "Warn: Project is vulnerable to: GHSA-9hmq-fm33-x4xx", + "Warn: Project is vulnerable to: GHSA-2rxp-v6pw-ch6m", "Warn: Project is vulnerable to: GHSA-4xqq-m2hx-25v8", + "Warn: Project is vulnerable to: GHSA-5866-49gr-22v4", "Warn: Project is vulnerable to: GHSA-8cr8-4vfw-mr7h", + "Warn: Project is vulnerable to: GHSA-r55c-59qm-vjw6", "Warn: Project is vulnerable to: GHSA-vg3r-rm7w-2xgh", + "Warn: Project is vulnerable to: GHSA-vmwr-mc7x-5vc3", "Warn: Project is vulnerable to: GHSA-3qc2-v3hp-6cv8", "Warn: Project is vulnerable to: GHSA-grh7-935j-hg6w", "Warn: Project is vulnerable to: GHSA-jrfj-98qg-qjgv", - "Warn: Project is vulnerable to: GHSA-2x8x-jmrp-phxw", + "Warn: Project is vulnerable to: GHSA-hxx2-7vcw-mqr3", "Warn: Project is vulnerable to: GHSA-qp49-3pvw-x4m5", + "Warn: Project is vulnerable to: GHSA-6f62-3596-g6w7", "Warn: Project is vulnerable to: GHSA-jphg-qwrw-7w9g", "Warn: Project is vulnerable to: GHSA-8c56-cpmw-89x7", "Warn: Project is vulnerable to: GHSA-x2fm-93ww-ggvx", "Warn: Project is vulnerable to: GHSA-mm33-5vfq-3mm3", + "Warn: Project is vulnerable to: GHSA-wwhv-wxv9-rpgw", "Warn: Project is vulnerable to: GHSA-xp5h-f8jf-rc8q", "Warn: Project is vulnerable to: GHSA-hq7p-j377-6v63", "Warn: Project is vulnerable to: GHSA-8h22-8cf7-hq6g", @@ -793,7 +804,7 @@ ], "documentation": { "short": "Determines if the project has open, known unfixed vulnerabilities.", - "url": "https://github.com/ossf/scorecard/blob/093669b630d2f32dc44f8b5a0c6778daba135c1b/docs/checks.md#vulnerabilities" + "url": "https://github.com/ossf/scorecard/blob/51f31c9882b6e5998e0df571096147a99842092b/docs/checks.md#vulnerabilities" } } ] diff --git a/scanpipe/tests/regen_test_data.py b/scanpipe/tests/regen_test_data.py index 0b8bddd1b..acd856bc7 100644 --- a/scanpipe/tests/regen_test_data.py +++ b/scanpipe/tests/regen_test_data.py @@ -26,6 +26,8 @@ from django.core.management import call_command from django.test import TestCase +import requests + from scanpipe.models import Project from scanpipe.pipes import codebase from scanpipe.pipes import input @@ -149,3 +151,32 @@ def test_regen_asgiref_test_files(self): "package": True, }, ) + + def test_regenerate_scorecard_data(self): + """ + Regenerate and save scorecard data by directly calling the OSSF Scorecard + API + """ + scorecard_data_file = self.data / "scorecode" / "scorecard_response.json" + platform, org, repo = "github.com", "nexB", "scancode-toolkit" + + OSSF_SCORECARD_API_URL = "https://api.securityscorecards.dev" + + url = f"{OSSF_SCORECARD_API_URL}/projects/{platform}/{org}/{repo}" + + try: + # Fetch the scorecard data from the API + response = requests.get(url, timeout=10) + response.raise_for_status() + scorecard_data = response.json() + + scorecard_data_file.parent.mkdir(parents=True, exist_ok=True) + + scorecard_data_file.write_text(json.dumps(scorecard_data, indent=2)) + + print(f"Scorecard data successfully saved to {scorecard_data_file}") + + except requests.exceptions.Timeout: + print("The request timed out.") + except requests.exceptions.RequestException as e: + print(f"Error fetching scorecard data: {e}") diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 2b1d6bbd3..be14aa377 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2492,12 +2492,17 @@ def test_scorecard_models(self): self.assertEqual( package_score.scoring_tool, DiscoveredPackageScore.ScoringTool.OSSF ) - self.assertEqual(package_score.score, "4.4") + self.assertGreaterEqual(float(package_score.score), -1) checks = package_score.discovered_packages_score_checks.all() - self.assertEqual(checks.count(), 15) - self.assertEqual(checks[0].check_name, "Code-Review") - self.assertEqual(checks[0].check_score, "7") + self.assertGreaterEqual(checks.count(), 1) + + for check in checks: + self.assertIsInstance(check.check_name, str) + if check.check_score == "-1": + self.assertEqual(check.check_score, "-1") + else: + self.assertRegex(check.check_score, r"^\d+(\.\d+)?$") def test_scanpipe_model_codebase_resource_compliance_alert_queryset_mixin(self): severities = CodebaseResource.Compliance From 64e17fe17b02b34a95bd5ff23150dc2b06b0687b Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 2 Dec 2024 21:01:50 -0500 Subject: [PATCH 44/50] update migration file nexB#1283 Signed-off-by: 404-geek --- ...ct_purl_discoveredpackagescore_and_more.py | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py diff --git a/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py b/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py new file mode 100644 index 000000000..203dec295 --- /dev/null +++ b/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py @@ -0,0 +1,49 @@ +# Generated by Django 5.1.3 on 2024-12-02 22:53 + +import django.db.models.deletion +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('scanpipe', '0069_project_purl'), + ] + + operations = [ + migrations.AlterField( + model_name='project', + name='purl', + field=models.CharField(blank=True, help_text="Package URL (PURL) for the project, required for pushing the project's scan result to FederatedCode. For example, if the input is an input URL like https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz, the corresponding PURL would be pkg:npm/lodash@4.17.21.", max_length=2048), + ), + migrations.CreateModel( + name='DiscoveredPackageScore', + fields=[ + ('scoring_tool', models.CharField(blank=True, choices=[('ossf-scorecard', 'Ossf'), ('others', 'Others')], help_text='Defines the source of a score or any other scoring metricsFor example: ossf-scorecard for scorecard data', max_length=100)), + ('scoring_tool_version', models.CharField(blank=True, help_text='Defines the version of the scoring tool used for scanning thepackageFor Eg : 4.6 current version of OSSF - scorecard', max_length=50)), + ('score', models.CharField(blank=True, help_text='Score of the package which is scanned', max_length=50)), + ('scoring_tool_documentation_url', models.CharField(blank=True, help_text='Documentation URL of the scoring tool used', max_length=100)), + ('score_date', models.DateTimeField(blank=True, editable=False, help_text='Date when the scoring was calculated on the package', null=True)), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), + ('discovered_package', models.ForeignKey(blank=True, editable=False, help_text='The package for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score', to='scanpipe.discoveredpackage')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='ScorecardCheck', + fields=[ + ('check_name', models.CharField(blank=True, help_text='Defines the name of check corresponding to the OSSF scoreFor example: Code-Review or CII-Best-PracticesThese are the some of the checks which are performed on a scanned package', max_length=100)), + ('check_score', models.CharField(blank=True, help_text='Defines the score of the check for the package scannedFor Eg : 9 is a score given for Code-Review', max_length=50)), + ('reason', models.CharField(blank=True, help_text='Gives a reason why a score was given for a specific checkFor eg, : Found 9/10 approved changesets -- score normalized to 9', max_length=300)), + ('details', models.JSONField(blank=True, default=list, help_text='A list of details/errors regarding the score')), + ('uuid', models.UUIDField(db_index=True, default=uuid.uuid4, editable=False, primary_key=True, serialize=False, verbose_name='UUID')), + ('for_package_score', models.ForeignKey(blank=True, editable=False, help_text='The checks for which the score is given', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='discovered_packages_score_checks', to='scanpipe.discoveredpackagescore')), + ], + options={ + 'abstract': False, + }, + ), + ] From 027fe2def7ff966ce72d9f696ed4e0c7f55461d5 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Mon, 2 Dec 2024 21:22:46 -0500 Subject: [PATCH 45/50] remove unwanted change nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 018cea655..9ef08e11c 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -1892,10 +1892,10 @@ class Run(UUIDPKModel, ProjectRelatedModel, AbstractTaskFieldsModel): scancodeio_version = models.CharField(max_length=100, blank=True) description = models.TextField(blank=True) current_step = models.CharField(max_length=256, blank=True) - selected_steps = models.JSONField( + selected_groups = models.JSONField( null=True, blank=True, validators=[validate_none_or_list] ) - selected_groups = models.JSONField( + selected_steps = models.JSONField( null=True, blank=True, validators=[validate_none_or_list] ) From f6f19a7acc8e90d18c4ad174c7c85eb11b680861 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 23 Feb 2025 22:21:31 -0500 Subject: [PATCH 46/50] unit tests for scorecard model functions and minor fixes nexB#1283 Signed-off-by: 404-geek --- scanpipe/models.py | 216 ++++++++++++--------- scanpipe/pipelines/fetch_scorecode_info.py | 14 +- scanpipe/tests/__init__.py | 9 - scanpipe/tests/test_models.py | 114 ++++++++++- scanpipe/tests/test_pipelines.py | 1 - 5 files changed, 238 insertions(+), 116 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index 3f5c5852e..4af2a1b8d 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -4038,103 +4038,6 @@ def as_spdx(self): ) -class DiscoveredPackageScore(UUIDPKModel, PackageScoreMixin): - def __str__(self): - return self.score or str(self.uuid) - - discovered_package = models.ForeignKey( - DiscoveredPackage, - related_name="discovered_packages_score", - help_text=_("The package for which the score is given"), - on_delete=models.CASCADE, - editable=False, - blank=True, - null=True, - ) - - def parse_score_date(date_str, formats=None): - """ - Parse a date string into a timezone-aware datetime object, - or return None if parsing fails. - """ - if not formats: - formats = ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%SZ"] - - if date_str: - for fmt in formats: - try: - naive_datetime = datetime.strptime(date_str, fmt) - return timezone.make_aware( - naive_datetime, timezone.get_current_timezone() - ) - except ValueError: - continue - - # Return None if date_str is None or parsing fails - return None - - @classmethod - @transaction.atomic() - def create_from_scorecard_data( - cls, discovered_package, scorecard_data, scoring_tool=None - ): - """Create ScoreCard object from scorecard data and discovered package""" - final_data = { - "score": scorecard_data.score, - "scoring_tool_version": scorecard_data.scoring_tool_version, - "scoring_tool_documentation_url": ( - scorecard_data.scoring_tool_documentation_url - ), - "score_date": cls.parse_score_date(scorecard_data.score_date), - } - - scorecard_object = cls.objects.create( - **final_data, - discovered_package=discovered_package, - scoring_tool=scoring_tool, - ) - - for check in scorecard_data.checks: - ScorecardCheck.create_from_data(package_score=scorecard_object, check=check) - - return scorecard_object - - @classmethod - def create_from_package_and_scorecard(cls, scorecard_data, package): - score_object = cls.create_from_scorecard_data( - discovered_package=package, - scorecard_data=scorecard_data, - scoring_tool="ossf-scorecard", - ) - return score_object - - -class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): - def __str__(self): - return self.check_score or str(self.uuid) - - for_package_score = models.ForeignKey( - DiscoveredPackageScore, - related_name="discovered_packages_score_checks", - help_text=_("The checks for which the score is given"), - on_delete=models.CASCADE, - editable=False, - blank=True, - null=True, - ) - - @classmethod - def create_from_data(cls, package_score, check): - """Create a ScorecardCheck instance from provided data.""" - return cls.objects.create( - check_name=check.check_name, - check_score=check.check_score, - reason=check.reason or "", - details=check.details or [], - for_package_score=package_score, - ) - - def normalize_package_url_data(purl_mapping, ignore_nulls=False): """ Normalize a mapping of purl data so database queries with @@ -4376,3 +4279,122 @@ def create_auth_token(sender, instance=None, created=False, **kwargs): """Create an API key token on user creation, using the signal system.""" if created: Token.objects.create(user_id=instance.pk) + + +class DiscoveredPackageScore(UUIDPKModel, PackageScoreMixin): + """Represents a security or quality score for a DiscoveredPackage.""" + + discovered_package = models.ForeignKey( + DiscoveredPackage, + related_name="discovered_packages_score", + help_text=_("The package for which the score is given"), + on_delete=models.CASCADE, + editable=False, + ) + + class Meta: + verbose_name = "discovered package score" + verbose_name_plural = "discovered package scores" + ordering = ["-score"] + indexes = [ + models.Index(fields=["score"]), + models.Index(fields=["scoring_tool_version"]), + ] + + def __str__(self): + return self.score or str(self.uuid) + + @classmethod + def parse_score_date(cls, date_str, formats=None): + """ + Parse a date string into a timezone-aware datetime object, + or return None if parsing fails. + """ + if not formats: + formats = ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%SZ"] + + if date_str: + for fmt in formats: + try: + naive_datetime = datetime.strptime(date_str, fmt) + return timezone.make_aware( + naive_datetime, timezone.get_current_timezone() + ) + except ValueError: + continue + + # Return None if date_str is None or parsing fails + return None + + @classmethod + @transaction.atomic() + def create_from_scorecard_data( + cls, discovered_package, scorecard_data, scoring_tool=None + ): + """Create ScoreCard object from scorecard data and discovered package""" + final_data = { + "score": scorecard_data.score, + "scoring_tool_version": scorecard_data.scoring_tool_version, + "scoring_tool_documentation_url": ( + scorecard_data.scoring_tool_documentation_url + ), + "score_date": cls.parse_score_date(scorecard_data.score_date), + } + + scorecard_object = cls.objects.create( + **final_data, + discovered_package=discovered_package, + scoring_tool=scoring_tool, + ) + + for check in scorecard_data.checks: + ScorecardCheck.create_from_data(package_score=scorecard_object, check=check) + + return scorecard_object + + @classmethod + def create_from_package_and_scorecard(cls, scorecard_data, package): + score_object = cls.create_from_scorecard_data( + discovered_package=package, + scorecard_data=scorecard_data, + scoring_tool="ossf-scorecard", + ) + return score_object + + +class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): + """ + Represents an individual check within a Scorecard evaluation for a + DiscoveredPackageScore. + """ + + for_package_score = models.ForeignKey( + DiscoveredPackageScore, + related_name="discovered_packages_score_checks", + help_text=_("The checks for which the score is given"), + on_delete=models.CASCADE, + editable=False, + ) + + class Meta: + verbose_name = "scorecard check" + verbose_name_plural = "scorecard checks" + ordering = ["-check_score"] + indexes = [ + models.Index(fields=["check_score"]), + models.Index(fields=["check_name"]), + ] + + def __str__(self): + return self.check_score or str(self.uuid) + + @classmethod + def create_from_data(cls, package_score, check): + """Create a ScorecardCheck instance from provided data.""" + return cls.objects.create( + check_name=check.check_name, + check_score=check.check_score, + reason=check.reason or "", + details=check.details or [], + for_package_score=package_score, + ) diff --git a/scanpipe/pipelines/fetch_scorecode_info.py b/scanpipe/pipelines/fetch_scorecode_info.py index 21049fc99..6c84e6977 100644 --- a/scanpipe/pipelines/fetch_scorecode_info.py +++ b/scanpipe/pipelines/fetch_scorecode_info.py @@ -41,17 +41,17 @@ class FetchScoreCodeInfo(Pipeline): @classmethod def steps(cls): return ( - cls.check_scorecode_service_availability, - cls.fetch_packages_scorecode_info, + cls.check_ScoreCode_service_availability, + cls.fetch_packages_ScoreCode_info, ) - def check_scorecode_service_availability(self): - """Check if the scorecode service is configured and available.""" + def check_ScoreCode_service_availability(self): + """Check if the ScoreCode service is configured and available.""" if not ossf_scorecard.is_available(): - raise Exception("scorecode service is not available.") + raise Exception("ScoreCode service is not available.") - def fetch_packages_scorecode_info(self): - """Fetch scorecode information for each of the project's discovered packages.""" + def fetch_packages_ScoreCode_info(self): + """Fetch ScoreCode information for each of the project's discovered packages.""" for package in self.project.discoveredpackages.all(): scorecard_data = ossf_scorecard.fetch_scorecard_info( package=package, logger=None diff --git a/scanpipe/tests/__init__.py b/scanpipe/tests/__init__.py index f1f06e27f..502412750 100644 --- a/scanpipe/tests/__init__.py +++ b/scanpipe/tests/__init__.py @@ -20,11 +20,9 @@ # ScanCode.io is a free software code scanning tool from nexB Inc. and others. # Visit https://github.com/nexB/scancode.io for support and download. -import json import os import uuid from datetime import datetime -from pathlib import Path from unittest import mock from django.apps import apps @@ -300,10 +298,3 @@ def make_message(project, **data): "license_key": "mpl-2.0", }, } - -scorecard_data = None - -data = Path(__file__).parent / "data" - -with open(f"{data}/scorecode/scorecard_response.json") as file: - scorecard_data = json.load(file) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 4e3543fbe..7adacfdd3 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -67,6 +67,7 @@ from scanpipe.models import Run from scanpipe.models import RunInProgressError from scanpipe.models import RunNotAllowedToStart +from scanpipe.models import ScorecardCheck from scanpipe.models import UUIDTaggedItem from scanpipe.models import WebhookSubscription from scanpipe.models import convert_glob_to_django_regex @@ -86,7 +87,6 @@ from scanpipe.tests import mocked_now from scanpipe.tests import package_data1 from scanpipe.tests import package_data2 -from scanpipe.tests import scorecard_data from scanpipe.tests.pipelines.do_nothing import DoNothing scanpipe_app = apps.get_app_config("scanpipe") @@ -2512,7 +2512,10 @@ def test_scanpipe_codebase_resource_queryset_elfs(self): self.assertTrue("e" in paths) self.assertTrue("a" in paths) - def test_scorecard_models(self): + def test_scanpipe_scorecard_models(self): + with open(self.data / "scorecode/scorecard_response.json") as file: + scorecard_data = json.load(file) + package = DiscoveredPackage.create_from_data(self.project1, package_data1) scorecard_obj = PackageScore.from_data(scorecard_data) package_score = DiscoveredPackageScore.create_from_package_and_scorecard( @@ -2535,6 +2538,113 @@ def test_scorecard_models(self): else: self.assertRegex(check.check_score, r"^\d+(\.\d+)?$") + def test_scanpipe_create_from_scorecard_data(self): + """Test that create_from_scorecard_data successfully creates a package score.""" + with open(self.data / "scorecode/scorecard_response.json") as file: + scorecard_data = json.load(file) + + package = DiscoveredPackage.create_from_data(self.project1, package_data1) + + scorecard_obj = PackageScore.from_data(scorecard_data) + package_score = DiscoveredPackageScore.create_from_scorecard_data( + discovered_package=package, + scorecard_data=scorecard_obj, + scoring_tool="ossf-scorecard", + ) + + self.assertIsNotNone(package_score) + self.assertEqual(package_score.discovered_package, package) + self.assertEqual(package_score.score, scorecard_obj.score) + self.assertEqual( + package_score.scoring_tool_version, scorecard_obj.scoring_tool_version + ) + self.assertIsNotNone(package_score.score_date) + + actual_checks = package_score.discovered_packages_score_checks.all() + expected_checks = {check["name"]: check for check in scorecard_data["checks"]} + + self.assertEqual( + set(check.check_name for check in actual_checks), + set(expected_checks.keys()), + ) + + for check in actual_checks: + expected = expected_checks[check.check_name] + self.assertEqual(check.check_score, str(expected["score"])) + self.assertEqual(check.reason, expected["reason"]) + self.assertEqual(check.details, expected["details"] or []) + + def test_scanpipe_parse_score_date(self): + """Test parse_score_date with valid, invalid, and custom date formats.""" + # Valid date formats + valid_dates = { + "2024-02-22T12:34:56Z": timezone.datetime( + 2024, 2, 22, 12, 34, 56, tzinfo=tz.utc + ), + "2024-02-22": timezone.datetime( + 2024, 2, 22, tzinfo=timezone.get_current_timezone() + ), + } + for date_str, expected in valid_dates.items(): + with self.subTest(date_str=date_str): + parsed_date = DiscoveredPackageScore.parse_score_date(date_str) + self.assertIsNotNone(parsed_date) + self.assertEqual(parsed_date, expected) + + # Invalid date formats + invalid_dates = [ + "2024/02/22", + "Feb 22, 2024", + "22-02-2024", + "not-a-date", + None, + "", + ] + for date_str in invalid_dates: + with self.subTest(date_str=date_str): + self.assertIsNone(DiscoveredPackageScore.parse_score_date(date_str)) + + # Custom date format + custom_date_str = "22-02-2024 14:30" + custom_format = ["%d-%m-%Y %H:%M"] + parsed_custom = DiscoveredPackageScore.parse_score_date( + custom_date_str, custom_format + ) + + self.assertIsNotNone(parsed_custom) + self.assertEqual(parsed_custom.date(), timezone.datetime(2024, 2, 22).date()) + + def test_scanpipe_create_scorecard_check_from_data(self): + """Test create_from_data successfully creates a ScorecardCheck instance.""" + with open(self.data_path / "scorecode/scorecard_response.json") as file: + scorecard_data = json.load(file) + + package = DiscoveredPackage.create_from_data(self.project1, package_data1) + scorecard_obj = PackageScore.from_data(scorecard_data) + package_score = DiscoveredPackageScore.create_from_package_and_scorecard( + package=package, scorecard_data=scorecard_obj + ) + + # Step 4: Retrieve the first check that was automatically created + check_data = scorecard_data["checks"][0] # Extract first check + scorecard_check = ScorecardCheck.objects.get( + for_package_score=package_score, check_name=check_data["name"] + ) + + # Step 5: Assertions to validate correct object creation + self.assertIsNotNone(scorecard_check) + self.assertEqual(scorecard_check.for_package_score, package_score) + self.assertEqual(scorecard_check.check_name, check_data["name"]) + self.assertEqual(scorecard_check.check_score, str(check_data["score"])) + self.assertEqual(scorecard_check.reason, check_data["reason"]) + self.assertEqual(scorecard_check.details, check_data["details"] or []) + + # Step 6: Ensure the number of checks matches the scorecard data + self.assertEqual( + package_score.discovered_packages_score_checks.count(), + len(scorecard_data["checks"]), + ) + def test_scanpipe_model_codebase_resource_compliance_alert_queryset_mixin(self): severities = CodebaseResource.Compliance make_resource_file(self.project1, path="none") diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index 45e2924b5..795fc3b81 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -1252,7 +1252,6 @@ def test_scanpipe_get_scorecard_info_packages_integration(self, mock_is_availabl run = project1.add_pipeline(pipeline_name) pipeline = run.make_pipeline_instance() - # mock_is_configured.return_value = True mock_is_available.return_value = True exitcode, out = pipeline.execute() From 3baeac397fb638b17cb344741e95faaa3ecde179 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 28 Feb 2025 18:25:38 -0500 Subject: [PATCH 47/50] updated built-in-pipelines.rst with `ScoreCode` pipeline Signed-off-by: 404-geek --- docs/built-in-pipelines.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/built-in-pipelines.rst b/docs/built-in-pipelines.rst index 952e57741..36eda0630 100644 --- a/docs/built-in-pipelines.rst +++ b/docs/built-in-pipelines.rst @@ -229,3 +229,9 @@ Scan Single Package .. autoclass:: scanpipe.pipelines.scan_single_package.ScanSinglePackage() :members: :member-order: bysource + +Fetch ScoreCode Info for Package +--------------------------------- +.. autoclass:: scanpipe.pipelines.fetch_scorecode_info.FetchScoreCodeInfo() + :members: + :member-order: bysource From c6b9832641fd4a43957aaf52153254a823f838e9 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Fri, 28 Feb 2025 18:50:31 -0500 Subject: [PATCH 48/50] fix path bugs Signed-off-by: 404-geek --- scanpipe/tests/test_models.py | 2 +- scanpipe/tests/test_pipelines.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scanpipe/tests/test_models.py b/scanpipe/tests/test_models.py index 047b3fe37..8813d4910 100644 --- a/scanpipe/tests/test_models.py +++ b/scanpipe/tests/test_models.py @@ -2705,7 +2705,7 @@ def test_scanpipe_parse_score_date(self): def test_scanpipe_create_scorecard_check_from_data(self): """Test create_from_data successfully creates a ScorecardCheck instance.""" - with open(self.data_path / "scorecode/scorecard_response.json") as file: + with open(self.data / "scorecode/scorecard_response.json") as file: scorecard_data = json.load(file) package = DiscoveredPackage.create_from_data(self.project1, package_data1) diff --git a/scanpipe/tests/test_pipelines.py b/scanpipe/tests/test_pipelines.py index d2b3d2f2d..4800d686a 100644 --- a/scanpipe/tests/test_pipelines.py +++ b/scanpipe/tests/test_pipelines.py @@ -1251,7 +1251,7 @@ def test_scanpipe_get_scorecard_info_packages_integration(self, mock_is_availabl mock_is_available.return_value = False exitcode, out = pipeline.execute() self.assertEqual(1, exitcode, msg=out) - self.assertIn("scorecode service is not available.", out) + self.assertIn("ScoreCode service is not available.", out) run = project1.add_pipeline(pipeline_name) pipeline = run.make_pipeline_instance() From 8679ddc5c8bc8e0fe4a2e8ce897b2b80e2f160ab Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sat, 1 Mar 2025 22:47:10 -0500 Subject: [PATCH 49/50] change migration file and update `ScoreCode` version Signed-off-by: 404-geek --- ...070_alter_project_purl_discoveredpackagescore_and_more.py | 5 ----- setup.cfg | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py b/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py index 203dec295..f9a9b22a5 100644 --- a/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py +++ b/scanpipe/migrations/0070_alter_project_purl_discoveredpackagescore_and_more.py @@ -12,11 +12,6 @@ class Migration(migrations.Migration): ] operations = [ - migrations.AlterField( - model_name='project', - name='purl', - field=models.CharField(blank=True, help_text="Package URL (PURL) for the project, required for pushing the project's scan result to FederatedCode. For example, if the input is an input URL like https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz, the corresponding PURL would be pkg:npm/lodash@4.17.21.", max_length=2048), - ), migrations.CreateModel( name='DiscoveredPackageScore', fields=[ diff --git a/setup.cfg b/setup.cfg index 36c93878b..443dd48ad 100644 --- a/setup.cfg +++ b/setup.cfg @@ -99,7 +99,7 @@ install_requires = # MatchCode-toolkit matchcode-toolkit==7.0.0 # ScoreCode - scorecode==0.0.2 + scorecode==0.0.3 # Univers univers==30.12.1 # Markdown From c6a8ac55600a30808f7e1836a2df5d847fc555e0 Mon Sep 17 00:00:00 2001 From: 404-geek Date: Sun, 6 Jul 2025 12:05:03 -0400 Subject: [PATCH 50/50] cosmetic changes to pipeline Signed-off-by: 404-geek --- scanpipe/models.py | 7 +++-- scanpipe/pipelines/fetch_scorecode_info.py | 14 +++++----- scanpipe/tests/regen_test_data.py | 30 +++++++++------------- 3 files changed, 21 insertions(+), 30 deletions(-) diff --git a/scanpipe/models.py b/scanpipe/models.py index c13647165..55f384f59 100644 --- a/scanpipe/models.py +++ b/scanpipe/models.py @@ -4408,7 +4408,7 @@ class DiscoveredPackageScore(UUIDPKModel, PackageScoreMixin): discovered_package = models.ForeignKey( DiscoveredPackage, - related_name="discovered_packages_score", + related_name="scores", help_text=_("The package for which the score is given"), on_delete=models.CASCADE, editable=False, @@ -4449,7 +4449,6 @@ def parse_score_date(cls, date_str, formats=None): return None @classmethod - @transaction.atomic() def create_from_scorecard_data( cls, discovered_package, scorecard_data, scoring_tool=None ): @@ -4490,9 +4489,9 @@ class ScorecardCheck(UUIDPKModel, ScorecardChecksMixin): DiscoveredPackageScore. """ - for_package_score = models.ForeignKey( + package_score = models.ForeignKey( DiscoveredPackageScore, - related_name="discovered_packages_score_checks", + related_name="checks", help_text=_("The checks for which the score is given"), on_delete=models.CASCADE, editable=False, diff --git a/scanpipe/pipelines/fetch_scorecode_info.py b/scanpipe/pipelines/fetch_scorecode_info.py index 6c84e6977..608eb02c0 100644 --- a/scanpipe/pipelines/fetch_scorecode_info.py +++ b/scanpipe/pipelines/fetch_scorecode_info.py @@ -29,7 +29,7 @@ class FetchScoreCodeInfo(Pipeline): """ - Fetch ScoreCode information for packages and dependencies. + Fetch ScoreCode information for packages. This pipeline retrieves ScoreCode data for each package in the project and stores it in the corresponding package instances. @@ -41,21 +41,19 @@ class FetchScoreCodeInfo(Pipeline): @classmethod def steps(cls): return ( - cls.check_ScoreCode_service_availability, - cls.fetch_packages_ScoreCode_info, + cls.check_scoreCode_service_availability, + cls.fetch_packages_scoreCode_info, ) - def check_ScoreCode_service_availability(self): + def check_scoreCode_service_availability(self): """Check if the ScoreCode service is configured and available.""" if not ossf_scorecard.is_available(): raise Exception("ScoreCode service is not available.") - def fetch_packages_ScoreCode_info(self): + def fetch_packages_scoreCode_info(self): """Fetch ScoreCode information for each of the project's discovered packages.""" for package in self.project.discoveredpackages.all(): - scorecard_data = ossf_scorecard.fetch_scorecard_info( - package=package, logger=None - ) + scorecard_data = ossf_scorecard.fetch_scorecard_info(package=package) if scorecard_data: DiscoveredPackageScore.create_from_package_and_scorecard( diff --git a/scanpipe/tests/regen_test_data.py b/scanpipe/tests/regen_test_data.py index acd856bc7..c80a9381b 100644 --- a/scanpipe/tests/regen_test_data.py +++ b/scanpipe/tests/regen_test_data.py @@ -33,6 +33,7 @@ from scanpipe.pipes import input from scanpipe.pipes import output from scanpipe.pipes import scancode +from scorecode.ossf_scorecard import fetch_scorecard class RegenTestData(TestCase): @@ -154,29 +155,22 @@ def test_regen_asgiref_test_files(self): def test_regenerate_scorecard_data(self): """ - Regenerate and save scorecard data by directly calling the OSSF Scorecard - API + Regenerate and save scorecard data by calling the OSSF Scorecard API. """ scorecard_data_file = self.data / "scorecode" / "scorecard_response.json" platform, org, repo = "github.com", "nexB", "scancode-toolkit" - OSSF_SCORECARD_API_URL = "https://api.securityscorecards.dev" - - url = f"{OSSF_SCORECARD_API_URL}/projects/{platform}/{org}/{repo}" - try: - # Fetch the scorecard data from the API - response = requests.get(url, timeout=10) - response.raise_for_status() - scorecard_data = response.json() - - scorecard_data_file.parent.mkdir(parents=True, exist_ok=True) - - scorecard_data_file.write_text(json.dumps(scorecard_data, indent=2)) - - print(f"Scorecard data successfully saved to {scorecard_data_file}") - + scorecard_data = fetch_scorecard(platform, org, repo) except requests.exceptions.Timeout: - print("The request timed out.") + print("The request to the OSSF Scorecard API timed out.") + return except requests.exceptions.RequestException as e: print(f"Error fetching scorecard data: {e}") + return + + scorecard_data_file.parent.mkdir(parents=True, exist_ok=True) + scorecard_data_file.write_text( + json.dumps(scorecard_data.to_dict(), indent=2) + ) + print(f"Scorecard data successfully saved to {scorecard_data_file}")