Skip to content
Open
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
19 changes: 18 additions & 1 deletion .github/integration_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ CONFIG_FILE_USING_DEFAULT_FILENAME="$PROJECT_DIR/nvd-clojure.edn"
DOGFOODING_CONFIG_FILE="$PROJECT_DIR/.github/nvd-dogfooding-config.edn"
TOOLS_CONFIG_FILE="$PROJECT_DIR/.github/nvd-tool-config.edn"
DATAFEED_CONFIG_FILE="$PROJECT_DIR/.github/nvd-datafeed-config.edn"
NODE_AUDIT_CONFIG_FILE="$PROJECT_DIR/.github/nvd-node-audit-config.edn"

JSON_CONFIG_FILE="$PROJECT_DIR/.github/nvd-config.json"
JSON_DOGFOODING_CONFIG_FILE="$PROJECT_DIR/.github/nvd-dogfooding-config.json"
JSON_TOOLS_CONFIG_FILE="$PROJECT_DIR/.github/nvd-tool-config.json"

A_CUSTOM_CHANGE=":a-custom-change"
SUCCESS_REGEX="[1-9][0-9] vulnerabilities detected\. Severity: "
SUCCESS_REGEX="[1-9][0-9]* vulnerabilities detected\. Severity: "

if ! lein with-profile -user,-dev,+ci install; then
exit 1
Expand Down Expand Up @@ -123,6 +124,22 @@ if ! grep --silent "$SUCCESS_REGEX" test-output; then
exit 1
fi

# 1.5 - Exercise `main` program (non-default analyzer)

step_name=">>> [Step 1.5 lein & non-default analyzer]"

echo "$step_name starting..."

if lein with-profile -user,-dev,+ci run -m nvd.task.check "$NODE_AUDIT_CONFIG_FILE" example/package-lock.json > test-output; then
echo "$step_name Should have failed with non-zero code!"
exit 1
fi

if ! grep --silent "$SUCCESS_REGEX" test-output; then
echo "$step_name Should have found vulnerabilities!"
exit 1
fi

# cd to the root dir, so that one runs `defproject nvd-clojure` which is the most clean and realistic way to run `main`:
cd "$PROJECT_DIR" || exit 1

Expand Down
3 changes: 3 additions & 0 deletions .github/nvd-node-audit-config.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{:suppression-file ".github/example_nvd_suppressions.xml"
:analyzer {:ossindex-warn-only-on-remote-errors true
:node-audit-enabled true}}
225 changes: 225 additions & 0 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions example/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "example-with-known-vulnerabilities",
"version": "1.4.17",
"private": true,
"dependencies": {
"tar-fs": "2.1.3"
}
}
61 changes: 29 additions & 32 deletions src/nvd/task/check.clj
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,41 @@
[trptcolin.versioneer.core :refer [get-version]])
(:import
(java.io File)
(java.util.regex Pattern)
(org.owasp.dependencycheck Engine)
(org.owasp.dependencycheck.exception ExceptionCollection)))

(def version
(delay {:nvd-clojure (get-version "nvd-clojure" "nvd-clojure")
:dependency-check (.getImplementationVersion (.getPackage Engine))}))

(defn jar? [^String filename]
(.endsWith filename ".jar"))
(def classpath-separator-re
(re-pattern (Pattern/quote File/pathSeparator)))

(defn absolute-path ^String [file]
(s/replace-first file #"^~" (System/getProperty "user.home")))
(s/replace-first file #"^~(?=$|/)" (System/getProperty "user.home")))

(defn parse-classpath
"Accepts a classpath string (i.e. colon-separated paths) and returns a sequence of analyzable
absolute paths.

In particular, source paths such as `src`, while part of the classpath, won't be meaningfully
analyzed by dependency-check-core. We only care about regular files (e.g. *.jar or
package-lock.json). Thus, skip directories in general as well as non-existing files."
[classpath-string]
(into []
(comp (map absolute-path)
(remove (fn [^String s]
(let [file (io/file s)]
(or (.isDirectory file)
(not (.exists file)))))))
(s/split classpath-string classpath-separator-re)))

(defn- scan-and-analyze [project]
(let [^Engine engine (:engine project)]
;; See `parse-classpath` for details on which classpath entries are considered here.
(doseq [p (:classpath project)]
(when (jar? p)
(.scan engine (absolute-path p))))
(.scan engine (absolute-path p)))
(try
(.analyzeDependencies engine)
(catch ExceptionCollection e
Expand Down Expand Up @@ -94,25 +111,18 @@
fail-build?
conditional-exit)))

(def classpath-separator-re
(re-pattern (str File/pathSeparatorChar)))

(defn -main [& [config-filename ^String classpath-string]]
(when (s/blank? classpath-string)
(throw (ex-info "nvd-clojure requires a classpath value to be explicitly passed as a CLI argument.
Older usages are deprecated." {})))

(let [classpath (s/split classpath-string classpath-separator-re)
classpath (into []
(remove (fn [^String s]
;; Only .jar (and perhaps .zip) files are relevant.
;; source paths such as `src`, while are part of the classpath,
;; won't be meaningfully analyzed by dependency-check-core.
;; Keeping only .jars facilitates various usage patterns.
(let [file (io/file s)]
(or (.isDirectory file)
(not (.exists file))))))
classpath)]
(let [classpath (parse-classpath classpath-string)]

(when (empty? classpath)
(throw (ex-info "No entries in given classpath qualify for analysis.

Note that only regular files (non-directories) are considered."
{:classpath classpath-string})))

(when-not (System/getProperty "nvd-clojure.internal.skip-self-check")
(when-let [bad-entry (->> classpath
Expand All @@ -127,19 +137,6 @@ Please refer to the project's README for recommended usages."
{:bad-entry bad-entry
:classpath classpath-string}))))

;; perform some sanity checks for ensuring the calculated classpath has the expected format:
(let [f (-> classpath ^String (first) File.)]
(when-not (.exists f)
(throw (ex-info (str "The classpath variable should be a vector of simple strings denoting existing files: "
(pr-str f))
{}))))

(let [f (-> classpath ^String (last) File.)]
(when-not (.exists f)
(throw (ex-info (str "The classpath variable should be a vector of simple strings denoting existing files: "
(pr-str f))
{}))))

;; specifically handle blank strings (in addition to nil)
;; so that CLI callers can skip the first argument by simply passing an empty string:
(let [config-filename (if (s/blank? config-filename)
Expand Down
Loading