From 38604389031a626c04ef4edae8f71de299cdacd8 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 13:18:06 +1000 Subject: [PATCH 01/16] Test travis docker --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2452b5b..f6a2e8c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,11 +5,17 @@ python: - 2.7 env: - TEST_PATH=tests/data + +services: + - docker # - 3.6 #matrix: # allow_failures: # - python: 3.6 - Commenting out testing for Python 3.6 until ready +before_install: + - docker build -t vulnwhisperer-local + - docker-compose -f docker-compose-test.yml up install: - pip install -r requirements.txt - pip install flake8 # pytest # add another testing frameworks later From 0102ccb2f71936e6f621bff50eee6de1f7021c53 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 13:47:53 +1000 Subject: [PATCH 02/16] Fix build command --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f6a2e8c..795e02e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ services: # - python: 3.6 - Commenting out testing for Python 3.6 until ready before_install: - - docker build -t vulnwhisperer-local + - docker build -t vulnwhisperer-local . - docker-compose -f docker-compose-test.yml up install: - pip install -r requirements.txt From bfcb10ea0ed41d9f6744cd22d59d9147eb7925b8 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 13:57:53 +1000 Subject: [PATCH 03/16] Fix permissions for ES --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 795e02e..316d5f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,9 @@ services: # - python: 3.6 - Commenting out testing for Python 3.6 until ready before_install: + - mkdir -p ./data/esdata1 + - mkdir -p ./data/es_snapshots + - chown 1000:1000 ./data/es* - docker build -t vulnwhisperer-local . - docker-compose -f docker-compose-test.yml up install: From 5828d05627c3783200e33f7fb7037e75bba3ccd8 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 14:00:54 +1000 Subject: [PATCH 04/16] fix --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 316d5f1..ed51366 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ services: before_install: - mkdir -p ./data/esdata1 - mkdir -p ./data/es_snapshots - - chown 1000:1000 ./data/es* + - chown -R 1000:1000 ./data/es* - docker build -t vulnwhisperer-local . - docker-compose -f docker-compose-test.yml up install: From 47a96a2984b2e49a502faa7b0ea4319367db95a1 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 15:10:45 +1000 Subject: [PATCH 05/16] sudo chown --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ed51366..e7475e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ services: before_install: - mkdir -p ./data/esdata1 - mkdir -p ./data/es_snapshots - - chown -R 1000:1000 ./data/es* + - sudo chown -R 1000:1000 ./data/es* - docker build -t vulnwhisperer-local . - docker-compose -f docker-compose-test.yml up install: From e0de8c6818d1402c4d654f3bd585c062793a1b64 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 17:24:59 +1000 Subject: [PATCH 06/16] Expose Logstash API port --- docker-compose-test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker-compose-test.yml b/docker-compose-test.yml index 9beb9fc..a29ecc5 100644 --- a/docker-compose-test.yml +++ b/docker-compose-test.yml @@ -67,6 +67,8 @@ services: - xpack.monitoring.enabled=false depends_on: - elasticsearch + ports: + - 9600:9600 networks: esnet: aliases: From a7ae44f981aff5cf850ab0422a2fa0a55aca57ad Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 17:25:44 +1000 Subject: [PATCH 07/16] Add docker test script --- .travis.yml | 3 +- tests/test-docker.sh | 90 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100755 tests/test-docker.sh diff --git a/.travis.yml b/.travis.yml index e7475e2..2627b5e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ before_install: - mkdir -p ./data/es_snapshots - sudo chown -R 1000:1000 ./data/es* - docker build -t vulnwhisperer-local . - - docker-compose -f docker-compose-test.yml up + - docker-compose -f docker-compose-test.yml up -d install: - pip install -r requirements.txt - pip install flake8 # pytest # add another testing frameworks later @@ -48,6 +48,7 @@ script: # Test only qualy_vuln - rm -rf /tmp/VulnWhisperer - vuln_whisperer -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] + - bash tests/test-docker.sh notifications: on_success: change on_failure: change # `always` will be the setting once code changes slow down diff --git a/tests/test-docker.sh b/tests/test-docker.sh new file mode 100755 index 0000000..14a7c47 --- /dev/null +++ b/tests/test-docker.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +NORMAL=$(tput sgr0) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +RED=$(tput setaf 1) + +function red() { + echo -e "$RED$*$NORMAL" +} + +function green() { + echo -e "$GREEN$*$NORMAL" +} + +function yellow() { + echo -e "$YELLOW$*$NORMAL" +} + +elasticsearch_url="localhost:9200" +logstash_url="localhost:9600" + +until curl -s "$elasticsearch_url/_cluster/health?pretty" | grep '"status"' | grep -qE "green|yellow"; do + curl -s "$elasticsearch_url/_cluster/health?pretty" + yellow "\nWaiting for Elasticsearch..." + sleep 5 +done +curl -s "$elasticsearch_url/_cluster/health?pretty" + +until [[ $(curl -s "$logstash_url/_node/stats" | jq '.events.out') == 1236 ]] ; do + curl -s "$logstash_url/_node/stats" | jq '.events' + yellow "\nWaiting for Logstash load to finish..." + sleep 10 +done + +return_code=0 + +if [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then + green "✅ Passed logstash-vulnwhisperer-2019.03 document count == 1232" +else + red "❌ Failed logstash-vulnwhisperer-2019.03 document count == 1232 was: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count") instead" + ((return_code = return_code + 1)) +fi + +# Test Nessus plugin_name:Backported Security Patch Detection (FTP) +nessus_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=plugin_name:%22Backported%20Security%20Patch%20Detection%20(FTP)%22%20AND%20asset:176.28.50.164%20AND%20tags:nessus" | jq '.hits.hits[]._source') +if echo $nessus_doc | jq '.risk' | grep -q "None"; then + green "✅ Passed Nessus risk == None" +else + red "❌ Failed Nessus risk == None was: $(echo $nessus_doc | jq '.risk') instead" + ((return_code = return_code + 1)) +fi + +# Test Tenable plugin_name:Backported Security Patch Detection (FTP) +tenable_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=plugin_name:%22Backported%20Security%20Patch%20Detection%20(FTP)%22%20AND%20asset:176.28.50.164%20AND%20tags:tenable" | jq '.hits.hits[]._source') +# Test asset +if echo $tenable_doc | jq .asset | grep -q '176.28.50.164'; then + green "✅ Passed Tenable asset == 2019-03-30T10:17:41.000Z" +else + red "❌ Failed Tenable asset == 176.28.50.164 was: $(echo $tenable_doc | jq .asset) instead" + ((return_code = return_code + 1)) +fi + +# Test @timestamp +if echo $tenable_doc | jq '.["@timestamp"]' | grep -q '2019-03-30T15:45:44.000Z'; then + green "✅ Passed Tenable @timestamp == 2019-03-30T10:17:41.000Z" +else + red "❌ Failed Tenable @timestamp == 2019-03-30T15:45:44.000Z was: $(echo $tenable_doc | jq '.["@timestamp"]') instead" + ((return_code = return_code + 1)) +fi + +# Test Qualys plugin_name:OpenSSL Multiple Remote Security Vulnerabilities +qualys_vuln_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=tags:qualys_vuln%20AND%20ip:%22176.28.50.164%22%20AND%20plugin_name:%22OpenSSL%20Multiple%20Remote%20Security%20Vulnerabilities%22%20AND%20port:465" | jq '.hits.hits[]._source') +# Test @timestamp +if echo $qualys_vuln_doc | jq '.["@timestamp"]' | grep -q '2019-03-30T10:17:41.000Z'; then + green "✅ Passed Qualys VM @timestamp == 2019-03-30T10:17:41.000Z" +else + red "❌ Failed Qualys VM @timestamp == 2019-03-30T10:17:41.000Z was: $(echo $qualys_vuln_doc | jq '.["@timestamp"]') instead" + ((return_code = return_code + 1)) +fi + +# Test @XXXX +if echo $qualys_vuln_doc | jq '.cvss' | grep -q '6.8'; then + green "✅ Passed Qualys VM cvss == 6.8" +else + red "❌ Failed Qualys VM cvss == 6.8 was: $(echo $qualys_vuln_doc | jq '.cvss') instead" + ((return_code = return_code + 1)) +fi + +exit $return_code From c3fb65e67a607cc835b1dd38abef43a79fa13328 Mon Sep 17 00:00:00 2001 From: pemontto Date: Tue, 16 Apr 2019 17:33:30 +1000 Subject: [PATCH 08/16] Update test --- .travis.yml | 12 ++++++------ tests/test-docker.sh | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2627b5e..f16b0b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,23 +31,23 @@ script: - python setup.py install # Test successful scan download and parsing - rm -rf /tmp/VulnWhisperer - - vuln_whisperer -c configs/test.ini --mock --mock_dir ${TEST_PATH} + - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH} # Run a second time with no scans to import - - vuln_whisperer -c configs/test.ini --mock --mock_dir ${TEST_PATH} + - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH} # Test one failed scan - rm -rf /tmp/VulnWhisperer - rm -f ${TEST_PATH}/nessus/GET_scans_exports_164_download - - vuln_whisperer -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] + - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] # Test two failed scans - rm -rf /tmp/VulnWhisperer - rm -f ${TEST_PATH}/qualys_vuln/scan_1553941061.87241 - - vuln_whisperer -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]] + - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]] # Test only nessus - rm -rf /tmp/VulnWhisperer - - vuln_whisperer -c configs/test.ini -s nessus --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] + - vuln_whisperer -F -c configs/test.ini -s nessus --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] # Test only qualy_vuln - rm -rf /tmp/VulnWhisperer - - vuln_whisperer -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] + - vuln_whisperer -F -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] - bash tests/test-docker.sh notifications: on_success: change diff --git a/tests/test-docker.sh b/tests/test-docker.sh index 14a7c47..a101513 100755 --- a/tests/test-docker.sh +++ b/tests/test-docker.sh @@ -21,14 +21,14 @@ elasticsearch_url="localhost:9200" logstash_url="localhost:9600" until curl -s "$elasticsearch_url/_cluster/health?pretty" | grep '"status"' | grep -qE "green|yellow"; do - curl -s "$elasticsearch_url/_cluster/health?pretty" + yellow $(curl -s "$elasticsearch_url/_cluster/health?pretty") yellow "\nWaiting for Elasticsearch..." sleep 5 done curl -s "$elasticsearch_url/_cluster/health?pretty" until [[ $(curl -s "$logstash_url/_node/stats" | jq '.events.out') == 1236 ]] ; do - curl -s "$logstash_url/_node/stats" | jq '.events' + yellow $(curl -s "$logstash_url/_node/stats" | jq '.events') yellow "\nWaiting for Logstash load to finish..." sleep 10 done From e30dbe244b3ce0c05b7c9ea4780b62c0d5ab33b6 Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 08:19:49 +1000 Subject: [PATCH 09/16] standardise /tmp to /opt --- .travis.yml | 10 +++++----- Dockerfile | 3 +-- configs/test.ini | 28 ++++++++++++++-------------- resources/elk6/init_kibana.sh | 6 +++--- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index f16b0b3..ea759ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,23 +30,23 @@ before_script: script: - python setup.py install # Test successful scan download and parsing - - rm -rf /tmp/VulnWhisperer + - rm -rf /opt/VulnWhisperer - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH} # Run a second time with no scans to import - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH} # Test one failed scan - - rm -rf /tmp/VulnWhisperer + - rm -rf /opt/VulnWhisperer - rm -f ${TEST_PATH}/nessus/GET_scans_exports_164_download - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] # Test two failed scans - - rm -rf /tmp/VulnWhisperer + - rm -rf /opt/VulnWhisperer - rm -f ${TEST_PATH}/qualys_vuln/scan_1553941061.87241 - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]] # Test only nessus - - rm -rf /tmp/VulnWhisperer + - rm -rf /opt/VulnWhisperer - vuln_whisperer -F -c configs/test.ini -s nessus --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] # Test only qualy_vuln - - rm -rf /tmp/VulnWhisperer + - rm -rf /opt/VulnWhisperer - vuln_whisperer -F -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] - bash tests/test-docker.sh notifications: diff --git a/Dockerfile b/Dockerfile index a2806ee..667cba1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,8 +20,7 @@ RUN python setup.py clean --all && \ WORKDIR /opt/VulnWhisperer -RUN python setup.py install && \ - ln -s /opt/VulnWhisperer /tmp/VulnWhisperer +RUN python setup.py install CMD vuln_whisperer -c /opt/VulnWhisperer/frameworks_example.ini diff --git a/configs/test.ini b/configs/test.ini index b8ce72f..b5f04b5 100755 --- a/configs/test.ini +++ b/configs/test.ini @@ -4,8 +4,8 @@ hostname=nessus port=443 username=nessus_username password=nessus_password -write_path=/tmp/VulnWhisperer/data/nessus/ -db_path=/tmp/VulnWhisperer/data/database +write_path=/opt/VulnWhisperer/data/nessus/ +db_path=/opt/VulnWhisperer/data/database trash=false verbose=true @@ -15,8 +15,8 @@ hostname=tenable port=443 username=tenable.io_username password=tenable.io_password -write_path=/tmp/VulnWhisperer/data/tenable/ -db_path=/tmp/VulnWhisperer/data/database +write_path=/opt/VulnWhisperer/data/tenable/ +db_path=/opt/VulnWhisperer/data/database trash=false verbose=true @@ -26,8 +26,8 @@ enabled = false hostname = qualys_web username = exampleuser password = examplepass -write_path=/tmp/VulnWhisperer/data/qualys_web/ -db_path=/tmp/VulnWhisperer/data/database +write_path=/opt/VulnWhisperer/data/qualys_web/ +db_path=/opt/VulnWhisperer/data/database verbose=true # Set the maximum number of retries each connection should attempt. @@ -42,8 +42,8 @@ enabled = true hostname = qualys_vuln username = exampleuser password = examplepass -write_path=/tmp/VulnWhisperer/data/qualys_vuln/ -db_path=/tmp/VulnWhisperer/data/database +write_path=/opt/VulnWhisperer/data/qualys_vuln/ +db_path=/opt/VulnWhisperer/data/database verbose=true [detectify] @@ -54,8 +54,8 @@ hostname = detectify username = exampleuser #password variable used as secretKey password = examplepass -write_path =/tmp/VulnWhisperer/data/detectify/ -db_path = /tmp/VulnWhisperer/data/database +write_path =/opt/VulnWhisperer/data/detectify/ +db_path = /opt/VulnWhisperer/data/database verbose = true [openvas] @@ -64,8 +64,8 @@ hostname = openvas port = 4000 username = exampleuser password = examplepass -write_path=/tmp/VulnWhisperer/data/openvas/ -db_path=/tmp/VulnWhisperer/data/database +write_path=/opt/VulnWhisperer/data/openvas/ +db_path=/opt/VulnWhisperer/data/database verbose=true [jira] @@ -73,8 +73,8 @@ enabled = false hostname = jira-host username = username password = password -write_path = /tmp/VulnWhisperer/data/jira/ -db_path = /tmp/VulnWhisperer/data/database +write_path = /opt/VulnWhisperer/data/jira/ +db_path = /opt/VulnWhisperer/data/database verbose = true dns_resolv = False diff --git a/resources/elk6/init_kibana.sh b/resources/elk6/init_kibana.sh index eca079d..656160c 100755 --- a/resources/elk6/init_kibana.sh +++ b/resources/elk6/init_kibana.sh @@ -12,7 +12,7 @@ saved_objects_file="kibana_APIonly.json" until curl -s "$elasticsearch_url/_cluster/health?pretty" | grep '"status"' | grep -qE "green|yellow"; do curl -s "$elasticsearch_url/_cluster/health?pretty" - echo "Waiting for Elasticsearch" + echo "Waiting for Elasticsearch..." sleep 5 done @@ -30,8 +30,8 @@ else fi until [ "`curl -s -I "$kibana_url"/status | head -n1 |cut -d$' ' -f2`" == "200" ]; do - curl -I "$kibana_url"/status - echo "Waiting for Kibana" + curl -s -I "$kibana_url"/status + echo "Waiting for Kibana..." sleep 5 done From bb60fae67e49d6f60f292455445725e5eb31be43 Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 08:24:08 +1000 Subject: [PATCH 10/16] Move vulnwhisperer tests to a script --- .travis.yml | 20 +------- tests/test-docker.sh | 11 ++--- tests/test-vuln_whisperer.sh | 90 ++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+), 25 deletions(-) create mode 100755 tests/test-vuln_whisperer.sh diff --git a/.travis.yml b/.travis.yml index ea759ab..d98caaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,25 +29,7 @@ before_script: - flake8 . --count --exit-zero --exclude=deps/qualysapi --max-complexity=10 --max-line-length=127 --statistics script: - python setup.py install - # Test successful scan download and parsing - - rm -rf /opt/VulnWhisperer - - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH} - # Run a second time with no scans to import - - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH} - # Test one failed scan - - rm -rf /opt/VulnWhisperer - - rm -f ${TEST_PATH}/nessus/GET_scans_exports_164_download - - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] - # Test two failed scans - - rm -rf /opt/VulnWhisperer - - rm -f ${TEST_PATH}/qualys_vuln/scan_1553941061.87241 - - vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]] - # Test only nessus - - rm -rf /opt/VulnWhisperer - - vuln_whisperer -F -c configs/test.ini -s nessus --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] - # Test only qualy_vuln - - rm -rf /opt/VulnWhisperer - - vuln_whisperer -F -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]] + - bash tests/test-vuln_whisperer.sh - bash tests/test-docker.sh notifications: on_success: change diff --git a/tests/test-docker.sh b/tests/test-docker.sh index a101513..c50b881 100755 --- a/tests/test-docker.sh +++ b/tests/test-docker.sh @@ -17,23 +17,22 @@ function yellow() { echo -e "$YELLOW$*$NORMAL" } +return_code=0 + elasticsearch_url="localhost:9200" logstash_url="localhost:9600" until curl -s "$elasticsearch_url/_cluster/health?pretty" | grep '"status"' | grep -qE "green|yellow"; do - yellow $(curl -s "$elasticsearch_url/_cluster/health?pretty") - yellow "\nWaiting for Elasticsearch..." + yellow "Waiting for Elasticsearch..." sleep 5 done curl -s "$elasticsearch_url/_cluster/health?pretty" until [[ $(curl -s "$logstash_url/_node/stats" | jq '.events.out') == 1236 ]] ; do - yellow $(curl -s "$logstash_url/_node/stats" | jq '.events') - yellow "\nWaiting for Logstash load to finish..." + yellow "Waiting for Logstash load to finish..." sleep 10 done - -return_code=0 +curl -s "$logstash_url/_node/stats" | jq '.events' if [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then green "✅ Passed logstash-vulnwhisperer-2019.03 document count == 1232" diff --git a/tests/test-vuln_whisperer.sh b/tests/test-vuln_whisperer.sh new file mode 100755 index 0000000..77f2e72 --- /dev/null +++ b/tests/test-vuln_whisperer.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +NORMAL=$(tput sgr0) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +RED=$(tput setaf 1) + +function red() { + echo -e "$RED$*$NORMAL" +} + +function green() { + echo -e "$GREEN$*$NORMAL" +} + +function yellow() { + echo -e "$YELLOW$*$NORMAL" +} + +return_code=0 + +yellow "\n*********************************************" +yellow "* Test successful scan download and parsing *" +yellow "*********************************************" +rm -rf /opt/VulnWhisperer/* +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; then + green "\n✅ Passed: Test successful scan download and parsing" +else + red "\n❌ Failed: Test successful scan download and parsing" + ((return_code = return_code + 1)) +fi + +yellow "\n*********************************************" +yellow "* Test run with no scans to import *" +yellow "*********************************************" +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; then + green "\n✅ Passed: Test run with no scans to import" +else + red "\n❌ Failed: Test run with no scans to import" + ((return_code = return_code + 1)) +fi + +yellow "\n*********************************************" +yellow "* Test one failed scan *" +yellow "*********************************************" +rm -rf /opt/VulnWhisperer/* +rm -f ${TEST_PATH}/nessus/GET_scans_exports_164_download +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then + green "\n✅ Passed: Test one failed scan" +else + red "\n❌ Failed: Test one failed scan" + ((return_code = return_code + 1)) +fi + +yellow "\n*********************************************" +yellow "* Test two failed scans *" +yellow "*********************************************" +rm -rf /opt/VulnWhisperer/* +rm -f ${TEST_PATH}/qualys_vuln/scan_1553941061.87241 +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]]; then + green "\n✅ Passed: Test two failed scans" +else + red "\n❌ Failed: Test two failed scans" + ((return_code = return_code + 1)) +fi + +yellow "\n*********************************************" +yellow "* Test only nessus with one failed scan *" +yellow "*********************************************" +rm -rf /opt/VulnWhisperer/* +if vuln_whisperer -F -c configs/test.ini -s nessus --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then + green "\n✅ Passed: Test only nessus with one failed scan" +else + red "\n❌ Failed: Test only nessus with one failed scan" + ((return_code = return_code + 1)) +fi + +echo -e "\n\n" +yellow "*********************************************" +yellow "* Test only Qualys VM with one failed scan *" +yellow "*********************************************" +rm -rf /opt/VulnWhisperer/* +if vuln_whisperer -F -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then + green "\n✅ Passed: Test only Qualys VM with one failed scan" +else + red "\n❌ Failed: Test only Qualys VM with one failed scan" + ((return_code = return_code + 1)) +fi + +exit $return_code \ No newline at end of file From 60b9e2b3d9c32778cc043d28606dfcf600a23cce Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 09:25:36 +1000 Subject: [PATCH 11/16] Test updates --- tests/test-docker.sh | 49 +++++++++++++++++++++++------------- tests/test-vuln_whisperer.sh | 3 ++- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/tests/test-docker.sh b/tests/test-docker.sh index c50b881..e9ed789 100755 --- a/tests/test-docker.sh +++ b/tests/test-docker.sh @@ -26,27 +26,42 @@ until curl -s "$elasticsearch_url/_cluster/health?pretty" | grep '"status"' | gr yellow "Waiting for Elasticsearch..." sleep 5 done -curl -s "$elasticsearch_url/_cluster/health?pretty" +green "✅ Elasticsearch status is green..." +count=0 until [[ $(curl -s "$logstash_url/_node/stats" | jq '.events.out') == 1236 ]] ; do - yellow "Waiting for Logstash load to finish..." + yellow "Waiting for Logstash load to finish... attempt $count of 30" + ((count++)) && ((count!=30)) && break sleep 10 done -curl -s "$logstash_url/_node/stats" | jq '.events' +green "✅ Logstash load finished..." -if [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then - green "✅ Passed logstash-vulnwhisperer-2019.03 document count == 1232" +count=0 +curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count' +until [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]] ; do + yellow "Waiting for Elasticsearch index to sync... $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') of 1232" + ((count++)) && ((count==30)) && break + sleep 2 +done +if [[ count -le 30 ]]; then + green "✅ logstash-vulnwhisperer-2019.03 document count == 1232" else - red "❌ Failed logstash-vulnwhisperer-2019.03 document count == 1232 was: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count") instead" - ((return_code = return_code + 1)) + red "❌ TIMED OUT waitin for logstash-vulnwhisperer-2019.03 document count: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq) != 1232" fi +# if [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then +# green "✅ Passed: logstash-vulnwhisperer-2019.03 document count == 1232" +# else +# red "❌ Failed: logstash-vulnwhisperer-2019.03 document count == 1232 was: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count") instead" +# ((return_code = return_code + 1)) +# fi + # Test Nessus plugin_name:Backported Security Patch Detection (FTP) nessus_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=plugin_name:%22Backported%20Security%20Patch%20Detection%20(FTP)%22%20AND%20asset:176.28.50.164%20AND%20tags:nessus" | jq '.hits.hits[]._source') if echo $nessus_doc | jq '.risk' | grep -q "None"; then - green "✅ Passed Nessus risk == None" + green "✅ Passed: Nessus risk == None" else - red "❌ Failed Nessus risk == None was: $(echo $nessus_doc | jq '.risk') instead" + red "❌ Failed: Nessus risk == None was: $(echo $nessus_doc | jq '.risk') instead" ((return_code = return_code + 1)) fi @@ -54,17 +69,17 @@ fi tenable_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=plugin_name:%22Backported%20Security%20Patch%20Detection%20(FTP)%22%20AND%20asset:176.28.50.164%20AND%20tags:tenable" | jq '.hits.hits[]._source') # Test asset if echo $tenable_doc | jq .asset | grep -q '176.28.50.164'; then - green "✅ Passed Tenable asset == 2019-03-30T10:17:41.000Z" + green "✅ Passed: Tenable asset == 2019-03-30T10:17:41.000Z" else - red "❌ Failed Tenable asset == 176.28.50.164 was: $(echo $tenable_doc | jq .asset) instead" + red "❌ Failed: Tenable asset == 176.28.50.164 was: $(echo $tenable_doc | jq .asset) instead" ((return_code = return_code + 1)) fi # Test @timestamp if echo $tenable_doc | jq '.["@timestamp"]' | grep -q '2019-03-30T15:45:44.000Z'; then - green "✅ Passed Tenable @timestamp == 2019-03-30T10:17:41.000Z" + green "✅ Passed: Tenable @timestamp == 2019-03-30T10:17:41.000Z" else - red "❌ Failed Tenable @timestamp == 2019-03-30T15:45:44.000Z was: $(echo $tenable_doc | jq '.["@timestamp"]') instead" + red "❌ Failed: Tenable @timestamp == 2019-03-30T15:45:44.000Z was: $(echo $tenable_doc | jq '.["@timestamp"]') instead" ((return_code = return_code + 1)) fi @@ -72,17 +87,17 @@ fi qualys_vuln_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=tags:qualys_vuln%20AND%20ip:%22176.28.50.164%22%20AND%20plugin_name:%22OpenSSL%20Multiple%20Remote%20Security%20Vulnerabilities%22%20AND%20port:465" | jq '.hits.hits[]._source') # Test @timestamp if echo $qualys_vuln_doc | jq '.["@timestamp"]' | grep -q '2019-03-30T10:17:41.000Z'; then - green "✅ Passed Qualys VM @timestamp == 2019-03-30T10:17:41.000Z" + green "✅ Passed: Qualys VM @timestamp == 2019-03-30T10:17:41.000Z" else - red "❌ Failed Qualys VM @timestamp == 2019-03-30T10:17:41.000Z was: $(echo $qualys_vuln_doc | jq '.["@timestamp"]') instead" + red "❌ Failed: Qualys VM @timestamp == 2019-03-30T10:17:41.000Z was: $(echo $qualys_vuln_doc | jq '.["@timestamp"]') instead" ((return_code = return_code + 1)) fi # Test @XXXX if echo $qualys_vuln_doc | jq '.cvss' | grep -q '6.8'; then - green "✅ Passed Qualys VM cvss == 6.8" + green "✅ Passed: Qualys VM cvss == 6.8" else - red "❌ Failed Qualys VM cvss == 6.8 was: $(echo $qualys_vuln_doc | jq '.cvss') instead" + red "❌ Failed: Qualys VM cvss == 6.8 was: $(echo $qualys_vuln_doc | jq '.cvss') instead" ((return_code = return_code + 1)) fi diff --git a/tests/test-vuln_whisperer.sh b/tests/test-vuln_whisperer.sh index 77f2e72..22e9edf 100755 --- a/tests/test-vuln_whisperer.sh +++ b/tests/test-vuln_whisperer.sh @@ -44,6 +44,7 @@ yellow "\n*********************************************" yellow "* Test one failed scan *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* +yellow "Removing ${TEST_PATH}/nessus/GET_scans_exports_164_download" rm -f ${TEST_PATH}/nessus/GET_scans_exports_164_download if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then green "\n✅ Passed: Test one failed scan" @@ -56,6 +57,7 @@ yellow "\n*********************************************" yellow "* Test two failed scans *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* +yellow "Removing ${TEST_PATH}/qualys_vuln/scan_1553941061.87241" rm -f ${TEST_PATH}/qualys_vuln/scan_1553941061.87241 if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]]; then green "\n✅ Passed: Test two failed scans" @@ -75,7 +77,6 @@ else ((return_code = return_code + 1)) fi -echo -e "\n\n" yellow "*********************************************" yellow "* Test only Qualys VM with one failed scan *" yellow "*********************************************" From 2c5fbfc3efc9e508e52b3735755b0635ea5c661b Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 09:48:18 +1000 Subject: [PATCH 12/16] restore deleted files --- tests/test-vuln_whisperer.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tests/test-vuln_whisperer.sh b/tests/test-vuln_whisperer.sh index 22e9edf..050a56b 100755 --- a/tests/test-vuln_whisperer.sh +++ b/tests/test-vuln_whisperer.sh @@ -23,7 +23,7 @@ yellow "\n*********************************************" yellow "* Test successful scan download and parsing *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* -if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; then +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir "${TEST_PATH}"; then green "\n✅ Passed: Test successful scan download and parsing" else red "\n❌ Failed: Test successful scan download and parsing" @@ -33,7 +33,7 @@ fi yellow "\n*********************************************" yellow "* Test run with no scans to import *" yellow "*********************************************" -if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; then +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir "${TEST_PATH}"; then green "\n✅ Passed: Test run with no scans to import" else red "\n❌ Failed: Test run with no scans to import" @@ -45,8 +45,8 @@ yellow "* Test one failed scan *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* yellow "Removing ${TEST_PATH}/nessus/GET_scans_exports_164_download" -rm -f ${TEST_PATH}/nessus/GET_scans_exports_164_download -if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then +mv "${TEST_PATH}/nessus/GET_scans_exports_164_download"{,.bak} +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir "${TEST_PATH}"; [[ $? -eq 1 ]]; then green "\n✅ Passed: Test one failed scan" else red "\n❌ Failed: Test one failed scan" @@ -58,8 +58,8 @@ yellow "* Test two failed scans *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* yellow "Removing ${TEST_PATH}/qualys_vuln/scan_1553941061.87241" -rm -f ${TEST_PATH}/qualys_vuln/scan_1553941061.87241 -if vuln_whisperer -F -c configs/test.ini --mock --mock_dir ${TEST_PATH}; [[ $? -eq 2 ]]; then +mv "${TEST_PATH}/qualys_vuln/scan_1553941061.87241"{,.bak} +if vuln_whisperer -F -c configs/test.ini --mock --mock_dir "${TEST_PATH}"; [[ $? -eq 2 ]]; then green "\n✅ Passed: Test two failed scans" else red "\n❌ Failed: Test two failed scans" @@ -70,7 +70,7 @@ yellow "\n*********************************************" yellow "* Test only nessus with one failed scan *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* -if vuln_whisperer -F -c configs/test.ini -s nessus --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then +if vuln_whisperer -F -c configs/test.ini -s nessus --mock --mock_dir "${TEST_PATH}"; [[ $? -eq 1 ]]; then green "\n✅ Passed: Test only nessus with one failed scan" else red "\n❌ Failed: Test only nessus with one failed scan" @@ -81,11 +81,15 @@ yellow "*********************************************" yellow "* Test only Qualys VM with one failed scan *" yellow "*********************************************" rm -rf /opt/VulnWhisperer/* -if vuln_whisperer -F -c configs/test.ini -s qualys_vuln --mock --mock_dir ${TEST_PATH}; [[ $? -eq 1 ]]; then +if vuln_whisperer -F -c configs/test.ini -s qualys_vuln --mock --mock_dir "${TEST_PATH}"; [[ $? -eq 1 ]]; then green "\n✅ Passed: Test only Qualys VM with one failed scan" else red "\n❌ Failed: Test only Qualys VM with one failed scan" ((return_code = return_code + 1)) fi +# Restore the removed files +mv" ${TEST_PATH}/qualys_vuln/scan_1553941061.87241.bak" "${TEST_PATH}/qualys_vuln/scan_1553941061.87241" +mv "${TEST_PATH}/nessus/GET_scans_exports_164_download.bak" "${TEST_PATH}/nessus/GET_scans_exports_164_download.bak" + exit $return_code \ No newline at end of file From e9aba0796f04ffd8aa97556294fb6651aad67982 Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 09:48:35 +1000 Subject: [PATCH 13/16] increase timeout for ES sync --- tests/test-docker.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/test-docker.sh b/tests/test-docker.sh index e9ed789..7a499df 100755 --- a/tests/test-docker.sh +++ b/tests/test-docker.sh @@ -37,16 +37,15 @@ done green "✅ Logstash load finished..." count=0 -curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count' until [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]] ; do yellow "Waiting for Elasticsearch index to sync... $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') of 1232" - ((count++)) && ((count==30)) && break + ((count++)) && ((count==150)) && break sleep 2 done -if [[ count -le 30 ]]; then +if [[ count -le 50 && $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then green "✅ logstash-vulnwhisperer-2019.03 document count == 1232" else - red "❌ TIMED OUT waitin for logstash-vulnwhisperer-2019.03 document count: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq) != 1232" + red "❌ TIMED OUT waiting for logstash-vulnwhisperer-2019.03 document count: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq) != 1232" fi # if [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then From 549791470a226766f2777c519098a864fe9968f3 Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 10:02:34 +1000 Subject: [PATCH 14/16] Set limit to bail out on --- tests/test-docker.sh | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/test-docker.sh b/tests/test-docker.sh index 7a499df..5e7f7bd 100755 --- a/tests/test-docker.sh +++ b/tests/test-docker.sh @@ -29,21 +29,27 @@ done green "✅ Elasticsearch status is green..." count=0 -until [[ $(curl -s "$logstash_url/_node/stats" | jq '.events.out') == 1236 ]] ; do - yellow "Waiting for Logstash load to finish... attempt $count of 30" - ((count++)) && ((count!=30)) && break - sleep 10 +until [[ $(curl -s "$logstash_url/_node/stats" | jq '.events.out') -ge 1236 ]]; do + yellow "Waiting for Logstash load to finish... $(curl -s "$logstash_url/_node/stats" | jq '.events.out') of 1236 (attempt $count of 60)" + ((count++)) && ((count==60)) && break + sleep 5 done -green "✅ Logstash load finished..." + +if [[ count -le 60 && $(curl -s "$logstash_url/_node/stats" | jq '.events.out') -ge 1236 ]]; then + green "✅ Logstash load finished..." +else + red "❌ Logstash load didn't complete... $(curl -s "$logstash_url/_node/stats" | jq '.events.out')" +fi + count=0 -until [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]] ; do - yellow "Waiting for Elasticsearch index to sync... $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') of 1232" +until [[ $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') -ge 1232 ]] ; do + yellow "Waiting for Elasticsearch index to sync... $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') of 1232 logs loaded (attempt $count of 150)" ((count++)) && ((count==150)) && break sleep 2 done -if [[ count -le 50 && $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') == 1232 ]]; then - green "✅ logstash-vulnwhisperer-2019.03 document count == 1232" +if [[ count -le 50 && $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq '.count') -ge 1232 ]]; then + green "✅ logstash-vulnwhisperer-2019.03 document count >= 1232" else red "❌ TIMED OUT waiting for logstash-vulnwhisperer-2019.03 document count: $(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_count" | jq) != 1232" fi @@ -68,7 +74,7 @@ fi tenable_doc=$(curl -s "$elasticsearch_url/logstash-vulnwhisperer-2019.03/_search?q=plugin_name:%22Backported%20Security%20Patch%20Detection%20(FTP)%22%20AND%20asset:176.28.50.164%20AND%20tags:tenable" | jq '.hits.hits[]._source') # Test asset if echo $tenable_doc | jq .asset | grep -q '176.28.50.164'; then - green "✅ Passed: Tenable asset == 2019-03-30T10:17:41.000Z" + green "✅ Passed: Tenable asset == 176.28.50.164" else red "❌ Failed: Tenable asset == 176.28.50.164 was: $(echo $tenable_doc | jq .asset) instead" ((return_code = return_code + 1)) From 30e3efe2cb2a3532b79a1cc1863c268352f0462e Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 10:12:29 +1000 Subject: [PATCH 15/16] set default path and fix restore --- tests/test-vuln_whisperer.sh | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/test-vuln_whisperer.sh b/tests/test-vuln_whisperer.sh index 050a56b..7739e8b 100755 --- a/tests/test-vuln_whisperer.sh +++ b/tests/test-vuln_whisperer.sh @@ -19,6 +19,8 @@ function yellow() { return_code=0 +TEST_PATH=${TEST_PATH:-"tests/data"} + yellow "\n*********************************************" yellow "* Test successful scan download and parsing *" yellow "*********************************************" @@ -89,7 +91,7 @@ else fi # Restore the removed files -mv" ${TEST_PATH}/qualys_vuln/scan_1553941061.87241.bak" "${TEST_PATH}/qualys_vuln/scan_1553941061.87241" -mv "${TEST_PATH}/nessus/GET_scans_exports_164_download.bak" "${TEST_PATH}/nessus/GET_scans_exports_164_download.bak" +mv "${TEST_PATH}/qualys_vuln/scan_1553941061.87241.bak" "${TEST_PATH}/qualys_vuln/scan_1553941061.87241" +mv "${TEST_PATH}/nessus/GET_scans_exports_164_download.bak" "${TEST_PATH}/nessus/GET_scans_exports_164_download" -exit $return_code \ No newline at end of file +exit $return_code From c3167bd76b9225c78cc538611df3cb1217b2d936 Mon Sep 17 00:00:00 2001 From: pemontto Date: Wed, 17 Apr 2019 10:13:33 +1000 Subject: [PATCH 16/16] fix test output --- tests/test-docker.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test-docker.sh b/tests/test-docker.sh index 5e7f7bd..3d15b76 100755 --- a/tests/test-docker.sh +++ b/tests/test-docker.sh @@ -82,7 +82,7 @@ fi # Test @timestamp if echo $tenable_doc | jq '.["@timestamp"]' | grep -q '2019-03-30T15:45:44.000Z'; then - green "✅ Passed: Tenable @timestamp == 2019-03-30T10:17:41.000Z" + green "✅ Passed: Tenable @timestamp == 2019-03-30T15:45:44.000Z" else red "❌ Failed: Tenable @timestamp == 2019-03-30T15:45:44.000Z was: $(echo $tenable_doc | jq '.["@timestamp"]') instead" ((return_code = return_code + 1))