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

fix #49 by improving tool invocation #53

Merged
merged 1 commit into from
Jan 13, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# CHANGELOG

* v5.0.2 in progress
* Address [#49](https://github.com/clj-holmes/clj-watson/issues/49) by improving the `-T` invocation to support short names, symbols for strings, and all the defaults.
* Address [#48](https://github.com/clj-holmes/clj-watson/issues/48) by updating all of the project dependencies, including DependencyCheck to 9.0.8.
* Address [#47](https://github.com/clj-holmes/clj-watson/issues/47) by printing out the optional properties read from the `clj-watson.properties` file.
* Documentation improvements.
Expand Down
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,19 @@ clojure -Tclj-watson scan :deps-edn-path '"deps.edn"' :output '"stdout"'
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)
The tool option keywords match the long-form CLI option names (see below)
but the abbreviations are also supported. In addition, any string option may
be specified as a bare Clojure symbol (if it is legally representable as such),
which means the above command-line can be simplified to just:

```bash
clojure -Tclj-watson scan :p deps.edn
```

`:output` can be omitted because it defaults to `stdout`, and `:deps-edn-path`
can be shortened to `:p` (matching the `-p` short form of `--deps-edn-path`).

> Note: `:aliases` (or `:a`) should be specified as a vector of keywords (or symbols), e.g., `:a '[:foo :bar]`, whereas it would be specified multiple times (as strings) in the regular CLI, `-a foo -a bar`.

# How it works

Expand Down Expand Up @@ -178,8 +190,13 @@ EDN-style options for the CLI tool which can be a bit unwieldy as present:

```bash
clojure -Tclj-watson scan '{:output "stdout" :fail-on-result true :deps-edn-path "deps.edn" :suggest-fix true :aliases ["*"] :database-strategy "dependency-check"}'
# or:
clojure -Tclj-watson scan :f true :p deps.edn :s true :a '[*]'
```

Both `:output` (`:o`) and `:database-strategy` (`:t`) can be omitted because
they default to `"stdout"` and `"dependency-check"` respectively.

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`:
Expand Down
45 changes: 5 additions & 40 deletions src/clj_watson/cli.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,11 @@
(:gen-class)
(:require
[cli-matic.core :as cli]
[clj-watson.cli-spec :refer [CONFIGURATION]]
[clj-watson.entrypoint :as entrypoint]))

(def CONFIGURATION
{:app {:command "clj-watson"
:description "run clj-holmes" :version (System/getProperty "clj-watson.version")}
:commands [{:command "scan"
:description "Performs a scan on a deps.edn file"
:opts [{:option "deps-edn-path" :short "p"
:type :string
:default :present
:as "path of deps.edn to scan."}
{:option "output" :short "o"
:type #{"json" "edn" "stdout" "stdout-simple" "sarif"} ; keep stdout type to avoid break current automations
:default "stdout"
:as "Output type."}
{:option "aliases" :short "a"
:type :string
:multiple true
:as "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."}
{:option "dependency-check-properties" :short "d"
:type :string
:default nil
:as "[ONLY APPLIED IF USING DEPENDENCY-CHECK STRATEGY] Path of a dependency-check properties file. If not provided uses resources/dependency-check.properties."}
{:option "clj-watson-properties" :short "w"
:type :string
:default nil
:as "[ONLY APPLIED IF USING DEPENDENCY-CHECK STRATEGY] Path of an additional, optional properties file."}
{:option "database-strategy" :short "t"
:type #{"dependency-check" "github-advisory"}
:default "dependency-check"
:as "Vulnerability database strategy."}
{:option "suggest-fix" :short "s"
:type :with-flag
:default false
:as "Suggest a new deps.edn file fixing all vulnerabilities found."}
{:option "fail-on-result" :short "f"
:type :with-flag
:default false
:as "Enable or disable fail if results were found (useful for CI/CD)."}]
:runs entrypoint/scan}]})

(defn -main [& args]
(cli/run-cmd args CONFIGURATION))
(cli/run-cmd args
(update-in CONFIGURATION
[:commands 0]
(assoc :runs entrypoint/scan))))
76 changes: 76 additions & 0 deletions src/clj_watson/cli_spec.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
(ns clj-watson.cli-spec)

(def CONFIGURATION
{:app {:command "clj-watson"
:description "run clj-holmes" :version (System/getProperty "clj-watson.version")}
:commands [{:command "scan"
:description "Performs a scan on a deps.edn file"
:opts [{:option "deps-edn-path" :short "p"
:type :string
:default :present
:as "path of deps.edn to scan."}
{:option "output" :short "o"
:type #{"json" "edn" "stdout" "stdout-simple" "sarif"} ; keep stdout type to avoid break current automations
:default "stdout"
:as "Output type."}
{:option "aliases" :short "a"
:type :string
:multiple true
:as "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."}
{:option "dependency-check-properties" :short "d"
:type :string
:default nil
:as "[ONLY APPLIED IF USING DEPENDENCY-CHECK STRATEGY] Path of a dependency-check properties file. If not provided uses resources/dependency-check.properties."}
{:option "clj-watson-properties" :short "w"
:type :string
:default nil
:as "[ONLY APPLIED IF USING DEPENDENCY-CHECK STRATEGY] Path of an additional, optional properties file."}
{:option "database-strategy" :short "t"
:type #{"dependency-check" "github-advisory"}
:default "dependency-check"
:as "Vulnerability database strategy."}
{:option "suggest-fix" :short "s"
:type :with-flag
:default false
:as "Suggest a new deps.edn file fixing all vulnerabilities found."}
{:option "fail-on-result" :short "f"
:type :with-flag
:default false
:as "Enable or disable fail if results were found (useful for CI/CD)."}]
;; injected by clj-watson.cli to avoid circular dependency:
:runs nil #_entrypoint/scan}]})

(def DEFAULTS
(into {}
(map (fn [{:keys [option default]}]
[(keyword option) (when-not (= default :present) default)]))
(-> CONFIGURATION :commands first :opts)))

(def ABBREVIATIONS
(into {}
(map (fn [{:keys [option short]}]
[(keyword short) (keyword option)]))
(-> CONFIGURATION :commands first :opts)))

(defn clean-options
"Implement defaults for tool invocation and allow for abbreviations and
symbols as strings."
[opts]
(into DEFAULTS
(comp (map (fn [[k v]] ; expand abbreviations first:
(if (and (contains? ABBREVIATIONS k)
(not (contains? opts (get ABBREVIATIONS k))))
[(get ABBREVIATIONS k) v]
[k v])))
(map (fn [[k v]] ; supply defaults:
(if (contains? DEFAULTS k)
[k (if (some? v) v (get DEFAULTS k))]
[k v])))
(map (fn [[k v]]
[k (if (symbol? v) (str v) v)])))
opts))

(comment
(clean-options {:p 'resources/deps.edn
:database-strategy 'dependency-check
:s true}))
2 changes: 1 addition & 1 deletion src/clj_watson/controller/dependency_check/scanner.clj
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
(if additional-properties-file-path
(->> add-props (.mergeProperties settings))
(some->> add-props slurp .getBytes ByteArrayInputStream. (.mergeProperties settings))))
(println "No additional properties found."))
(println "No additional properties found.\n"))
settings))

(defn ^:private build-engine [dependency-check-properties clj-watson-properties]
Expand Down
7 changes: 5 additions & 2 deletions src/clj_watson/entrypoint.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
(ns clj-watson.entrypoint
(:require
[clj-watson.adapter.config :as adapter.config]
[clj-watson.cli-spec :as cli-spec]
[clj-watson.controller.dependency-check.scanner :as controller.dc.scanner]
[clj-watson.controller.dependency-check.vulnerability :as controller.dc.vulnerability]
[clj-watson.controller.deps :as controller.deps]
Expand Down Expand Up @@ -38,8 +39,10 @@
(defmethod scan* :default [opts]
(scan* (assoc opts :database-strategy "dependency-check")))

(defn scan [{:keys [fail-on-result output deps-edn-path] :as opts}]
(let [vulnerabilities (scan* opts)
(defn scan [opts]
(let [opts (cli-spec/clean-options opts)
{:keys [fail-on-result output deps-edn-path]} opts
vulnerabilities (scan* opts)
contains-vulnerabilities? (->> vulnerabilities
(map (comp empty? :vulnerabilities))
(some false?))]
Expand Down
Loading