diff options
Diffstat (limited to 'bin/acme')
-rwxr-xr-x | bin/acme/patcher.json | 20 | ||||
-rwxr-xr-x | bin/acme/srtool_jira_acme.py (renamed from bin/acme/srtool_jira.py) | 375 |
2 files changed, 224 insertions, 171 deletions
diff --git a/bin/acme/patcher.json b/bin/acme/patcher.json new file mode 100755 index 00000000..365990fa --- /dev/null +++ b/bin/acme/patcher.json @@ -0,0 +1,20 @@ +{ + "_comments_" : "Blank values indicate defaults", + "label" : "ACME", + "patcher_dir" : "bin/acme/patcher", + "patch_set" : [ + { + "_comments_" : "The ACME custom version of the Jira integration script", + "original" : "bin/common/srtool_jira_template.py", + "custom" : "bin/acme/srtool_jira_acme.py", + "patch" : "", + "options" : "" + }, + { + "original" : "bin/srt", + "custom" : "bin/srt", + "patch" : "", + "options" : "DISABLE" + } + ] +} diff --git a/bin/acme/srtool_jira.py b/bin/acme/srtool_jira_acme.py index f9b8103b..d7ef0507 100755 --- a/bin/acme/srtool_jira.py +++ b/bin/acme/srtool_jira_acme.py @@ -5,7 +5,7 @@ # # Security Response Tool Commandline Tool # -# Copyright (C) 2018 Wind River Systems +# Copyright (C) 2018-2019 Wind River Systems # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as @@ -21,33 +21,41 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ### Usage Examples (run from top level directory) -# Updating Jira Issues: ./bin/srtool_jira.py -U - - -### -### THIS IS A SAMPLE JIRA INTEGRATION SCRIPT FOR -### MANAGING AN ORGANIZATION'S SRTOOL INTEGRATION -### -### INSTALLATION INSTRUCTIONS AND DOCUMENATION OF THE JIRA PYTHON -### LIBRARIES CAN BE FOUND HERE: -### https://jira.readthedocs.io -### - +# Updating Jira Issues: ./bin/<app>/srtool_jira<_app>.py -u + +## +## THIS IS A JIRA INTEGRATION SCRIPT FOR +## MANAGING AN ORGANIZATION'S SRTOOL INTEGRATION +## +## You can use the "bin/common/srtool_patcher.py" to extend this template +## with your custom changes yet keep in sync with the shared upstream file. +## +## See the example: "bin/acme/srtool_jira_acme.py" +## +## INSTALLATION INSTRUCTIONS AND DOCUMENATION OF THE JIRA PYTHON +## LIBRARIES CAN BE FOUND HERE: +## https://jira.readthedocs.io +## + +### ACME_EXTENSION_BEGIN ### +# +# This is the ACME 'patcher' extension of: +# 'bin/common/srtool_jira_template.py' +# +# To merge edits in common areas to upstream, run: +# $ ./bin/common/srtool_patcher.py -j bin/acme/patcher.json --merge-custom +# To merge upstream into this custom extension, run: +# $ ./bin/common/srtool_patcher.py -j bin/acme/patcher.json --merge-original +# +### ACME_EXTENSION_END ### import os import sys import re -import csv -import xml.etree.ElementTree as ET import argparse import sqlite3 -import subprocess import json -from jira import JIRA -from time import sleep from datetime import datetime, date -from urllib.request import urlopen, URLError -from urllib.parse import urlparse # load the srt.sqlite schema indexes dir_path = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) @@ -55,37 +63,66 @@ sys.path.insert(0, dir_path) from common.srt_schema import ORM # Setup: +master_log = '' +srt_user = '' +srt_passwd = '' +force_update = False + srtDbName = 'srt.sqlite' srtErrorLog = 'srt_errors.txt' -### -### THESE ARE SAMPLE JIRA INTEGRATION LINKS: -### The 'production' link is to the main Jira server -### The 'test' link is to a test Jira server, for example to pre-test defect creation -### The 'browse' link is how to format the Jira defect lookup link that is passed to the SRTool users -### +# +# Load Jira test +# -# Jira constants -JIRA_PRODUCTION_LINK = 'https://jira.acme.com' -JIRA_BROWSE_LINK_FORMAT = 'http://jira.acme.com/browse/%s' -JIRA_TESTSERVER_LINK = 'https://jira.acmetest.com' +try: + from jira import JIRA +except: + # could be SRTDBG_SKIP_DEFECT_IMPORT + pass -### -### THESE ARE SAMPLE JIRA CUSTOM FIELD LINKS: -### These are example links that you can use to define and populate the respective fields for the SRTool -### These are not defined in the standard Jira schema, and would presumably be custom added -### You can extend and cusomize the Jira integration to SRTool by added additional custom fields using this model -### The two indicated fields below are part of the SRTool design. They can be present as empty strings if they -### do not exist in your schema: -### The 'PUBLISHED' field is used to indicate if and when a Jira defect has been published to the customers -### The 'FIX_VERSION' field is used to indicate which version/release/update/service pack of the product has the fix -### +## +## THESE ARE JIRA INTEGRATION LINKS: +## The 'production' link is to the main Jira server +## The 'test' link is to a test Jira server, for example to pre-test defect creation +## The 'browse' link is how to format the Jira defect lookup link that is passed to the SRTool users +## + +# Jira constants: examples +JIRA_PRODUCTION_LINK = 'https://jira.sample.com' +JIRA_BROWSE_LINK_FORMAT = 'http://jira.sample.com/browse/%s' +JIRA_TESTSERVER_LINK = 'https://jira.sampletest.com' +JIRA_NEW_ASSIGNEE = 'kilroy' + +### ACME_EXTENSION_BEGIN ### +JIRA_PRODUCTION_LINK = 'https://jira.wrs.com' +JIRA_BROWSE_LINK_FORMAT = 'http://jira.wrs.com/browse/%s' +JIRA_TESTSERVER_LINK = 'http://jiratest.wrs.com' +JIRA_NEW_ASSIGNEE = 'dreyna' +### ACME_EXTENSION_END ### + +## +## THESE ARE SAMPLE JIRA CUSTOM FIELD LINKS: +## These are example links that you can use to define and populate the respective fields for the SRTool +## These are not defined in the standard Jira schema, and would presumably be custom added +## You can extend and cusomize the Jira integration to SRTool by added additional custom fields using this model +## The two indicated fields below are part of the SRTool design. They can be present as empty strings if they +## do not exist in your schema: +## The 'PUBLISHED' field is used to indicate if and when a Jira defect has been published to the customers +## The 'FIX_VERSION' field is used to indicate which version/release/update/service pack of the product has the fix +## # Custom Jira fields -JIRA_PUBLISHED_FIELD = 'customfield_10010' ### REPLACE WITH YOUR CUSTOM FIELD VALUE -JIRA_FIX_VERSION_FIELD = 'customfield_10011' ### REPLACE WITH YOUR CUSTOM FIELD VALUE +# Custom Jira fields +JIRA_PUBLISHED_FIELD = 'customfield_10001' ### REPLACE WITH YOUR CUSTOM FIELD VALUE +JIRA_FIX_VERSION_FIELD = 'customfield_10002' ### REPLACE WITH YOUR CUSTOM FIELD VALUE # ... +### ACME_EXTENSION_BEGIN ### +JIRA_PUBLISHED_FIELD = 'customfield_10010' +JIRA_FIX_VERSION_FIELD = 'customfield_11002' +### ACME_EXTENSION_END ### + ################################# # Helper methods # @@ -98,14 +135,14 @@ def debugMsg(msg): overrides = {} -def set_override(key,value=None): +def set_override(key,value=None,quite=False): if not value is None: overrides[key] = value elif key in os.environ.keys(): overrides[key] = 'yes' if os.environ[key].startswith('1') else 'no' else: overrides[key] = 'no' - if 'yes' == overrides[key]: + if 'yes' == overrides[key] and not quite: print("OVERRIDE: %s = %s" % (key,overrides[key])) def get_override(key): @@ -126,47 +163,38 @@ def get_tag_key(tag,key): # class to hold fields of a Jira issues # -class Defect: +class Defect(): project = '' product_id = '' - - def __init__(self,*args, **kwargs): - self.reset() - - # reset all but persistent project info - def reset(self): - self.id = -1 - self.name = '' - self.summary = '' - self.url = '' - self.priority = -1 - self.status = '' - self.resolution = 'Unresolved' - self.publish = '' - - # RCPL - self.release_version = '' - - self.date_created = '' - self.date_updated = '' - - # extra fields - self.cve_status = '' - self.vi_status = '' - self.vi_outcome = '' + id = -1 + name = '' + summary = '' + url = '' + priority = -1 + status = '' + resolution = 'Unresolved' + publish = '' + # RCPL + release_version = '' + date_created = '' + date_updated = '' + # extra fields + cve_status = '' + vi_status = '' + vi_outcome = '' ################################# -# Import Jira states +# import Jira states # -# if too slow, change to check update times and ignore those that need nothing -# can also move parsing JSON so that it doesnt happen if record is up to date +#if too slow, change to check update times and ignore those that need nothing (should do anyway to be honest...) +#can also move parsing JSON so that it doesnt happen if record is up to date def do_update_jira(): try: jira = JIRA(JIRA_PRODUCTION_LINK, auth=(srt_user, srt_passwd)) except Exception as e: print("CONNECTION TO JIRA FAILED") - return + return 1 conn = sqlite3.connect(srtDbName) c = conn.cursor() @@ -175,14 +203,14 @@ def do_update_jira(): weeknum = today.strftime("%W") weekday = today.isoweekday() - log = open("./update_logs/update_jira_log_%s_%s.txt" % (weeknum, weekday), "a") + update_log = open("./update_logs/update_jira_log_%s_%s.txt" % (weeknum, weekday), "a") - log.write("BEGINNING JIRA UPDATES\n") + update_log.write("BEGINNING JIRA UPDATES\n") pre_update_time = datetime.now() products = c.execute('''SELECT * FROM orm_product''').fetchall() for i,product in enumerate(products): -# print("FOO1:%s,%s" % (product[ORM.PRODUCT_DEFECT_TAGS],get_tag_key(product[ORM.PRODUCT_DEFECT_TAGS],'key'))) +# print("JIRA_PRODUCT_SCAN:%s,%s" % (product[ORM.PRODUCT_DEFECT_TAGS],get_tag_key(product[ORM.PRODUCT_DEFECT_TAGS],'key'))) product_defect_prefix = get_tag_key(product[ORM.PRODUCT_DEFECT_TAGS],'key') if get_override('SRTDBG_MINIMAL_DB') and (i > 1): @@ -190,14 +218,13 @@ def do_update_jira(): #specify which fields to get in order to speed up request! #print("\tupdating ... " + product[ORM.PRODUCT_NAME] + " " + product[ORM.PRODUCT_VERSION] + " " + product[ORM.PRODUCT_PROFILE] + "\tloading " + spinner[block_num % 3], end='\r', flush=True) - log.write("\tUPDATING ... " + product[ORM.PRODUCT_NAME] + " " + product[ORM.PRODUCT_VERSION] + " " + product[ORM.PRODUCT_PROFILE] + "\n") + update_log.write("\tUPDATING ... " + product[ORM.PRODUCT_NAME] + " " + product[ORM.PRODUCT_VERSION] + " " + product[ORM.PRODUCT_PROFILE] + "\n") block_size = 500 block_num = 0 spinner = [' ', '. ', '.. ', '...'] while True: print("\tloading" + spinner[block_num % 4] + "\t" + product[ORM.PRODUCT_NAME] + " " + product[ORM.PRODUCT_VERSION] + " " + product[ORM.PRODUCT_PROFILE], end='\r', flush=True) -# print("\tloading" + spinner[block_num % 4] + "\t" + product[ORM.PRODUCT_NAME] + " " + product[ORM.PRODUCT_VERSION] + " " + product[ORM.PRODUCT_PROFILE], flush=True) start_idx = block_num*block_size #searches current project's bug issues that contain "cve" in their text issues = jira.search_issues('project=%s AND text ~ "cve*" AND type = Bug' % product_defect_prefix, start_idx, block_size, False, fields='key,summary,priority,status,resolution,project,updated,created,%s,%s' % (JIRA_PUBLISHED_FIELD, JIRA_FIX_VERSION_FIELD)) @@ -206,26 +233,28 @@ def do_update_jira(): break # Development support block_num += 1 - update_project_issues(product, issues, conn, log) + update_project_issues(product, issues, conn, update_log) +# sleep(1.0) # give time for Sqlite to sync conn.commit() #commit to db after each block +# sleep(1.0) # give time for Sqlite to sync +# conn.commit() #commit to db after each product print("\tfinished \t" + product[ORM.PRODUCT_NAME] + " " + product[ORM.PRODUCT_VERSION] + " " + product[ORM.PRODUCT_PROFILE], flush=True) conn.commit() - log.write("began updates: %s\n" % str(pre_update_time)) - log.write("finished updates: %s\n" % str(datetime.now())) - log.write("=============================================================================\n") - log.write("\n") + update_log.write("began updates: %s\n" % str(pre_update_time)) + update_log.write("finished updates: %s\n" % str(datetime.now())) + update_log.write("=============================================================================\n") + update_log.write("\n") # Reset datasource's lastModifiedDate as today sql = "UPDATE orm_datasource SET lastModifiedDate=? WHERE name='Jira'" date_string = datetime.now().strftime(ORM.DATASOURCE_DATETIME_FORMAT) - c.execute(sql, (date_string,) ) + ret = c.execute(sql, (date_string,) ) conn.commit() c.close() conn.close() #############################################################################3 -### Update the defect status from the Jira database ### def new_vulnerability_name(cur): @@ -254,10 +283,6 @@ def new_investigation_name(cur): cur.execute(sql, (index, cvi[ORM.SRTSETTING_ID])) return "INV-%05d" % index -# -# Translate Jira values to SRTool values -# - def translate_priority(j,p): NONE = 0 MINOR = 1 @@ -279,6 +304,21 @@ def translate_priority(j,p): srt_error_log("ERROR: unknown priority string '%s=%s'" % (j,p)) return '0' +def translate_priority_srt_to_jira(s): + Priority = ( + ('Undefined', 'None'), + ('Minor', 'P4'), + ('Low', 'P3'), + ('Medium', 'P2'), + ('High', 'P1'), + ) + for i in range(len(Priority)): + if s == Priority[i][0]: + return str(Priority[i][1]) + print("ERROR: unknown priority string '%s'" % (s)) + srt_error_log("ERROR: unknown priority string '%s'" % (s)) + return 'None' + def translate_status(j,s): OPEN = 0 IN_PROGRESS = 1 @@ -301,7 +341,7 @@ def translate_status(j,s): srt_error_log("ERROR: unknown status string '%s=%s'" % (j,s)) return '0' -def translate_resolution(j,r): +def translate_resolution(j,r,log): Resolution = ( (ORM.DEFECT_UNRESOLVED, 'Unresolved', ORM.STATUS_VULNERABLE,ORM.STATUS_NOT_VULNERABLE,ORM.OUTCOME_OPEN), (ORM.DEFECT_RESOLVED, 'Resolved', ORM.STATUS_VULNERABLE,ORM.STATUS_NOT_VULNERABLE,ORM.OUTCOME_FIXED), @@ -322,10 +362,6 @@ def translate_resolution(j,r): log.write("ERROR: unknown resolution string '%s=%s'" % (j,r)) return 0,0,0,0 -# -# Update the defect status from the Jira database -# - #handles updating a list of issues for a single product/project #DOES NOT CALL COMMIT (should change this?) def update_project_issues(project, issues, conn, log): @@ -347,11 +383,10 @@ def update_project_issues(project, issues, conn, log): USER_SRTOOL_ID = "SRTool" - d = Defect() - d.project = project[ORM.PRODUCT_NAME] + " " + project[ORM.PRODUCT_VERSION] + " " + project[ORM.PRODUCT_PROFILE] - d.product_id = project[ORM.PRODUCT_ID] + project_str = project[ORM.PRODUCT_NAME] + " " + project[ORM.PRODUCT_VERSION] + " " + project[ORM.PRODUCT_PROFILE] + product_id = project[ORM.PRODUCT_ID] - cve_regex = re.compile("CVE-\d+-\d+") + cve_regex = re.compile(r"CVE-\d+-\d+") srtool_today = datetime.today().strftime('%Y-%m-%d') c = conn.cursor() @@ -362,7 +397,11 @@ def update_project_issues(project, issues, conn, log): break issue_json = issue.raw - d.reset() + + d = Defect() + d.project = project_str + d.product_id = product_id + d.name = issue_json['key'] d.date_updated = issue_json['fields']['updated'] d.date_created = issue_json['fields']['created'] @@ -372,17 +411,13 @@ def update_project_issues(project, issues, conn, log): d.status = translate_status(d.name,issue_json['fields']['status']['name']) if issue_json['fields']['resolution'] is not None: - d.resolution,cve_status,vi_status,vi_outcome = translate_resolution(d.name,issue_json['fields']['resolution']['name']) + d.resolution,cve_status,vi_status,vi_outcome = translate_resolution(d.name,issue_json['fields']['resolution']['name'],log) else: - d.resolution,cve_status,vi_status,vi_outcome = translate_resolution(d.name,'Unresolved') + d.resolution,cve_status,vi_status,vi_outcome = translate_resolution(d.name,'Unresolved',log) if JIRA_PUBLISHED_FIELD in issue_json['fields'] and issue_json['fields'][JIRA_PUBLISHED_FIELD] is not None: d.publish = issue_json['fields'][JIRA_PUBLISHED_FIELD]['value'] - else: - d.publish = '' if JIRA_FIX_VERSION_FIELD in issue_json['fields'] and issue_json['fields'][JIRA_FIX_VERSION_FIELD] is not None: d.release_version = issue_json['fields'][JIRA_FIX_VERSION_FIELD]['name'] - else: - d.release_version = '' sql = "SELECT * FROM orm_defect WHERE name='%s'" % d.name defect = c.execute(sql).fetchone() @@ -444,6 +479,7 @@ def update_project_issues(project, issues, conn, log): # Also create CVE history entry sql = '''INSERT INTO orm_cvehistory (cve_id, comment, date, author) VALUES (?,?,?,?)''' c.execute(sql, (c_id,'Created from defect %s' % d.name,srtool_today,USER_SRTOOL_ID)) +# sleep(0.1) else: c_id = cve[ORM.CVE_ID] @@ -467,6 +503,7 @@ def update_project_issues(project, issues, conn, log): # Also create Vulnerability history entry sql = '''INSERT INTO orm_vulnerabilityhistory (vulnerability_id, comment, date, author) VALUES (?,?,?,?)''' c.execute(sql, (v_id,'Created from defect %s' % d.name,srtool_today,USER_SRTOOL_ID)) +# sleep(0.1) else: print("FOUND VULNERABILITY ID for %s" % (cve_name)) v_id = c2v[ORM.CVETOVULNERABLILITY_VULNERABILITY_ID] @@ -493,6 +530,7 @@ def update_project_issues(project, issues, conn, log): # Also create Investigation history entry sql = '''INSERT INTO orm_investigationhistory (investigation_id, comment, date, author) VALUES (?,?,?,?)''' c.execute(sql, (i_id,'Created from defect %s' % d.name,srtool_today,USER_SRTOOL_ID)) +# sleep(0.1) else: print("FOUND INVESTIGATION ID for %s" % (cve_name)) i_id = investigation[ORM.INVESTIGATION_ID] @@ -506,6 +544,7 @@ def update_project_issues(project, issues, conn, log): log.write("\tINSERTING INVESTIGATION to DEFECT for %s\n" % i_name) sql = '''INSERT INTO orm_investigationtodefect (investigation_id, product_id, defect_id) VALUES (?,?,?)''' c.execute(sql, (i_id,d.product_id,defect_id)) +# sleep(0.1) #print("=========================================================================================\n") #print("\n") @@ -520,13 +559,13 @@ def jira_update_list(jira_list): jira = JIRA(JIRA_PRODUCTION_LINK, auth=(srt_user, srt_passwd)) except Exception as e: print("CONNECTION TO JIRA FAILED") - return + return 1 conn = sqlite3.connect(srtDbName) c = conn.cursor() products = c.execute('''SELECT * FROM orm_product''').fetchall() - log = sys.stdout # open("./update_logs/update_jira_log_%s_%s.txt" % (weeknum, weekday), "a") + log = sys.stdout for jira_name in jira_list.split(','): print("Updating:\t" + jira_name, flush=True) @@ -546,6 +585,7 @@ def jira_update_list(jira_list): # Development support block_num += 1 update_project_issues(product, issues, conn, log) +# sleep(1.0) # give time for Sqlite to sync conn.commit() #commit to db after each block ################################# @@ -554,20 +594,19 @@ def jira_update_list(jira_list): #Gets all JIRA Enhancement Requests for the specified project def get_jira_er(project_prefix): - #log.write("GETTING ENHANCEMENT REQUESTS FOR " + project_prefix) print ("GETTING ENHANCEMENT REQUESTS FOR " + project_prefix) try: jira = JIRA(JIRA_PRODUCTION_LINK, auth=(srt_user, srt_passwd)) except Exception as e: print("CONNECTION TO JIRA FAILED") - return + return 1 block_size = 100 block_num = 0 while True: start_idx = block_num*block_size #searches current project's bug issues that contain "cve" in their text - issues = jira.search_issues('project=%s AND type = "Enhancement Request"' % project_prefix, start_idx, block_size, False) #project argument could be better written I guess :) + issues = jira.search_issues('project=%s AND type = "Enhancement Request"' % project_prefix, start_idx, block_size, False) if len(issues) == 0: # Retrieve issues until there are no more to come break @@ -583,6 +622,9 @@ def jira_add_to_defect_db(jira_name): print("Jira_name=%s" % (jira_name)) jira_name = jira_name.strip().upper() + # Just error errors to terminal + log = sys.stdout + #try connecting to jira try: jira = JIRA(JIRA_PRODUCTION_LINK, auth=(srt_user, srt_passwd)) @@ -610,11 +652,10 @@ def jira_add_to_defect_db(jira_name): d.priority = translate_priority(d.name,issue_json['fields']['priority']['name']) d.status = translate_status(d.name,issue_json['fields']['status']['name']) - if issue_json['fields']['resolution'] is not None: - d.resolution,d.cve_status,d.vi_status,d.vi_outcome = translate_resolution(d.name,issue_json['fields']['resolution']['name']) + d.resolution,d.cve_status,d.vi_status,d.vi_outcome = translate_resolution(d.name,issue_json['fields']['resolution']['name'],log) else: - d.resolution,d.cve_status,d.vi_status,d.vi_outcome = translate_resolution(d.name,'Unresolved') + d.resolution,d.cve_status,d.vi_status,d.vi_outcome = translate_resolution(d.name,'Unresolved',log) if JIRA_PUBLISHED_FIELD in issue_json['fields'] and issue_json['fields'][JIRA_PUBLISHED_FIELD] is not None: d.publish = issue_json['fields'][JIRA_PUBLISHED_FIELD]['value'] else: @@ -632,7 +673,7 @@ def jira_add_to_defect_db(jira_name): d.product_id = product[ORM.PRODUCT_ID] break - #log.write("\tINSERTING %s\n" % d.name) + #_log("\tINSERTING %s\n" % d.name) sql = '''INSERT INTO orm_defect (name, summary, url, priority, status, resolution, publish, release_version, product_id, date_created, date_updated) VALUES (?,?,?,?,?,?,?,?,?,?,?)''' c.execute(sql, (d.name, d.summary, d.url, d.priority, d.status, d.resolution, str(d.publish), d.release_version, d.product_id, d.date_created, d.date_updated)) conn.commit() @@ -648,20 +689,15 @@ def jira_add_to_defect_db(jira_name): # Not yet implemented def jira_del_from_defect_db(jira_name): - pass + return 1 ################################# # New defect # -### -### You will need to fill in any required custom fields required -### to create new organization defects in Jira -### - # Use "jiratest" for development testing -IS_TEST = True -IS_SIMULATE = True +JIRA_IS_TEST = True +JIRA_IS_SIMULATE = True def simulate_new_defect_name(product_prefix): conn = sqlite3.connect(srtDbName) @@ -688,32 +724,17 @@ def simulate_new_defect(product_defect_tags,summary,cve_list,description,reason, defect_name = simulate_new_defect_name(product_defect_prefix) print("CREATED:%s,%s/browse/%s" % (defect_name,jira_url,defect_name)) -def translate_priority_srt_to_jira(s): - Priority = ( - ('Undefined', 'None'), - ('Minor', 'P4'), - ('Low', 'P3'), - ('Medium', 'P2'), - ('High', 'P1'), - ) - for i in range(len(Priority)): - if s == Priority[i][0]: - return str(Priority[i][1]) - print("ERROR: unknown priority string '%s'" % (s)) - srt_error_log("ERROR: unknown priority string '%s'" % (s)) - return 'None' - -def jira_new_defect(product_defect_tags,summary,description,priority,components,link): - #srt_error_log("NEW DEFECT:%s|%s|%s|%s|%s|%s|%s|%s" % (product_defect_tags,summary,cve_list,description,reason,priority,components,link)) +def jira_new_defect(product_defect_tags,summary,cve_list,description,reason,priority,components,link): + srt_error_log("NEW DEFECT:%s|%s|%s|%s|%s|%s|%s|%s" % (product_defect_tags,summary,cve_list,description,reason,priority,components,link)) - if IS_TEST: + if JIRA_IS_TEST: # Test URL jira_url = JIRA_TESTSERVER_LINK else: # Production URL jira_url = JIRA_PRODUCTION_LINK - if IS_SIMULATE: + if JIRA_IS_SIMULATE: return simulate_new_defect(product_defect_tags,summary,cve_list,description,reason,priority,components,link,jira_url) # Connect to Jira server @@ -721,7 +742,8 @@ def jira_new_defect(product_defect_tags,summary,description,priority,components, jira = JIRA(jira_url, auth=(srt_user, srt_passwd)) except Exception as e: print("CONNECTION TO JIRA FAILED") - return + return 1 + #srt_error_log("Jira connection made") conn = sqlite3.connect(srtDbName) c = conn.cursor() @@ -734,7 +756,7 @@ def jira_new_defect(product_defect_tags,summary,description,priority,components, # Translate the SRTool priority to Jira priority priority = translate_priority_srt_to_jira(priority) - #print("JIRA_NEW_DEFECT:%s,%s,%s" % (product_defect_prefix,summary,description)) + #print("FOO1:%s,%s,%s" % (product_defect_prefix,summary,description)) jira_components=list() for component in components.split(' '): @@ -745,19 +767,24 @@ def jira_new_defect(product_defect_tags,summary,description,priority,components, 'summary': summary, 'description': description, 'issuetype': {'name': 'Bug'}, - 'priority': {'name': priority}, - 'components': jira_components, # Components by name - 'assignee': {"name":SRT_USER }, # assign to the SRTool developer Jira account -### 'customfield_11000': 'unknown', # EXAMPLE: "Found In Versions" = "unknown" -### 'customfield_11001': {"value":"Review"}, # EXAMPLE: "Where Found" = "Review" + 'components': jira_components, # Components by name + 'assignee': {"name":JIRA_NEW_ASSIGNEE}, # assign to the SRTool developer for now } - if True: - new_issue = jira.create_issue(fields=issue_dict) - else: - print("CREATE:%s" % issue_dict) - new_issue = '%s-%s' % (product_defect_prefix,datetime.now().strftime('%H%M%S')) +## +## Add custom fields here, using the format... +## issue_dict['custom_field_10001'] = value +## + + ### ACME_EXTENSION_BEGIN ### + ## HERE IS AN EXAMPLE OF ADJUSTMENTS TO THE JIRA QUERY + issue_dict['customfield_13304'] = {"value":"Review"} # "Where Found" = "Review" + ### ACME_EXTENSION_END ### + + new_issue = jira.create_issue(fields=issue_dict) + #print("CREATE:%s" % issue_dict) + #new_issue = '%s-%s' % (product_defect_prefix,datetime.now().strftime('%H%M%S')) new_issue = str(new_issue.key) if not new_issue.startswith(product_defect_prefix): @@ -767,12 +794,11 @@ def jira_new_defect(product_defect_tags,summary,description,priority,components, def get_projects(): - try: jira = JIRA(JIRA_PRODUCTION_LINK, auth=(srt_user, srt_passwd)) except Exception as e: print("CONNECTION TO JIRA FAILED") - return + return 1 # Get all projects viewable by anonymous users. projects = jira.projects() @@ -784,9 +810,6 @@ def get_projects(): # def update_jira(is_init): - if get_override('SRTDBG_SKIP_DEFECT_IMPORT'): - print("...Skipping Defect import") - exit(0) try: print("BEGINNING JIRA UPDATES PLEASE WAIT ... this can take some time") do_update_jira() @@ -795,6 +818,8 @@ def update_jira(is_init): except Exception as e: master_log.write("SRTOOL:%s:DEFECT TABLE & JIRA ISSUES:\t\t\t...\t\t\tFAILED ... %s\n" % (date.today(), e)) print("DATABASE UPDATES FAILED ... %s" % e) + return(1) + return(0) ################################# # main loop @@ -820,13 +845,17 @@ def main(argv): parser.add_argument('--add', nargs=1, help='Add an existing defect to SRTool defect database') parser.add_argument('--delete', nargs=1, help='Delete an existing defect from SRTool defect database') parser.add_argument('--new', action='store_const', const='new', dest='command', help='Create a new defect "--new --product-tags --summary --cve --description --reason --priority --components --link"') - parser.add_argument('--jira-projects', '-P', action='store_const', const='jira-projects', dest='command', help='Jira projects') + parser.add_argument('--jira-projects', '-j', action='store_const', const='jira-projects', dest='command', help='Jira projects') # Be flexible with arguments to support sub-parse trees args, argv = parser.parse_known_args() master_log = open("./update_logs/master_log.txt", "a") + if get_override('SRTDBG_SKIP_DEFECT_IMPORT'): + print("...Skipping Defect import") + exit(0) + # Authorization if args.user: srt_user = args.user @@ -854,12 +883,13 @@ def main(argv): if None != args.jira_update_list: jira_list = args.jira_update_list + ret = 0 if args.jira_er: - get_jira_er(args.jira_er[0]) + ret = get_jira_er(args.jira_er[0]) elif args.add: - jira_add_to_defect_db(args.add[0]) + ret = jira_add_to_defect_db(args.add[0]) elif args.delete: - jira_del_from_defect_db(args.add[0]) + ret = jira_del_from_defect_db(args.add[0]) elif 'new' == args.command: # Instantiate a sub-parse tree for "new" specific arguments # Example: @@ -877,7 +907,7 @@ def main(argv): new_parser.add_argument('--link','-L', help='Link to upstream CVE') args, argv = new_parser.parse_known_args() if verbose: - srt_error_log("SRTool_Jira_New: NOTE unprocessed arguments: %s" % argv) + srt_error_log("SRTool_Jira:NEW: NOTE unprocessed arguments: %s" % argv) jira_new_defect( args.tags if args.tags else '{}', args.summary if args.summary else '', @@ -889,23 +919,26 @@ def main(argv): args.link if args.link else '', ) elif 'init_jira' == args.command: - update_jira(True) + ret = update_jira(True) elif 'update_jira' == args.command: - update_jira(False) + ret = update_jira(False) elif jira_list: - jira_update_list(jira_list) + ret = jira_update_list(jira_list) elif 'jira-projects' == args.command: - get_projects() + ret = get_projects() else: print("Command not found") -if __name__ == '__main__': - global srtool_basepath + if 0 != ret: + exit(ret) + +if __name__ == '__main__': if verbose: print("srtool_jira(%s)" % sys.argv[1:]) # fetch any environment overrides - #set_override('SRTDBG_MINIMAL_DB') + set_override('SRTDBG_SKIP_DEFECT_IMPORT') + set_override('SRTDBG_MINIMAL_DB') srtool_basepath = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))) main(sys.argv[1:]) |