Issue 5600 check command should be able to pull requirements from lock file (#5607)

* Allow pipenv check inputs to be built from the lockfile categories instead of whats installed.

* fix lint

* add news fragment.

* update pipenv check documentation.

* Revise logic for pipenv check and change default behavior to check lockfile.

* fix issue revealed by tests

* fix docs for pipenv check changes.

* change conditional ordering in prep for supporting for future default categories env var.
This commit is contained in:
Matt Davis
2023-02-18 14:58:47 -05:00
committed by GitHub
parent 8877d7944f
commit ca436af2bc
5 changed files with 83 additions and 50 deletions
+35 -42
View File
@@ -390,57 +390,50 @@ It can be used to specify multiple categories also.
Pipenv includes the `safety <https://github.com/pyupio/safety>`_ package, and will use it to scan your dependency graph
for known security vulnerabilities!
By default ``pipenv check`` will scan the Pipfile.lock default packages group and use this as the input to the safety command.
To scan other package categories pass the specific ``--categories`` you want to check against.
To have ``pipenv check`` scan the virtualenv packages for what is installed and use this as the input to the safety command,
run``pipenv check --use-installed``.
Note: ``--use-installed`` was the default behavior in ``pipenv<=2023.2.4``
Example::
$ cat Pipfile
[packages]
django = "==1.10.1"
$ pipenv install wheel==0.37.1
$ cat Pipfile.lock
...
"default": {
"wheel": {
"hashes": [
"sha256:4bdcd7d840138086126cd09254dc6195fb4fc6f01c050a1d7236f2630db1d22a",
"sha256:e9a504e793efbca1b8e0e9cb979a249cf4a0a7b5b8c9e8b65a5e39d49529c1c4"
],
"index": "pypi",
"version": "==0.37.1"
}
},
...
$ pipenv check
Checking PEP 508 requirements...
Passed!
Checking installed package safety...
$ pipenv check --use-lock
...
-> Vulnerability found in wheel version 0.37.1
Vulnerability ID: 51499
Affected spec: <0.38.1
ADVISORY: Wheel 0.38.1 includes a fix for CVE-2022-40898: An issue discovered in Python Packaging Authority (PyPA) Wheel 0.37.1 and earlier allows remote attackers to cause a denial of service
via attacker controlled input to wheel cli.https://pyup.io/posts/pyup-discovers-redos-vulnerabilities-in-top-python-packages
CVE-2022-40898
For more information, please visit https://pyup.io/v/51499/742
33075: django >=1.10,<1.10.3 resolved (1.10.1 installed)!
Django before 1.8.x before 1.8.16, 1.9.x before 1.9.11, and 1.10.x before 1.10.3, when settings.DEBUG is True, allow remote attackers to conduct DNS rebinding attacks by leveraging failure to validate the HTTP Host header against settings.ALLOWED_HOSTS.
Scan was completed. 1 vulnerability was found.
...
33076: django >=1.10,<1.10.3 resolved (1.10.1 installed)!
Django 1.8.x before 1.8.16, 1.9.x before 1.9.11, and 1.10.x before 1.10.3 use a hardcoded password for a temporary database user created when running tests with an Oracle database, which makes it easier for remote attackers to obtain access to the database server by leveraging failure to manually specify a password in the database settings TEST dictionary.
33300: django >=1.10,<1.10.7 resolved (1.10.1 installed)!
CVE-2017-7233: Open redirect and possible XSS attack via user-supplied numeric redirect URLs
============================================================================================
Django relies on user input in some cases (e.g.
:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
to redirect the user to an "on success" URL. The security check for these
redirects (namely ``django.utils.http.is_safe_url()``) considered some numeric
URLs (e.g. ``http:999999999``) "safe" when they shouldn't be.
Also, if a developer relies on ``is_safe_url()`` to provide safe redirect
targets and puts such a URL into a link, they could suffer from an XSS attack.
CVE-2017-7234: Open redirect vulnerability in ``django.views.static.serve()``
=============================================================================
A maliciously crafted URL to a Django site using the
:func:`~django.views.static.serve` view could redirect to any other domain. The
view no longer does any redirects as they don't provide any known, useful
functionality.
Note, however, that this view has always carried a warning that it is not
hardened for production use and should be used only as a development aid.
✨🍰✨
.. note::
Each month, `PyUp.io <https://pyup.io>`_ updates the ``safety`` database of
insecure Python packages and `makes it available to the
community for free <https://pyup.io/safety/>`__. Pipenv
makes an API call to retrieve those results and use them
each time you run ``pipenv check`` to show you vulnerable
dependencies.
insecure Python packages and `makes it available to the open source
community for free <https://pyup.io/safety/>`__. Each time
you run ``pipenv check`` to show you vulnerable dependencies,
Pipenv makes an API call to retrieve and use those results.
For more up-to-date vulnerability data, you may also use your own safety
API key by setting the environment variable ``PIPENV_PYUP_API_KEY``.
+3
View File
@@ -0,0 +1,3 @@
Behavior change for ``pipenv check`` now checks the default packages group of the lockfile.
Specifying ``--categories`` to override which categories to check against.
Pass ``--use-installed`` to get the prior behavior of checking the packages actually installed into the environment.
+15 -2
View File
@@ -479,13 +479,23 @@ def run(state, command, args):
help="Path to where output file will be placed, if the path is a directory, "
"Safety will use safety-report.json as filename. Default: empty",
)
@option(
"--use-installed",
is_flag=True,
help="Whether to use the lockfile as input to check (instead of result from pip list).",
)
@option(
"--categories",
is_flag=False,
default="",
help="Use the specified categories from the lockfile as input to check.",
)
@common_options
@system_option
@pass_state
def check(
state,
db=None,
style=False,
ignore=None,
output="screen",
key=None,
@@ -495,6 +505,8 @@ def check(
save_json="",
audit_and_monitor=True,
project=None,
use_installed=False,
categories="",
**kwargs,
):
"""Checks for PyUp Safety security vulnerabilities and against PEP 508 markers provided in Pipfile."""
@@ -515,6 +527,8 @@ def check(
audit_and_monitor=audit_and_monitor,
safety_project=project,
pypi_mirror=state.pypi_mirror,
use_installed=use_installed,
categories=categories,
)
@@ -771,7 +785,6 @@ def verify(state):
def requirements(
state, dev=False, dev_only=False, hash=False, exclude_markers=False, categories=""
):
from pipenv.utils.dependencies import convert_deps_to_pip
lockfile = state.project.load_lockfile(expand_env_vars=False)
+16 -4
View File
@@ -57,7 +57,6 @@ from pipenv.vendor import click, plette, vistir
from pipenv.vendor.requirementslib.models.requirements import Requirement
if MYPY_RUNNING:
TSourceDict = Dict[str, Union[str, bool]]
@@ -2791,6 +2790,8 @@ def do_check(
audit_and_monitor=True,
safety_project=None,
pypi_mirror=None,
use_installed=False,
categories="",
):
import json
@@ -2897,9 +2898,20 @@ def do_check(
if safety_project:
options.append(f"--project={safety_project}")
target_venv_packages = run_command(
_cmd + ["-m", "pip", "list", "--format=freeze"], is_verbose=project.s.is_verbose()
)
if use_installed:
target_venv_packages = run_command(
_cmd + ["-m", "pip", "list", "--format=freeze"],
is_verbose=project.s.is_verbose(),
)
elif categories:
target_venv_packages = run_command(
["pipenv", "requirements", "--categories", categories],
is_verbose=project.s.is_verbose(),
)
else:
target_venv_packages = run_command(
["pipenv", "requirements"], is_verbose=project.s.is_verbose()
)
temp_requirements = tempfile.NamedTemporaryFile(
mode="w+",
+14 -2
View File
@@ -144,7 +144,7 @@ def test_pipenv_check(pipenv_instance_private_pypi):
with pipenv_instance_private_pypi() as p:
c = p.pipenv('install pyyaml')
assert c.returncode == 0
c = p.pipenv('check')
c = p.pipenv('check --use-installed')
assert c.returncode != 0
assert 'pyyaml' in c.stdout
c = p.pipenv('uninstall pyyaml')
@@ -158,11 +158,23 @@ def test_pipenv_check(pipenv_instance_private_pypi):
# the issue above is still not resolved.
# added also 51499
# https://github.com/pypa/wheel/issues/481
c = p.pipenv('check --ignore 35015 -i 51457 -i 51499')
c = p.pipenv('check --use-installed --ignore 35015 -i 51457 -i 51499')
assert c.returncode == 0
assert 'Ignoring' in c.stderr
@pytest.mark.cli
@pytest.mark.needs_internet(reason='required by check')
@pytest.mark.parametrize("category", ["CVE", "packages"])
def test_pipenv_check_check_lockfile_categories(pipenv_instance_pypi, category):
with pipenv_instance_pypi() as p:
c = p.pipenv(f'install wheel==0.37.1 --categories={category}')
assert c.returncode == 0
c = p.pipenv(f'check --categories={category}')
assert c.returncode != 0
assert 'wheel' in c.stdout
@pytest.mark.cli
def test_pipenv_clean(pipenv_instance_pypi):
with pipenv_instance_pypi(chdir=True) as p: