From ed32e48049f36a9b6b67d8f38a5bceef31f662ab Mon Sep 17 00:00:00 2001 From: Sean Corfield Date: Mon, 19 Aug 2024 14:57:58 -0700 Subject: [PATCH] fixes #104 by adding support for properties as env vars Signed-off-by: Sean Corfield --- README.md | 66 +++++++++++++++++-- .../controller/dependency_check/scanner.clj | 44 ++++++++++--- 2 files changed, 95 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 79b24cf..517d83b 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ clojure -M:clj-watson scan -p deps.edn The first time it runs, it will download the entire vulnerability database, which can take several minutes. Subsequent runs will be much faster. -> [!NOTE] +> [!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. `clj-watson` can also be installed as a Clojure CLI tool: @@ -105,7 +105,8 @@ It is easy to [request an API key](https://github.com/jeremylong/DependencyCheck You can specify you key via: 1. The `nvd.api.key` Java system property on the command line -2. Or, an `nvd.api.key` entry in your `clj-watson.properties` file +2. Or, the `CLJ_WATSON_NVD_API_KEY` environment variable +3. Or, an `nvd.api.key` entry in your `clj-watson.properties` file > [!CAUTION] > Keeping your nvd api key secret is your responsibility. @@ -129,7 +130,39 @@ clojure -J-Dnvd.api.key= -Tclj-watson scan :p deps.edn Replace `` with your actual api key. > [!CAUTION] -> You could specify this system property under `:jvm-opts` in your `deps.edn` under your `:clj-watson` alias, but be careful not to commit it to version control. +> You could specify this system property under `:jvm-opts` in your `deps.edn` under your `:clj-watson` alias, but be careful not to commit it to version control. + +##### Via Environment Variable + +Example usage: + +```shell +CLJ_WATSON_NVD_API_KEY= clojure -M:clj-watson scan -p deps.edn +``` + +Or: + +```shell +export CLJ_WATSON_NVD_API_KEY= + +clojure -M:clj-watson scan -p deps.edn +``` + +Or: + +```shell +CLJ_WATSON_NVD_API_KEY= clojure -Tclj-watson scan :p deps.edn +``` + +Or: + +```shell +export CLJ_WATSON_NVD_API_KEY= + +clojure -Tclj-watson scan :p deps.edn +``` + +Replace `` with your actual api key. ##### Via the `clj-watson.properties` File @@ -154,7 +187,7 @@ Or: clojure -Tclj-watson scan :p deps.edn :clj-watson-properties ./clj-watson.properties ``` -> [!CAUTION] +> [!CAUTION] > Be careful not to commit your key to version control. ### GitHub Advisory Database [experimental] @@ -233,7 +266,7 @@ the `--suggest-fix` or `-s` option when running `clj-watson`. # Installation > [!IMPORTANT] -> You'll need to [setup your NVD API key](#nist-nvd-api). +> You'll need to [setup your NVD API key](#nist-nvd-api). `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 @@ -309,6 +342,8 @@ OPTIONS valid when database-strategy is dependency-check: See docs for configuration. [false] ``` +## Properties + 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 @@ -324,6 +359,24 @@ 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. +In addition, relevant properties provided as Java system properties are +read by the underlying DependencyCheck scan, and take precedence over the +properties provided in these files. See the `-Dnvd.api.key=` example above. + +## Environment Variables + +`clj-watson` also supports environment variables that start with `CLJ_WATSON_`. +These are used to set properties that are not provided on the command line. +The `CLJ_WATSON_` prefix is removed, and the rest of the name is converted to +a lowercase property name with `_` replaced by `.` (e.g., `CLJ_WATSON_NVD_API_KEY`). +To specify a property name that contains an underscore, use two underscores +in the environment variable name, e.g., `CLJ_WATSON_DATA_FILE__NAME` to +set the `data.file_name` property. + +Properties set via environment variables take precedence over those set in +the properties files described above, but not over Java system properties +set on the command-line. + # Execution The minimum needed to run `clj-watson` is to provide the path to a `deps.edn` @@ -331,7 +384,7 @@ file, but it is recommended that you also provide the `-s` option so `clj-watson` will try to suggest remediations for any vulnerabilities found. > [!IMPORTANT] -> You'll need to first [setup your NVD API key](#nist-nvd-api). +> You'll need to first [setup your NVD API key](#nist-nvd-api). ```bash clojure -M:clj-watson -p deps.edn @@ -383,6 +436,7 @@ It writes settings and vulnerability findings to `stdout`. # Who uses it - [180 Seguros](https://180s.com.br) +- [org.clojure/tools.deps](https://github.com/clojure/tools.deps) - [World Singles Networks](https://worldsinglesnetworks.com/) # Development diff --git a/src/clj_watson/controller/dependency_check/scanner.clj b/src/clj_watson/controller/dependency_check/scanner.clj index 624b8f8..b244503 100644 --- a/src/clj_watson/controller/dependency_check/scanner.clj +++ b/src/clj_watson/controller/dependency_check/scanner.clj @@ -21,16 +21,41 @@ ;; ensure (fake) API key is redacted: (sanitize-property "nvd.api.key=72a48765-90ab-5678-abcd-1234abcd5489")) +(defn ^:private env-var->property [env-var] + (-> env-var + (string/replace #"^CLJ_WATSON_" "") ; strip prefix + (string/lower-case) ; lowercase + (string/replace "_" ".") ; _ -> . + (string/replace ".." "_"))) ; allow __ -> .. -> _ + +(comment + (env-var->property "CLJ_WATSON_NVD_API_KEY") + (env-var->property "CLJ_WATSON_DATA_FILE__NAME") + ) + +(defn ^:private set-watson-env-vars-as-properties [] + (run! (fn [[env-var value]] + (when (string/starts-with? env-var "CLJ_WATSON_") + (let [property (env-var->property env-var) + p-value (System/getProperty property)] + (if p-value + (println (str "Ignoring " env-var " as " property " is already set.")) + (do + (println (str "Setting " property " from " env-var ".")) + (System/setProperty property value)))))) + (System/getenv)) + (println)) + (defn ^:private create-settings [^String properties-file-path ^String additional-properties-file-path] - (let [settings (Settings.)] - (let [props - (if properties-file-path - (->> properties-file-path File.) - (->> "dependency-check.properties" io/resource))] - (println (str "\nRead " (count (line-seq (io/reader props))) " dependency-check properties.")) - (if properties-file-path - (->> props (.mergeProperties settings)) - (->> props slurp .getBytes ByteArrayInputStream. (.mergeProperties settings)))) + (let [settings (Settings.) + props + (if properties-file-path + (->> properties-file-path File.) + (->> "dependency-check.properties" io/resource))] + (println (str "\nRead " (count (line-seq (io/reader props))) " dependency-check properties.")) + (if properties-file-path + (->> props (.mergeProperties settings)) + (->> props slurp .getBytes ByteArrayInputStream. (.mergeProperties settings))) (if-let [add-props (if additional-properties-file-path (->> additional-properties-file-path File.) @@ -50,6 +75,7 @@ (->> add-props (.mergeProperties settings)) (some->> add-props slurp .getBytes ByteArrayInputStream. (.mergeProperties settings)))) (println "No additional properties found.\n")) + (set-watson-env-vars-as-properties) settings)) (defn ^:private validate-settings