mirror of https://github.com/daffainfo/nuclei.git
Merge pull request #753 from gano3s/dev
Do not create a new issue in Jira if it is already openeddev
commit
8300486bec
|
@ -33,8 +33,10 @@
|
||||||
|
|
||||||
# jira contains configuration options for jira issue tracker
|
# jira contains configuration options for jira issue tracker
|
||||||
#jira:
|
#jira:
|
||||||
# # Cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used
|
# # cloud is the boolean which tells if Jira instance is running in the cloud or on-prem version is used
|
||||||
# cloud: true
|
# cloud: true
|
||||||
|
# # update-existing is the boolean which tells if the existing, opened issue should be updated or new one should be created
|
||||||
|
# update-existing: false
|
||||||
# # URL is the jira application url
|
# # URL is the jira application url
|
||||||
# url: ""
|
# url: ""
|
||||||
# # account-id is the account-id of the jira user or username in case of on-prem Jira
|
# # account-id is the account-id of the jira user or username in case of on-prem Jira
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/andygrunwald/go-jira"
|
"github.com/andygrunwald/go-jira"
|
||||||
|
"github.com/projectdiscovery/gologger"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
"github.com/projectdiscovery/nuclei/v2/pkg/output"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/format"
|
"github.com/projectdiscovery/nuclei/v2/pkg/reporting/format"
|
||||||
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
"github.com/projectdiscovery/nuclei/v2/pkg/types"
|
||||||
|
@ -23,6 +23,8 @@ type Integration struct {
|
||||||
type Options struct {
|
type Options struct {
|
||||||
// Cloud value is set to true when Jira cloud is used
|
// Cloud value is set to true when Jira cloud is used
|
||||||
Cloud bool `yaml:"cloud"`
|
Cloud bool `yaml:"cloud"`
|
||||||
|
// UpdateExisting value if true, the existing opened issue is updated
|
||||||
|
UpdateExisting bool `yaml:"update-existing"`
|
||||||
// URL is the URL of the jira server
|
// URL is the URL of the jira server
|
||||||
URL string `yaml:"url"`
|
URL string `yaml:"url"`
|
||||||
// AccountID is the accountID of the jira user.
|
// AccountID is the accountID of the jira user.
|
||||||
|
@ -54,8 +56,8 @@ func New(options *Options) (*Integration, error) {
|
||||||
return &Integration{jira: jiraClient, options: options}, nil
|
return &Integration{jira: jiraClient, options: options}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateIssue creates an issue in the tracker
|
// CreateNewIssue creates a new issue in the tracker
|
||||||
func (i *Integration) CreateIssue(event *output.ResultEvent) error {
|
func (i *Integration) CreateNewIssue(event *output.ResultEvent) error {
|
||||||
summary := format.Summary(event)
|
summary := format.Summary(event)
|
||||||
|
|
||||||
fields := &jira.IssueFields{
|
fields := &jira.IssueFields{
|
||||||
|
@ -92,6 +94,52 @@ func (i *Integration) CreateIssue(event *output.ResultEvent) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateIssue creates an issue in the tracker or updates the existing one
|
||||||
|
func (i *Integration) CreateIssue(event *output.ResultEvent) error {
|
||||||
|
if i.options.UpdateExisting {
|
||||||
|
issueID, err := i.FindExistingIssue(event)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else if issueID != "" {
|
||||||
|
_, _, err = i.jira.Issue.AddComment(issueID, &jira.Comment{
|
||||||
|
Body: jiraFormatDescription(event),
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i.CreateNewIssue(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindExistingIssue checks if the issue already exists and returns its ID
|
||||||
|
func (i *Integration) FindExistingIssue(event *output.ResultEvent) (string, error) {
|
||||||
|
template := format.GetMatchedTemplate(event)
|
||||||
|
jql := fmt.Sprintf("summary ~ \"%s\" AND summary ~ \"%s\" AND status = \"Open\"", template, event.Host)
|
||||||
|
|
||||||
|
searchOptions := &jira.SearchOptions{
|
||||||
|
MaxResults: 1, // if any issue exists, then we won't create a new one
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk, resp, err := i.jira.Issue.Search(jql, searchOptions)
|
||||||
|
if err != nil {
|
||||||
|
var data string
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
d, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
data = string(d)
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("%s => %s", err, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
switch resp.Total {
|
||||||
|
case 0:
|
||||||
|
return "", nil
|
||||||
|
case 1:
|
||||||
|
return chunk[0].ID, nil
|
||||||
|
default:
|
||||||
|
gologger.Warning().Msgf("Discovered multiple opened issues %s for the host %s: The issue [%s] will be updated.", template, event.Host, chunk[0].ID)
|
||||||
|
return chunk[0].ID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// jiraFormatDescription formats a short description of the generated
|
// jiraFormatDescription formats a short description of the generated
|
||||||
// event by the nuclei scanner in Jira format.
|
// event by the nuclei scanner in Jira format.
|
||||||
func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove the code duplication: format.go <-> jira.go
|
func jiraFormatDescription(event *output.ResultEvent) string { // TODO remove the code duplication: format.go <-> jira.go
|
||||||
|
|
Loading…
Reference in New Issue