func CalculateHash(issue jira.Issue) string {
	description := issue.Fields.Description
	rexes := map[string]*regexp.Regexp{
		"source":         regexp.MustCompile(`(source:\s*(?P<source>\S+)\s)`),
		"target":         regexp.MustCompile(`(target:\s*(?P<target>\S+)\s)`),
		"vulnType":       regexp.MustCompile(`(type:\s*(?P<type>\w\s*)+)(\r\n|\r|\n)`),
		"severityText":   regexp.MustCompile(`(severity_text:\s*(?P<severity>.+)(\r\n|\r|\n))`),
		"cvss":           regexp.MustCompile(`(cvss:\s*(?P<cvss>[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)(\r\n|\r|\n))`),
		"confidenceText": regexp.MustCompile(`(confidence_text:\s*(?P<confidence>\w+)(\r\n|\r|\n))`),
		"scanStartTime":  regexp.MustCompile(`(scan_start_time:\s*(.+)(\r\n|\r|\n))`),
		"scan_id":        regexp.MustCompile(`(scan_id:\s*(.+)(\r\n|\r|\n))`),
		"tool_name":      regexp.MustCompile(`(tool_name:\s*(.+)(\r\n|\r|\n))`),
		"first_found":    regexp.MustCompile(`(first_found:\s*(.+)(\r\n|\r|\n))`),
		"false_positive": regexp.MustCompile(`(false_positive:\s*(.+)(\r\n|\r|\n))`),
		"jira_code_tag":  regexp.MustCompile(`({code:?})`),
		"hash":           regexp.MustCompile(`(hash:\s*(?P<hash>\w+)(\r\n|\r|\n))`),
	}
	if len(namedGroupMatching(rexes["hash"], description)["hash"]) > 0 {
		return namedGroupMatching(rexes["hash"], description)["hash"]
	}
	cvssVal, err := strconv.ParseFloat(namedGroupMatching(rexes["cvss"], description)["cvss"], 64)
	if err != nil {
		log.Println("Could not extract CVSS from the description")
	}
	desc := description
	for _, regex := range rexes {
		desc = regex.ReplaceAllLiteralString(desc, "")
	}
	draconIssue := &v1.Issue{
		Target:      namedGroupMatching(rexes["target"], description)["target"],
		Type:        namedGroupMatching(rexes["vulnType"], description)["type"],
		Title:       issue.Fields.Summary,
		Severity:    document.TextToSeverity(namedGroupMatching(rexes["severityText"], description)["severity"]),
		Cvss:        cvssVal,
		Confidence:  document.TextToConfidence(namedGroupMatching(rexes["confidenceText"], description)["confidence"]),
		Description: strings.TrimSpace(desc),
		Source:      namedGroupMatching(rexes["source"], description)["source"],
	}
	hash := enrichment.GetHash(draconIssue)
	return hash
}
CalculateHash assumes the Jira Ticket doesn't have a custom hash field or the field is not mapped in the config
tries to gather the info from the rest of the ticket, last resort method of calculating hashes.
quite inacurrate
package sync
import (
	"context"
	"database/sql"
	"errors"
	"fmt"
	"log"
	"regexp"
	"strconv"
	"strings"
	v1 "github.com/thought-machine/dracon/api/proto/v1"
	"github.com/thought-machine/dracon/common/jira/config"
	"github.com/thought-machine/dracon/common/jira/document"
	"github.com/thought-machine/dracon/pkg/enrichment"
	"github.com/thought-machine/dracon/pkg/enrichment/db"
	jira "github.com/andygrunwald/go-jira"
)
func GetHash(issue jira.Issue, config config.Config) (string, error) {
	var jiraHashField, jiraHashFieldType string
	for _, mapping := range config.Mappings {
		if mapping.DraconField == "hash" {
			jiraHashField = mapping.JiraField
			jiraHashFieldType = mapping.FieldType
		}
	}
	if jiraHashField == "" {
		return "", errors.New("Config is missing a jira field mapping for hash")
	}
	if jiraHashFieldType != "single-value" {
		return "", errors.New("Hash must be single value, each vulnerability has one hash")
	}
	hash, err := issue.Fields.Unknowns.String(jiraHashField)
	if err != nil {
		return "", err
	}
	return hash, nil
}