This repository has been archived by the owner on Sep 11, 2019. It is now read-only.
forked from snyk/snyk-to-jira
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsnyk_to_jira.sh
executable file
·218 lines (186 loc) · 6.45 KB
/
snyk_to_jira.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#!/bin/bash
## Prerequisites:
#
# 1. Add custom field for snyk-vuln-id in JIRA:
# - Settings --> Issues --> Custom Fields --> Add Custom Field -->
# Text Field Single Line
# 'snyk-vuln-id'
# Select relevant project screens
#
# 2. Add custom field for snyk-path in JIRA:
# - Settings --> Issues --> Custom Fields --> Add Custom Field -->
# Text Field Single Line
# 'snyk-path'
# Select relevant project screens
#
# 3. Create .jirac file in local directorty with four lines
# export JIRA_USER=<USER>
# export JIRA_PASSWORD=<PWD>
# export BASE_JIRA_URL=<URL>
# export JIRA_PROJECT_NAME=<PROJECT>
## Debug: DEBUG=1 to activate, DEBUG= to deactivate
DEBUG=
## Add comment: ADD_COMMENT=1 to add comment if open issue with same vuln already exists. ADD_COMMENT= to skip
ADD_COMMENT=
JIRA_SNYK_CUSTOM_FIELD_VULN_NAME=snyk-vuln-id
JIRA_SNYK_CUSTOM_FIELD_PATH_NAME=snyk-path
## .jirarc format:
# export JIRA_USER=<USER>
# export JIRA_PASSWORD=<PWD>
if [ -r .jirarc ]
then
source .jirarc
else
echo ".jirarc file not found"
exit 1
fi
[ $JIRA_USER ] || (echo JIRA_USER not specified && exit 1)
[ $JIRA_PASSWORD ] || (echo JIRA_PASSWORD not specified && exit 1)
[ $BASE_JIRA_URL ] || (echo BASE_JIRA_URL not specified && exit 1)
[ $JIRA_PROJECT_NAME ] || (echo BASE_JIRA_URL not specified && exit 1)
function usage()
{
echo "Usage: $0 <snyk_test.json>"
echo "snyk_test.json should be the output of running 'snyk test --json > snyk_test.json'"
}
function uc_first()
{
local UC_FIRST=`echo -n ${1:0:1} | tr '[a-z]' '[A-Z]'`${1:1}
echo $UC_FIRST
}
function urlencode()
{
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
}
function jira_curl()
{
local API=$1
local COMMAND=${2:-"GET"}
local DATA_FILE=$3
if [[ $COMMAND == "POST" ]] ; then
curl -s -S -u $JIRA_USER:$JIRA_PASSWORD -X $COMMAND --data @$DATA_FILE -H "Content-Type: application/json" $BASE_JIRA_URL/rest/api/2/$API
else
curl -s -S -u $JIRA_USER:$JIRA_PASSWORD -X $COMMAND -H "Content-Type: application/json" $BASE_JIRA_URL/rest/api/2/$API
fi
}
function jira_get_project_id()
{
local PROJECT_NAME=$1
local PROJECT_ID=`jira_curl issue/createmeta | jq ".projects[] | select(.name==\"$PROJECT_NAME\") | .id" | tr -d '\"'`
local re='^[0-9]+$'
if ! [[ $PROJECT_ID =~ $re ]] ; then
echo "Error: could not find project with name $PROJECT_NAME" >&2
exit 1
fi
echo $PROJECT_ID;
}
function jira_get_custom_field_id()
{
local CUSTOM_FIELD_NAME=$1
local CUSTOM_FIELD_ID=`jira_curl field | jq ".[] | select(.name==\"$CUSTOM_FIELD_NAME\") | .id" | tr -d '\"'`
local re='^customfield_[0-9]+$'
if ! [[ $CUSTOM_FIELD_ID =~ $re ]] ; then
echo "Error: could not find field with name $CUSTOM_FIELD_NAME" >&2
exit 1
fi
echo $CUSTOM_FIELD_ID;
}
function jira_create_issue()
{
local PROJECT_ID=$1
local SUMMARY=$2
local SNYK_VULN_ID=$3
local SNYK_PATH=$4
local SEVERITY=`uc_first $5`
local SNYK_VULN_ID_ENC=`urlencode "$SNYK_VULN_ID"`
local SNYK_PATH_ENC=`urlencode "$SNYK_PATH"`
local PAYLOAD_FILE=`mktemp`
local ISSUE_KEY=`jira_curl "search?jql=project=$PROJECT_ID+AND+status!=Done+AND+$JIRA_SNYK_CUSTOM_FIELD_VULN_NAME~$SNYK_VULN_ID_ENC+AND+$JIRA_SNYK_CUSTOM_FIELD_PATH_NAME~\"$SNYK_PATH_ENC\"&maxResults=1&fields=id,key" | jq '.issues[0].key' | tr -d '"'`
local re='^[A-Za-z]{3}-[0-9]+$'
if [[ $ISSUE_KEY =~ $re ]] ; then
## Issue with same vuln and path exists
if [[ $ADD_COMMENT == 1 ]] ; then
[ $DEBUG ] && echo "Found exising issue with snyk-vuln-id=$SNYK_VULN_ID (id=$ISSUE_KEY) [$SNYK_PATH] --> Adding comment"
cat > $PAYLOAD_FILE <<EOM
{
"body": "Vulnerability not resolved yet"
}
EOM
jira_curl issue/$ISSUE_KEY/comment POST $PAYLOAD_FILE | grep -v "self"
else
[ $DEBUG ] && echo "Found exising issue with snyk-vuln-id=$SNYK_VULN_ID (id=$ISSUE_KEY) [$SNYK_PATH] --> Skipping"
fi
else
## New issue
[ $DEBUG ] && echo "Creating new issue for snyk-vuln-id=$SNYK_VULN_ID: $SUMMARY"
cat > $PAYLOAD_FILE <<EOM
{
"fields": {
"project": {
"id": "$PROJECT_ID"
},
"summary": "$SUMMARY",
"priority": {
"name": "$SEVERITY"
},
"issuetype": {
"name": "Bug"
},
"description": "For more information please refer to https://snyk.io/vuln/$SNYK_VULN_ID",
"$JIRA_SNYK_CUSTOM_FIELD_VULN_ID": "$SNYK_VULN_ID",
"$JIRA_SNYK_CUSTOM_FIELD_PATH_ID": "$SNYK_PATH"
}
}
EOM
jira_curl issue POST $PAYLOAD_FILE
echo
fi
}
####################
# START OF PROGRAM
####################
if ! [ $# -eq 1 ]; then
usage
exit 1
fi
JSON_FILE=$1
if ! [ -r $JSON_FILE ]; then
echo "Could not open $JSON_FILE for reading"
exit 1
fi
N_VULNS=`cat $JSON_FILE | jq '.vulnerabilities | length'`
re='^[0-9]+$'
if ! [[ $N_VULNS =~ $re ]]; then
echo $JSON_FILE does not [$N_VULNS] seem to be an output of 'snyk test --json'
exit 1
fi
if [ $N_VULNS -eq 0 ]; then
echo "Good for you! No vulns found."
exit 0
fi
[ $DEBUG ] && echo Found $N_VULNS vulns
[ $DEBUG ] && echo Connecting with user $JIRA_USER
[ $DEBUG ] && echo Base JIRA URL: $BASE_JIRA_URL
JIRA_PROJECT_ID=`jira_get_project_id $JIRA_PROJECT_NAME`
[ $DEBUG ] && echo Found project id $JIRA_PROJECT_ID for $JIRA_PROJECT_NAME
JIRA_SNYK_CUSTOM_FIELD_VULN_ID=`jira_get_custom_field_id $JIRA_SNYK_CUSTOM_FIELD_VULN_NAME`
[ $DEBUG ] && echo Found custom field id $JIRA_SNYK_CUSTOM_FIELD_VULN_ID for $JIRA_SNYK_CUSTOM_FIELD_VULN_NAME
JIRA_SNYK_CUSTOM_FIELD_PATH_ID=`jira_get_custom_field_id $JIRA_SNYK_CUSTOM_FIELD_PATH_NAME`
[ $DEBUG ] && echo Found custom field id $JIRA_SNYK_CUSTOM_FIELD_PATH_ID for $JIRA_SNYK_CUSTOM_FIELD_PATH_NAME
for ((i=0;i<$N_VULNS;i++)); do
TITLE=`cat $JSON_FILE | jq ".vulnerabilities[$i].title" | tr -d '"'`
SEVERITY=`cat $JSON_FILE | jq ".vulnerabilities[$i].severity"| tr -d '"'`
SNYK_VULN_ID=`cat $JSON_FILE | jq ".vulnerabilities[$i].alternativeIds[0]"| tr -d '"'`
MODULE=`cat $JSON_FILE | jq ".vulnerabilities[$i].moduleName"| tr -d '"'`
PACKAGE=`cat $JSON_FILE | jq ".vulnerabilities[$i].from[0] | split(\"@\") | .[0]" | tr -d '"'`
SNYK_PATH=`cat $JSON_FILE | jq ".vulnerabilities[$i].from | join(\" -> \")" | tr -d '"'`
SUMMARY="[SNYK] ${TITLE/\"/g}: $SEVERITY severity vulnerability found in '$MODULE' for $PACKAGE ($SNYK_VULN_ID)"
jira_create_issue $JIRA_PROJECT_ID "$SUMMARY" "$SNYK_VULN_ID" "$SNYK_PATH" "$SEVERITY"
done