![JAR search and dependency download from the Maven repository](/logo.png)
me.shib.lib.jirabugsbuddy.VulnerabilityIssueHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jira-bugs-buddy Show documentation
Show all versions of jira-bugs-buddy Show documentation
A plug that helps in building automation to create and maintain bugs in JIRA
package me.shib.lib.jirabugsbuddy;
import me.shib.java.lib.jiraclient.*;
import me.shib.lib.jirabugsbuddy.types.JiraConfig;
import me.shib.lib.jirabugsbuddy.types.Vulnerability;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public final class VulnerabilityIssueHandler {
private boolean errorFound;
private JiraConfig jiraConfig;
private String repo;
private JiraClient jira;
private String project;
private int created;
private int updated;
private boolean allowWrite;
public VulnerabilityIssueHandler() throws IOException, JiraException {
this.jiraConfig = JiraConfig.getConfig();
this.jira = JiraConfig.getJiraClient();
this.project = jiraConfig.getProjectKey();
this.repo = JiraConfig.getGitRepo();
this.errorFound = false;
this.created = 0;
this.updated = 0;
this.allowWrite = true;
}
public void disableWrite() {
System.out.println("Disabling write operations in JIRA");
this.allowWrite = false;
}
private void createIssueForVulnerability(Vulnerability vulnerability) throws JiraException {
String summary = vulnerability.getJiraSummary();
List jiraLabels = vulnerability.getJiraLabels();
jiraLabels.add(jiraConfig.getAutomationLabel());
Issue.FluentCreate fluentCreate = jira.createIssue(project, jiraConfig.getIssueType())
.field(Field.SUMMARY, summary)
.field(Field.DESCRIPTION, vulnerability.getJiraDescription())
.field(Field.LABELS, jiraLabels)
.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: " + issue.getKey() + " - " + issue.getSummary() + " with priority "
+ issue.getPriority().getName());
created++;
}
private void updateIssueForVulnerability(Issue issue, Vulnerability vulnerability) throws JiraException {
if (jiraConfig.isIssueIgnorable(issue)) {
System.out.println("Ignoring the issue: " + issue.getKey());
return;
}
boolean issueUpdated = false;
Issue.FluentUpdate fluentUpdate = issue.update();
if (jiraConfig.isSummaryUpdateAllowed() && !issue.getSummary().contentEquals(vulnerability.getJiraSummary())) {
fluentUpdate.field(Field.SUMMARY, vulnerability.getJiraSummary());
issueUpdated = true;
}
if (jiraConfig.isDescriptionUpdateAllowed() && !issue.getDescription().contentEquals(vulnerability.getJiraDescription())) {
fluentUpdate.field(Field.DESCRIPTION, vulnerability.getJiraDescription());
issueUpdated = true;
}
StringBuilder comment = new StringBuilder();
if (jiraConfig.isReprioritizeAllowed() || jiraConfig.isDeprioritizeAllowed()) {
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) && (jiraConfig.isReprioritizeAllowed())) || ((issuePriority > vulnerabilityPriority) && (jiraConfig.isDeprioritizeAllowed()))) {
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());
}
updated++;
}
if (jiraConfig.isOpenAllowedForStatus(issue.getStatus().getName())) {
reopenIssue(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("\"");
Set jiraSearchLabels = new HashSet<>(vulnerability.getJiraKeyLabels());
jiraSearchLabels.add(jiraConfig.getAutomationLabel());
jiraSearchLabels.add(repo);
for (String label : jiraSearchLabels) {
jql.append(" AND labels = ").append("\"").append(label).append("\"");
}
List issues = jira.searchIssues(jql.toString(), JiraConfig.maxSearchResult).issues;
if (issues.size() == 0) {
if (allowWrite) {
createIssueForVulnerability(vulnerability);
} else {
System.out.println("Creating issue DUMMY-CREATED-" + created + ": " + vulnerability.getJiraSummary());
}
} else {
if (issues.size() == 1) {
if (allowWrite) {
updateIssueForVulnerability(issues.get(0), vulnerability);
} else {
System.out.println("Skipping Update of " + issues.get(0).getKey() + ": " + issues.get(0).getSummary());
}
} else {
throw new Exception("More than one issue listed:\n"
+ "Labels: " + Arrays.toString(jiraSearchLabels.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) {
try {
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;
}
} catch (Exception e) {
e.printStackTrace();
errorFound = true;
}
return false;
}
private void reopenIssue(Issue issue) throws JiraException {
System.out.print("Issue: " + issue.getKey() + " is resolved, 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 (issue.getAssignee() != null && !jira.getSelf().equalsIgnoreCase(issue.getAssignee().getName())) {
comment.append("\n[~").append(issue.getAssignee().getName()).append("]");
}
if (issue.getReporter() != null && !jira.getSelf().equalsIgnoreCase(issue.getReporter().getName())) {
comment.append("\n[~").append(issue.getReporter().getName()).append("]");
}
issue.addComment(comment.toString());
}
System.out.print("\n");
}
private void closeIssue(Issue issue) throws JiraException {
if (jiraConfig.isIssueIgnorable(issue)) {
System.out.println("Ignoring the issue: " + issue.getKey());
return;
}
System.out.print("Issue: " + issue.getKey() + " has been fixed.");
boolean transitioned = false;
if (jiraConfig.toClose().isTansitionAllowed() && jiraConfig.isClosingTransitionAllowedForStatus(issue.getStatus().getName())) {
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 (issue.getAssignee() != null && !jira.getSelf().equalsIgnoreCase(issue.getAssignee().getName())) {
comment.append("\n[~").append(issue.getAssignee().getName()).append("]");
}
if (issue.getReporter() != null && !jira.getSelf().equalsIgnoreCase(issue.getReporter().getName())) {
comment.append("\n[~").append(issue.getReporter().getName()).append("]");
}
issue.addComment(comment.toString());
}
System.out.print("\n");
}
public boolean processBugs(List vulnerabilities) throws Exception {
System.out.println("Vulnerabilities found: " + vulnerabilities.size());
for (Vulnerability vulnerability : vulnerabilities) {
processVulnerability(vulnerability);
}
if (jiraConfig.isClosingAllowed()) {
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.getCloseStatuses()) {
jql.append(" AND status != \"").append(status).append("\"");
}
List issues = jira.searchIssues(jql.toString(), JiraConfig.maxSearchResult).issues;
for (Issue issue : issues) {
if (!isVulnerabilityExists(issue, vulnerabilities)) {
if (allowWrite) {
closeIssue(issue);
} else {
System.out.println("Skipping attempt to close: " + issue.getKey() + ": " + issue.getSummary());
}
updated++;
}
}
}
System.out.println("Issues created: " + created);
System.out.println("Issues updated: " + updated);
return !errorFound;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy