Last active
September 18, 2018 04:58
-
-
Save ekristen/f5b6081f80320c36cb5e16256926dbf5 to your computer and use it in GitHub Desktop.
NowSecure Auto CI Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# NowSecure Auto CI Script | |
# | |
# Uploads a Binary to Auto, performs preflight checks, | |
# then performs an assessment, and compares summary score | |
# and exits non-zero if score is lower than score threshold | |
# | |
# --------------------------------------------------------------- | |
# | |
# Basic Usage | |
# | |
# export TOKEN=(API_TOKEN) | |
# bash auto-ci.sh /path/to/binary/of/android/or/ios | |
# | |
# -OR- | |
# | |
# TOKEN=(API_TOKEN) bash auto-ci.sh /path/to/binary/of/android/or/ios | |
# | |
# --------------------------------------------------------------- | |
# | |
# API Call Steps | |
# Step 1 - POST /binary/ | |
# Step 2 - GET /binary/:digest/analysis | |
# Step 3 - POST /app/:platform/:package/assessment/ | |
# Step 4 - GET /app/:platform/:package/assessment/:task/report | |
# | |
# --------------------------------------------------------------- | |
# | |
# This script require only a single environment variable by default | |
# called TOKEN, this is the API Token used to authenticate to the API | |
# You can optionally provide a SCORE_THRESHOLD which is set at 50 by | |
# default. If the app scores below this threshold, the script exits | |
# non-zero as the value of the score. | |
# | |
# If you know preflight has already been completed you can skip it by | |
# setting SKIP_PREFLIGHT to any value. | |
# | |
# If you know analysis was already started, you can skip starting analysis | |
# again by passing ANALYSIS_TASK set to the appropriate ID from a previous | |
# run. | |
# | |
# To debug the script set DEBUG to any value | |
# | |
if [ "x${DEBUG}" != "x" ]; then | |
set -x | |
fi | |
BASEURL=${BASEURL:-"https://lab-api.nowsecure.com"} | |
TOKEN=${TOKEN:-""} | |
SCORE_THRESHOLD=${SCORE_THRESHOLD:-50} | |
if [ "x${BASEURL}" == "x" ]; then | |
echo "BASEURL env var missing or empty." | |
exit 101 | |
fi | |
if [ "x${TOKEN}" == "x" ]; then | |
echo "TOKEN env var missing or empty." | |
exit 102 | |
fi | |
if [ $# -ne 1 ]; then | |
echo "Usage: $0 <android_or_ios_binary>" | |
exit 103 | |
fi | |
if [ ! -f ${1} ]; then | |
echo "ERROR: File does not exist." | |
exit 104 | |
fi | |
BINARY_FILE=${1} | |
OUTPUT_UPLOAD="" | |
OUTPUT_ANALYSIS="" | |
OUTPUT_SUMMARY="" | |
APP_DIGEST="" | |
APP_PLATFORM="" | |
APP_PACKAGE="" | |
ANALYSIS_TASK=${ANALYSIS_TASK:-""} | |
info () { | |
echo " [INFO] ${1}" | |
} | |
warning () { | |
echo " [WARN] ${1} - Details: ${2}" | |
} | |
fatal () { | |
echo "" | |
echo "[FATAL] ${1}" | |
echo "" | |
exit 10 | |
} | |
retry() { | |
local retry_max=$1 | |
shift | |
local count=$retry_max | |
while [ $count -gt 0 ]; do | |
"$@" && break | |
count=$(($count - 1)) | |
sleep $(echo "1.2" "$count" | awk '{printf "%4.3f\n",$1*$2}') | |
done | |
[ $count -eq 0 ] && { | |
warning "Retry failed [$retry_max]: $@" >&2 | |
return 1 | |
} | |
return 0 | |
} | |
download_jq () { | |
if [ "x$(which jq)" != "x" ]; then | |
info "jq already present" | |
return 0 | |
fi | |
info "Downloading jq ... " | |
wget https://github.com/stedolan/jq/releases/download/jq-1.5/jq-linux64 | |
} | |
upload_binary () { | |
OUTPUT_UPLOAD=$(curl -s -H "Authorization: Bearer ${TOKEN}" ${BASEURL}/binary/ --data-binary @${BINARY_FILE}) | |
if [ $? -ne 0 ]; then | |
echo $OUTPUT | |
return 1 | |
fi | |
APP_DIGEST=$(echo $OUTPUT_UPLOAD | jq -rM '.digest') | |
APP_PLATFORM=$(echo $OUTPUT_UPLOAD | jq -rM '.platform') | |
APP_PACKAGE=$(echo $OUTPUT_UPLOAD | jq -rM '.package') | |
info "Upload Successful!" | |
return 0 | |
} | |
run_preflight () { | |
if [ "x${SKIP_PREFLIGHT}" != "x" ]; then | |
warn "Skipping Preflight" | |
return 0 | |
fi | |
OUTPUT_PREFLIGHT=$(curl -s -H "Authorization: Bearer ${TOKEN}" -XGET ${BASEURL}/binary/${APP_DIGEST}/analysis) | |
if [ $? -ne 0 ]; then | |
warning "Unable to trigger preflight" $OUTPUT_PREFLIGHT | |
return 1 | |
fi | |
info "Preflight ran successfully" | |
return 0 | |
} | |
run_analysis () { | |
if [ "x${ANALYSIS_TASK}" != "x" ]; then | |
info "Skipping Starting Analysis already have Task ID ..." | |
return 0 | |
fi | |
OUTPUT_ANALYSIS=$(curl -s -H "Authorization: Bearer ${TOKEN}" -XPOST ${BASEURL}/app/${APP_PLATFORM}/${APP_PACKAGE}/assessment/) | |
ANALYSIS_TASK=$(echo "${OUTPUT_ANALYSIS}" | jq -rM '.task') | |
if [ "x${ANALYSIS_TASK}" == "x" ]; then | |
warning "Unable to obtain TASK ID for the Analysis" | |
return 1 | |
fi | |
info "Queued App for Analysis, Task ID: ${ANALYSIS_TASK}" | |
return 0 | |
} | |
poll_summary () { | |
OUTPUT_SUMMARY=$(curl -s -H "Authorization: Bearer ${TOKEN}" -XGET ${BASEURL}/assessment/${ANALYSIS_TASK}/summary${GROUP_URL}) | |
if [ $? -ne 0 ]; then | |
warning "Unable to poll for analysis results" | |
return 1 | |
fi | |
if [ "x${OUTPUT_SUMMARY}" == "x" ]; then | |
info "Polling for Summary ..." | |
return 1 | |
fi | |
return 0 | |
} | |
parse_results () { | |
SCORE=$(echo "${OUTPUT_SUMMARY}" | jq -rM '.score' | awk -F'.' '{ print $1 }') | |
if [ $SCORE -lt $SCORE_THRESHOLD ]; then | |
warning "Application Scored Lower Than Threshold (Score: ${SCORE}, Threshold: ${SCORE_THRESHOLD})" | |
exit $SCORE | |
fi | |
info "Score: ${SCORE}" | |
info "Analysis Complete" | |
info "Full Results" | |
echo $OUTPUT_SUMMARY | jq . | |
exit 0 | |
} | |
retry 3 download_jq || fatal "Download jq" | |
retry 3 upload_binary || fatal "Uploading Binary" | |
retry 3 run_preflight || fatal "Running Preflight Checks" | |
retry 3 run_analysis || fatal "Running Analysis" | |
retry 60 poll_summary || fatal "Waiting for Analysis to Complete" | |
retry 3 parse_results || fatal "Unable to Parse Results" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment