Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ignored_vulnerabilities field on the Project configuration #1271 #1281

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ v34.6.3 (unreleased)
- Fix an issue in the d2d JavaScript mapper.
https://github.com/nexB/scancode.io/pull/1274

- Add support for a ``ignored_vulnerabilities`` field on the Project configuration.
https://github.com/nexB/scancode.io/issues/1271

v34.6.2 (2024-06-18)
--------------------

Expand Down
40 changes: 32 additions & 8 deletions docs/project-configuration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,20 @@ Content of a ``scancode-config.yml`` file:
product_name: My Product Name
product_version: '1.0'
ignored_patterns:
- '*.tmp'
- 'tests/*'
- '*.tmp'
- 'tests/*'
ignored_dependency_scopes:
- package_type: npm
scope: devDependencies
- package_type: pypi
scope: tests
ignored_vulnerabilities:
- VCID-q4q6-yfng-aaag
- CVE-2024-27351
- GHSA-vm8q-m57g-pff3

See the :ref:`project_configuration_settings` section for the details about each
setting.
See the following :ref:`project_configuration_settings` section for the details about
each setting.

.. tip::
You can generate the project configuration file from the
Expand Down Expand Up @@ -125,10 +129,10 @@ packages, define the following in your ``scancode-config.yml`` configuration fil
.. code-block:: yaml

ignored_dependency_scopes:
- package_type: npm
scope: devDependencies
- package_type: pypi
scope: tests
- package_type: npm
scope: devDependencies
- package_type: pypi
scope: tests

If you prefer to use the :ref:`user_interface_project_settings` form, list each
ignored scope using the `package_type:scope` syntax, **one per line**, such as:
Expand All @@ -141,3 +145,23 @@ ignored scope using the `package_type:scope` syntax, **one per line**, such as:
.. warning::
Be precise when listing scope names to avoid unintended exclusions.
Ensure the scope names are correct and reflect your project requirements.

ignored_vulnerabilities
^^^^^^^^^^^^^^^^^^^^^^^

Provide one or more vulnerability id to be ignored, **one per line**.

You can provide ``VCID`` from VulnerableCode or any aliases such as ``CVE`` or
``GHSA``.

For example::

.. code-block:: yaml

ignored_vulnerabilities:
- VCID-q4q6-yfng-aaag
- CVE-2024-27351
- GHSA-vm8q-m57g-pff3
- OSV-2020-871
- BIT-django-2024-24680
- PYSEC-2024-28
10 changes: 8 additions & 2 deletions docs/scancode-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@
# - Use ``*`` to match multiple characters.
# - Use ``?`` to match a single character.
#ignored_patterns:
# - '*.tmp'
# - 'tests/*'
# - '*.tmp'
# - 'tests/*'

# Specify certain dependency scopes to be ignored for a given package type.
#ignored_dependency_scopes:
# - package_type: npm
# scope: devDependencies
# - package_type: pypi
# scope: tests

# Specify certain vulnerabilities to be ignored using VCID, CVE, or any aliases.
#ignored_vulnerabilities:
# - VCID-q4q6-yfng-aaag
# - CVE-2024-27351
# - GHSA-vm8q-m57g-pff3
18 changes: 18 additions & 0 deletions scanpipe/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,10 +365,16 @@ def prepare_value(self, value):
"""


ignored_vulnerabilities_help = """
Specify certain vulnerabilities to be ignored using VCID, CVE, or any aliases.
"""


class ProjectSettingsForm(forms.ModelForm):
settings_fields = [
"ignored_patterns",
"ignored_dependency_scopes",
"ignored_vulnerabilities",
"attribution_template",
"product_name",
"product_version",
Expand Down Expand Up @@ -399,6 +405,18 @@ class ProjectSettingsForm(forms.ModelForm):
key_name="package_type",
value_name="scope",
)
ignored_vulnerabilities = ListTextarea(
label="Ignored vulnerabilities",
required=False,
help_text=convert_markdown_to_html(ignored_vulnerabilities_help.strip()),
widget=forms.Textarea(
attrs={
"class": "textarea is-dynamic",
"rows": 2,
"placeholder": "VCID-q4q6-yfng-aaag\nCVE-2024-27351",
},
),
)
attribution_template = forms.CharField(
label="Attribution template",
required=False,
Expand Down
19 changes: 19 additions & 0 deletions scanpipe/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,25 @@ def ignored_dependency_scopes_index(self):
"""
return self.get_ignored_dependency_scopes_index()

def get_ignored_vulnerabilities_set(self):
"""
Return a set of ``ignored_vulnerabilities`` setting values defined in this
Project env.
"""
ignored_vulnerabilities = self.get_env(field_name="ignored_vulnerabilities")
if ignored_vulnerabilities:
return set(entry for entry in ignored_vulnerabilities)

return []

@cached_property
def ignored_vulnerabilities_set(self):
"""
Return the computed value of get_ignored_vulnerabilities_set.
The value is only generated once and cached for further calls.
"""
return self.get_ignored_vulnerabilities_set()

def clear_tmp_directory(self):
"""
Delete the whole content of the tmp/ directory.
Expand Down
12 changes: 10 additions & 2 deletions scanpipe/pipelines/find_vulnerabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,17 @@ def check_vulnerablecode_service_availability(self):
def lookup_packages_vulnerabilities(self):
"""Check for vulnerabilities for each of the project's discovered package."""
packages = self.project.discoveredpackages.all()
vulnerablecode.fetch_vulnerabilities(packages, logger=self.log)
vulnerablecode.fetch_vulnerabilities(
packages=packages,
ignore_set=self.project.ignored_vulnerabilities_set,
logger=self.log,
)

def lookup_dependencies_vulnerabilities(self):
"""Check for vulnerabilities for each of the project's discovered dependency."""
dependencies = self.project.discovereddependencies.filter(is_resolved=True)
vulnerablecode.fetch_vulnerabilities(dependencies, logger=self.log)
vulnerablecode.fetch_vulnerabilities(
packages=dependencies,
ignore_set=self.project.ignored_vulnerabilities_set,
logger=self.log,
)
21 changes: 19 additions & 2 deletions scanpipe/pipes/vulnerablecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,19 @@ def bulk_search_by_cpes(
return request_post(url, data, timeout)


def fetch_vulnerabilities(packages, chunk_size=1000, logger=logger.info):
def filter_vulnerabilities(vulnerabilities, ignore_set):
"""Filter out vulnerabilities based on a list of ignored IDs and aliases."""
return [
vulnerability
for vulnerability in vulnerabilities
if vulnerability.get("vulnerability_id") not in ignore_set
and not any(alias in ignore_set for alias in vulnerability.get("aliases", []))
]


def fetch_vulnerabilities(
packages, chunk_size=1000, logger=logger.info, ignore_set=None
):
"""
Fetch and store vulnerabilities for each provided ``packages``.
The PURLs are used for the lookups in batch of ``chunk_size`` per request.
Expand All @@ -217,7 +229,12 @@ def fetch_vulnerabilities(packages, chunk_size=1000, logger=logger.info):
unsaved_objects = []
for package in packages:
if package_data := vulnerabilities_by_purl.get(package.package_url):
if affected_by := package_data.get("affected_by_vulnerabilities", []):
affected_by = package_data.get("affected_by_vulnerabilities", [])

if ignore_set and affected_by:
affected_by = filter_vulnerabilities(affected_by, ignore_set)

if affected_by:
package.affected_by_vulnerabilities = affected_by
unsaved_objects.append(package)

Expand Down
12 changes: 12 additions & 0 deletions scanpipe/templates/scanpipe/project_settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,18 @@
{{ form.ignored_dependency_scopes.help_text|safe|linebreaksbr }}
</div>
</div>

<div class="field">
<label class="label" for="{{ form.ignored_vulnerabilities.id_for_label }}">
{{ form.ignored_vulnerabilities.label }}
</label>
<div class="control">
{{ form.ignored_vulnerabilities }}
</div>
<div class="help">
{{ form.ignored_vulnerabilities.help_text|safe|linebreaksbr }}
</div>
</div>
</div>
</div>

Expand Down
8 changes: 6 additions & 2 deletions scanpipe/tests/data/settings/scancode-config.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
product_name: My Product Name
product_version: '1.0'
ignored_patterns:
- '*.tmp'
- 'tests/*'
- '*.tmp'
- 'tests/*'
ignored_dependency_scopes:
- package_type: npm
scope: devDependencies
- package_type: pypi
scope: tests
ignored_vulnerabilities:
- VCID-q4q6-yfng-aaag
- CVE-2024-27351
- GHSA-vm8q-m57g-pff3
Loading