Exemple #1
0
 def auth(self):
     try:
         client = JIRA(server=self.server_url, basic_auth=(
             self.username, self.password), max_retries=1)
         client.project(self.project)
         return client
     except:
         print("Authentication Error")
Exemple #2
0
 def __authenticate(self):
     client = JIRA(
         server=self.server,
         basic_auth=(
             self.username,
             self.password
         )
     )
     client.project(self.project)
     return client
Exemple #3
0
class JiraAccess:
    def __init__(self, hostname, username, password):
        self.jira = JIRA(hostname, basic_auth=(username, password))

    @staticmethod
    def has_field(issue, field_name):
        return hasattr(issue.fields, field_name) and getattr(
            issue.fields, field_name) is not None

    @staticmethod
    def get_story_points(issue):
        story_points_field_name = "customfield_10092"
        if JiraAccess.has_field(issue, story_points_field_name):
            return int(getattr(issue.fields, story_points_field_name))
        else:
            return None

    @staticmethod
    def get_jql_field_and_week(filter_id, issue_field_name, week_index):
        issues_in_week_jql = f'filter = {filter_id} AND issuetype in standardIssueTypes() AND {issue_field_name} >= ' \
                             f'startOfWeek({week_index}w)' \
                             f'AND {issue_field_name} <= endOfWeek({week_index}w)'
        return issues_in_week_jql

    def get_projects(self):
        self.jira.projects()

    def get_project(self, project_name):
        self.jira.project(project_name)

    def get_issue(self, issue_key):
        self.jira.issue(issue_key)

    def get_sprints_data(self, board_id, text_in_board_name):
        sprints = self.jira.sprints(board_id)
        sprints_list = list(
            filter(lambda x: f"{text_in_board_name}" in x.name, sprints))[-6:]
        for s in sprints_list:
            sprint_issues = self.jira.search_issues(f"sprint = {s.id}")
            sprint_bugs = self.jira.search_issues(
                f"sprint = {s.id} AND issueType = BUG")
            return SprintData(s.id, s.name, -1, len(sprint_bugs),
                              len(sprint_issues))

    # TODO: @cache results
    def get_resolved_in_week(self, filter_id, week_index):
        resolved_issues_in_week_jql = JiraAccess.get_jql_field_and_week(
            filter_id, "resolved", week_index)
        resolved_issues_in_week = self.jira.search_issues(
            resolved_issues_in_week_jql)

        return resolved_issues_in_week
Exemple #4
0
def main():
    args = handleArgs()
    configuration = loadConfiguration()
    project_name = configuration["project-key"]
    user_name = ''
    jira = ''
    if configuration["auth-type"] == "http":
        user_name = configuration["http-user"]["name"]
        jira = JIRA(configuration["options"],
                    auth=(configuration["http-user"]["name"],
                          configuration["http-user"]["password"]
                          ))  # a username/password tuple
    else:
        print("Authentication appears to be configured incorrectly")
        exit()
    project = jira.project(project_name)
    if len(args.mode) < 1:
        print("Please supply a mode!")
        exit()
    if args.mode[0] == 'list':
        tc.listIssues(jira, project_name)
    elif args.mode[0] == 'create':
        issue = ti.createIssue(user_name)
        issue['project']['id'] = project.id
        tc.createIssue(jira, issue)
    elif args.mode[0] == 'view':
        if len(args.search_string) < 1:
            print("Please provide an issue key")
            exit()
        issue = tc.openIssue(jira, args.search_string[0])
        ti.viewIssue(issue)
    elif args.mode[0] == 'edit':
        if len(args.search_string) < 1:
            print("Please provide an issue key")
            exit()
        issue = tc.openIssue(jira, args.search_string[0])
        ti.editIssue(issue)
    elif args.mode[0] == 'resolve':
        if len(args.search_string) < 1:
            print("Please provide an issue key")
            exit()
        issue = tc.openIssue(jira, args.search_string[0])
        issue_transition_fields = ti.resolveIssue()
        issue_transition_fields['assignee']['name'] = user_name
        tc.tranisitionIssue(jira, issue, issue_transition_fields,
                            'Resolve Issue')
    elif args.mode[0] == "qresolve":
        if len(args.search_string) < 1:
            print("Please provide an issue key")
            exit()
        if len(args.message) < 1:
            print('Please provide a resolution message')
            exit()
        issue = tc.openIssue(jira, args.search_string[0])
        issue_transition_fields = ti.resolveIssue(args.message[0])
        issue_transition_fields['assignee']['name'] = user_name
        tc.tranisitionIssue(jira, issue, issue_transition_fields,
                            'Resolve Issue')
    else:
        print("Unrecognized Command")
Exemple #5
0
def jira_prj_versions(project, version_range):
    (from_str, to_str) = version_range.split('-', 1)
    from_ver = parse_version(from_str)
    to_ver = parse_version(to_str)
    if from_ver == None or to_ver == None:
        raise ValueError("Cannot parse range %s" % version_range)
    if type(from_ver) != type(to_ver):
        raise ValueError("Inconsistent types in range %s" % version_range)

    jira = JIRA(server="https://jira.opendaylight.org")
    prj = jira.project(project)

    versions = set()
    for version in jira.project_versions(prj):
        name = version.name
        ver = parse_version(name)
        if type(ver) == type(from_ver) and ver >= from_ver and ver <= to_ver:
            versions.add(name)

    if len(versions) == 0:
        raise ValueError("No versions selected for project %s range %s" %
                         (project, version_range))

    versions = list(versions)
    versions.sort()
    versions = ", ".join(versions)

    return (jira, prj, from_str, to_str, versions)
Exemple #6
0
    def GET(self):
        gl.GL_WEBINPUT = web.input()
        projectname = gl.GL_WEBINPUT.product_name
        productline_list = gl.GL_DB.query("select distinct version from crashinfo where appName='" + projectname + "'")
        # select *, count(distinct name) from table group by name
        result = []
        result_g_version = []
        result_jira_version = []
        #jira = JIRA(server='http://127.0.0.1:1194', basic_auth=('wangyang', 'qwerty123456'))
        jira = JIRA(server=jira_server, basic_auth=(user_accout, user_pass))

        for name in project:
            if name in projectname:
                jira_name = project[name]["projectname"]

        versions = jira.project_versions(jira.project(jira_name))

        for item in productline_list:
            item_dict = {"game_version": item.version}
            result_g_version.append(item_dict)

        [result_jira_version.append({"jira_version": v.name}) for v in reversed(versions)]

        result.append(result_g_version)
        result.append(result_jira_version)

        encodedjson = json.dumps(result)

        return encodedjson
def update_zephyr(test_cases_list):
    args = parse_zapi_config()

    if "JIRA_URL" == args['jira_url']:
        print("Zephyr is not configured, skipping...")
        return
    """"Main routine"""

    jira = JIRA(basic_auth=(args["user"], args["passwd"]),
                options={'server': args["jira_url"]})

    proj = jira.project(args["project"])
    #verid = get_jira_release_id(args.release, jira, proj)
    verid = "32880"
    cycleName = args["cycle"]
    cycleName = cycleName + "_" + str(
        (datetime.datetime.now()).strftime("%Y%m%d%H%M%S"))

    reporter = zapi.Zapi(project_id=proj.id,
                         version_id=verid,
                         environment=str(args["environment"]),
                         build=args["build"],
                         jira_url=args["jira_url"],
                         usr=args["user"],
                         pwd=args["passwd"])
    if args["cycle"] is None:
        args["cycle"] = args["build"]
    reporter.get_or_create_cycle(str(cycleName))

    result = ""

    for i in range(len(test_cases_list)):
        test_name = test_cases_list[i][0]
        print "Test_name :" + test_name
        test_id = get_test_id_from_meta_file(args["metafile"], test_name)

        if test_id:
            print "Found Test ID in Meta file : " + test_id
            issue = jira.issue(test_id)
        if args["updateautomationstatus"]:
            update_automation_status(issue)

        exec_id = reporter.create_execution(str(issue.id))
        result = test_cases_list[i][1]
        print "Test case Result: " + result
        log_data = "sample log data"
        if result == 'FAIL':
            result = 'FAIL'
        if result == 'OK':
            result = 'PASS'
        if result == 'None':
            result = 'FAIL'
        if result == 'SKIP':
            result = 'NOT TESTED'
        if result == 'Exp FAIL':
            result = 'FAIL'

        reporter.set_execution(result, exec_id, log_data)
Exemple #8
0
def execute(args_list):
    args = parse_args(args_list)
    print("Running JIRA Tabulations for Releases")
    jira_options = {"server": "https://battlefy.atlassian.net"}
    jira = JIRA(
        options=jira_options,
        basic_auth=(args.user, args.api_token),
    )

    releases = args.releases.split(",")
    releases_container = []
    project_configs = {}

    for release in releases:
        release_obj = Release(release, [], 0.0)
        releases_container.append(release_obj)
        query_string = "fixVersion={}".format(release)
        # get a list of the issues first, just by summary and comprehend the
        # projects
        issue_projects = list(
            set([
                e.fields.project.id for e in jira.search_issues(query_string)
            ]))

        if len(issue_projects) != 1:
            print("Multiple projects in release; unable to assert size.")
            return -1
        root_project_id = issue_projects[0]

        if root_project_id not in project_configs:
            project_configs[
                root_project_id] = epicTimeRollup.generate_project_constants(
                    jira, jira.project(root_project_id))

        cust_keys = list(
            set([
                project_configs[root_project_id].story.estimation_key,
                project_configs[root_project_id].task.estimation_key
            ]))
        cust_key_str = ",".join(cust_keys)

        release_obj.issues = [
            epicTimeRollup.UserStory(
                e, e.fields.subtasks if hasattr(e.fields, "subtasks") else [],
                0.0)
            for e in jira.search_issues(
                query_string,
                fields="{}, subtasks, summary, issuetype".format(cust_key_str))
        ]

        for release in releases_container:
            for issue in release.issues:
                epicTimeRollup.extract_issue_estimate(
                    jira, issue, project_configs[root_project_id])
                release.summed_time += issue.summed_time

    if args.export_estimates:
        export_releases_json(args.export_estimates_path, releases_container)
def generate_page():
    options = {'server': 'http://shaipjira.local.tmvse.com'}
    jira = JIRA(options)
    project = jira.project('10002')
    requirements = jira.search_issues(
        'project = SHAIP AND issuetype = Requirement AND resolution = Unresolved ORDER BY id ASC',
        expand="renderedFields")

    template_requirements = []
    for requirement in requirements:
        links = []
        for link in requirement.fields.issuelinks:
            if link.type.name != "Defines":
                continue

            link_type = None
            issue = None
            if hasattr(link, 'outwardIssue'):
                link_type = "defines"
                issue = link.outwardIssue
            else:
                link_type = "is defined by"
                issue = link.inwardIssue

            links.append({
                'key': issue.key,
                'summary': issue.fields.summary,
                'icon_type': issue.fields.issuetype.iconUrl,
                'permalink': issue.permalink(),
                'closed': issue.fields.status.name == "Done",
                'link_type': link_type
            })

        template_requirements.append({
            'key':
            requirement.key,
            'summary':
            requirement.fields.summary,
            'description':
            requirement.renderedFields.description,
            'links':
            links,
            'permalink':
            requirement.permalink(),
            'labels':
            requirement.fields.labels
        })

    renderer = pystache.Renderer()
    context = {
        'project_name': project.name,
        'requirements': template_requirements,
        'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    }

    return renderer.render_path("templates/requirements.html.mustache",
                                context)
Exemple #10
0
def version_update_reporter(bot):
    jira_access = JIRA(
        server="https://bugs.mojang.com",
        basic_auth=(mojira_username, mojira_password),
    )

    # All the different minecraft versions on the bug tracker
    versions = jira_access.project("MC").versions

    embed = discord.Embed(color=discord.Colour.magenta())

    # We check for the different kinds of version changes.
    # We can just return after that since updates between the different version updates will never be faster
    # than the period of the loop.

    # Check for new versions, if there are we send the embed containing that info.
    new = new_version(bot, versions)
    if new:
        embed.title = str(new)
        embed.add_field(name="Affected", value=str(affected_bugs(str(new), jira_access)))
        embed.add_field(name="Fixed", value=str(fixed_bugs(str(new), jira_access)))

        content = "Version **{}** has just been created!".format(str(new))

        jira_access.close()
        return embed, content

    # Check for archived versions, if there are we send the embed containing that info.
    archived = archived_version(bot, versions)
    if archived:
        embed.title = str(archived)
        embed.add_field(name="Affected", value=str(affected_bugs(str(archived), jira_access)))
        embed.add_field(name="Fixed", value=str(fixed_bugs(str(archived), jira_access)))
        embed.add_field(name="Released", value=str(archived.released))

        content = "Version **{}** has just been archived!".format(str(archived))

        jira_access.close()
        return embed, content

    # Check for released versions, if there are we send the embed containing that info.
    released = released_version(bot, versions)
    if released:
        embed.title = str(released)
        embed.add_field(name="Affected", value=str(affected_bugs(str(released), jira_access)))
        embed.add_field(name="Fixed", value=str(fixed_bugs(str(released), jira_access)))
        embed.add_field(name="Released", value=str(released.released))

        content = "Version **{}** has just been released!".format(str(released))

        jira_access.close()
        return embed, content

    jira_access.close()
    return None
Exemple #11
0
class Jira:
    def __init__(self):
        self.user = "******"
        self.apikey = "your_jira_api_key"
        self.server = "https://your_emakina_jira_instance.com"
        self.project = "your_project_name"
        self.options = {'server': self.server}
        self.jira = JIRA(self.options, basic_auth=(self.user, self.apikey))

    def create_issue(self, summary, description, timestamp):
        self.jira.project(self.project)
        self.jira.create_issue(project=self.project,
                               summary=f"{summary} {timestamp}",
                               description=f"{description}",
                               issuetype={"name": "Task"})

    def add_attachment_to_ticket(self, filename):
        self.jira.add_attachment(
            issue=self.jira.search_issues(f'project={self.project}')[0],
            attachment=f"{filename}")
def get_project(params):
  api_server = params['api_url']
  api_username = params['api_username']
  api_password = params['api_password']
  auth = (api_username, api_password)
  jira = JIRA( {'server': api_server}, basic_auth=auth)
  key = params['project_key']
  try:
    return jira.project(key)
  except:
    return None
class JiraConnection(object):
    """Manages a connection to a Jira database"""
    def __init__(self):
        self.jira = None
        self.project = None

    def connect(self, url, user, passwd):
        """
        Connect to a Jira server

        Arguments:
        url    -- URL of the Jira server
        user   -- username
        passwd -- password
        """
        options = {'server': url}
        self.jira = JIRA(options, basic_auth=(user, passwd))

    def get_project_list(self):
        """
        Returns a list of available projects.
        Projects are tuples with the format (key, name).
        """
        plist = []
        for project in self.jira.projects():
            plist.append((project.key, project.name))
        return plist

    def set_project(self, key):
        """
        Sets the active project.

        Arguments:
        key -- project key
        """
        self.project = self.jira.project(key)
    
    def get_epic_list(self, project=None):
        """
        Returns a list of epics for the project.

        Arguments:
        project -- project key (optional if project is set)
        """
        if project is None and self.project is not None:
            project = self.project.key
        else:
            raise ValueError('A project is required')

        return self.jira.search_issues('project={0} and type=Epic'.format(project))
Exemple #14
0
def validate_config_value(config):
    """
    :param config: Project XML config class object
    :return: bool True if Project XML config values are valid else raises Exception
    """
    try:
        logger.debug("Connecting with Project JIRA server at URL [{}]".format(config.url))
        jira = JIRA(server=config.url, basic_auth=(config.user, config.passwd))
        logger.debug("Successfully connected!")
        logger.debug("Checking if project key exists [{0}] in server".format(config.key))
        name = jira.project(config.key).name
        logger.debug("Project key [{0}] with name [{1}] exists in server".format(config.key, name))
        return True
    except Exception:
        raise
Exemple #15
0
def get_versions(bot):
    jira_access = JIRA(
        server="https://bugs.mojang.com",
        basic_auth=(mojira_username, mojira_password),
    )
    versions = jira_access.project("MC").versions
    bot.mc_versions = {str(version) for version in versions}

    bot.latest_version = str(versions[-1])
    bot.previous_version = str(versions[-2])
    bot.latest_version_archive_status = versions[-1].archived
    bot.previous_version_archive_status = versions[-2].archived
    bot.latest_version_release_status = versions[-1].released

    jira_access.close()
Exemple #16
0
    class JIRACLASS(object):
        def __init__(self):
            self.jira = JIRA({'server': 'https://rajsimhag.atlassian.net'},
                             basic_auth=('*****@*****.**',
                                         'gautham999'))

        def getProjects(self, data):
            return self.jira.project(data)

        def getIssue(self, id):
            return self.jira.issue(id)

        def createIssue(self, data):
            return self.jira.create_issue(data)

        def deleteIssue(self, id):
            self.jira.delete_issue(id)
Exemple #17
0
    class JIRACLASS(object):
        def __init__(self):
            self.jira = JIRA(
                {'server': 'https://manojteluguntla.atlassian.net'},
                basic_auth=('*****@*****.**',
                            'Western852$@'))

        def getProjects(self, data):
            return self.jira.project(data)

        def getIssue(self, id):
            return self.jira.issue(id)

        def createIssue(self, data):
            return self.jira.create_issue(data)

        def deleteIssue(self, id):
            self.jira.delete_issue(id)
Exemple #18
0
def validate_config_value(config):
    """
    :param config: Project XML config class object
    :return: bool True if Project XML config values are valid else raises Exception
    """
    try:
        logger.debug("Connecting with Project JIRA server at URL [{}]".format(
            config.url))
        jira = JIRA(server=config.url, basic_auth=(config.user, config.passwd))
        logger.debug("Successfully connected!")
        logger.debug("Checking if project key exists [{0}] in server".format(
            config.key))
        name = jira.project(config.key).name
        logger.debug(
            "Project key [{0}] with name [{1}] exists in server".format(
                config.key, name))
        return True
    except Exception:
        raise
Exemple #19
0
class JiraService:
    def __init__(self):
        self.jira = JIRA(AppConstants.JIRA_SERVER_URL,
                         basic_auth=(AppConstants.JIRA_USERNAME,
                                     AppConstants.JIRA_PASSWORD))

    def get_all_projects(self) -> List[Project]:
        projects = self.jira.projects()
        return projects

    def get_project(self, project_id: str) -> Project:
        project = self.jira.project(id=project_id)
        return project

    def get_issues_for_project(self, project_id: str,
                               max_results: int) -> List[Issue]:
        issues = self.jira.search_issues(f"project = '{project_id}'",
                                         maxResults=max_results)
        return issues
Exemple #20
0
class JIRAProject:
    """
    Custom class which represents a JIRA project for DSR report
    """
    JQL = 'project="{project}" AND ((created >= "{start}" and created <= "{end}") ' \
          'OR (updated >= "{start}" and updated <= "{end}")) order by updated asc'

    def __init__(self, config, start_date, end_date):
        self.config = config
        self.start_date = start_date
        self.end_date = end_date
        self.jira = JIRA(server=config.url, basic_auth=(config.user,
                                                        config.passwd))
        self.timezone = pytz.timezone(config.timezone)
        self.name = self.jira.project(config.key).name

    def __str__(self):
        return self.name

    def __eq__(self, other):
        return self.config.key == other

    def get_project_issues(self):
        """
        This method returns a list of JIRA issue objects which have
        any activities within specified start and end date
        s
        :return: [JIRAIssue objects]
        """
        jira_issues_in_proj = self.jira.search_issues(
            JIRAProject.JQL.format(project=self.config.key, start=self.start_date, end=self.end_date))
        if jira_issues_in_proj:
            project_issues = list()
            for issue in jira_issues_in_proj:
                project_issue = JIRAIssue(self,
                                          self.jira,
                                          issue.key,
                                          self.start_date,
                                          self.end_date)
                project_issues.append(project_issue)
            return project_issues
Exemple #21
0
class JIRAProject:
    """
    Custom class which represents a JIRA project for DSR report
    """
    JQL = 'project="{project}" AND ((created >= "{start}" and created <= "{end}") ' \
          'OR (updated >= "{start}" and updated <= "{end}")) order by updated asc'

    def __init__(self, config, start_date, end_date):
        self.config = config
        self.start_date = start_date
        self.end_date = end_date
        self.jira = JIRA(server=config.url,
                         basic_auth=(config.user, config.passwd))
        self.timezone = pytz.timezone(config.timezone)
        self.name = self.jira.project(config.key).name

    def __str__(self):
        return self.name

    def __eq__(self, other):
        return self.config.key == other

    def get_project_issues(self):
        """
        This method returns a list of JIRA issue objects which have
        any activities within specified start and end date
        s
        :return: [JIRAIssue objects]
        """
        jira_issues_in_proj = self.jira.search_issues(
            JIRAProject.JQL.format(project=self.config.key,
                                   start=self.start_date,
                                   end=self.end_date))
        if jira_issues_in_proj:
            project_issues = list()
            for issue in jira_issues_in_proj:
                project_issue = JIRAIssue(self, self.jira, issue.key,
                                          self.start_date, self.end_date)
                project_issues.append(project_issue)
            return project_issues
def create_project(params):
  api_server = params['api_url']
  api_username = params['api_username']
  api_password = params['api_password']
  auth = (api_username, api_password)
  jira = JIRA( {'server': api_server}, basic_auth=auth)
  project_key = params['project_key']
  project_name = params['project_name']
  assignee = params['assignee']

  # create project and view
  if not jira.create_project(project_key, name=project_name, assignee=assignee):
    return None
  proj = jira.project(project_key)
  board = jira.create_board("{0} View".format(project_name), project_key, preset='scrum')
  issue = jira.create_issue(
             project=project_key,
             summary="Sample Issue for {0}".format(project_name),
             description="This is just sample",
             issuetype={"name":"Task"}
          )
  return proj
Exemple #23
0
def push_ticket(jira: Jira, ticket: JiraTicket):
    """Push a JiraTicket to a Jira server.

    Args:
        jira: The Jira server to get tickets from.
        ticket: The ticket to push to the Jira server.
    """
    # Create the ticket
    ticket_fields = {
        "description": add_source_link_to_description(
            ticket.description, ticket.source_link
        ),
        "issuetype": {"name": "Task"},
        "priority": {"name": ticket.priority},
        "project": {"id": jira.project(ticket.project).id},
        "summary": ticket.summary,
    }

    new_ticket = jira.create_issue(fields=ticket_fields)

    # Transition the ticket
    if ticket.resolution is not None:
        # List available transitions and search for the one we want (if
        # it exists)
        transitions = jira.transitions(new_ticket)

        id_ = None

        for transition in transitions:
            if transition["name"] == ticket.resolution:
                # Found it
                id_ = transition["id"]
                break

        # Transition not available. That's okay.
        if id_ is None:
            return

        jira.transition_issue(new_ticket, id_)
Exemple #24
0
class Api(object):
    versions = None

    def __init__(self):
        self.j = JIRA(
            server=settings.JIRA_URL,
            basic_auth=(settings.JIRA_USERNAME, settings.JIRA_PASSWORD),
        )
        self.project = self.j.project(settings.JIRA_PROJECT)

    def get_versions(self):
        return self.j.project_versions(self.project)

    def get_issues(self, version_name, username):
        if self.versions is None:
            self.versions = self.get_versions()

        version = next(
            (v for v in self.versions
             if version_name in v.name
             and '1C' not in v.name
             and '1С' not in v.name
             and 'WWW' not in v.name
             ), None
        )
        if version is None:
            return []
        else:
            jql = 'project=VIP ' \
                  'AND resolution=Unresolved ' \
                  'AND fixVersion="{fixVersion}"' \
                  'AND assignee in ({assignee})'.format(
                fixVersion=version.name,
                assignee=username,
            )
            return self.j.search_issues(jql)
Exemple #25
0
def update_zephyr(test_cases_list):
    args = parse_zapi_config()
    if len(args) == 0:
        print("Zephyr is not configured, skipping...")
        return
    print('Starting Zephyr Execution....')

    for z in args:
        if "JIRA_URL" == z['jira_url'] or "JIRAPASSWORD" == z['passwd']:
            # This is not configure, skip to next
            continue
        """"Main routine"""

        jira = JIRA(basic_auth=(z["user"], z["passwd"]),
                    options={'server': z["jira_url"]})

        proj = jira.project(z["project"])
        verid = get_jira_release_id(z['release'], jira, proj)
        cycleName = z["cycle"]
        cycleName = cycleName + "_" + str(
            (datetime.datetime.now()).strftime("%Y%m%d%H%M%S"))

        reporter = zapi.Zapi(project_id=proj.id,
                             version_id=verid,
                             environment=str(z["environment"]),
                             build=z["build"],
                             jira_url=z["jira_url"],
                             usr=z["user"],
                             pwd=z["passwd"])
        if z["cycle"] is None:
            z["cycle"] = z["build"]
        reporter.get_or_create_cycle(str(cycleName))

        result = ""

        for i in range(len(test_cases_list)):
            test_name = test_cases_list[i][0]
            print("Test_name :" + test_name)
            test_id = get_test_id_from_meta_file(z["metafile"], test_name)

            if test_id:
                print("Found Test ID in Meta file : " + test_id)
                issue = jira.issue(test_id)
            else:
                continue

            if z["updateautomationstatus"]:
                update_automation_status(issue)

            exec_id = reporter.create_execution(str(issue.id))
            result = test_cases_list[i][1]
            print("Test case Result: " + result)
            log_data = "sample log data"
            if result == 'FAIL':
                result = 'FAIL'
            if result == 'OK':
                result = 'PASS'
            if result == 'None':
                result = 'FAIL'
            if result == 'SKIP':
                result = 'NOT TESTED'
            if result == 'Exp FAIL':
                result = 'FAIL'

            if 'status_codes' in z:
                ret = reporter.set_execution(
                    result,
                    exec_id,
                    log_data,
                    status_code_dict=z['status_codes'])
            else:
                ret = reporter.set_execution(result, exec_id, log_data)

            if ret.status_code != requests.codes.ok:
                raise Exception(
                    "Error = %s, when trying to set execution status" % ret)
Exemple #26
0
class JiraAPI(object):
    def __init__(self,
                 hostname=None,
                 username=None,
                 password=None,
                 path="",
                 debug=False,
                 clean_obsolete=True,
                 max_time_window=12):
        self.logger = logging.getLogger('JiraAPI')
        if debug:
            self.logger.setLevel(logging.DEBUG)

        if "https://" not in hostname:
            hostname = "https://{}".format(hostname)
        self.username = username
        self.password = password
        self.jira = JIRA(options={'server': hostname},
                         basic_auth=(self.username, self.password))
        self.logger.info("Created vjira service for {}".format(hostname))
        self.all_tickets = []
        self.JIRA_REOPEN_ISSUE = "Reopen Issue"
        self.JIRA_CLOSE_ISSUE = "Close Issue"
        self.max_time_tracking = max_time_window  #in months
        #<JIRA Resolution: name=u'Obsolete', id=u'11'>
        self.JIRA_RESOLUTION_OBSOLETE = "Obsolete"
        self.JIRA_RESOLUTION_FIXED = "Fixed"
        self.clean_obsolete = clean_obsolete
        self.template_path = 'vulnwhisp/reporting/resources/ticket.tpl'
        if path:
            self.download_tickets(path)
        else:
            self.logger.warn(
                "No local path specified, skipping Jira ticket download.")

    def create_ticket(self, title, desc, project="IS", components=[], tags=[]):
        labels = ['vulnerability_management']
        for tag in tags:
            labels.append(str(tag))

        self.logger.info("creating ticket for project {} title[20] {}".format(
            project, title[:20]))
        self.logger.info("project {} has a component requirement: {}".format(
            project, self.PROJECT_COMPONENT_TABLE[project]))
        project_obj = self.jira.project(project)
        components_ticket = []
        for component in components:
            exists = False
            for c in project_obj.components:
                if component == c.name:
                    self.logger.debug(
                        "resolved component name {} to id {}".format(
                            c.name, c.id))
                    components_ticket.append({"id": c.id})
                    exists = True
            if not exists:
                self.logger.error(
                    "Error creating Ticket: component {} not found".format(
                        component))
                return 0

        new_issue = self.jira.create_issue(project=project,
                                           summary=title,
                                           description=desc,
                                           issuetype={'name': 'Bug'},
                                           labels=labels,
                                           components=components_ticket)

        self.logger.info("Ticket {} created successfully".format(new_issue))
        return new_issue

    #Basic JIRA Metrics
    def metrics_open_tickets(self, project=None):
        jql = "labels= vulnerability_management and resolution = Unresolved"
        if project:
            jql += " and (project='{}')".format(project)
        self.logger.debug('Executing: {}'.format(jql))
        return len(self.jira.search_issues(jql, maxResults=0))

    def metrics_closed_tickets(self, project=None):
        jql = "labels= vulnerability_management and NOT resolution = Unresolved"
        if project:
            jql += " and (project='{}')".format(project)
        return len(self.jira.search_issues(jql, maxResults=0))

    def sync(self, vulnerabilities, project, components=[]):
        #JIRA structure of each vulnerability: [source, scan_name, title, diagnosis, consequence, solution, ips, risk, references]
        self.logger.info("JIRA Sync started")

        # [HIGIENE] close tickets older than 12 months as obsolete
        # Higiene clean up affects to all tickets created by the module, filters by label 'vulnerability_management'
        if self.clean_obsolete:
            self.close_obsolete_tickets()

        for vuln in vulnerabilities:
            # JIRA doesn't allow labels with spaces, so making sure that the scan_name doesn't have spaces
            # if it has, they will be replaced by "_"
            if " " in vuln['scan_name']:
                vuln['scan_name'] = "_".join(vuln['scan_name'].split(" "))

            exists = False
            to_update = False
            ticketid = ""
            ticket_assets = []
            exists, to_update, ticketid, ticket_assets = self.check_vuln_already_exists(
                vuln)

            if exists:
                # If ticket "resolved" -> reopen, as vulnerability is still existent
                self.reopen_ticket(ticketid)
                self.add_label(ticketid, vuln['risk'])
                continue
            elif to_update:
                self.ticket_update_assets(vuln, ticketid, ticket_assets)
                self.add_label(ticketid, vuln['risk'])
                continue

            try:
                tpl = template(self.template_path, vuln)
            except Exception as e:
                self.logger.error('Exception templating: {}'.format(str(e)))
                return 0
            self.create_ticket(title=vuln['title'],
                               desc=tpl,
                               project=project,
                               components=components,
                               tags=[
                                   vuln['source'], vuln['scan_name'],
                                   'vulnerability', vuln['risk']
                               ])

        self.close_fixed_tickets(vulnerabilities)
        # we reinitialize so the next sync redoes the query with their specific variables
        self.all_tickets = []
        return True

    def check_vuln_already_exists(self, vuln):
        # we need to return if the vulnerability has already been reported and the ID of the ticket for further processing
        #function returns array [duplicated(bool), update(bool), ticketid, ticket_assets]
        title = vuln['title']
        labels = [
            vuln['source'], vuln['scan_name'], 'vulnerability_management',
            'vulnerability'
        ]
        #list(set()) to remove duplicates
        assets = list(
            set(
                re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b",
                           ",".join(vuln['ips']))))

        if not self.all_tickets:
            self.logger.info(
                "Retrieving all JIRA tickets with the following tags {}".
                format(labels))
            # we want to check all JIRA tickets, to include tickets moved to other queues
            # will exclude tickets older than 12 months, old tickets will get closed for higiene and recreated if still vulnerable
            jql = "{} AND NOT labels=advisory AND created >=startOfMonth(-{})".format(
                " AND ".join(["labels={}".format(label) for label in labels]),
                self.max_time_tracking)

            self.all_tickets = self.jira.search_issues(jql, maxResults=0)

        #WARNING: function IGNORES DUPLICATES, after finding a "duplicate" will just return it exists
        #it wont iterate over the rest of tickets looking for other possible duplicates/similar issues
        self.logger.info("Comparing Vulnerabilities to created tickets")
        for index in range(len(self.all_tickets) - 1):
            checking_ticketid, checking_title, checking_assets = self.ticket_get_unique_fields(
                self.all_tickets[index])
            if title == checking_title:
                difference = list(
                    set(assets).symmetric_difference(checking_assets))
                #to check intersection - set(assets) & set(checking_assets)
                if difference:
                    self.logger.info(
                        "Asset mismatch, ticket to update. Ticket ID: {}".
                        format(checking_ticketid))
                    return False, True, checking_ticketid, checking_assets  #this will automatically validate
                else:
                    self.logger.info(
                        "Confirmed duplicated. TickedID: {}".format(
                            checking_ticketid))
                    return True, False, checking_ticketid, [
                    ]  #this will automatically validate
        return False, False, "", []

    def ticket_get_unique_fields(self, ticket):
        title = ticket.raw.get('fields',
                               {}).get('summary').encode("ascii").strip()
        ticketid = ticket.key.encode("ascii")
        try:
            affected_assets_section = ticket.raw.get(
                'fields', {}).get('description').encode("ascii").split(
                    "{panel:title=Affected Assets}")[1].split("{panel}")[0]
            assets = list(
                set(
                    re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b",
                               affected_assets_section)))
        except:
            self.logger.error(
                "Ticket IPs regex failed. Ticket ID: {}".format(ticketid))
            assets = []

        return ticketid, title, assets

    def get_ticket_reported_assets(self, ticket):
        #[METRICS] return a list with all the affected assets for that vulnerability (including already resolved ones)
        return list(
            set(
                re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b",
                           str(self.jira.issue(ticket).raw))))

    def get_resolution_time(self, ticket):
        #get time a ticket took to be resolved
        ticket_obj = self.jira.issue(ticket)
        if self.is_ticket_resolved(ticket_obj):
            ticket_data = ticket_obj.raw.get('fields')
            #dates follow format '2018-11-06T10:36:13.849+0100'
            created = [
                int(x) for x in ticket_data['created'].split('.')[0].replace(
                    'T', '-').replace(':', '-').split('-')
            ]
            resolved = [
                int(x)
                for x in ticket_data['resolutiondate'].split('.')[0].replace(
                    'T', '-').replace(':', '-').split('-')
            ]

            start = datetime(created[0], created[1], created[2], created[3],
                             created[4], created[5])
            end = datetime(resolved[0], resolved[1], resolved[2], resolved[3],
                           resolved[4], resolved[5])

            return (end - start).days
        else:
            self.logger.error(
                "Ticket {ticket} is not resolved, can't calculate resolution time"
                .format(ticket=ticket))

        return False

    def ticket_update_assets(self, vuln, ticketid, ticket_assets):
        # correct description will always be in the vulnerability to report, only needed to update description to new one
        self.logger.info("Ticket {} exists, UPDATE requested".format(ticketid))

        if self.is_ticket_resolved(self.jira.issue(ticketid)):
            self.reopen_ticket(ticketid)
        try:
            tpl = template(self.template_path, vuln)
        except Exception as e:
            self.logger.error('Exception updating assets: {}'.format(str(e)))
            return 0

        ticket_obj = self.jira.issue(ticketid)
        ticket_obj.update()
        assets = list(
            set(
                re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b",
                           ",".join(vuln['ips']))))
        difference = list(set(assets).symmetric_difference(ticket_assets))

        comment = ''
        #put a comment with the assets that have been added/removed
        for asset in difference:
            if asset in assets:
                comment += "Asset {} have been added to the ticket as vulnerability *has been newly detected*.\n".format(
                    asset)
            elif asset in ticket_assets:
                comment += "Asset {} have been removed from the ticket as vulnerability *has been resolved*.\n".format(
                    asset)

        try:
            ticket_obj.update(description=tpl,
                              comment=comment,
                              fields={"labels": ticket_obj.fields.labels})
            self.logger.info("Ticket {} updated successfully".format(ticketid))
            self.add_label(ticketid, 'updated')
        except:
            self.logger.error(
                "Error while trying up update ticket {}".format(ticketid))
        return 0

    def add_label(self, ticketid, label):
        ticket_obj = self.jira.issue(ticketid)

        if label not in ticket_obj.fields.labels:
            ticket_obj.fields.labels.append(label)

        try:
            ticket_obj.update(fields={"labels": ticket_obj.fields.labels})
            self.logger.info("Added label {label} to ticket {ticket}".format(
                label=label, ticket=ticketid))
        except:
            self.logger.error(
                "Error while trying to add label {label} to ticket {ticket}".
                format(label=label, ticket=ticketid))
        return 0

    def close_fixed_tickets(self, vulnerabilities):
        # close tickets which vulnerabilities have been resolved and are still open
        found_vulns = []
        for vuln in vulnerabilities:
            found_vulns.append(vuln['title'])

        comment = '''This ticket is being closed as it appears that the vulnerability no longer exists.
        If the vulnerability reappears, a new ticket will be opened.'''

        for ticket in self.all_tickets:
            if ticket.raw['fields']['summary'].strip() in found_vulns:
                self.logger.info(
                    "Ticket {} is still vulnerable".format(ticket))
                continue
            self.logger.info(
                "Ticket {} is no longer vulnerable".format(ticket))
            self.close_ticket(ticket, self.JIRA_RESOLUTION_FIXED, comment)
        return 0

    def is_ticket_reopenable(self, ticket_obj):
        transitions = self.jira.transitions(ticket_obj)
        for transition in transitions:
            if transition.get('name') == self.JIRA_REOPEN_ISSUE:
                self.logger.debug("Ticket is reopenable")
                return True
        self.logger.warn("Ticket can't be opened. Check Jira transitions.")
        return False

    def is_ticket_closeable(self, ticket_obj):
        transitions = self.jira.transitions(ticket_obj)
        for transition in transitions:
            if transition.get('name') == self.JIRA_CLOSE_ISSUE:
                return True
        self.logger.warn("Ticket can't closed. Check Jira transitions.")
        return False

    def is_ticket_resolved(self, ticket_obj):
        #Checks if a ticket is resolved or not
        if ticket_obj is not None:
            if ticket_obj.raw['fields'].get('resolution') is not None:
                if ticket_obj.raw['fields'].get('resolution').get(
                        'name') != 'Unresolved':
                    self.logger.debug(
                        "Checked ticket {} is already closed".format(
                            ticket_obj))
                    self.logger.info("Ticket {} is closed".format(ticket_obj))
                    return True
        self.logger.debug(
            "Checked ticket {} is already open".format(ticket_obj))
        return False

    def is_risk_accepted(self, ticket_obj):
        if ticket_obj is not None:
            if ticket_obj.raw['fields'].get('labels') is not None:
                labels = ticket_obj.raw['fields'].get('labels')
                if "risk_accepted" in labels:
                    self.logger.warn(
                        "Ticket {} accepted risk, will be ignored".format(
                            ticket_obj))
                    return True
                elif "server_decomission" in labels:
                    self.logger.warn(
                        "Ticket {} server decomissioned, will be ignored".
                        format(ticket_obj))
                    return True
        self.logger.info(
            "Ticket {} risk has not been accepted".format(ticket_obj))
        return False

    def reopen_ticket(self, ticketid):
        self.logger.debug(
            "Ticket {} exists, REOPEN requested".format(ticketid))
        # this will reopen a ticket by ticketid
        ticket_obj = self.jira.issue(ticketid)

        if self.is_ticket_resolved(ticket_obj):
            if not self.is_risk_accepted(ticket_obj):
                try:
                    if self.is_ticket_reopenable(ticket_obj):
                        comment = '''This ticket has been reopened due to the vulnerability not having been fixed (if multiple assets are affected, all need to be fixed; if the server is down, lastest known vulnerability might be the one reported).
                        In the case of the team accepting the risk and wanting to close the ticket, please add the label "*risk_accepted*" to the ticket before closing it.
                        If server has been decomissioned, please add the label "*server_decomission*" to the ticket before closing it.
                        If you have further doubts, please contact the Security Team.'''
                        error = self.jira.transition_issue(
                            issue=ticketid,
                            transition=self.JIRA_REOPEN_ISSUE,
                            comment=comment)
                        self.logger.info(
                            "Ticket {} reopened successfully".format(ticketid))
                        self.add_label(ticketid, 'reopened')
                        return 1
                except Exception as e:
                    # continue with ticket data so that a new ticket is created in place of the "lost" one
                    self.logger.error("error reopening ticket {}: {}".format(
                        ticketid, e))
                    return 0
        return 0

    def close_ticket(self, ticketid, resolution, comment):
        # this will close a ticket by ticketid
        self.logger.debug("Ticket {} exists, CLOSE requested".format(ticketid))
        ticket_obj = self.jira.issue(ticketid)
        if not self.is_ticket_resolved(ticket_obj):
            try:
                if self.is_ticket_closeable(ticket_obj):
                    #need to add the label before closing the ticket
                    self.add_label(ticketid, 'closed')
                    error = self.jira.transition_issue(
                        issue=ticketid,
                        transition=self.JIRA_CLOSE_ISSUE,
                        comment=comment,
                        resolution={"name": resolution})
                    self.logger.info(
                        "Ticket {} closed successfully".format(ticketid))
                    return 1
            except Exception as e:
                # continue with ticket data so that a new ticket is created in place of the "lost" one
                self.logger.error("error closing ticket {}: {}".format(
                    ticketid, e))
                return 0

        return 0

    def close_obsolete_tickets(self):
        # Close tickets older than 12 months, vulnerabilities not solved will get created a new ticket
        self.logger.info(
            "Closing obsolete tickets older than {} months".format(
                self.max_time_tracking))
        jql = "labels=vulnerability_management AND created <startOfMonth(-{}) and resolution=Unresolved".format(
            self.max_time_tracking)
        tickets_to_close = self.jira.search_issues(jql, maxResults=0)

        comment = '''This ticket is being closed for hygiene, as it is more than 12 months old.
        If the vulnerability still exists, a new ticket will be opened.'''

        for ticket in tickets_to_close:
            self.close_ticket(ticket, self.JIRA_RESOLUTION_OBSOLETE, comment)

        return 0

    def project_exists(self, project):
        try:
            self.jira.project(project)
            return True
        except:
            return False
        return False

    def download_tickets(self, path):
        #saves all tickets locally, local snapshot of vulnerability_management ticktes
        #check if file already exists
        check_date = str(date.today())
        fname = '{}jira_{}.json'.format(path, check_date)
        if os.path.isfile(fname):
            self.logger.info(
                "File {} already exists, skipping ticket download".format(
                    fname))
            return True
        try:
            self.logger.info(
                "Saving locally tickets from the last {} months".format(
                    self.max_time_tracking))
            jql = "labels=vulnerability_management AND created >=startOfMonth(-{})".format(
                self.max_time_tracking)
            tickets_data = self.jira.search_issues(jql, maxResults=0)

            #end of line needed, as writelines() doesn't add it automatically, otherwise one big line
            to_save = [
                json.dumps(ticket.raw.get('fields')) + "\n"
                for ticket in tickets_data
            ]
            with open(fname, 'w') as outfile:
                outfile.writelines(to_save)
                self.logger.info("Tickets saved succesfully.")

            return True

        except Exception as e:
            self.logger.error(
                "Tickets could not be saved locally: {}.".format(e))

        return False
Exemple #27
0
    parser.error("Must to specify ALL commandline flags")

jiraserver = options.jiraserver
jbide_fixversion = options.jbidefixversion
jbds_fixversion = options.jbdsfixversion

from components import checkFixVersionsExist, queryComponentLead, defaultAssignee

if checkFixVersionsExist(jbide_fixversion, jbds_fixversion, jiraserver,
                         options.usernameJIRA, options.passwordJIRA) == True:

    frombranch = options.frombranch
    jira = JIRA(options={'server': jiraserver},
                basic_auth=(options.usernameJIRA, options.passwordJIRA))
    CLJBIDE = jira.project_components(
        jira.project('JBIDE'))  # full list of components in JBIDE
    CLJBDS = jira.project_components(
        jira.project('JBDS'))  # full list of components in JBIDE

    taskdescription = options.taskdescription
    taskdescriptionfull = options.taskdescriptionfull
    if not options.taskdescriptionfull:
        taskdescriptionfull = options.taskdescription

    ## The jql query across for all task issues
    tasksearchquery = '((project in (JBDS) and fixVersion = "' + jbds_fixversion + '") or (project in (JBIDE) and fixVersion = "' + jbide_fixversion + '")) AND labels = task'

    tasksearch = jiraserver + '/issues/?jql=' + urllib.quote_plus(
        tasksearchquery)

    rootJBDS_dict = {
Exemple #28
0
class JiraTestManager(object):
    """Used to instantiate and populate the JIRA instance with data used by the unit tests.

    Attributes:
        CI_JIRA_ADMIN (str): Admin user account name.
        CI_JIRA_USER (str): Limited user account name.
        max_retries (int): number of retries to perform for recoverable HTTP errors.
    """

    # __metaclass__ = Singleton

    # __instance = None
    #
    # Singleton implementation
    # def __new__(cls, *args, **kwargs):
    #     if not cls.__instance:
    #         cls.__instance = super(JiraTestManager, cls).__new__(
    #                             cls, *args, **kwargs)
    #     return cls.__instance

    #  Implementing some kind of Singleton, to prevent test initialization
    # http://stackoverflow.com/questions/31875/is-there-a-simple-elegant-way-to-define-singletons-in-python/33201#33201
    __shared_state = {}

    @retry(stop=stop_after_attempt(2))
    def __init__(self):
        self.__dict__ = self.__shared_state

        if not self.__dict__:
            self.initialized = 0

            try:

                if 'CI_JIRA_URL' in os.environ:
                    self.CI_JIRA_URL = os.environ['CI_JIRA_URL']
                    self.max_retries = 5
                else:
                    self.CI_JIRA_URL = "https://pycontribs.atlassian.net"
                    self.max_retries = 5

                if 'CI_JIRA_ADMIN' in os.environ:
                    self.CI_JIRA_ADMIN = os.environ['CI_JIRA_ADMIN']
                else:
                    self.CI_JIRA_ADMIN = 'ci-admin'

                if 'CI_JIRA_ADMIN_PASSWORD' in os.environ:
                    self.CI_JIRA_ADMIN_PASSWORD = os.environ[
                        'CI_JIRA_ADMIN_PASSWORD']
                else:
                    self.CI_JIRA_ADMIN_PASSWORD = '******'

                if 'CI_JIRA_USER' in os.environ:
                    self.CI_JIRA_USER = os.environ['CI_JIRA_USER']
                else:
                    self.CI_JIRA_USER = '******'

                if 'CI_JIRA_USER_PASSWORD' in os.environ:
                    self.CI_JIRA_USER_PASSWORD = os.environ[
                        'CI_JIRA_USER_PASSWORD']
                else:
                    self.CI_JIRA_USER_PASSWORD = '******'

                self.CI_JIRA_ISSUE = os.environ.get('CI_JIRA_ISSUE', 'Bug')

                if OAUTH:
                    self.jira_admin = JIRA(
                        oauth={
                            'access_token': 'hTxcwsbUQiFuFALf7KZHDaeAJIo3tLUK',
                            'access_token_secret':
                            'aNCLQFP3ORNU6WY7HQISbqbhf0UudDAf',
                            'consumer_key': CONSUMER_KEY,
                            'key_cert': KEY_CERT_DATA
                        })
                else:
                    if self.CI_JIRA_ADMIN:
                        self.jira_admin = JIRA(
                            self.CI_JIRA_URL,
                            basic_auth=(self.CI_JIRA_ADMIN,
                                        self.CI_JIRA_ADMIN_PASSWORD),
                            logging=False,
                            validate=True,
                            max_retries=self.max_retries)
                    else:
                        self.jira_admin = JIRA(self.CI_JIRA_URL,
                                               validate=True,
                                               logging=False,
                                               max_retries=self.max_retries)
                if self.jira_admin.current_user() != self.CI_JIRA_ADMIN:
                    # self.jira_admin.
                    self.initialized = 1
                    sys.exit(3)

                if OAUTH:
                    self.jira_sysadmin = JIRA(oauth={
                        'access_token': '4ul1ETSFo7ybbIxAxzyRal39cTrwEGFv',
                        'access_token_secret':
                        'K83jBZnjnuVRcfjBflrKyThJa0KSjSs2',
                        'consumer_key': CONSUMER_KEY,
                        'key_cert': KEY_CERT_DATA
                    },
                                              logging=False,
                                              max_retries=self.max_retries)
                else:
                    if self.CI_JIRA_ADMIN:
                        self.jira_sysadmin = JIRA(
                            self.CI_JIRA_URL,
                            basic_auth=(self.CI_JIRA_ADMIN,
                                        self.CI_JIRA_ADMIN_PASSWORD),
                            logging=False,
                            validate=True,
                            max_retries=self.max_retries)
                    else:
                        self.jira_sysadmin = JIRA(self.CI_JIRA_URL,
                                                  logging=False,
                                                  max_retries=self.max_retries)

                if OAUTH:
                    self.jira_normal = JIRA(
                        oauth={
                            'access_token': 'ZVDgYDyIQqJY8IFlQ446jZaURIz5ECiB',
                            'access_token_secret':
                            '5WbLBybPDg1lqqyFjyXSCsCtAWTwz1eD',
                            'consumer_key': CONSUMER_KEY,
                            'key_cert': KEY_CERT_DATA
                        })
                else:
                    if self.CI_JIRA_ADMIN:
                        self.jira_normal = JIRA(
                            self.CI_JIRA_URL,
                            basic_auth=(self.CI_JIRA_USER,
                                        self.CI_JIRA_USER_PASSWORD),
                            validate=True,
                            logging=False,
                            max_retries=self.max_retries)
                    else:
                        self.jira_normal = JIRA(self.CI_JIRA_URL,
                                                validate=True,
                                                logging=False,
                                                max_retries=self.max_retries)

                # now we need some data to start with for the tests

                # jira project key is max 10 chars, no letter.
                # [0] always "Z"
                # [1-6] username running the tests (hope we will not collide)
                # [7-8] python version A=0, B=1,..
                # [9] A,B -- we may need more than one project
                """ `jid` is important for avoiding concurency problems when
                executing tests in parallel as we have only one test instance.

                jid length must be less than 9 characters because we may append
                another one and the JIRA Project key length limit is 10.

                Tests run in parallel:
                * git branches master or developer, git pr or developers running
                  tests outside Travis
                * Travis is using "Travis" username

                https://docs.travis-ci.com/user/environment-variables/
                """

                self.jid = get_unique_project_name()

                self.project_a = self.jid + 'A'  # old XSS
                self.project_a_name = "Test user=%s key=%s A" \
                                      % (getpass.getuser(), self.project_a)
                self.project_b = self.jid + 'B'  # old BULK
                self.project_b_name = "Test user=%s key=%s B" \
                                      % (getpass.getuser(), self.project_b)
                self.project_c = self.jid + 'C'  # For Service Desk
                self.project_c_name = "Test user=%s key=%s C" \
                                      % (getpass.getuser(), self.project_c)

                # TODO(ssbarnea): find a way to prevent SecurityTokenMissing for On Demand
                # https://jira.atlassian.com/browse/JRA-39153
                try:
                    self.jira_admin.project(self.project_a)
                except Exception as e:
                    logging.warning(e)
                    pass
                else:
                    try:
                        self.jira_admin.delete_project(self.project_a)
                    except Exception as e:
                        pass

                try:
                    self.jira_admin.project(self.project_b)
                except Exception as e:
                    logging.warning(e)
                    pass
                else:
                    try:
                        self.jira_admin.delete_project(self.project_b)
                    except Exception as e:
                        pass

                try:
                    self.jira_admin.project(self.project_c)
                except Exception as e:
                    logging.warning(e)
                    pass
                else:
                    try:
                        self.jira_admin.delete_project(self.project_c)
                    except Exception as e:
                        pass

                # wait for the project to be deleted
                for i in range(1, 20):
                    try:
                        self.jira_admin.project(self.project_b)
                    except Exception as e:
                        break
                    sleep(2)

                try:
                    self.jira_admin.create_project(self.project_a,
                                                   self.project_a_name)
                except Exception:
                    # we care only for the project to exist
                    pass
                self.project_a_id = self.jira_admin.project(self.project_a).id
                # except Exception as e:
                #    logging.warning("Got %s" % e)
                # try:
                # assert self.jira_admin.create_project(self.project_b,
                # self.project_b_name) is  True, "Failed to create %s" %
                # self.project_b

                try:
                    self.jira_admin.create_project(self.project_b,
                                                   self.project_b_name)
                except Exception:
                    # we care only for the project to exist
                    pass

                # Create project for Jira Service Desk
                try:
                    self.jira_admin.create_project(
                        self.project_c,
                        self.project_c_name,
                        template_name='IT Service Desk')
                except Exception:
                    pass

                sleep(1)  # keep it here as often JIRA will report the
                # project as missing even after is created
                self.project_b_issue1_obj = self.jira_admin.create_issue(
                    project=self.project_b,
                    summary='issue 1 from %s' % self.project_b,
                    issuetype=self.CI_JIRA_ISSUE)
                self.project_b_issue1 = self.project_b_issue1_obj.key

                self.project_b_issue2_obj = self.jira_admin.create_issue(
                    project=self.project_b,
                    summary='issue 2 from %s' % self.project_b,
                    issuetype={'name': self.CI_JIRA_ISSUE})
                self.project_b_issue2 = self.project_b_issue2_obj.key

                self.project_b_issue3_obj = self.jira_admin.create_issue(
                    project=self.project_b,
                    summary='issue 3 from %s' % self.project_b,
                    issuetype={'name': self.CI_JIRA_ISSUE})
                self.project_b_issue3 = self.project_b_issue3_obj.key

            except Exception as e:
                logging.exception("Basic test setup failed")
                self.initialized = 1
                py.test.exit("FATAL: %s\n%s" % (e, traceback.format_exc()))

            if not hasattr(self, 'jira_normal') or not hasattr(
                    self, 'jira_admin'):
                py.test.exit("FATAL: WTF!?")

            self.initialized = 1

        else:
            # already exist but we need to be sure it was initialized
            counter = 0
            while not self.initialized:
                sleep(1)
                counter += 1
                if counter > 60:
                    logging.fatal(
                        "Something is clearly not right with " +
                        "initialization, killing the tests to prevent a " +
                        "deadlock.")
                    sys.exit(3)
Exemple #29
0
        logging.debug("No more folders.")
        packUpdateandSend(headers,GLOBAL_url_xray,mutation)
        mutation = ""
        return
    else:
        for folder in repository['folders']:
            processFolders(folder,project,mutation,headers)



keyStats = []
timeStats = []
count= 0
for project in GLOBAL_projectRepositoryList:
    startExec = time.time()
    cloudproject = jiraCloud.project(project)
    r = requests.get('' + GLOBAL_onPremiseURL+'/rest/raven/1.0/api/testrepository/'+ project +'/folders', auth=HTTPBasicAuth(GLOBAL_basic_auth_user, GLOBAL_basic_auth_pass))
    if r.text == "" or r.text == None or r.text=="[]":
        break
    else :
        try:
            json_data = json.loads(r.text)
        except:
            logging.error("An error as occurred  - Skipping " + project +" Project")
            logging.error(r.text)
            break
        repository = json.loads(r.text)
        processFolders(repository,cloudproject,mutation,headers)
        if commandExecutionExceptions.export != None:
            fileExport.write("%s\n" % project)
            fileExport.flush()
from collections import defaultdict
from bs4 import BeautifulSoup
import requests
import os.path
import re
from jira import JIRA
import argparse
import datetime

server = "https://issues.couchbase.com"
options = dict(server=server)
jira = JIRA(options)
project_code = "PYCBC"
project = jira.project(project_code)
print("got project {}".format(project.versions))
parser = argparse.ArgumentParser(description="Generate release notes in Asciidoc format")
parser.add_argument('version',type=str)
args=parser.parse_args()
ver_num = args.version
project_version = next(iter(filter(lambda x: x.name == ver_num, project.versions)), None)
relnotes_raw = requests.get(
    "{}/secure/ReleaseNote.jspa?projectId={}&version={}".format(server, project.id,
                                                                project_version.id))
soup = BeautifulSoup(relnotes_raw.text, 'html.parser')
content = soup.find("section", class_="aui-page-panel-content")
outputdir = os.path.join("build")

date = datetime.date.today().strftime("{day} %B %Y").format(day=datetime.date.today().day)
try:
    os.makedirs(outputdir)
except:
def update_or_create_jira_issue(study_id, user_token, is_curator):
    try:
        params = app.config.get('JIRA_PARAMS')
        user_name = params['username']
        password = params['password']

        updated_studies = []
        try:
            jira = JIRA(options=options, basic_auth=(user_name, password))
        except:
            return False, 'Could not connect to JIRA server, incorrect username or password?', updated_studies

        # Get the MetaboLights project
        mtbls_project = jira.project(project)

        studies = [study_id]
        if not study_id and is_curator:
            studies = get_all_studies(user_token)

        for study in studies:
            study_id = study[0]
            user_name = study[1]
            release_date = study[2]
            update_date = study[3]
            study_status = study[4]
            curator = study[5]
            issue = []
            summary = None

            # Get an issue based on a study accession search pattern
            search_param = "project='" + mtbls_project.key + "' AND summary  ~ '" + study_id + " \\\-\\\ 20*'"
            issues = jira.search_issues(search_param)  # project = MetaboLights AND summary ~ 'MTBLS121 '
            new_summary = study_id + ' - ' + release_date.replace('-', '') + ' - ' + \
                          study_status + ' (' + user_name + ')'
            try:
                if issues:
                    issue = issues[0]
                else:
                    if study_status == 'Submitted':
                        logger.info("Could not find Jira issue for " + search_param)
                        print("Creating new Jira issue for " + search_param)
                        issue = jira.create_issue(project=mtbls_project.key, summary='MTBLS study - To be updated',
                                                  description='Created by API', issuetype={'name': 'Story'})
                    else:
                        continue  # Only create new cases if the study is in status Submitted
            except Exception:  # We could not find or create a Jira issue
                    continue

            summary = issue.fields.summary  # Follow pattern 'MTBLS123 - YYYYMMDD - Status'
            try:
                assignee = issue.fields.assignee.name
            except:
                assignee = ""

            valid_curator = False
            jira_curator = ""
            if curator:
                if curator.lower() == 'mark':
                    jira_curator = 'mwilliam'
                    valid_curator = True
                elif curator.lower() == 'keeva':
                    jira_curator = 'keeva'
                    valid_curator = True
            else:
                jira_curator = ""

            # Release date or status has changed, or the assignee (curator) has changed
            if summary.startswith('MTBLS') and (summary != new_summary or assignee != jira_curator):

                # Add "Curation" Epic
                issues_to_add = [issue.key]
                jira.add_issues_to_epic(curation_epic, issues_to_add)  # Add the Curation Epic
                labels = maintain_jira_labels(issue, study_status, user_name)

                # Add a comment to the issue.
                comment_text = 'Status ' + study_status + '. Database update date ' + update_date
                jira.add_comment(issue, comment_text)

                # Change the issue's summary, comments and description.
                issue.update(summary=new_summary, fields={"labels": labels}, notify=False)

                if valid_curator:  # ToDo, what if the curation log is not up to date?
                    issue.update(assignee={'name': jira_curator})

                updated_studies.append(study_id)
                logger.info('Updated Jira case for study ' + study_id)
                print('Updated Jira case for study ' + study_id)
    except Exception:
        return False, 'Update failed', updated_studies
    return True, 'Ticket(s) updated successfully', updated_studies
Exemple #32
0
from jira import JIRA

jira_connect = JIRA(server='', basic_auth=('', ''))
project = jira_connect.project('')
jira_connect.create_issue(project='',
                          summary=b,
                          description=a,
                          issuetype={'name': 'Task'})
			failureDetails = failureDetails + '{code:title=' + testurl + '' + className_re + '/' + name_re + '}\n'
			failureDetails = failureDetails + prettyXML(s)
			failureDetails = failureDetails + '\n{code}\n\n'
			#print failureDetails

		rootJBIDE_dict = {
			'project' : { 'key': 'JBIDE' },
			'summary' : str(len(testcaselist)) + ' Test Failure(s) in JBIDE ' + jbide_affectedversion + ' for ' + component + ' component',
			'description' :  failureSummary + failureDetails,
			'issuetype' : { 'name' : 'Task' },
			'priority' : { 'name' :'Critical'},
			'versions' : [{ "name" : jbide_affectedversion }],
			'components' : [{ "name" : component }],
			'labels' : [ "testfailure" ]
			}

		jira = JIRA(options={'server':jiraserver}, basic_auth=(options.usernameJIRA, options.passwordJIRA))
		CLJBIDE = jira.project_components(jira.project('JBIDE')) # full list of components in JBIDE
		rootJBIDE = jira.create_issue(fields=rootJBIDE_dict)
		componentLead = queryComponentLead(CLJBIDE, component, 0)
		try:
			jira.assign_issue(rootJBIDE, componentLead)
		except:
			print "[WARNING] Unexpected error! User {0} tried to assign {1} to {2}: {3}".format(options.usernameJIRA, rootJBIDE, componentLead, sys.exc_info()[0])
		accept = raw_input("\nAccept new JIRA " + jiraserver + '/browse/' + rootJBIDE.key + " => " + componentLead + " ? [Y/n] ")
		if accept.capitalize() in ["N"] :
			rootJBIDE.delete()

	# see JIRA_components listing in components.py

	# Sample usage: see createTestFailureJIRA.py.examples.txt
class AntonJira():
    def __init__(self, server, email, apitoken):
        self.jira_instance = JIRA(server=server, basic_auth=(email, apitoken))

    def get_project(self, project_key):
        """
		name -- project name
		lead.displayName -- leader name
		"""
        return self.jira_instance.project(project_key)

    def get_project_components(self, project):
        """
		requires : project instance
		returns : list of components
		"""
        return [
            comp.name
            for comp in self.jira_instance.project_components(project)
        ]

    def get_issue_detail(self, issue_key):
        """
		.fields.summary -- summary
		.fields.votes.votes -- votes
		.fields.description
		.fields.comment : [{
			.author.displayName
			.body
		}]
		"""
        return self.jira_instance.issue(issue_key)

    def get_issues_in_project(self, project_key):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(f"project={project_key}")

    def get_issues_of_current_user_in_project(self, project_key):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(
            f"project={project_key} and assignee=currentuser()")

    def get_issues_of_current_user(self):
        """
		[
			.fields.summary -- summary
			.fields.votes.votes -- votes
			.fields.description
			.fields.comment : [{
				.author.displayName
				.body
			}]
		]
		"""
        return self.jira_instance.search_issues(f"assignee=currentuser()")


# jira = JIRA('https://anton3.atlassian.net',basic_auth=('*****@*****.**', 'TKLhcdc5zw2anmiX8DQ946BD'))
# jra = jira.project('AN')
# print(jra.name)
# print(jra.lead.displayName)

# email:[email protected]
# password: pratikbaid@2471

# jira = AntonJira('https://anton3.atlassian.net','*****@*****.**', 'TKLhcdc5zw2anmiX8DQ946BD')
# print(jira.get_issues_of_current_user('AN'))
dashboards = jira.dashboards()
for dash in dashboards:
	print(dash.name, dash.id)


cizo_dashboard = jira.dashboard(id=11105)
# curago_dashboard = jira.dashboard('CURAGO')

cizo_dash_page = requests.get(cizo_dashboard.view).text

print(cizo_dash_page)





for project in projects:
	print (project)



cizo = jira.project('SEN')
curago = jira.project('CUR')

print ('Project: ', cizo.name)
print ('Cizo Lead: ', cizo.lead.displayName)
print ('==============================')
print ('Project: ', curago.name)
print ('Cizo Lead: ', curago.lead.displayName)

Exemple #36
0
app = Flask(__name__)
app.secret_key = os.urandom(24)
CORS(app)

chk2.initializeRoute(app)

client = MongoClient('localhost', 27017)

db = client.app  #database
post = db.posts  #objects in database

jira = JIRA('http://localhost:8080', auth=('Arijit82', 'admin'))

projects = jira.projects()

jra = jira.project('AR123')
print(jra.name)  # 'JIRA'
print(jra.lead.displayName)
print(projects)

issue_dict = {
    'project': {
        'key': 'AR123'
    },
    'summary': 'New issue from jira-python',
    'description': 'Look into this one',
    'issuetype': {
        'name': 'Task'
    },
}
Exemple #37
0
class JiraTestManager(object):
    """
    Used to instantiate and populate the JIRA instance with data used by the unit tests.
    Attributes:
        CI_JIRA_ADMIN (str): Admin user account name.
        CI_JIRA_USER (str): Limited user account name.
        max_retries (int): number of retries to perform for recoverable HTTP errors.
    """
    __shared_state = {}

    def __init__(self):
        self.__dict__ = self.__shared_state

        if not self.__dict__:
            self.initialized = 0

            try:

                if CI_JIRA_URL in os.environ:
                    self.CI_JIRA_URL = os.environ['CI_JIRA_URL']
                    self.max_retries = 5
                else:
                    self.CI_JIRA_URL = "https://pycontribs.atlassian.net"
                    self.max_retries = 5

                if CI_JIRA_ADMIN in os.environ:
                    self.CI_JIRA_ADMIN = os.environ['CI_JIRA_ADMIN']
                else:
                    self.CI_JIRA_ADMIN = 'ci-admin'

                if CI_JIRA_ADMIN_PASSWORD in os.environ:
                    self.CI_JIRA_ADMIN_PASSWORD = os.environ[
                        'CI_JIRA_ADMIN_PASSWORD']
                else:
                    self.CI_JIRA_ADMIN_PASSWORD = '******'

                if 'CI_JIRA_USER' in os.environ:
                    self.CI_JIRA_USER = os.environ['CI_JIRA_USER']
                else:
                    self.CI_JIRA_USER = '******'

                if 'CI_JIRA_USER_PASSWORD' in os.environ:
                    self.CI_JIRA_USER_PASSWORD = os.environ[
                        'CI_JIRA_USER_PASSWORD']
                else:
                    self.CI_JIRA_USER_PASSWORD = '******'

                self.CI_JIRA_ISSUE = os.environ.get('CI_JIRA_ISSUE', 'Bug')

                if OAUTH:
                    self.jira_admin = JIRA(oauth={
                        'access_token': 'hTxcwsbUQiFuFALf7KZHDaeAJIo3tLUK',
                        'access_token_secret': 'aNCLQFP3ORNU6WY7HQISbqbhf0UudDAf',
                        'consumer_key': CONSUMER_KEY,
                        'key_cert': KEY_CERT_DATA})
                else:
                    if self.CI_JIRA_ADMIN:
                        self.jira_admin = JIRA(self.CI_JIRA_URL, basic_auth=(self.CI_JIRA_ADMIN,
                                                                             self.CI_JIRA_ADMIN_PASSWORD),
                                               logging=False, validate=True, max_retries=self.max_retries)
                    else:
                        self.jira_admin = JIRA(self.CI_JIRA_URL, validate=True,
                                               logging=False, max_retries=self.max_retries)
                if self.jira_admin.current_user() != self.CI_JIRA_ADMIN:
                    # self.jira_admin.
                    self.initialized = 1
                    sys.exit(3)

                if OAUTH:
                    self.jira_sysadmin = JIRA(oauth={
                        'access_token': '4ul1ETSFo7ybbIxAxzyRal39cTrwEGFv',
                        'access_token_secret':
                            'K83jBZnjnuVRcfjBflrKyThJa0KSjSs2',
                        'consumer_key': CONSUMER_KEY,
                        'key_cert': KEY_CERT_DATA}, logging=False, max_retries=self.max_retries)
                else:
                    if self.CI_JIRA_ADMIN:
                        self.jira_sysadmin = JIRA(self.CI_JIRA_URL,
                                                  basic_auth=(self.CI_JIRA_ADMIN,
                                                              self.CI_JIRA_ADMIN_PASSWORD),
                                                  logging=False, validate=True, max_retries=self.max_retries)
                    else:
                        self.jira_sysadmin = JIRA(self.CI_JIRA_URL,
                                                  logging=False, max_retries=self.max_retries)

                if OAUTH:
                    self.jira_normal = JIRA(oauth={
                        'access_token': 'ZVDgYDyIQqJY8IFlQ446jZaURIz5ECiB',
                        'access_token_secret':
                            '5WbLBybPDg1lqqyFjyXSCsCtAWTwz1eD',
                        'consumer_key': CONSUMER_KEY,
                        'key_cert': KEY_CERT_DATA})
                else:
                    if self.CI_JIRA_ADMIN:
                        self.jira_normal = JIRA(self.CI_JIRA_URL,
                                                basic_auth=(self.CI_JIRA_USER,
                                                            self.CI_JIRA_USER_PASSWORD),
                                                validate=True, logging=False, max_retries=self.max_retries)
                    else:
                        self.jira_normal = JIRA(self.CI_JIRA_URL,
                                                validate=True, logging=False, max_retries=self.max_retries)

                # now we need some data to start with for the tests

                # jira project key is max 10 chars, no letter.
                # [0] always "Z"
                # [1-6] username running the tests (hope we will not collide)
                # [7-8] python version A=0, B=1,..
                # [9] A,B -- we may need more than one project

                prefix = 'Z' + (re.sub("[^A-Z]", "",
                                       getpass.getuser().upper()))[0:6] + \
                         chr(ord('A') + sys.version_info[0]) + \
                         chr(ord('A') + sys.version_info[1])

                self.project_a = prefix + 'A'  # old XSS
                self.project_a_name = "Test user=%s python=%s.%s A" \
                                      % (getpass.getuser(), sys.version_info[0],
                                         sys.version_info[1])
                self.project_b_name = "Test user=%s python=%s.%s B" \
                                      % (getpass.getuser(), sys.version_info[0],
                                         sys.version_info[1])
                self.project_b = prefix + 'B'  # old BULK

                try:
                    self.jira_admin.project(self.project_a)
                except Exception as e:
                    logging.warning(e)
                    pass
                else:
                    self.jira_admin.delete_project(self.project_a)

                try:
                    self.jira_admin.project(self.project_b)
                except Exception as e:
                    logging.warning(e)
                    pass
                else:
                    self.jira_admin.delete_project(self.project_b)

                self.jira_admin.create_project(self.project_a,
                                               self.project_a_name)
                self.project_a_id = self.jira_admin.project(self.project_a).id

                self.jira_admin.create_project(self.project_b,
                                               self.project_b_name)

                self.project_b_issue1_obj = self.jira_admin.create_issue(project=self.project_b,
                                                                         summary='issue 1 from %s'
                                                                                 % self.project_b,
                                                                         issuetype=self.CI_JIRA_ISSUE)
                self.project_b_issue1 = self.project_b_issue1_obj.key

                self.project_b_issue2_obj = self.jira_admin.create_issue(project=self.project_b,
                                                                         summary='issue 2 from %s'
                                                                                 % self.project_b,
                                                                         issuetype={'name': self.CI_JIRA_ISSUE})
                self.project_b_issue2 = self.project_b_issue2_obj.key

                self.project_b_issue3_obj = self.jira_admin.create_issue(project=self.project_b,
                                                                         summary='issue 3 from %s'
                                                                                 % self.project_b,
                                                                         issuetype={'name': self.CI_JIRA_ISSUE})
                self.project_b_issue3 = self.project_b_issue3_obj.key

            except Exception as e:
                # exc_type, exc_value, exc_traceback = sys.exc_info()
                formatted_lines = traceback.format_exc().splitlines()
                msg = "Basic test setup failed: %s\n\t%s" % (
                    e, "\n\t".join(formatted_lines))
                logging.fatal(msg)
                self.initialized = 1
                pytest.exit("FATAL")

            self.initialized = 1

        else:
            # already exist but we need to be sure it was initialized
            counter = 0
            while not self.initialized:
                sleep(1)
                counter += 1
                if counter > 60:
                    logging.fatal("Something is clearly not right with " +
                                  "initialization, killing the tests to prevent a " +
                                  "deadlock.")
                    sys.exit(3)
Exemple #38
0
def Update_TotalData_from_Jira(VDD):

    SheetNames = VDD.sheetnames

    TotalDataWS = VDD['Total Data']

    NumRows = TotalDataWS.max_row
    NumColumn = TotalDataWS.max_column
    CRs = ['' for x in range(NumRows + 1)]
    newTotalData = VDD.copy_worksheet(TotalDataWS)
    newTotalData.title = 'New TD jira'
    AllM145Issues = VDD.create_sheet('AllM145')
    #for row in range(1,NumRows):
    for row in range(1, NumRows + 1):
        CRs[row] = str(TotalDataWS[row][8].value)
    # cleanup list of CRs so that only 1 CR per
    for row in range(1, len(CRs)):
        i = 0
        for char in CRs[row]:
            if char == '\n':
                CRs[row] = CRs[row][:i]
            elif char == 'O' and CRs[row][i:i + 3] == 'OMS' and i > 3:
                CRs[row] = CRs[row][:i]
            elif char == 'I' and CRs[row][i:i + 4] == 'IFIS' and i > 3:
                CRs[row] = CRs[row][:i]
            elif char == 'E' and CRs[row][i:i + 5] == 'EICAS' and i > 3:
                CRs[row] = CRs[row][:i]
            elif char == 'F' and CRs[row][i:i + 4] == 'FDSA' and i > 3:
                CRs[row] = CRs[row][:i]
            i += 1
    options = {'server': 'http://alm.rockwellcollins.com/issues/'}
    jira = JIRA(options, basic_auth=('jpgaviri', 'PSW*'))  #Use RCI password
    # Get all projects viewable by anonymous users.
    projects = jira.projects()
    M145 = jira.project('GLOBALA')
    #M145_issues = jira.search_issues('project=GLOBALA')
    block_size = 50
    block_num = 0
    i = 1
    while True:
        start_idx = block_num * block_size
        M145_issues = jira.search_issues('project=GLOBALA', start_idx,
                                         block_size)
        #---------------------

        Wp_type, summary, description, function, fix_version, affected_projects,labels, \
            Operational_impact,Plain_English,Criticality = '','','','','','','','','',''
        for issue in M145_issues:
            print(issue)
            Wp_type, summary, description, function, fix_version, affected_projects,labels, \
                Operational_impact,Plain_English,Criticality = '','','','','','','','','',''
            #english_description = issue.raw['fields']['customfield_20330']
            for field in issue.raw['fields']:
                if field == 'customfield_12909':
                    if issue.raw['fields']['customfield_12909'] != None:
                        Wp_type = issue.raw['fields']['customfield_12909'][
                            'value']
                if field == 'summary':
                    if issue.raw['fields']['summary'] != None:
                        summary = issue.raw['fields']['summary']
                if field == 'description':
                    if issue.raw['fields']['description'] != None:
                        description = issue.raw['fields']['description']
                if field == 'customfield_19307':
                    if issue.raw['fields']['customfield_19307'] != None:
                        function = issue.raw['fields']['customfield_19307'][
                            'value']
                if field == 'fixVersions':
                    if issue.raw['fields']['fixVersions'] != []:
                        fix_version = issue.raw['fields']['fixVersions'][0][
                            'name']
                if field == 'customfield_13705':
                    if issue.raw['fields']['customfield_13705'] != None:
                        affected_projects = issue.raw['fields'][
                            'customfield_13705']
                if field == 'labels':
                    if issue.raw['fields']['labels'] != None:
                        labels = issue.raw['fields']['labels']
                if field == 'customfield_12906':
                    if issue.raw['fields']['customfield_12906'] != None:
                        Operational_impact = issue.raw['fields'][
                            'customfield_12906']
                if field == 'customfield_18527':
                    if issue.raw['fields']['customfield_18527'] != None:
                        Plain_English = issue.raw['fields'][
                            'customfield_18527']
                if field == 'customfield_13514':
                    if issue.raw['fields']['customfield_13514'] != []:
                        Criticality = issue.raw['fields']['customfield_13514'][
                            0]
            #last_update = issue.raw['fields']['customfield_19063']
            #print ("this seems to have worked")
            label = ''
            if labels != '':
                for l in labels:
                    label = label + ', ' + str(l)
            label = str(label)
            AllM145Issues.cell(row=i, column=2)
            AllM145Issues.cell(row=i, column=3)
            AllM145Issues[i][0].value = 'CR NUmber: ' + str(issue.key) + '\n' \
                                        'Work Package Type: ' + str(Wp_type) + '\n' \
                                        + 'Fix Version: '+ str(fix_version) +'\n' \
                                        + 'Labels: '+ str(label) + '\n' \
                                        + 'Summary: ' + str(summary) + '\n' \
                                        + 'Operational Impact: '+ str(Operational_impact) +'\n' \
                                        + 'English Description: '+ str(Plain_English) +'\n' \
                                        + 'Description: ' + str(description) +'\n'
            AllM145Issues[i][1].value = str(issue.key)
            AllM145Issues[i][2].value = str(fix_version)
            i += 1

        #--------------------
        time.sleep(2)
        if len(M145_issues) == 0:
            # Retrieve issues until there are no more to come
            break
        block_num += 1

    return VDD
Exemple #39
0
class JiraAPI(object):
    def __init__(self, hostname=None, username=None, password=None, path="", debug=False, clean_obsolete=True, max_time_window=12):
        self.logger = logging.getLogger('JiraAPI')
        if debug:
            self.logger.setLevel(logging.DEBUG)

        if "https://" not in hostname:
            hostname = "https://{}".format(hostname)
        self.username = username
        self.password = password
        self.jira = JIRA(options={'server': hostname}, basic_auth=(self.username, self.password))
        self.logger.info("Created vjira service for {}".format(hostname))
        self.all_tickets = []
        self.JIRA_REOPEN_ISSUE = "Reopen Issue"
        self.JIRA_CLOSE_ISSUE = "Close Issue"
        self.max_time_tracking = max_time_window #in months
        #<JIRA Resolution: name=u'Obsolete', id=u'11'>
        self.JIRA_RESOLUTION_OBSOLETE = "Obsolete"
        self.JIRA_RESOLUTION_FIXED = "Fixed"
        self.clean_obsolete = clean_obsolete
        self.template_path = 'vulnwhisp/reporting/resources/ticket.tpl'
        if path:
            self.download_tickets(path)
        else:
            self.logger.warn("No local path specified, skipping Jira ticket download.")

    def create_ticket(self, title, desc, project="IS", components=[], tags=[]):
        labels = ['vulnerability_management']
        for tag in tags:
            labels.append(str(tag))

        self.logger.info("creating ticket for project {} title[20] {}".format(project, title[:20]))
        self.logger.info("project {} has a component requirement: {}".format(project, self.PROJECT_COMPONENT_TABLE[project]))
        project_obj = self.jira.project(project)
        components_ticket = []
        for component in components:
            exists = False
            for c in project_obj.components:
                if component == c.name:
                    self.logger.debug("resolved component name {} to id {}".format(c.name, c.id))
                    components_ticket.append({ "id": c.id })
                    exists=True
            if not exists:
                self.logger.error("Error creating Ticket: component {} not found".format(component))
                return 0
                    
        new_issue = self.jira.create_issue(project=project,
                                           summary=title,
                                           description=desc,
                                           issuetype={'name': 'Bug'},
                                           labels=labels,
                                           components=components_ticket)

        self.logger.info("Ticket {} created successfully".format(new_issue))
        return new_issue
    
    #Basic JIRA Metrics
    def metrics_open_tickets(self, project=None):
        jql = "labels= vulnerability_management and resolution = Unresolved" 
        if project:
            jql += " and (project='{}')".format(project)
        self.logger.debug('Executing: {}'.format(jql)) 
        return len(self.jira.search_issues(jql, maxResults=0))

    def metrics_closed_tickets(self, project=None):
        jql = "labels= vulnerability_management and NOT resolution = Unresolved AND created >=startOfMonth(-{})".format(self.max_time_tracking) 
        if project:
            jql += " and (project='{}')".format(project)
        return len(self.jira.search_issues(jql, maxResults=0))

    def sync(self, vulnerabilities, project, components=[]):
        #JIRA structure of each vulnerability: [source, scan_name, title, diagnosis, consequence, solution, ips, risk, references]
        self.logger.info("JIRA Sync started")

        # [HIGIENE] close tickets older than 12 months as obsolete
        # Higiene clean up affects to all tickets created by the module, filters by label 'vulnerability_management'
        if self.clean_obsolete:
            self.close_obsolete_tickets()

        for vuln in vulnerabilities:
            # JIRA doesn't allow labels with spaces, so making sure that the scan_name doesn't have spaces
            # if it has, they will be replaced by "_"
            if " " in  vuln['scan_name']:
                vuln['scan_name'] = "_".join(vuln['scan_name'].split(" "))
            
            exists = False
            to_update = False
            ticketid = ""
            ticket_assets = []
            exists, to_update, ticketid, ticket_assets = self.check_vuln_already_exists(vuln)

            if exists:
                # If ticket "resolved" -> reopen, as vulnerability is still existent
                self.reopen_ticket(ticketid)
                self.add_label(ticketid, vuln['risk'])
                continue
            elif to_update:
                self.ticket_update_assets(vuln, ticketid, ticket_assets)
                self.add_label(ticketid, vuln['risk'])
                continue

            try:
                tpl = template(self.template_path, vuln)
            except Exception as e:
                self.logger.error('Exception templating: {}'.format(str(e)))
                return 0
            self.create_ticket(title=vuln['title'], desc=tpl, project=project, components=components, tags=[vuln['source'], vuln['scan_name'], 'vulnerability', vuln['risk']])
        
        self.close_fixed_tickets(vulnerabilities)
        # we reinitialize so the next sync redoes the query with their specific variables
        self.all_tickets = []
        return True

    def check_vuln_already_exists(self, vuln):
        # we need to return if the vulnerability has already been reported and the ID of the ticket for further processing
        #function returns array [duplicated(bool), update(bool), ticketid, ticket_assets]
        title = vuln['title']
        labels = [vuln['source'], vuln['scan_name'], 'vulnerability_management', 'vulnerability'] 
        #list(set()) to remove duplicates
        assets = list(set(re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", ",".join(vuln['ips']))))
        
        if not self.all_tickets:
            self.logger.info("Retrieving all JIRA tickets with the following tags {}".format(labels))
            # we want to check all JIRA tickets, to include tickets moved to other queues
            # will exclude tickets older than 12 months, old tickets will get closed for higiene and recreated if still vulnerable
            jql = "{} AND NOT labels=advisory AND created >=startOfMonth(-{})".format(" AND ".join(["labels={}".format(label) for label in labels]), self.max_time_tracking)
            
            self.all_tickets = self.jira.search_issues(jql, maxResults=0)
        
        #WARNING: function IGNORES DUPLICATES, after finding a "duplicate" will just return it exists
        #it wont iterate over the rest of tickets looking for other possible duplicates/similar issues
        self.logger.info("Comparing Vulnerabilities to created tickets")
        for index in range(len(self.all_tickets)-1):
            checking_ticketid, checking_title, checking_assets = self.ticket_get_unique_fields(self.all_tickets[index])
            if title == checking_title: 
                difference = list(set(assets).symmetric_difference(checking_assets))
                #to check intersection - set(assets) & set(checking_assets)
                if difference: 
                    self.logger.info("Asset mismatch, ticket to update. Ticket ID: {}".format(checking_ticketid))
                    return False, True, checking_ticketid, checking_assets #this will automatically validate
                else:
                    self.logger.info("Confirmed duplicated. TickedID: {}".format(checking_ticketid))
                    return True, False, checking_ticketid, [] #this will automatically validate
        return False, False, "", []

    def ticket_get_unique_fields(self, ticket):
        title = ticket.raw.get('fields', {}).get('summary').encode("ascii").strip()
        ticketid = ticket.key.encode("ascii")
        try:
            affected_assets_section = ticket.raw.get('fields', {}).get('description').encode("ascii").split("{panel:title=Affected Assets}")[1].split("{panel}")[0]
            assets = list(set(re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", affected_assets_section)))
        except:
            self.logger.error("Ticket IPs regex failed. Ticket ID: {}".format(ticketid))
            assets = []
        
        return ticketid, title, assets

    def get_ticket_reported_assets(self, ticket):
        #[METRICS] return a list with all the affected assets for that vulnerability (including already resolved ones) 
        return list(set(re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b",str(self.jira.issue(ticket).raw))))

    def get_resolution_time(self, ticket):
        #get time a ticket took to be resolved
        ticket_obj = self.jira.issue(ticket)
        if self.is_ticket_resolved(ticket_obj):
            ticket_data = ticket_obj.raw.get('fields')
            #dates follow format '2018-11-06T10:36:13.849+0100'
            created = [int(x) for x in ticket_data['created'].split('.')[0].replace('T', '-').replace(':','-').split('-')]
            resolved =[int(x) for x in ticket_data['resolutiondate'].split('.')[0].replace('T', '-').replace(':','-').split('-')]
            
            start = datetime(created[0],created[1],created[2],created[3],created[4],created[5])
            end = datetime(resolved[0],resolved[1],resolved[2],resolved[3],resolved[4],resolved[5])
            
            return (end-start).days
        else:
            self.logger.error("Ticket {ticket} is not resolved, can't calculate resolution time".format(ticket=ticket))

        return False

    def ticket_update_assets(self, vuln, ticketid, ticket_assets):
        # correct description will always be in the vulnerability to report, only needed to update description to new one
        self.logger.info("Ticket {} exists, UPDATE requested".format(ticketid))
        
        if self.is_ticket_resolved(self.jira.issue(ticketid)):
            self.reopen_ticket(ticketid)
        try:
            tpl = template(self.template_path, vuln)
        except Exception as e:
            self.logger.error('Exception updating assets: {}'.format(str(e)))
            return 0

        ticket_obj = self.jira.issue(ticketid)
        ticket_obj.update()
        assets = list(set(re.findall(r"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", ",".join(vuln['ips']))))
        difference = list(set(assets).symmetric_difference(ticket_assets))
        
        comment = ''
        #put a comment with the assets that have been added/removed
        for asset in difference:
            if asset in assets:
                comment += "Asset {} have been added to the ticket as vulnerability *has been newly detected*.\n".format(asset)
            elif asset in ticket_assets:
                comment += "Asset {} have been removed from the ticket as vulnerability *has been resolved*.\n".format(asset)
       
        try:
            ticket_obj.update(description=tpl, comment=comment, fields={"labels":ticket_obj.fields.labels})
            self.logger.info("Ticket {} updated successfully".format(ticketid))
            self.add_label(ticketid, 'updated')
        except:
            self.logger.error("Error while trying up update ticket {}".format(ticketid))
        return 0

    def add_label(self, ticketid, label):
        ticket_obj = self.jira.issue(ticketid)
        
        if label not in ticket_obj.fields.labels:
                ticket_obj.fields.labels.append(label)
        
        try:
            ticket_obj.update(fields={"labels":ticket_obj.fields.labels})
            self.logger.info("Added label {label} to ticket {ticket}".format(label=label, ticket=ticketid))
        except:
            self.logger.error("Error while trying to add label {label} to ticket {ticket}".format(label=label, ticket=ticketid))
        return 0

    def close_fixed_tickets(self, vulnerabilities):
        # close tickets which vulnerabilities have been resolved and are still open
        found_vulns = []
        for vuln in vulnerabilities:
            found_vulns.append(vuln['title'])

        comment = '''This ticket is being closed as it appears that the vulnerability no longer exists.
        If the vulnerability reappears, a new ticket will be opened.'''

        for ticket in self.all_tickets:
            if ticket.raw['fields']['summary'].strip() in found_vulns:
                self.logger.info("Ticket {} is still vulnerable".format(ticket))
                continue
            self.logger.info("Ticket {} is no longer vulnerable".format(ticket))
            self.close_ticket(ticket, self.JIRA_RESOLUTION_FIXED, comment) 
        return 0


    def is_ticket_reopenable(self, ticket_obj):
        transitions = self.jira.transitions(ticket_obj)
        for transition in transitions:
            if transition.get('name') == self.JIRA_REOPEN_ISSUE:
                self.logger.debug("Ticket is reopenable")
                return True
        self.logger.warn("Ticket can't be opened. Check Jira transitions.")
        return False

    def is_ticket_closeable(self, ticket_obj):
        transitions = self.jira.transitions(ticket_obj)
        for transition in transitions:
            if transition.get('name') == self.JIRA_CLOSE_ISSUE:
                return True
        self.logger.warn("Ticket can't closed. Check Jira transitions.")
        return False

    def is_ticket_resolved(self, ticket_obj):
        #Checks if a ticket is resolved or not
        if ticket_obj is not None:
            if ticket_obj.raw['fields'].get('resolution') is not None:
                if ticket_obj.raw['fields'].get('resolution').get('name') != 'Unresolved':
                    self.logger.debug("Checked ticket {} is already closed".format(ticket_obj))
                    self.logger.info("Ticket {} is closed".format(ticket_obj))
                    return True
        self.logger.debug("Checked ticket {} is already open".format(ticket_obj))
        return False


    def is_risk_accepted(self, ticket_obj):
        if ticket_obj is not None:
            if ticket_obj.raw['fields'].get('labels') is not None:
                labels = ticket_obj.raw['fields'].get('labels')
                if "risk_accepted" in labels:
                    self.logger.warn("Ticket {} accepted risk, will be ignored".format(ticket_obj))
                    return True
                elif "server_decomission" in labels:
                    self.logger.warn("Ticket {} server decomissioned, will be ignored".format(ticket_obj))
                    return True
        self.logger.info("Ticket {} risk has not been accepted".format(ticket_obj))
        return False

    def reopen_ticket(self, ticketid):
        self.logger.debug("Ticket {} exists, REOPEN requested".format(ticketid))
        # this will reopen a ticket by ticketid
        ticket_obj = self.jira.issue(ticketid)
        
        if self.is_ticket_resolved(ticket_obj):
            if not self.is_risk_accepted(ticket_obj):
                try:
                    if self.is_ticket_reopenable(ticket_obj):
                        comment = '''This ticket has been reopened due to the vulnerability not having been fixed (if multiple assets are affected, all need to be fixed; if the server is down, lastest known vulnerability might be the one reported).
                        In the case of the team accepting the risk and wanting to close the ticket, please add the label "*risk_accepted*" to the ticket before closing it.
                        If server has been decomissioned, please add the label "*server_decomission*" to the ticket before closing it.
                        If you have further doubts, please contact the Security Team.'''
                        error = self.jira.transition_issue(issue=ticketid, transition=self.JIRA_REOPEN_ISSUE, comment = comment)
                        self.logger.info("Ticket {} reopened successfully".format(ticketid))
                        self.add_label(ticketid, 'reopened')
                        return 1
                except Exception as e:
                    # continue with ticket data so that a new ticket is created in place of the "lost" one
                    self.logger.error("error reopening ticket {}: {}".format(ticketid, e))
                    return 0
        return 0

    def close_ticket(self, ticketid, resolution, comment):
        # this will close a ticket by ticketid
        self.logger.debug("Ticket {} exists, CLOSE requested".format(ticketid))
        ticket_obj = self.jira.issue(ticketid)
        if not self.is_ticket_resolved(ticket_obj):
            try:
                if self.is_ticket_closeable(ticket_obj):
                    #need to add the label before closing the ticket
                    self.add_label(ticketid, 'closed')
                    error = self.jira.transition_issue(issue=ticketid, transition=self.JIRA_CLOSE_ISSUE, comment = comment, resolution = {"name": resolution })
                    self.logger.info("Ticket {} closed successfully".format(ticketid))
                    return 1
            except Exception as e:
                # continue with ticket data so that a new ticket is created in place of the "lost" one
                self.logger.error("error closing ticket {}: {}".format(ticketid, e))
                return 0
                
        return 0

    def close_obsolete_tickets(self):
        # Close tickets older than 12 months, vulnerabilities not solved will get created a new ticket 
        self.logger.info("Closing obsolete tickets older than {} months".format(self.max_time_tracking))
        jql = "labels=vulnerability_management AND created <startOfMonth(-{}) and resolution=Unresolved".format(self.max_time_tracking)
        tickets_to_close = self.jira.search_issues(jql, maxResults=0)
        
        comment = '''This ticket is being closed for hygiene, as it is more than 12 months old.
        If the vulnerability still exists, a new ticket will be opened.'''
        
        for ticket in tickets_to_close:
                self.close_ticket(ticket, self.JIRA_RESOLUTION_OBSOLETE, comment)
        
        return 0

    def project_exists(self, project):
        try:
            self.jira.project(project)
            return True
        except:
            return False
        return False

    def download_tickets(self, path):
        #saves all tickets locally, local snapshot of vulnerability_management ticktes
        #check if file already exists
        check_date = str(date.today())
        fname = '{}jira_{}.json'.format(path, check_date) 
        if os.path.isfile(fname):
            self.logger.info("File {} already exists, skipping ticket download".format(fname))
            return True
        try:
            self.logger.info("Saving locally tickets from the last {} months".format(self.max_time_tracking))
            jql = "labels=vulnerability_management AND created >=startOfMonth(-{})".format(self.max_time_tracking)
            tickets_data = self.jira.search_issues(jql, maxResults=0)
            
            #end of line needed, as writelines() doesn't add it automatically, otherwise one big line
            to_save = [json.dumps(ticket.raw.get('fields'))+"\n" for ticket in tickets_data]
            with open(fname, 'w') as outfile:
                outfile.writelines(to_save)
                self.logger.info("Tickets saved succesfully.")
            
            return True

        except Exception as e:
            self.logger.error("Tickets could not be saved locally: {}.".format(e))
        
        return False