Walkthrough

Before you start, please remember that Valiant is brand new and still in a state of change/development. You should make sure that you use Valiant with this is mind.

Install

You need to be running Python 3.8 or higher. If you're not running 3.8, pyenv can make this very easy for you and I'd strongly recommend checking out their instructions.

I'd also recommend using a virtual environment. The "built in" approach to this (once you have Python 3.8 installed) is to:

python -m virtualenv --python 3.8 venv
. venv/bin/activate
python --version

Hopefully you get something like Python 3.8.x. With that going you can now install Valiant:

pip install valiant

...and check it's working:

valiant about

Containers

Containers can be handy if you're just taking Valiant for a spin.

Grab a copy of the Python 3.8 image:

docker pull docker.io/python:3.8

Start it up:

docker run --rm -it docker.io/python:3.8 /bin/bash

Once in the container shell you can install Valiant and try it out:

pip install valiant
valiant about

From the GitHub project

pip install git+https://github.com/pomes/valiant.git

It's a really good idea to do this type of thing in a virtual env! Poetry will help you out here and install Valiant as a dev dependency:

poetry add -D git+https://github.com/pomes/valiant.git

Configuration

Please check out the Configuration page for details.

Review a dependency

Say you wanted to find out about a dependency. The report command will give you information about the project/release plus run some checks.

Let's try it out:

valiant report flask 1.1.1

You'll get the following output:

Package metadata
+-------------+----------------------------------------------------------------+
|    Item     |                            Value(s)                            |
+=============+================================================================+
| Package     | Flask                                                          |
+-------------+----------------------------------------------------------------+
| Version     | 1.1.1                                                          |
+-------------+----------------------------------------------------------------+
| Repository  | https://pypi.org/pypi                                          |
+-------------+----------------------------------------------------------------+
| License     | BSD-3-Clause                                                   |
+-------------+----------------------------------------------------------------+
| Summary     | A simple framework for building complex web applications.      |
+-------------+----------------------------------------------------------------+
| Resources   | Project: https://palletsprojects.com/p/flask/                  |
|             | Code: https://github.com/pallets/flask                         |
|             | Documentation: https://flask.palletsprojects.com/              |
|             | Issue tracker:: https://github.com/pallets/flask/issues        |
+-------------+----------------------------------------------------------------+
| Classifiers | Development Status :: 5 - Production/Stable                    |
|             | Environment :: Web Environment                                 |
|             | Framework :: Flask                                             |
|             | Intended Audience :: Developers                                |
|             | License :: OSI Approved :: BSD License                         |
|             | Operating System :: OS Independent                             |
|             | Programming Language :: Python                                 |
|             | Programming Language :: Python :: 2                            |
|             | Programming Language :: Python :: 2.7                          |
|             | Programming Language :: Python :: 3                            |
|             | Programming Language :: Python :: 3.5                          |
|             | Programming Language :: Python :: 3.6                          |
|             | Programming Language :: Python :: 3.7                          |
|             | Topic :: Internet :: WWW/HTTP :: Dynamic Content               |
|             | Topic :: Internet :: WWW/HTTP :: WSGI :: Application           |
|             | Topic :: Software Development :: Libraries :: Application      |
|             | Frameworks                                                     |
|             | Topic :: Software Development :: Libraries :: Python Modules   |
+-------------+----------------------------------------------------------------+
| Artifacts   | bdist_wheel: https://files.pythonhosted.org/packages/9b/93/628 |
|             | 509b8d5dc749656a9641f4caf13540e2cdec85276964ff8f43bbb1d3b/Flas |
|             | k-1.1.1-py2.py3-none-any.whl                                   |
|             | ---                                                            |
|             | sdist: https://files.pythonhosted.org/packages/2e/80/3726a729d |
|             | e758513fd3dbc64e93098eb009c49305a97c6751de55b20b694/Flask-1.1. |
|             | 1.tar.gz                                                       |
+-------------+----------------------------------------------------------------+

Report: Basic [https://pypi.org/pypi :: Flask :: 1.1.1]
No findings

Report: SPDX License [https://pypi.org/pypi :: Flask :: 1.1.1]
+----------+---------+----------+--------------------+--------------+
| Priority |   ID    | Category |       Title        |   Message    |
+==========+=========+==========+====================+==============+
|   info   | SPDX001 | license  | SPDX License found | BSD-3-Clause |
+----------+---------+----------+--------------------+--------------+

Report: Safety [https://pypi.org/pypi :: Flask :: 1.1.1]
No findings

It all looks pretty good. Let's try another one:

valiant report rdflib 4.2.2

This will yield some findings for us to consider:

Package metadata
+-------------+----------------------------------------------------------------+
|    Item     |                            Value(s)                            |
+=============+================================================================+
| Package     | rdflib                                                         |
+-------------+----------------------------------------------------------------+
| Version     | 4.2.2                                                          |
+-------------+----------------------------------------------------------------+
| Repository  | https://pypi.org/pypi                                          |
+-------------+----------------------------------------------------------------+
| License     | https://raw.github.com/RDFLib/rdflib/master/LICENSE            |
+-------------+----------------------------------------------------------------+
| Summary     | RDFLib is a Python library for working with RDF, a simple yet  |
|             | powerful language for representing information.                |
+-------------+----------------------------------------------------------------+
| Resources   | Project: https://github.com/RDFLib/rdflib                      |
|             | Code:                                                          |
|             | Documentation:                                                 |
|             | Issue tracker::                                                |
+-------------+----------------------------------------------------------------+
| Classifiers | License :: OSI Approved :: BSD License                         |
|             | Natural Language :: English                                    |
|             | Operating System :: OS Independent                             |
|             | Programming Language :: Python                                 |
|             | Programming Language :: Python :: 2                            |
|             | Programming Language :: Python :: 2.6                          |
|             | Programming Language :: Python :: 2.7                          |
|             | Programming Language :: Python :: 3                            |
|             | Programming Language :: Python :: 3.3                          |
|             | Programming Language :: Python :: 3.4                          |
|             | Programming Language :: Python :: 3.5                          |
|             | Topic :: Software Development :: Libraries :: Python Modules   |
+-------------+----------------------------------------------------------------+
| Artifacts   | bdist_wheel: https://files.pythonhosted.org/packages/3c/fe/630 |
|             | bacb652680f6d481b9febbb3e2c3869194a1a5fc3401a4a41195a2f8f/rdfl |
|             | ib-4.2.2-py3-none-any.whl                                      |
|             | ---                                                            |
|             | sdist: https://files.pythonhosted.org/packages/c5/77/1fa0f4cff |
|             | d5faad496b1344ab665902bb2609f56e0fb19bcf80cff485da0/rdflib-4.2 |
|             | .2.tar.gz                                                      |
+-------------+----------------------------------------------------------------+

Report: Basic [https://pypi.org/pypi :: rdflib :: 4.2.2]
+----------+----------+----------+----------------------+----------------------+
| Priority |    ID    | Category |        Title         |       Message        |
+==========+==========+==========+======================+======================+
| warning  | BASIC003 | project  | No link to codebase  | The project doesn't  |
|          |          |          |                      | provide a link to    |
|          |          |          |                      | its codebase.        |
+----------+----------+----------+----------------------+----------------------+
| warning  | BASIC004 | project  | An artifact has not  | A package of type    |
|          |          |          | been signed          | bdist_wheel has not  |
|          |          |          |                      | been signed          |
+----------+----------+----------+----------------------+----------------------+
| warning  | BASIC004 | project  | An artifact has not  | A package of type    |
|          |          |          | been signed          | sdist has not been   |
|          |          |          |                      | signed               |
+----------+----------+----------+----------------------+----------------------+

Report: SPDX License [https://pypi.org/pypi :: rdflib :: 4.2.2]
+----------+---------+----------+-----------------------+----------------------+
| Priority |   ID    | Category |         Title         |       Message        |
+==========+=========+==========+=======================+======================+
|   info   | SPDX002 | license  | SPDX License not      | Could not map        |
|          |         |          | found                 | licence https://raw. |
|          |         |          |                       | github.com/RDFLib/rd |
|          |         |          |                       | flib/master/LICENSE  |
|          |         |          |                       | to an SPDX license   |
+----------+---------+----------+-----------------------+----------------------+

Report: Safety [https://pypi.org/pypi :: rdflib :: 4.2.2]
+----------+-----------+----------+---------------------+----------------------+
| Priority |    ID     | Category |        Title        |       Message        |
+==========+===========+==========+=====================+======================+
| priority | SAFETY001 | security | Vulnerability found | The CLI tools in     |
|          |           |          |                     | RDFLib 4.2.2 can     |
|          |           |          |                     | load Python modules  |
|          |           |          |                     | from the current     |
|          |           |          |                     | working directory,   |
|          |           |          |                     | allowing code        |
|          |           |          |                     | injection, because   |
|          |           |          |                     | "python -m" looks in |
|          |           |          |                     | this directory, as   |
|          |           |          |                     | demonstrated by      |
|          |           |          |                     | rdf2dot.             |
+----------+-----------+----------+---------------------+----------------------+

Sometimes you just want the findings:

valiant report rdflib 4.2.2 -s

This will give us a quick table to check:

+--------------+-----------+----------+----------+--------------+--------------+
|   Package    |    ID     |  Level   | Category |    Title     |   Message    |
| Coordinates  |           |          |          |              |              |
+==============+===========+==========+==========+==============+==============+
| https://pypi | BASIC003  | warning  | project  | No link to   | The project  |
| .org/pypi :: |           |          |          | codebase     | doesn't      |
| rdflib ::    |           |          |          |              | provide a    |
| 4.2.2        |           |          |          |              | link to its  |
|              |           |          |          |              | codebase.    |
+--------------+-----------+----------+----------+--------------+--------------+
| https://pypi | BASIC004  | warning  | project  | An artifact  | A package of |
| .org/pypi :: |           |          |          | has not been | type         |
| rdflib ::    |           |          |          | signed       | bdist_wheel  |
| 4.2.2        |           |          |          |              | has not been |
|              |           |          |          |              | signed       |
+--------------+-----------+----------+----------+--------------+--------------+
| https://pypi | BASIC004  | warning  | project  | An artifact  | A package of |
| .org/pypi :: |           |          |          | has not been | type sdist   |
| rdflib ::    |           |          |          | signed       | has not been |
| 4.2.2        |           |          |          |              | signed       |
+--------------+-----------+----------+----------+--------------+--------------+
| https://pypi | SPDX002   | info     | license  | SPDX License | Could not    |
| .org/pypi :: |           |          |          | not found    | map licence  |
| rdflib ::    |           |          |          |              | https://raw. |
| 4.2.2        |           |          |          |              | github.com/R |
|              |           |          |          |              | DFLib/rdflib |
|              |           |          |          |              | /master/LICE |
|              |           |          |          |              | NSE to an    |
|              |           |          |          |              | SPDX license |
+--------------+-----------+----------+----------+--------------+--------------+
| https://pypi | SAFETY001 | priority | security | Vulnerabilit | The CLI      |
| .org/pypi :: |           |          |          | y found      | tools in     |
| rdflib ::    |           |          |          |              | RDFLib 4.2.2 |
| 4.2.2        |           |          |          |              | can load     |
|              |           |          |          |              | Python       |
|              |           |          |          |              | modules from |
|              |           |          |          |              | the current  |
|              |           |          |          |              | working      |
|              |           |          |          |              | directory,   |
|              |           |          |          |              | allowing     |
|              |           |          |          |              | code         |
|              |           |          |          |              | injection,   |
|              |           |          |          |              | because      |
|              |           |          |          |              | "python -m"  |
|              |           |          |          |              | looks in     |
|              |           |          |          |              | this         |
|              |           |          |          |              | directory,   |
|              |           |          |          |              | as           |
|              |           |          |          |              | demonstrated |
|              |           |          |          |              | by rdf2dot.  |
+--------------+-----------+----------+----------+--------------+--------------+

You can run specific reports by listing them. In the command below I just ask for the report from the safety reporter:

valiant report rdflib 4.2.2 safety -s

For multiple reports, just use a comma separator:

valiant report rdflib 4.2.2 safety,basic -s

You can see the list of available reports by running the valiant config command.

JSON reports

You can get a copy of the report in JSON by setting the output:

valiant report rdflib 4.2.2 -o json

You can also produce a JSON-based findings report:

valiant report rdflib 4.2.2 -s -o json

As we saw in the test output examples, you can limit the reports you want:

valiant report rdflib 4.2.2 safety -s -o json

As a hint, it can be useful to pass the result to the handy jq tool:

poetry run valiant report flask 1.1.1 -o json | jq

This will give you something like:

[
  {
    "id": "SAFETY001",
    "coordinates": {
      "name": "rdflib",
      "version": "4.2.2",
      "repository_url": "https://pypi.org/pypi"
    },
    "level": "priority",
    "category": "security",
    "title": "Vulnerability found",
    "message": "The CLI tools in RDFLib 4.2.2 can load Python modules from the current working directory, allowing code injection, because \"python -m\" looks in this directory, as demonstrated by rdf2dot.",
    "data": {
      "name": "rdflib",
      "spec": "==4.2.2",
      "version": "4.2.2",
      "advisory": "The CLI tools in RDFLib 4.2.2 can load Python modules from the current working directory, allowing code injection, because \"python -m\" looks in this directory, as demonstrated by rdf2dot.",
      "vuln_id": "36882"
    },
    "url": "https://github.com/pyupio/safety-db"
  }
]

Auditing a project

An audit is essentially a review of multiple dependencies. Valiant uses a requirements file as input. Importantly, the packages listed in the requirements file must be pinned to a specific version. The example below illustrates how this looks:

click==7.1.1
flask==1.1.1
isodate==0.6.0
itsdangerous==1.1.0
jinja2==2.11.1
markupsafe==1.1.1
numpy==1.18.2
pandas==1.0.3
pyparsing==2.4.6
python-dateutil==2.8.1
pytz==2019.3
rdflib==4.2.2
six==1.14.0
werkzeug==1.0.0

Thankfully, Poetry's export command makes this easy and we'll use this in the walk-through.

Let's go through the steps of creating a small project and running an audit.

First of all, create a directory for the test project:

# Setup the project
mkdir test-valiant
cd test-valiant

Make sure you're running Python 3.8 (or greater). I use pyenv and this makes it easy:

pyenv local 3.8.2

Better still, create a virtualenv - see the instructions at the beginning of this page.

Now we set up the Poetry project and add some dependencies:

pip install poetry
poetry init -n

# Add some dependencies
poetry add flask rdflib pandas requests

It's now possible to export the pinned requirements file:

# Export the requirements file
poetry export --without-hashes --format requirements.txt --output requirements.txt

You can now run an audit of your dependencies with:

valiant audit requirements.txt

This will pump out a lot of information for you to sift through! It's basically a set of reports - much like running the valiant report command for each package.

If you just want to view the findings across all reports:

valiant audit requirements.txt -s

JSON audit reports

As with the one-off report, you can get the audit in JSON format:

poetry run valiant audit requirements.txt -o json

The findings-only listing is also available:

poetry run valiant audit requirements.txt -s -o json