All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.shib.lib.jirabugsbuddy.VulnerabilityIssueHandler Maven / Gradle / Ivy

There is a newer version: 0.1.4
Show newest version
package me.shib.lib.jirabugsbuddy;

import me.shib.lib.jirabugsbuddy.types.JiraConfig;
import me.shib.lib.jirabugsbuddy.types.Vulnerability;
import net.rcarz.jiraclient.*;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class VulnerabilityIssueHandler {

    private JiraConfig jiraConfig;
    private String repo;
    private JiraClient jira;
    private String project;

    public VulnerabilityIssueHandler(String repo) throws IOException, JiraException {
        this.jiraConfig = JiraConfig.getConfig();
        this.jira = JiraConfig.getJiraClient();
        this.project = jiraConfig.getProjectKey();
        this.repo = repo;
    }

    private void createIssueForVulnerability(Vulnerability vulnerability) throws JiraException {
        String summary = vulnerability.getJiraSummary(repo);
        Issue.FluentCreate fluentCreate = jira.createIssue(project, jiraConfig.getIssueType())
                .field(Field.SUMMARY, summary)
                .field(Field.DESCRIPTION, vulnerability.getJiraDescription(repo))
                .field(Field.LABELS, vulnerability.getJiraLabels(repo, jiraConfig.getAutomationLabel()))
                .field(Field.PRIORITY, vulnerability.getPriority());
        if (jiraConfig.getUsers().getReporter() != null) {
            fluentCreate.field(Field.REPORTER, jiraConfig.getUsers().getReporter());
        }
        if (jiraConfig.getUsers().getAssignee() != null) {
            fluentCreate.field(Field.ASSIGNEE, jiraConfig.getUsers().getAssignee());
        }
        for (String key : jiraConfig.getCustomFields().keySet()) {
            fluentCreate.field(key, Field.valueById(jiraConfig.getCustomFields().get(key)));
        }
        Issue issue = fluentCreate.execute();
        for (String watcher : jiraConfig.getUsers().getWatchers()) {
            issue.addWatcher(watcher);
        }
        System.out.println("Created new issue: " + summary + " with priority "
                + vulnerability.getPriority());
    }

    private void updateIssueForVulnerability(Issue issue, Vulnerability vulnerability) throws JiraException {
        boolean issueUpdated = false;
        Issue.FluentUpdate fluentUpdate = issue.update();
        if (jiraConfig.isSummaryUpdateAllowed() && !issue.getSummary().contentEquals(vulnerability.getJiraSummary(repo))) {
            fluentUpdate.field(Field.SUMMARY, vulnerability.getJiraSummary(repo));
            issueUpdated = true;
        }
        if (jiraConfig.isSummaryUpdateAllowed() && !issue.getDescription().contentEquals(vulnerability.getJiraDescription(repo))) {
            fluentUpdate.field(Field.DESCRIPTION, vulnerability.getJiraDescription(repo));
            issueUpdated = true;
        }

        StringBuilder comment = new StringBuilder();
        int issuePriority;
        try {
            issuePriority = jiraConfig.getPriorities().get(issue.getPriority().getName());
        } catch (Exception e) {
            issuePriority = -1;
        }
        int vulnerabilityPriority = jiraConfig.getPriorities().get(vulnerability.getPriority());
        if (issuePriority < vulnerabilityPriority) {
            fluentUpdate.field(Field.PRIORITY, vulnerability.getPriority());
            comment.append("Reprioritizing to *")
                    .append(vulnerability.getPriority())
                    .append("* based on actual priority.");
            issueUpdated = true;
        }

        if (issueUpdated) {
            fluentUpdate.execute();
            if (!comment.toString().isEmpty()) {
                issue.addComment(comment.toString());
            }
        }

        if (jiraConfig.isOpenAllowed(issue.getStatus().getName())) {
            openIssue(issue);
        } else if (issueUpdated) {
            System.out.println("Updated the issue: " + issue.getKey() + " - "
                    + issue.getSummary());
        } else {
            System.out.println("Issue up-to date: " + issue.getKey() + " - "
                    + issue.getSummary());
        }
    }

    private void processVulnerability(Vulnerability vulnerability) throws Exception {
        StringBuilder jql = new StringBuilder();
        jql.append("project = ").append(project);
        jql.append(" AND issuetype = \"").append(jiraConfig.getIssueType()).append("\"");
        for (String label : vulnerability.getJiraLabels(repo, jiraConfig.getAutomationLabel())) {
            jql.append(" AND labels = ").append("\"").append(label).append("\"");
        }
        List issues = jira.searchIssues(jql.toString(), JiraConfig.maxSearchResult).issues;
        if (issues.size() == 0) {
            createIssueForVulnerability(vulnerability);
        } else {
            if (issues.size() == 1) {
                updateIssueForVulnerability(issues.get(0), vulnerability);
            } else {
                throw new Exception("More than one issue listed:\n"
                        + "Labels: " + Arrays.toString(vulnerability.getJiraLabels(repo, jiraConfig.getAutomationLabel()).toArray()) + "\n"
                        + "Issues: " + Arrays.toString(issues.toArray()));
            }
        }
    }

    private boolean isVulnerabilityExists(Issue issue, List vulnerabilities) {
        for (Vulnerability vulnerability : vulnerabilities) {
            if (issue.getLabels().containsAll(vulnerability.getJiraKeyLabels())) {
                return true;
            }
        }
        return false;
    }

    private String getStatusTransition(Issue issue, String status) throws JiraException {
        List transitions = issue.getTransitions();
        for (Transition transition : transitions) {
            if (transition.getToStatus().getName().equalsIgnoreCase(status)) {
                return transition.getName();
            }
        }
        return null;
    }

    private boolean transitionIssue(List transitions, Issue issue, String verb) throws JiraException {
        if (transitions.size() > 1) {
            StringBuilder consoleLog = new StringBuilder();
            consoleLog.append(" ").append(verb).append(" the issue ")
                    .append(issue.getKey()).append(": ").append(transitions.get(0));
            for (int i = 1; i < transitions.size(); i++) {
                consoleLog.append(" -> ").append(transitions.get(i));
                issue.transition().execute(getStatusTransition(issue, transitions.get(i)));
            }
            System.out.print(consoleLog.toString());
            return true;
        }
        return false;
    }

    private void openIssue(Issue issue) throws JiraException {
        System.out.print("Issue: " + issue.getKey() + " is closed, but not actually fixed. ");
        boolean transitioned = false;
        if (jiraConfig.toOpen().isTansitionAllowed()) {
            List transitions = jiraConfig.getTransitionsToOpen(issue.getStatus().getName());
            transitioned = transitionIssue(transitions, issue, "Reopening");
            if (!transitioned) {
                System.out.println(" No path defined to Open the issue from \"" + issue.getStatus().getName() + "\" state.");
            }
        }
        if (jiraConfig.toOpen().isCommentingAllowed(issue, JiraConfig.issueNotFixedComment)) {
            StringBuilder comment = new StringBuilder();
            comment.append(JiraConfig.issueNotFixedComment);
            if (!transitioned) {
                comment.append(JiraConfig.issueReopenComment);
            }
            if (!jira.getSelf().equalsIgnoreCase(issue.getAssignee().getName())) {
                comment.append(" [~").append(issue.getAssignee().getName()).append("]");
            }
            issue.addComment(comment.toString());
        }
        System.out.print("\n");
    }

    private void closeIssue(Issue issue) throws JiraException {
        System.out.print("Issue: " + issue.getKey() + " has been fixed.");
        boolean transitioned = false;
        if (jiraConfig.toClose().isTansitionAllowed()) {
            List transitions = jiraConfig.getTransitionsToClose(issue.getStatus().getName());
            transitioned = transitionIssue(transitions, issue, "Closing");
            if (!transitioned) {
                System.out.println(" No path defined to Close the issue from \"" + issue.getStatus().getName() + "\" state.");
            }
        }
        if (jiraConfig.toClose().isCommentingAllowed(issue, JiraConfig.issueFixedComment)) {
            StringBuilder comment = new StringBuilder();
            comment.append(JiraConfig.issueFixedComment);
            if (!transitioned) {
                comment.append(JiraConfig.issueCloseComment);
            }
            if (!jira.getSelf().equalsIgnoreCase(issue.getAssignee().getName())) {
                comment.append(" [~").append(issue.getAssignee().getName()).append("]");
            }
            issue.addComment(comment.toString());
        }
        System.out.print("\n");
    }

    public void processBugs(List vulnerabilities) throws Exception {
        for (Vulnerability vulnerability : vulnerabilities) {
            processVulnerability(vulnerability);
        }
        if (jiraConfig.isCloseAllowed()) {
            StringBuilder jql = new StringBuilder();
            jql.append("project = ").append(project)
                    .append(" AND labels = ").append("\"").append(jiraConfig.getAutomationLabel()).append("\"")
                    .append(" AND labels = ").append("\"").append(repo).append("\"")
                    .append(" AND issuetype = \"").append(jiraConfig.getIssueType()).append("\"");
            for (String status : jiraConfig.getClosedStatuses()) {
                jql.append(" AND status != \"").append(status).append("\"");
            }
            List issues = jira.searchIssues(jql.toString(), JiraConfig.maxSearchResult).issues;
            for (Issue issue : issues) {
                if (!isVulnerabilityExists(issue, vulnerabilities)) {
                    closeIssue(issue);
                }
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy