def scan()

in src/plugins/scanners/jira.py [0:0]


def scan(KibbleBit, source):
    jira = re.match(r"(https?://.+)/browse/([A-Z0-9]+)", source['sourceURL'])
    if jira:
        
        # JIRA NEEDS credentials to do a proper scan!
        creds = None
        if source['creds'] and 'username' in source['creds'] and source['creds']['username'] and len(source['creds']['username']) > 0:
            creds = "%s:%s" % (source['creds']['username'], source['creds']['password'])
        if not creds:
            KibbleBit.pprint("JIRA at %s requires authentication, but none was found! Bailing." % source['sourceURL'])
            source['steps']['issues'] = {
                'time': time.time(),
                'status': 'JIRA endpoint requires auth, but none was provided!',
                'running': False,
                'good': False
            }
            KibbleBit.updateSource(source)
            return
        
        source['steps']['issues'] = {
            'time': time.time(),
            'status': 'Parsing JIRA changes...',
            'running': True,
            'good': True
        }
        KibbleBit.updateSource(source)
        
        badOnes = 0
        jsa = []
        jsp = []
        pendingTickets = []
        KibbleBit.pprint("Parsing JIRA activity at %s" % source['sourceURL'])
        source['steps']['issues'] = {
            'time': time.time(),
            'status': 'Downloading changeset',
            'running': True,
            'good': True
        }
        KibbleBit.updateSource(source)
        
        # Get base URL, list and domain to parse
        u = jira.group(1)
        instance = jira.group(2)
        lastTicket = 0
        latestURL = "%s/rest/api/2/search?jql=project=%s+order+by+createdDate+DESC&fields=id,key&maxResults=1" % (u, instance)
        js = None
        
        try:
            js = plugins.utils.jsonapi.get(latestURL, auth = creds)
        except requests.exceptions.ConnectionError as err:
            KibbleBit.pprint("Connection error, skipping this ticket for now!")
            source['steps']['issues'] = {
                 'time': time.time(),
                 'status': 'Connection error occurred while scanning',
                 'running': False,
                 'good': False
             }
             KibbleBit.updateSource(source)
             return
        if 'issues' in js and len(js['issues']) == 1:
            key = js['issues'][0]['key']
            m = re.search(r"-(\d+)$", key)
            if m:
                lastTicket = int(m.group(1))
        
        
        openTickets = []
        startAt = 0
        badTries = 0
        while True and badTries < 10:
            openURL = "%s/rest/api/2/search?jql=project=%s+and+status=open+order+by+createdDate+ASC&fields=id,key&maxResults=100&startAt=%u" % (u, instance, startAt)
            #print(openURL)
            try:
                ojs = plugins.utils.jsonapi.get(openURL, auth = creds)
                if not 'issues' in ojs or len(ojs['issues']) == 0:
                    break
                for item in ojs['issues']:
                    openTickets.append(item['key'])
                KibbleBit.pprint("Found %u open tickets" % len(openTickets))
                startAt += 100
            except:
                KibbleBit.pprint("JIRA borked, retrying")
                badTries += 1
        KibbleBit.pprint("Found %u open tickets" % len(openTickets))
        
        badOnes = 0
        for i in reversed(range(1,lastTicket+1)):
            key = "%s-%u" % (instance, i)
            pendingTickets.append([key, u, source])
        
        threads = []
        block = threading.Lock()
        KibbleBit.pprint("Scanning tickets using 4 sub-threads")
        for i in range(0,4):
            t = jiraThread(block, KibbleBit, source, creds, pendingTickets, openTickets)
            threads.append(t)
            t.start()
        
        for t in threads:
            t.join()
        
        KibbleBit.pprint("Done scanning %s" % source['sourceURL'])

        source['steps']['issues'] = {
            'time': time.time(),
            'status': 'Issue tracker (JIRA) successfully scanned at ' + time.strftime("%Y/%m/%d %H:%M:%S", time.gmtime(time.time())),
            'running': False,
            'good': True
        }
        KibbleBit.updateSource(source)