Skip to content

Commit

Permalink
overhaul readme (#50)
Browse files Browse the repository at this point in the history
* overhaul readme

Signed-off-by: Sean Corfield <sean@corfield.org>

* remove rcf

linter does not like trailing ) on a separate line anyway

Signed-off-by: Sean Corfield <sean@corfield.org>

---------

Signed-off-by: Sean Corfield <sean@corfield.org>
  • Loading branch information
seancorfield authored Jan 13, 2024
1 parent 68f85bb commit 673085b
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 68 deletions.
15 changes: 6 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
.clj-kondo/*/
.cpcache/
.hg/
.hgignore
.idea/
.lsp/
.portal/vs-code.edn
*.class
*.iml
*.jar
/.calva/output-window/
/.clj-kondo/.cache/
/.cpcache/
/.idea/
/.lein-*
/.lsp/.cache/
/.nrepl-port
/.portal/vs-code.edn
/.prepl-port
/checkouts
/classes
Expand All @@ -18,5 +17,3 @@ pom.xml
pom.xml.asc
profiles.clj
target/
.lsp/
.portal/
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# CHANGELOG

* v5.0.2 in progress
* Documentation improvements.

* v5.0.1 d1ec6e5 -- 2024-01-09
* Fix [#44](https://github.com/clj-holmes/clj-watson/issues/44) -- locating `clj-watson.properties` file.

Expand Down
223 changes: 165 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,43 @@
# clj-watson
Clojure's software composition analysis (SCA).
clj-watson scans dependencies in a clojure `deps.edn` seeking for vulnerable direct/transitive dependencies and build a report with all the information needed to help you understand how the vulnerability manifest in your software.

* v5.x.x -- uses DependencyCheck 9.0.x and the new NIST NVD API.
* v4.x.x -- uses an earlier version of DependencyCheck and the old NVD data feeds, which have been deprecated.
A Clojure tool for vulnerability checking.

`clj-watson` is a software composition analysis (SCA) tool, that scans
dependencies in a Clojure `deps.edn` file looking for vulnerable direct and
transitive dependencies, and builds a report with all the information needed
to help you understand how the vulnerabilities manifest in your software.

`clj-watson` can suggest a remediation for the vulnerabilities found,
and can check against both the
[NIST National Vulnerability Database (NVD)](https://nvd.nist.gov/)
(by default) and the
[GitHub Advisory Database](https://github.com/advisories)
(experimental).

## Quick Start

clj-watson can be added as an alias on a per-project basis in the project `deps.edn` file:
`clj-watson` can be added as an alias either on a per-project basis in the
project's `deps.edn` file or in your user `deps.edn` file
(either `~/.clojure/deps.edn` or `~/.config/clojure/deps.edn`):

```clojure
;; in :aliases
:clj-watson {:replace-deps {io.github.clj-holmes/clj-watson {:git/tag "v5.0.1" :git/sha "d1ec6e5"}}
;; in :aliases
:clj-watson {:replace-deps
{io.github.clj-holmes/clj-watson
{:git/tag "v5.0.1" :git/sha "d1ec6e5"}}
:main-opts ["-m" "clj-watson.cli" "scan"]}
```

Then run it with:
Then you can run it with:

```bash
clojure -M:clj-watson -p deps.edn
```

The first time it runs, it will download the vulnerability database, which can take a few minutes. Subsequent runs will be much faster.
The first time it runs, it will download the vulnerability database, which
can take a few minutes. Subsequent runs will be much faster.

> Note: the database is stored in the `/tmp/db/` folder (on macOS/Linux) - in case you ever need to delete that folder, if it looks like the database is corrupted.
It can also be installed as a Clojure CLI tool:

Expand All @@ -33,18 +49,30 @@ Then run it with:

```bash
clojure -Tclj-watson scan :deps-edn-path '"deps.edn"' :output '"stdout"'
#or:
# or:
clojure -Tclj-watson scan '{:deps-edn-path "deps.edn" :output "stdout"}'
```

(this is somewhat verbose now but it will be improved over the next few releases)

# How it works

## Vulnerability database strategies
clj-watson supports two methods for vulnerabilities scan.

### dependency-check
[dependency-check](https://github.com/jeremylong/DependencyCheck) is the most used method around the clojure/java sca tools, it downloads all vulnerabilities from nvd and stores it in a database (located in `/tmp/db`), compose a [cpe](https://nvd.nist.gov/products/cpe) based on the dependencies, scans all jars in the classpath and matches vulnerabilities using it.
`clj-watson` supports two methods for vulnerabilities scan.

### DependencyCheck

[DependencyCheck](https://github.com/jeremylong/DependencyCheck) is the most
widely used method among the Clojure/Java SCA tools. It downloads all
vulnerabilities from NVD and stores it in a database (located in the `/tmp/db/`
folder), composes a
[Common Platform Enumeration (CPE)](https://nvd.nist.gov/products/cpe) based on
the dependencies, scans all JARs in the classpath and matches vulnerabilities
using it.

* `clj-watson` v5.x.x uses DependencyCheck 9.0.x and the new NIST NVD API.
* `clj-watson` v4.x.x uses an earlier version of DependencyCheck and the old NVD data feeds, which have been deprecated.

#### NIST NVD API

Expand All @@ -68,16 +96,30 @@ command-line option:
nvd.api.key=...your key here...
```

### Github advisory database [experimental]
It doesn't need to download a database since it uses the [github advisory database](https://github.com/advisories) via the [graphql api](https://docs.github.com/en/graphql/reference/objects#securityvulnerability), matches are made via package name.
But there's a requirements to use it, it's necessary to generate a [Github PAT (Personal Access Token)](https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#authenticating-with-graphql) to access graphql api or if you use Github actions it's possible to use their Github token.
Another important thing is that the api has a limit of 5K requests per hour/per PAT.
If you create a PAT or uses the github action token just set it in as an environment variabe named `GITHUB_TOKEN` to clj-watson be able to use it.
### GitHub Advisory Database [experimental]

This approach doesn't need to download a database since it uses the
[GitHub Advisory Database](https://github.com/advisories) via its
[GraphQL API](https://docs.github.com/en/graphql/reference/objects#securityvulnerability),
and matches are made via package names.

In order to use this approach, it is necessary to generate a
[GitHub Personal Access Token (PAT)](https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#authenticating-with-graphql)
to access the GraphQL API, or if you use GitHub Actions it is possible to use
their GitHub token.

Another important thing to be aware of is that the API has a limit of 5,000
requests per hour/per PAT.

If you create a PAT or use the GitHub Action token, you can set it as an
environment variable named `GITHUB_TOKEN` and `clj-watson` will be able to use it.

#### Allow Listing Known CVE's

Sometimes the dependency tree is not under your control and overrides are not possible,
but you can allways allow a CVE for a limited period by adding a config file at `resources/clj-watson-config.edn`:
Sometimes the transitive dependency tree is not under your control and it is
not always possible to override versions of dependencies that are vulnerable.
You can allow a CVE for a limited period by adding a `clj-watson-config.edn`
configuration file to your classpath with the following structure:

```clojure
{:allow-list {:cves [{:cve-label "CVE-0000"
Expand All @@ -86,47 +128,91 @@ but you can allways allow a CVE for a limited period by adding a config file at
:expires "2000-01-01"}]}}
```

> Note: this is for the GitHub Advisory Database strategy only.
## Remediation suggestion
#### The big difference from clj-watson to other tools.
Since fixing the found vulnerabilities manually could be truly frustrating `clj-watson` provides a way to suggest a remediation.
It basically lookups the whole dependency tree finding if the latest version of a parent dependency uses the secure version of the child dependency until it reaches the direct dependency.

**The big difference between `clj-watson` and other tools!**

Since fixing the vulnerabilities found manually can be a truly frustrating
process `clj-watson` provides a way to suggest a remediation.

It performs lookups for the whole dependency tree, checking if the latest
version of a parent dependency uses the secure version of the child dependency
until it reaches the direct dependency.

Given the following dependency tree,
```

```clojure
[dependency-a "v1"]
[dependency-b "v1"]
[dependency-c "v1"]
```
where the `dependency-c` is vulnerable and to fix it is necessary to bump from `v1` to `v2` clj-watson will try to find a version of `dependency-a` that uses `dependency-b` in a version that uses `dependency-c` on version `v2` and then propose a bump to `dependency-a`.

where `dependency-c` is vulnerable and fixing it would require a bump from `v1`
to `v2`, `clj-watson` will try to find a version of `dependency-a` that uses
a version of `dependency-b` that uses `dependency-c` at version `v2`, and then
`clj-watson` will propose updating `dependency-a`.

```clojure
{dependency-a {:mvn/version "v4"}}
```
If clj-watson does not find a version of dependency-b or dependency-a that satisfies this statement it'll propose an exclusion.

If `clj-watson` does not find a version of `dependency-b` or `dependency-a` that
satisfies this condition, it will propose an exclusion instead:

```clojure
{dependency-a {:exclusions [dependency-b]}
dependency-b {:mvn/version "v3"}}
````
In order to get the auto remediate suggestion it's necessary to provide a `--suggest-fix|-s` on the clj-watson execution.
```

In order to get the automated remediation suggestions, provide
the `--suggest-fix` or `-s` option when running `clj-watson`.

# Installation
It's possible to install clj-watson as a clojure tool and invoke it.

`clj-watson` can be installed as a Clojure CLI tool, as shown above. While
this is the easiest way to install the latest version and keep it up-to-date
(using `clojure -Ttools install-latest`), it also means using the key/value
EDN-style options for the CLI tool which can be a bit unwieldy as present:

```bash
$ clojure -Ttools install io.github.clj-holmes/clj-watson '{:git/tag "v4.1.2" :git/sha "eb15492"}' :as clj-watson
$ clojure -Tclj-watson scan '{:output "stdout" :fail-on-result true :deps-edn-path "deps.edn" :suggest-fix true :aliases ["*"] :database-strategy "dependency-check"}'
clojure -Tclj-watson scan '{:output "stdout" :fail-on-result true :deps-edn-path "deps.edn" :suggest-fix true :aliases ["*"] :database-strategy "dependency-check"}'
```
It can also be called directly.

In addition to the CLI tool install, shown above, it can also be invoked
directly via the Clojure CLI, by specifying `clj-watson` as a dependency
via `-Sdeps`:

```bash
$ clojure -Sdeps '{:deps {io.github.clj-holmes/clj-watson {:git/tag "v5.0.1" :git/sha "d1ec6e5"}}}' -M -m clj-watson.cli scan -p deps.edn
clojure -Sdeps '{:deps {io.github.clj-holmes/clj-watson {:git/tag "v5.0.1" :git/sha "d1ec6e5"}}}' -M -m clj-watson.cli scan -p deps.edn
```
Or you can just add it to your project `deps.edn`
Or you can just add it to your `deps.edn` file as an alias:

```clojure
{:deps {}
:aliases
{:clj-watson {:extra-deps {io.github.clj-holmes/clj-watson {:git/tag "v5.0.1" :git/sha "d1ec6e5"}}
:main-opts ["-m" "clj-watson.cli" "scan"]}}}
```

and invoke it with:

```bash
clojure -M:clj-watson -p deps.edn
```

# CLI Options

You can get a full list of the available options by running:

```bash
$ clojure -M:clj-watson scan -\?
clojure -M:clj-watson scan -\?
```

This produces:

```
NAME:
clj-watson scan - Performs a scan on a deps.edn file
Expand All @@ -135,38 +221,46 @@ USAGE:
OPTIONS:
-p, --deps-edn-path S* path of deps.edn to scan.
-o, --output edn|json|stdout|stdout-simple|sarif report Output type.
-o, --output edn|json|sarif|stdout|stdout-simple stdout Output type.
-a, --aliases S Specify a alias that will have the dependencies analysed alongside with the project deps.It's possible to provide multiple aliases. If a * is provided all the aliases are going to be analysed.
-d, --dependency-check-properties S [ONLY APPLIED IF USING DEPENDENCY-CHECK STRATEGY] Path of a dependency-check properties file. If not provided uses resources/dependency-check.properties.
-w, --clj-watson-properties S [ONLY APPLIED IF USING DEPENDENCY-CHECK STRATEGY] Path of an additional, optional properties file.
-t, --database-strategy dependency-check|github-advisory dependency-check Vulnerability database strategy.
-s, --[no-]suggest-fix Suggest a new deps.edn file fixing all vulnerabilities found.
-f, --[no-]fail-on-result Enable or disable fail if results were found (useful for CI/CD).
-s, --[no-]suggest-fix false Suggest a new deps.edn file fixing all vulnerabilities found.
-f, --[no-]fail-on-result false Enable or disable fail if results were found (useful for CI/CD).
-?, --help
```

By default, when using the DEPENDENCY-CHECK strategy, clj-watson will load
By default, when using the DEPENDENCY-CHECK strategy, `clj-watson` will load
its own `dependency-check.properties` file, and then look for a
`clj-watson.properties` file on the classpath and load that if found, for
additional properties to apply to the dependency-check scan.
additional properties to apply to the DependencyCheck scan.

If you provide `-d` (or `--dependency-check-properties`) then clj-watson will
If you provide `-d` (or `--dependency-check-properties`) then `clj-watson` will
load that file instead of its own `dependency-check.properties` file so it
needs to be a complete properties file, not just the properties you want to
override.

If you provide `-w` (or `--clj-watson-properties`) then clj-watson will load
If you provide `-w` (or `--clj-watson-properties`) then `clj-watson` will load
that file and apply those properties to the dependency-check scan. This is
in addition to the properties loaded from the `dependency-check.properties`
or the `-d` file. This can be useful to override just a few properties.

# Execution
The minimum necessary to execute clj-watson is to provide the path to a `deps.edn` file, but it's recommended that you all provide the `-s` option so `clj-watson` will try to provide a remediation suggestion to the vulnerabilities.

The minimum needed to run `clj-watson` is to provide the path to a `deps.edn`
file, but it is recommended that you also provide the `-s` option so
`clj-watson` will try to suggest a remediation for any vulnerabilities found.

```bash
$ clojure -M:clj-watson -p deps.edn
clojure -M:clj-watson -p deps.edn
```
```
...
Downloading/Updating database.
Download/Update completed.
...
Dependency Information
-----------------------------------------------------
NAME: dependency-e
Expand All @@ -185,28 +279,41 @@ FIX SUGGESTION: {dependency-a {:mvn/version "3"}}
Vulnerabilities
-----------------------------------------------------
CVE: CVE-2022-1000000
CVSSV3: 7.5
CVSSV2: 5.0
SUGGESTED BUMP: 1.55
CVE: CVE-2022-2000000
CVSSV3: 5.3
CVSSV2: 5.0
SUGGESTED BUMP: 1.55
SEVERITY: Information not available.
IDENTIFIERS: CVE-2022-1000000
CVSS: 7.5
PATCHED VERSION: 1.55
SEVERITY: Information not available.
IDENTIFIERS: CVE-2022-2000000
CVSS: 5.3
PATCHED VERSION: 1.55
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
```

# Who uses it

- [180 Seguros](https://180s.com.br)
- [World Singles Networks](https://worldsinglesnetworks.com/)

# Development

## nREPL

```bash
clojure -M:nREPL -m nrepl.cmdline
```
clj -M:nREPL -m nrepl.cmdline
```

## Lint

```bash
clojure -M:clojure-lsp format
clojure -M:clojure-lsp clean-ns
```
clj -M:clojure-lsp format
clj -M:clojure-lsp clean-ns
```

# License and Copyright

Copyright © 2021-2024 Matheus Bernardes

Distributed under the Eclipse Public License version 2.0.
3 changes: 2 additions & 1 deletion src/clj_watson/entrypoint.clj
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@
(defmethod scan* :github-advisory [{:keys [deps-edn-path suggest-fix aliases]}]
(let [{:keys [deps dependencies]} (controller.deps/parse deps-edn-path aliases)
repositories (select-keys deps [:mvn/repos])
config (edn/read-string (slurp (io/resource "clj-watson-config.edn")))
config (when-let [config-file (io/resource "clj-watson-config.edn")]
(edn/read-string (slurp config-file)))
allow-list (adapter.config/config->allow-config-map config)
vulnerable-dependencies (controller.gh.vulnerability/scan-dependencies dependencies repositories allow-list)]
(if suggest-fix
Expand Down

0 comments on commit 673085b

Please sign in to comment.