diff --git a/cve-vulner-manager/common/analysis.go b/cve-vulner-manager/common/analysis.go new file mode 100644 index 0000000000000000000000000000000000000000..aa13abb21a37ee6bd27555ff8f024879bc0617e8 --- /dev/null +++ b/cve-vulner-manager/common/analysis.go @@ -0,0 +1,54 @@ +package common + +import "k8s.io/apimachinery/pkg/util/sets" + +const ( + AnalysisWillFix = "正常修复" + AnalysisNoPatch = "暂不修复-上游无补丁" + AnalysisUpgrade = "暂不修复-待升级版本修复" + AnalysisOutScope = "不修复-超出修复范围" + AnalysisNotFix = "不修复-特殊原因导致不再修复" + AnalysisComponentNotPresent = "不受影响-组件不存在" + AnalysisMitigationsExist = "不受影响-已有消减措施" + AnalysisCannotControlled = "不受影响-漏洞代码不能被攻击者触发" + AnalysisNotExecute = "不受影响-漏洞代码不在调用点上" + AnalysisCodeNotPresent = "不受影响-漏洞代码不存在" + + TypeAffected = "Affected" + TypeUnaffected = "Unaffected" +) + +var AnalysisUnaffected = map[string]struct{}{ + AnalysisComponentNotPresent: {}, + AnalysisMitigationsExist: {}, + AnalysisCannotControlled: {}, + AnalysisNotExecute: {}, + AnalysisCodeNotPresent: {}, +} + +var AnalysisEnglishMap = map[string]string{ + AnalysisWillFix: "will fix", + AnalysisNoPatch: "none_available-No available patches in the upstream", + AnalysisUpgrade: "none_available-To be fixed through an upgraded version", + AnalysisOutScope: "no_fix_planned-Out of support scope", + AnalysisNotFix: "no_fix_planned-Will not fix", + AnalysisComponentNotPresent: "component_not_present", + AnalysisMitigationsExist: "inline_mitigations_already_exist", + AnalysisCannotControlled: "vulnerable_code_cannot_be_controlled_by_adversary", + AnalysisNotExecute: "vulnerable_code_not_in_execute_path", + AnalysisCodeNotPresent: "vulnerable_code_not_present", +} + +var ( + AnalysisSets = sets.NewString(AnalysisWillFix, AnalysisNoPatch, AnalysisUpgrade, AnalysisOutScope, AnalysisNotFix, + AnalysisComponentNotPresent, AnalysisMitigationsExist, AnalysisCannotControlled, AnalysisNotExecute, AnalysisCodeNotPresent) + + AffectedAnalysisSets = sets.NewString(AnalysisWillFix, AnalysisNoPatch, AnalysisUpgrade, AnalysisOutScope, AnalysisNotFix) + + UnaffectedAnalysisSets = sets.NewString(AnalysisComponentNotPresent, AnalysisMitigationsExist, AnalysisCannotControlled, AnalysisNotExecute, AnalysisCodeNotPresent) + + AnalysisMap = map[string]sets.String{ + "受影响": AffectedAnalysisSets, + "不受影响": UnaffectedAnalysisSets, + } +) diff --git a/cve-vulner-manager/controllers/hook.go b/cve-vulner-manager/controllers/hook.go index c5f131fabdca35611b365e9faadd729a8d89503c..52570c375ef7109d14b7b37be224dcabd671518b 100644 --- a/cve-vulner-manager/controllers/hook.go +++ b/cve-vulner-manager/controllers/hook.go @@ -444,9 +444,7 @@ func closeIssueProc(issueHook *models.IssuePayload, issueTmp *models.IssueTempla sigReviewSend(issueHook, issueTmp, token, owner, fixed, unFix, assignee, cveCenter) } if openScoreFlag { - unFixList := taskhandler.CheckAffectVerComplete(issueTmp.AffectedVersion, issueTmp.Repo, - issueTmp.OwnedVersion, cveCenter.OrganizationID) - if len(unFixList) > 0 { + if msg, tb, ok := taskhandler.CheckIssueAnalysisComplete(issueTmp, cveCenter.OrganizationID); !ok { //send comment to issue issueTmp.IssueStatus = 1 issueTmp.IssueLabel = unFix @@ -454,68 +452,53 @@ func closeIssueProc(issueHook *models.IssuePayload, issueTmp *models.IssueTempla _, issueErr := taskhandler.UpdateIssueToGit(token, owner, issueTmp.Repo, *cveCenter, *issueTmp) if issueErr == nil { - na := "\n**请确认分支信息是否填写完整,否则将无法关闭当前issue.**" - cc := fmt.Sprintf(CommentCheckVersion, issueHook.Sender.UserName, strings.Join(unFixList, ",")) + na + na := "\n**请确认分析内容的准确性,待分析内容请填写完整,否则将无法关闭当前issue.**" + //cc := fmt.Sprintf(ContentReview, "@"+issueHook.Sender.UserName) + tb + na + cc := fmt.Sprintf(CommentAnalysisCplTpl, issueHook.Sender.UserName, msg) + na taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) content := fmt.Sprintf("%v 仓库的CVE和安全问题的ISSUE,CVE编号: %v,", issueTmp.Repo, issueTmp.CveNum) - taskhandler.SendPrivateLetters(token, content, issueHook.Sender.UserName) + taskhandler.SendPrivateLetters(token, content+msg, issueHook.Sender.UserName) } } else { - if msg, tb, ok := taskhandler.CheckIssueClosedAnalysisComplete(issueTmp); !ok { - //send comment to issue + //1. change issue status + issueTmp.IssueStatus = 2 + //issueTmp.Status = 3 + cveCenter.IsExport = 3 + if issueTmp.MtAuditFlag == 0 { issueTmp.IssueStatus = 1 + issueTmp.Status = 1 + cveCenter.IsExport = 0 issueTmp.IssueLabel = unFix issueTmp.StatusName = "open" _, issueErr := taskhandler.UpdateIssueToGit(token, owner, issueTmp.Repo, *cveCenter, *issueTmp) if issueErr == nil { - na := "\n**请确认分析内容的准确性,待分析内容请填写完整,否则将无法关闭当前issue.**" - cc := fmt.Sprintf(ContentReview, "@"+issueHook.Sender.UserName) + tb + na + na := "\n**issue关闭前,请确认模板分析内容的准确性与完整性,确认无误后,请在评论区输入: /approve, 否则无法关闭当前issue.**" + cc := fmt.Sprintf(ContentReview, assignee) + tb + na taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) - content := fmt.Sprintf("%v 仓库的CVE和安全问题的ISSUE,CVE编号: %v,", issueTmp.Repo, issueTmp.CveNum) - taskhandler.SendPrivateLetters(token, content+msg, issueHook.Sender.UserName) - } - } else { - //1. change issue status - issueTmp.IssueStatus = 2 - //issueTmp.Status = 3 - cveCenter.IsExport = 3 - if issueTmp.MtAuditFlag == 0 { - issueTmp.IssueStatus = 1 - issueTmp.Status = 1 - cveCenter.IsExport = 0 - issueTmp.IssueLabel = unFix - issueTmp.StatusName = "open" - _, issueErr := taskhandler.UpdateIssueToGit(token, owner, issueTmp.Repo, - *cveCenter, *issueTmp) - if issueErr == nil { - na := "\n**issue关闭前,请确认模板分析内容的准确性与完整性,确认无误后,请在评论区输入: /approve, 否则无法关闭当前issue.**" - cc := fmt.Sprintf(ContentReview, assignee) + tb + na - taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) - } - return } - issueTmp.IssueLabel = unFix - issueTmp.StatusName = "open" - issueTmp.Status = 1 - issuePrFlag := VerifyIssueAsPr(issueTmp, *cveCenter, false, - assignee, issueHook.Sender.UserName) - if issuePrFlag { - issueTmp.StatusName = issueHook.Issue.StateName - issueTmp.Status = 3 - if isNormalCloseIssue(issueTmp.CveId, issueTmp.IssueStatus) { - issueTmp.IssueStatus = 2 - cveCenter.IsExport = 3 - issueTmp.IssueLabel = fixed - } else { - issueTmp.IssueStatus = 6 - cveCenter.IsExport = 2 - issueTmp.IssueLabel = unFix - } + return + } + issueTmp.IssueLabel = unFix + issueTmp.StatusName = "open" + issueTmp.Status = 1 + issuePrFlag := VerifyIssueAsPr(issueTmp, *cveCenter, false, + assignee, issueHook.Sender.UserName) + if issuePrFlag { + issueTmp.StatusName = issueHook.Issue.StateName + issueTmp.Status = 3 + if isNormalCloseIssue(issueTmp.CveId, issueTmp.IssueStatus) { + issueTmp.IssueStatus = 2 + cveCenter.IsExport = 3 + issueTmp.IssueLabel = fixed } else { - issueTmp.IssueStatus = 1 - cveCenter.IsExport = 0 + issueTmp.IssueStatus = 6 + cveCenter.IsExport = 2 + issueTmp.IssueLabel = unFix } + } else { + issueTmp.IssueStatus = 1 + cveCenter.IsExport = 0 } } } @@ -578,7 +561,7 @@ func handleIssueStateChange(issueHook *models.IssuePayload) error { } } - var checkFunc func(template *models.IssueTemplate, v *models.VulnCenter) (string, string, bool) + var checkFunc func(template *models.IssueTemplate, organizationID int8) (string, string, bool) switch cveCenter.OrganizationID { case util.Openeuler: checkFunc = taskhandler.CheckIssueAnalysisComplete @@ -589,7 +572,7 @@ func handleIssueStateChange(issueHook *models.IssuePayload) error { case IssueOpenState: issueTmp.Status = 1 cveCenter.IsExport = 0 - _, _, ok := checkFunc(&issueTmp, &cveCenter) + _, _, ok := checkFunc(&issueTmp, cveCenter.OrganizationID) if ok { issueTmp.IssueStatus = 3 } else { @@ -600,7 +583,7 @@ func handleIssueStateChange(issueHook *models.IssuePayload) error { case IssueProgressState: issueTmp.Status = 2 cveCenter.IsExport = 0 - _, _, ok := checkFunc(&issueTmp, &cveCenter) + _, _, ok := checkFunc(&issueTmp, cveCenter.OrganizationID) if ok { issueTmp.IssueStatus = 3 } else { @@ -671,8 +654,8 @@ func VerifyIssueAsPr(issueTmp *models.IssueTemplate, cveCenter models.VulnCenter } } - if sn.AffectProduct != "" && len(sn.AffectProduct) > 1 { - tmpAffectBranchsxList = strings.Split(sn.AffectProduct, "/") + if sn.WillFixProduct != "" && len(sn.WillFixProduct) > 1 { + tmpAffectBranchsxList = strings.Split(sn.WillFixProduct, "/") } affectProductList = common.RemoveDupString(tmpAffectBranchsxList) if len(affectProductList) > 0 { @@ -720,7 +703,7 @@ func VerifyIssueAsPr(issueTmp *models.IssueTemplate, cveCenter models.VulnCenter } } if len(branchMaps) == 0 { - logs.Info("sn.AffectProduct: ", sn.AffectProduct, ",There is no branch to follow to associate with pr") + logs.Info("sn.WillFixProduct: ", sn.WillFixProduct, ",There is no branch to follow to associate with pr") return true } brandStr := "" @@ -870,6 +853,29 @@ func paraAffectBrandBool(affectedVersion string) bool { return false } +func paraAnalysisBrandBool(analysisVersion string) bool { + unaffectedBranchList := make([]string, 0) + analysisVersion = strings.ReplaceAll(analysisVersion, ":", ":") + brandsGroup := strings.Split(analysisVersion, ",") + if len(brandsGroup) > 0 { + for _, brand := range brandsGroup { + if brand == "" || len(brand) < 2 { + continue + } + brand = common.BranchVersionRep(brand) + brandList := strings.Split(brand, ":") + if len(brandList) > 1 { + prams := strings.Replace(brandList[1], " ", "", -1) + if common.AnalysisSets.Has(prams) { + unaffectedBranchList = append(unaffectedBranchList, brandList[0]) + } + } + } + } + + return len(unaffectedBranchList) > 0 +} + func getPRRelatedBrandsAllIssue(token, owner, repo string, num int, issueNum string) bool { issueFlag := false url := fmt.Sprintf(`https://gitee.com/api/v5/repos/%s/%s/pulls/%v/issues`, owner, repo, num) @@ -1323,18 +1329,10 @@ func otherMaintainerApprove( func maintainerApprove(issueTmp *models.IssueTemplate, cuAccount, owner, token, fixed, unfixed string, organizationID int8) { - unFixList := taskhandler.CheckAffectVerComplete(issueTmp.AffectedVersion, - issueTmp.Repo, issueTmp.OwnedVersion, organizationID) - if len(unFixList) > 0 { - na := "\n**请确认分支信息是否填写完整,否则将无法关闭当前issue.**" - cc := fmt.Sprintf(CommentCheckVersion, cuAccount, strings.Join(unFixList, ",")) + na - taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) - return - } - if _, tb, ok := taskhandler.CheckIssueClosedAnalysisComplete(issueTmp); !ok { + if msg, _, ok := taskhandler.CheckIssueAnalysisComplete(issueTmp, organizationID); !ok { //send comment to issue na := "\n**请确认分析内容的准确性,待分析内容请填写完整,否则将无法关闭当前issue.**" - cc := fmt.Sprintf(AnalysisComplete, cuAccount) + tb + na + cc := fmt.Sprintf(CommentAnalysisCplTpl, cuAccount, msg) + na taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) return } else { @@ -1386,18 +1384,10 @@ func maintainerApprove(issueTmp *models.IssueTemplate, cuAccount, owner, token, func securityApprove(issueTmp *models.IssueTemplate, cuAccount, owner, token, fixed, unfixed string, organizationID int8) { - unFixList := taskhandler.CheckAffectVerComplete(issueTmp.AffectedVersion, - issueTmp.Repo, issueTmp.OwnedVersion, organizationID) - if len(unFixList) > 0 { - na := "\n**请确认分支信息是否填写完整,否则将无法关闭当前issue.**" - cc := fmt.Sprintf(CommentCheckVersion, cuAccount, strings.Join(unFixList, ",")) + na - taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) - return - } - if _, tb, ok := taskhandler.CheckIssueClosedAnalysisComplete(issueTmp); !ok { + if msg, _, ok := taskhandler.CheckIssueAnalysisComplete(issueTmp, organizationID); !ok { //send comment to issue na := "\n**请确认分析内容的准确性,待分析内容请填写完整,否则将无法关闭当前issue.**" - cc := fmt.Sprintf(AnalysisComplete, cuAccount) + tb + na + cc := fmt.Sprintf(CommentAnalysisCplTpl, cuAccount, msg) + na taskhandler.AddCommentToIssue(cc, issueTmp.IssueNum, owner, issueTmp.Repo, token) return } else { @@ -1787,6 +1777,13 @@ func analysisComment(owner, accessToken, path string, cuAccount string, cBody st cols = append(cols, k) } } + case "analysis_version": + if v != "" && len(v) > 1 { + if paraAnalysisBrandBool(v) { + issueTmp.AnalysisVersion = v + cols = append(cols, k) + } + } case "solution": issueTmp.Solution = v cols = append(cols, k) @@ -1835,14 +1832,14 @@ func analysisComment(owner, accessToken, path string, cuAccount string, cBody st logs.Error(webhookCommentLogTag, "canVerfy of ", issueTmp.IssueNum, canVerfy) if canVerfy { //Check whether the data is legal - var checkFunc func(template *models.IssueTemplate, v *models.VulnCenter) (string, string, bool) + var checkFunc func(template *models.IssueTemplate, organizationID int8) (string, string, bool) switch v.OrganizationID { case util.Openeuler: checkFunc = taskhandler.CheckIssueAnalysisComplete default: checkFunc = taskhandler.CheckOtherIssueAnalysisComplete } - if msg, tb, ok := checkFunc(&issueTmp, &v); !ok { + if msg, tb, ok := checkFunc(&issueTmp, v.OrganizationID); !ok { //send comment to issue issueTmp.IssueStatus = 1 err := models.UpdateIssueTemplate(&issueTmp, "issue_status") diff --git a/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/dto.go b/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/dto.go index 200e707a53da96de7e3c35a29a818719cdb2ff24..a79d50606f6dd04682a007976dbc4b6946e13326 100644 --- a/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/dto.go +++ b/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/dto.go @@ -12,6 +12,7 @@ type CveInfo struct { Summary string `json:"summary"` Description string `json:"description"` AffectProduct string `json:"affect_product"` + WillFixProduct string `json:"will_fix_product"` ReferenceLink string `json:"reference_link"` OpeneulerScore float64 `json:"openeuler_score"` Theme string `json:"theme"` @@ -19,3 +20,16 @@ type CveInfo struct { CveVersion string `json:"cve_version"` AbiVersion string `json:"abi_version"` } + +// 是否是新增了分析说明模块的数据 +func (c CveInfo) IsIssueWithAnalysis() bool { + return c.WillFixProduct != "" +} + +func (c CveInfo) GetAffectProduct() string { + if c.IsIssueWithAnalysis() { + return c.WillFixProduct + } else { + return c.AffectProduct + } +} diff --git a/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/impl.go b/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/impl.go index c5ac2d5c7875e387379f57cf5ca005467b13b851..995717b352b46ce056dd7b925f92ebc0b40eeea8 100644 --- a/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/impl.go +++ b/cve-vulner-manager/cve-ddd/infrastructure/repositoryimpl/impl.go @@ -25,7 +25,7 @@ func (impl repositoryImpl) FindCves(opt repository.Option) (cves domain.Cves, er sql := `select a.cve_num,a.cve_version,b.openeuler_score,b.openeuler_vector,b.issue_num, b.repo,b.abi_version,b.owned_component, b.cve_brief, b.cve_level, b.affected_version, - c.introduction, c.summary, c.description, c.affect_product, c.reference_link,c.theme + c.introduction, c.summary, c.description, c.affect_product, c.will_fix_product, c.reference_link,c.theme from cve_vuln_center a join cve_issue_template b on a.cve_id=b.cve_id join cve_security_notice c on a.cve_id=c.cve_id @@ -46,14 +46,14 @@ and b.status < 4 } for _, v := range data { - affectVersion := strings.Split(v.AffectProduct, "/") + affect := v.GetAffectProduct() cve := domain.Cve{ Component: v.OwnedComponent, Description: v.Description, SeverityLevel: v.CveLevel, - AffectedVersion: affectVersion, - AffectedProduct: v.AffectProduct, + AffectedVersion: strings.Split(affect, "/"), + AffectedProduct: affect, OpeneulerScore: v.OpeneulerScore, Theme: v.Theme, CveNum: v.CveNum, @@ -122,7 +122,21 @@ func (impl repositoryImpl) SaveIssueNum(num string) error { type list struct { models.IssueTemplate - AffectProduct string `orm:"column(affect_product)"` + AffectProduct string `orm:"column(affect_product)"` + WillFixProduct string `orm:"column(will_fix_product)"` +} + +// 是否是新增了分析说明模块的数据 +func (l list) IsIssueWithAnalysis() bool { + return l.WillFixProduct != "" +} + +func (l list) GetAffectProduct() []string { + if l.IsIssueWithAnalysis() { + return strings.Split(l.WillFixProduct, "/") + } else { + return strings.Split(l.AffectProduct, "/") + } } var statusMap = map[int8]string{ @@ -132,7 +146,7 @@ var statusMap = map[int8]string{ } func (impl repositoryImpl) GetAllIssue() (data domain.CollectedDataSlice, err error) { - sql := `select a.*, b.affect_product from cve_issue_template a + sql := `select a.*, b.affect_product, b.will_fix_product from cve_issue_template a join cve_security_notice b on a.cve_id=b.cve_id where a.cve_id in (select cve_id from cve_vuln_center where cve_status = 2 and is_export in (0,3) and organizate_id = 1) and a.status < 4 @@ -155,7 +169,7 @@ func (impl repositoryImpl) GetAllIssue() (data domain.CollectedDataSlice, err er CveNum: v.CveNum, Score: v.OpenEulerScore, Version: v.OwnedVersion, - AffectedProduct: strings.Split(v.AffectProduct, "/"), + AffectedProduct: v.GetAffectProduct(), CreateTime: v.CreateTime, } diff --git a/cve-vulner-manager/models/cve.go b/cve-vulner-manager/models/cve.go index e49d2c364699c318c2f259953196ee4bd312cb6e..53ba282cb64a9c3b04b2db101fe12fb8d6dd7440 100644 --- a/cve-vulner-manager/models/cve.go +++ b/cve-vulner-manager/models/cve.go @@ -1044,7 +1044,7 @@ func GetCanExportExcelData(cveNum, issueNum, repo string, issueId int64) (list [ sql := `SELECT b.num,c.*,a.issue_num,a.owned_component,a.cve_brief, d.sec_id,d.introduction,d.summary,d.theme,d.description,d.influence_component, d.affect_product,d.reference_link,d.affect_status, -e.public_date,e.openeuler_sa_num,a.cve_level,b.organizate_id,a.affected_version,a.issue_label +e.public_date,e.openeuler_sa_num,a.cve_level,b.organizate_id,a.affected_version,a.analysis_version,a.issue_label FROM cve_issue_template a RIGHT JOIN (SELECT (SELECT COUNT(*) FROM cve_vuln_center WHERE cve_num = ? AND is_export in (0,3) AND pack_name = ? AND organizate_id = 1) num, diff --git a/cve-vulner-manager/models/excel.go b/cve-vulner-manager/models/excel.go index 43d76ec669fb3c66288088c1c28f413e6679eb4b..ec4acb5f2945b51e1790f2aabb3d2d0b2f1ac48f 100644 --- a/cve-vulner-manager/models/excel.go +++ b/cve-vulner-manager/models/excel.go @@ -2,12 +2,15 @@ package models import ( "fmt" + "strings" "github.com/astaxie/beego/logs" "github.com/astaxie/beego/orm" + + "cvevulner/common" ) -//ExcelExport the export excel row content model +// ExcelExport the export excel row content model type ExcelExport struct { Num int64 Score @@ -27,39 +30,120 @@ type ExcelExport struct { CveLevel string `json:"cve_level" orm:"size(32);column(cve_level)"` OrganizateId int8 `json:"organizate_id" orm:"column(organizate_id)"` AffectedVersion string `json:"affected_version" orm:"column(affected_version)"` + AnalysisVersion string `json:"analysis_version" orm:"column(analysis_version)"` IssueLabel string `json:"issue_label" orm:"column(issue_label)"` Repo string `json:"repo" orm:"column(repo)"` } -//ExcelPackage Released packages +func (e ExcelExport) IsIssueWithAnalysisVersion() bool { + return e.AnalysisVersion != "" +} + +func (e ExcelExport) ParseAnalysisVersion() map[string]string { + result := make(map[string]string) + split := strings.Split(e.AnalysisVersion, ",") + for _, v := range split { + item := strings.Split(strings.ReplaceAll(v, ":", ":"), ":") + if len(item) != 2 || item[1] == "" { + return nil + } + + result[item[0]] = item[1] + } + + return result +} + +func (e ExcelExport) GetReasonByVersion(v string) string { + version := e.ParseAnalysisVersion() + reason, ok := version[v] + if ok { + english, ok2 := common.AnalysisEnglishMap[reason] + if ok2 { + return english + } + } + + return "" +} + +func (e ExcelExport) WillFixVersion() []string { + var version []string + + for v, reason := range e.ParseAnalysisVersion() { + if reason == common.AnalysisWillFix { + version = append(version, v) + } + } + + return version +} + +func (e ExcelExport) IsWillFixVersion(v string) bool { + for _, version := range e.WillFixVersion() { + if version == v { + return true + } + } + + return false +} + +func (e ExcelExport) IsNotWillFixVersion(v string) bool { + for version, reason := range e.ParseAnalysisVersion() { + if v == version && reason != common.AnalysisWillFix { + return true + } + } + + return false +} + +func (e ExcelExport) AffectType(v string) string { + if !e.IsIssueWithAnalysisVersion() { + return common.TypeUnaffected + } + + for version, reason := range e.ParseAnalysisVersion() { + if v == version { + if _, ok := common.AnalysisUnaffected[reason]; ok { + return common.TypeUnaffected + } + } + } + + return common.TypeAffected +} + +// ExcelPackage Released packages type ExcelPackage struct { PubTime string Repo string Packages string } -//Insert Insert a generated excel file record +// Insert Insert a generated excel file record func (er ExportRecord) Insert() error { o := orm.NewOrm() _, err := o.Insert(&er) return err } -//QueryLast query the last excel record +// QueryLast query the last excel record func (er *ExportRecord) QueryLast() error { o := orm.NewOrm() err := o.QueryTable(er).Filter("state", 0).OrderBy("-create_time").One(er) return err } -//Update update by column name +// Update update by column name func (er *ExportRecord) Update(field ...string) error { o := orm.NewOrm() _, err := o.Update(er, field...) return err } -//Read read by column name +// Read read by column name func (er *ExportRecord) Read(field ...string) error { o := orm.NewOrm() return o.Read(er, field...) diff --git a/cve-vulner-manager/models/modeldb.go b/cve-vulner-manager/models/modeldb.go index 47d3196d15f940c08871bcb12af64aff10c2f545..d9be60f6a556e686de7c3d3d72748854975f560a 100644 --- a/cve-vulner-manager/models/modeldb.go +++ b/cve-vulner-manager/models/modeldb.go @@ -146,6 +146,7 @@ type SecurityNotice struct { Description string `orm:"type(text);column(description)" description:"安全公告描述"` InfluenceComponent string `orm:"size(256);null;column(influence_component)" description:"影响组件"` AffectProduct string `orm:"size(256);null;column(affect_product)" description:"影响产品"` + WillFixProduct string `orm:"size(256);null;column(will_fix_product)" description:"正常修复产品"` ReferenceLink string `orm:"type(text);null;column(reference_link)" description:"参考链接"` Status int8 `orm:"default(0);column(sec_status)" description:"0:未发布;1:已发布"` AffectStatus string `orm:"size(16);null;column(affect_status)" description:"Fixed:已解决;UnFixed:未解决;UnAffected:不影响"` @@ -177,6 +178,7 @@ type IssueTemplate struct { CveAnalysis string `orm:"type(text);column(cve_analysis)" description:"影响性分析说明"` PrincipleAnalysis string `orm:"type(text);column(principle_analysis)" description:"原理分析"` AffectedVersion string `orm:"size(256);column(affected_version)" description:"受影响的版本"` + AnalysisVersion string `orm:"type(text);column(analysis_version)" description:"分析说明"` Solution string `orm:"type(text);column(solution)" description:"规避方案或消减措施"` IssueId int64 `orm:"column(issue_id)" description:"issue的id"` IssueNum string `orm:"size(64);column(issue_num)" description:"issue编号"` diff --git a/cve-vulner-manager/task/cve.go b/cve-vulner-manager/task/cve.go index 354500cf639c5f4841ce592e454740968952cd4e..6cc82376ca76ef57778a510226000a7aa3227069 100644 --- a/cve-vulner-manager/task/cve.go +++ b/cve-vulner-manager/task/cve.go @@ -15,12 +15,17 @@ import ( "github.com/opensourceways/server-common-lib/utils" "cvevulner/common" + "cvevulner/cve-ddd/infrastructure/obsimpl" "cvevulner/taskhandler" "github.com/astaxie/beego/config" "github.com/astaxie/beego/logs" ) +const ( + indexUnaffectTxt = "index_unaffect.txt" +) + // ProcCveOriginData Process raw data obtained by api func ProcCveOriginData(prcNum, days, credibilityLevel, openeulerNum int, cveRef, owner string) (bool, error) { // Process raw data obtained by api @@ -127,6 +132,8 @@ func ReleaseUnaffectedCve() error { return obsErr } + updateIndexAffectTxt(localFileName) + syncUnCVEUrl := beego.AppConfig.String("reflink::openeuler_api") + "/cve-security-notice-server/syncUnCVE" client := utils.NewHttpClient(3) @@ -157,3 +164,18 @@ func ReleaseUnaffectedCve() error { return nil } + +func updateIndexAffectTxt(fileName string) { + path := beego.AppConfig.String("obs::download_cvrf_dir") + indexUnaffectTxt + content, err := obsimpl.Instance().Download(path) + if err != nil { + logs.Error("download %s failed: %s ", indexUnaffectTxt, err.Error()) + return + } + + newContent := string(content) + "\n" + fileName + newContent = strings.TrimSpace(newContent) + if err = obsimpl.Instance().Upload(path, []byte(newContent)); err != nil { + logs.Error("upload %s failed: %s ", indexUnaffectTxt, err.Error()) + } +} diff --git a/cve-vulner-manager/taskhandler/check.go b/cve-vulner-manager/taskhandler/check.go index 2d869fc178b53fd67912e925eb112b3b4fee6265..cfeaa3ee1bfeaaf15e1c945a93766bf906300c35 100644 --- a/cve-vulner-manager/taskhandler/check.go +++ b/cve-vulner-manager/taskhandler/check.go @@ -11,15 +11,16 @@ import ( "github.com/astaxie/beego/logs" ) -func CheckIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCenter) (msg, tbStr string, ok bool) { +func CheckIssueAnalysisComplete(i *models.IssueTemplate, organizationID int8) (msg, tbStr string, ok bool) { tb := - `| 状态 | 需分析 | 内容 | + `| 状态 | 分析项目 | 内容 | |:--:|:--:|---------| |%v|%v|%v| |%v|%v|%v| |%v|%v|%v| |%v|%v|%v| |%v|%v|%v| +|%v|%v|%v| ` if i == nil { @@ -27,60 +28,93 @@ func CheckIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCenter) ( return msg, "", false } ok = true - tbContent := make([]interface{}, 15) + tbContent := make([]interface{}, 18) if util.TrimString(i.CveAnalysis) == "" || len(util.TrimString(i.CveAnalysis)) < 1 { - msg = fmt.Sprintf("1.影响性分析说明=> 没有填写或按正确格式填写") + msg = "1.影响性分析说明=> 没有填写或按正确格式填写" ok = false return } tbContent[0] = "已分析" tbContent[1] = "1.影响性分析说明" tbContent[2] = util.TrimStringNR(i.CveAnalysis) + + affectBranchsxList := make([]string, 0) + owner, accessToken := common.GetOwnerAndToken("", organizationID) + if organizationID == 1 || organizationID == 2 { + affectBranchsxList, _ = GetBranchesInfo(accessToken, owner, i.Repo, organizationID) + } else if organizationID == 3 || organizationID == 4 { + affectBranchsxList = CreateBrandAndTags(accessToken, owner, i.Repo, organizationID) + } + + //logs.Error("affectBranchsxList: ", affectBranchsxList) + if len(affectBranchsxList) == 0 { + msg = "获取仓库分支信息失败" + ok = false + return + } + + // check version affectedVersionFlag := 1 + affectedVersionMap := make(map[string]string) if i.AffectedVersion != "" { - versionfFlag := true - affectedVersionArry := strings.Split(i.AffectedVersion, ",") - if len(affectedVersionArry) > 0 { - for _, affectx := range affectedVersionArry { - affect := common.BranchVersionRep(affectx) - versionArry := strings.Split(affect, ":") - if len(versionArry) > 1 { - if versionArry[1] == "受影响" || versionArry[1] == "不受影响" { - if versionArry[1] == "受影响" { - affectedVersionFlag = 2 - } - continue - } else { - affectedVersionFlag = 3 - versionfFlag = false - break - } - } else { - affectedVersionFlag = 3 - versionfFlag = false - break - } + versions := make([]string, 0) + //affectVersionMap := make(map[string]string) + + // 必须对每个分支进行受影响分析 + affectVersionArry := strings.Split(i.AffectedVersion, ",") + for _, affectx := range affectVersionArry { + affect := common.BranchVersionRep(affectx) + versionAffect := strings.Split(affect, ":") + if len(versionAffect) < 2 { + msg = fmt.Sprintf("4.受影响版本排查(受影响/不受影响)=> 没有分析或未按正确格式填写:%v", affectx) + ok = false + return } + versions = append(versions, versionAffect[0]) + affectedVersionMap[versionAffect[0]] = versionAffect[1] } - if !versionfFlag { + + // 受影响版本分析填写的分支信息必须和配置的分支信息保持一致 + if len(affectBranchsxList) != len(versions) { msg = fmt.Sprintf("4.受影响版本排查(受影响/不受影响)=> 没有分析或未按正确格式填写:%v", i.AffectedVersion) ok = false return } - if versionfFlag { - tbContent[9] = "已分析" - tbContent[10] = "4.受影响版本排查" - tbContent[11] = util.TrimStringNR(i.AffectedVersion) - } else { - tbContent[9] = "待分析" - tbContent[10] = "4.受影响版本排查" - tbContent[11] = util.TrimStringNR(i.AffectedVersion) + + for _, abl := range affectBranchsxList { + flag := false + for _, version := range versions { + if abl == version { + flag = true + break + } + } + if !flag { + msg = fmt.Sprintf("4.受影响版本排查(受影响/不受影响)=> 没有分析或未按正确格式填写:%v", i.AffectedVersion) + ok = false + return + } + } + + // 每个版本的受影响分析内容必须是"受影响"或者"不受影响" + for _, version := range versions { + if affectedVersionMap[version] != "受影响" && affectedVersionMap[version] != "不受影响" { + msg = fmt.Sprintf("4.受影响版本排查(受影响/不受影响)=> 没有分析或未按正确格式填写:%v", version) + ok = false + return + } } + + affectedVersionFlag = 2 + tbContent[9] = "已分析" + tbContent[10] = "4.受影响版本排查" + tbContent[11] = util.TrimStringNR(i.AffectedVersion) } else { tbContent[9] = "已分析" tbContent[10] = "4.受影响版本排查" tbContent[11] = "" } + if affectedVersionFlag == 1 { tbContent[3] = "已分析" tbContent[4] = "2.openEulerScore" @@ -90,7 +124,7 @@ func CheckIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCenter) ( tbContent[8] = util.TrimStringNR(i.OpenEulerVector) } else { if i.OpenEulerScore == 0.0 && i.OpenEulerVector != util.VectorNone { - msg = fmt.Sprintf("2.openEulerScore=> 没有填写或正确填写(0-10)") + msg = "2.openEulerScore=> 没有填写或正确填写(0-10)" ok = false return } @@ -99,7 +133,7 @@ func CheckIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCenter) ( tbContent[5] = i.OpenEulerScore if i.OpenEulerVector == "" || len(i.OpenEulerVector) < 1 { - msg = fmt.Sprintf("2.openEulerVector=> 没有正确填写") + msg = "2.openEulerVector=> 没有正确填写" ok = false return } @@ -132,25 +166,76 @@ func CheckIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCenter) ( ok = false return } - if versionAbiFlag { - tbContent[12] = "已分析" - tbContent[13] = "5.修复是否涉及abi变化" - tbContent[14] = util.TrimStringNR(i.AbiVersion) - } else { - tbContent[12] = "待分析" - tbContent[13] = "5.修复是否涉及abi变化" - tbContent[14] = util.TrimStringNR(i.AbiVersion) - } - } else { tbContent[12] = "已分析" tbContent[13] = "5.修复是否涉及abi变化" - tbContent[14] = "" + tbContent[14] = util.TrimStringNR(i.AbiVersion) } + + if i.AnalysisVersion != "" { + versions := make([]string, 0) + analysisVersionMap := make(map[string]string) + + // 必须对每个分支进行原因分析说明 + analysisVersionArry := strings.Split(i.AnalysisVersion, ",") + for _, analysisx := range analysisVersionArry { + analysis := common.BranchVersionRep(analysisx) + versionAnalysis := strings.Split(analysis, ":") + if len(versionAnalysis) < 2 { + msg = fmt.Sprintf("6.原因说明=> 没有分析或未按正确格式填写:%v", analysisx) + ok = false + return + } + versions = append(versions, versionAnalysis[0]) + analysisVersionMap[versionAnalysis[0]] = versionAnalysis[1] + } + + // 原因分析填写的分支信息必须和配置的分支信息保持一致 + if len(affectBranchsxList) != len(versions) { + msg = fmt.Sprintf("6.原因说明=> 没有分析或未按正确格式填写:%v", i.AnalysisVersion) + ok = false + return + } + + for _, abl := range affectBranchsxList { + flag := false + for _, version := range versions { + if abl == version { + flag = true + break + } + } + if !flag { + msg = fmt.Sprintf("6.原因说明=> 没有分析或未按正确格式填写:%v", i.AnalysisVersion) + ok = false + return + } + } + + // 每个分支的原因说明必须和受影响版本分析内容对应,例如:master:受影响,那master的原因说明只能是受影响对应的五个原因之一 + for _, version := range versions { + affectVersionSet := common.AnalysisMap[affectedVersionMap[version]] + if !affectVersionSet.Has(analysisVersionMap[version]) { + msg = fmt.Sprintf("6.原因说明=> 分支原因必须和受影响版本分析内容对应:%v", version) + ok = false + return + } + } + + tbContent[15] = "已分析" + tbContent[16] = "6.原因说明" + tbContent[17] = util.TrimStringNR(i.AnalysisVersion) + + } else { + tbContent[15] = "已分析" + tbContent[16] = "6.原因说明" + tbContent[17] = "" + } + tbStr = fmt.Sprintf(tb, tbContent...) return } -func CheckOtherIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCenter) (msg, tbStr string, ok bool) { +func CheckOtherIssueAnalysisComplete(i *models.IssueTemplate, organizationID int8) (msg, tbStr string, ok bool) { tb := `| 状态 | 需分析 | 内容 | |:--:|:--:|---------| @@ -164,7 +249,7 @@ func CheckOtherIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCent return msg, "", false } var score, vector string - switch v.OrganizationID { + switch organizationID { case util.OpenLookeng: score = "openLooKengScore" vector = "openLooKengVector" @@ -237,7 +322,7 @@ func CheckOtherIssueAnalysisComplete(i *models.IssueTemplate, v *models.VulnCent tbContent[7] = "3." + vector tbContent[8] = util.TrimStringNR(i.OpenEulerVector) } else { - if v.OrganizationID != util.OpenGauss && i.OpenEulerScore == 0.0 { + if organizationID != util.OpenGauss && i.OpenEulerScore == 0.0 { msg = fmt.Sprintf("2.%s=> 没有填写或正确填写(0-10)", score) ok = false return diff --git a/cve-vulner-manager/taskhandler/common.go b/cve-vulner-manager/taskhandler/common.go index 196b7289efd3facecc678e1029800c1cf9a5d825..cd3cb498d44640617b71a4e6dd9703aef6f70dbc 100644 --- a/cve-vulner-manager/taskhandler/common.go +++ b/cve-vulner-manager/taskhandler/common.go @@ -89,6 +89,8 @@ const bodyTpl = `一、漏洞信息 %v 修复是否涉及abi变化(是/否): %v + 原因说明: + %v ` const bodyUpTpl = `一、漏洞信息 @@ -121,6 +123,8 @@ const bodyUpTpl = `一、漏洞信息 %v 修复是否涉及abi变化(是/否): %v + 原因说明: + %v ` const bodySecLinkTpl = `一、漏洞信息 漏洞编号:%v @@ -152,6 +156,8 @@ const bodySecLinkTpl = `一、漏洞信息 %v 修复是否涉及abi变化(是/否): %v + 原因说明: + %v 三、漏洞修复 安全公告链接:%v ` @@ -161,7 +167,7 @@ const commentCopyValue = ` **issue处理注意事项:** **1. 当前issue受影响的分支提交pr时, 须在pr描述中填写当前issue编号进行关联, 否则无法关闭当前issue;** **2. 模板内容需要填写完整, 无论是受影响或者不受影响都需要填写完整内容,未引入的分支不需要填写, 否则无法关闭当前issue;** -**3. 以下为模板中需要填写完整的内容, 请复制到评论区回复, 注: 内容的标题名称(影响性分析说明, openEuler评分, 受影响版本排查(受影响/不受影响), 修复是否涉及abi变化(是/否))不能省略,省略后cve-manager将无法正常解析填写内容.** +**3. 以下为模板中需要填写完整的内容, 请复制到评论区回复, 注: 内容的标题名称(影响性分析说明, openEuler评分, 受影响版本排查(受影响/不受影响), 修复是否涉及abi变化(是/否), 原因说明)不能省略,省略后cve-manager将无法正常解析填写内容.** ************************************************************************ 影响性分析说明: @@ -173,7 +179,23 @@ openEuler评分: (评分和向量) %v 修复是否涉及abi变化(是/否): %v +原因说明: +%v ----------------------------------------------------------------------- +原因说明填写请参考下方表格(注意:版本是否受影响和版本的原因说明必须对应,例如master版本分支受影响,那原因说明只能是受影响对应的原因之一!): +| 分支状态 | 原因说明 | +|:--:|:--:| +|受影响|正常修复| +|受影响|暂不修复-上游无补丁| +|受影响|暂不修复-待升级版本修复| +|受影响|不修复-超出修复范围| +|受影响|不修复-特殊原因导致不再修复| +|不受影响|不受影响-组件不存在| +|不受影响|不受影响-已有消减措施| +|不受影响|不受影响-漏洞代码不能被攻击者触发| +|不受影响|不受影响-漏洞代码不在调用点上| +|不受影响|不受影响-漏洞代码不存在| + issue处理具体操作请参考: %v pr关联issue具体操作请参考: @@ -443,7 +465,7 @@ func CommentTemplate(assignee, commentCmd, affectedVersion, path string, assignL } else { assigneeStr = "@" + assignee } - commentTemplate := fmt.Sprintf(commentCopyValue, assigneeStr, affectedVersion, affectedVersion, commentCmd, PrIssueLink) + commentTemplate := fmt.Sprintf(commentCopyValue, assigneeStr, affectedVersion, affectedVersion, affectedVersion, commentCmd, PrIssueLink) return commentTemplate } @@ -921,6 +943,7 @@ func CreateIssueBody(accessToken, owner, path, assignee string, } affectedVersion := AffectVersionExtract(brandArray, its.AffectedVersion, cve.PackName, cve.OrganizationID) abiVersion := AffectVersionExtract(brandArray, its.AbiVersion, cve.PackName, cve.OrganizationID) + analysisVersion := AffectVersionExtract(brandArray, its.AnalysisVersion, cve.PackName, cve.OrganizationID) updateTemplateAbi(brandArray, its) logs.Info("its.CreateTime: ", its.CreateTime) updateTime := its.CreateTime.Format(common.DATE_FORMAT) @@ -1017,12 +1040,12 @@ func CreateIssueBody(accessToken, owner, path, assignee string, if its.Status == 3 && len(its.SecLink) > 3 && cve.OrganizationID == 1 { body = fmt.Sprintf(bodySecLinkTpl, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion, its.SecLink) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion, analysisVersion, its.SecLink) } else { if cve.OrganizationID == 1 { body = fmt.Sprintf(bodyUpTplx, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion, analysisVersion) } else { body = fmt.Sprintf(bodyUpTplx, cveNumber, cveRepo, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), @@ -1038,7 +1061,7 @@ func CreateIssueBody(accessToken, owner, path, assignee string, if cve.OrganizationID == 1 { body = fmt.Sprintf(bodyTplx, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, affectedVersion, abiVersion) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, affectedVersion, abiVersion, analysisVersion) } else { body = fmt.Sprintf(bodyTplx, cveNumber, cveRepo, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), @@ -1054,7 +1077,7 @@ func CreateIssueBody(accessToken, owner, path, assignee string, if cve.OrganizationID == 1 { body = fmt.Sprintf(bodyTplx, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, affectedVersion, abiVersion) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, affectedVersion, abiVersion, analysisVersion) } else { body = fmt.Sprintf(bodyTplx, cveNumber, cveRepo, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), @@ -1086,12 +1109,12 @@ func CreateIssueBody(accessToken, owner, path, assignee string, if its.Status == 3 && len(its.SecLink) > 3 && cve.OrganizationID == 1 { body = fmt.Sprintf(bodySecLinkTpl, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion, its.SecLink) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion, analysisVersion, its.SecLink) } else { if cve.OrganizationID == 1 { body = fmt.Sprintf(bodyUpTplx, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, oVector, affectedVersion, abiVersion, analysisVersion) } else { body = fmt.Sprintf(bodyUpTplx, cveNumber, cveRepo, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), @@ -1107,7 +1130,7 @@ func CreateIssueBody(accessToken, owner, path, assignee string, if cve.OrganizationID == 1 { body = fmt.Sprintf(bodyTplx, cveNumber, cvePkg, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), - genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, affectedVersion, abiVersion) + genPatchInfo(cve.CveNum), cveAnalysis, openEulerScore, affectedVersion, abiVersion, analysisVersion) } else { body = fmt.Sprintf(bodyTplx, cveNumber, cveRepo, cve.CveVersion, nvdType, nveScore, nveVector, cve.Description, cve.RepairTime, updateTime, cve.CveDetailUrl+"\n"+getCveDetail(cve.CveNum)+"\n", commentCmd, holeSource(cve.DataSource), diff --git a/cve-vulner-manager/taskhandler/createissue.go b/cve-vulner-manager/taskhandler/createissue.go index 79435e7f775ca653d13a3afaef51567ecb5acb71..f387128e8fbefa0796210ff58b7e7a034ca5cf59 100644 --- a/cve-vulner-manager/taskhandler/createissue.go +++ b/cve-vulner-manager/taskhandler/createissue.go @@ -374,6 +374,7 @@ func CreateIssueToGit(accessToken, owner, path, assignee string, brandStr := strings.Join(brandArrayTmp, ",") issueTemp.AffectedVersion = brandStr issueTemp.AbiVersion = brandStr + issueTemp.AnalysisVersion = brandStr issueTemp.SaAuditFlag = 0 } else { issueTemp.SaAuditFlag = 1 @@ -465,7 +466,7 @@ func CreateIssueToGit(accessToken, owner, path, assignee string, } // Store security bulletin related information var sec models.SecurityNotice - CreateSecNoticeData(&sec, cve, path, branchs, sc.NVDScore) + CreateSecNoticeData(&sec, cve, path, branchs, it.AnalysisVersion, sc.NVDScore) secID, noticeErr := models.UpdateSecNotice(&sec) if noticeErr != nil { logs.Error("CreateIssueToGit, Failed to update security information,"+ @@ -568,7 +569,7 @@ func UpdateIssueToGit(accessToken, owner, path string, } // Store security bulletin related information var sec models.SecurityNotice - CreateSecNoticeData(&sec, cve, path, its.AffectedVersion, its.OpenEulerScore) + CreateSecNoticeData(&sec, cve, path, its.AffectedVersion, its.AnalysisVersion, its.OpenEulerScore) secId, err := models.UpdateSecNotice(&sec) if err != nil { logs.Error("UpdateIssueToGit, Failed to update security information, "+ @@ -860,9 +861,44 @@ func AddAffectBrands(branchVersion string) string { return branchs } +func AddWillFixBrands(analysisVersion string) string { + branchs := "" + if analysisVersion != "" && len(analysisVersion) > 1 { + brandsGroup := strings.Split(analysisVersion, ",") + if len(brandsGroup) > 0 { + for _, brand := range brandsGroup { + if brand == "" || len(brand) < 2 { + continue + } + brand = common.BranchVersionRep(brand) + brandList := strings.Split(brand, ":") + if len(brandList) > 1 { + prams := strings.Replace(brandList[1], " ", "", -1) + if prams == "正常修复" { + branchs += brandList[0] + "/" + } + } else { + brandList := strings.Split(brand, ":") + if len(brandList) > 1 { + prams := strings.Replace(brandList[1], " ", "", -1) + if prams == "正常修复" { + branchs += brandList[0] + "/" + } + } + } + } + } + } + if branchs != "" && len(branchs) > 1 { + branchs = branchs[:len(branchs)-1] + } + return branchs +} + func CreateSecNoticeData(sec *models.SecurityNotice, iss models.VulnCenter, - path, branchVersion string, opScore float64) { + path, branchVersion, analysisVersion string, opScore float64) { branchs := AddAffectBrands(branchVersion) + willFixBrands := AddWillFixBrands(analysisVersion) sec.CveId = iss.CveId sec.CveNum = iss.CveNum opScoreLeve := models.OpenEulerScoreProc(opScore) @@ -892,6 +928,7 @@ func CreateSecNoticeData(sec *models.SecurityNotice, iss models.VulnCenter, " is available for each vulnerability from the CVElink(s) in the References section." } sec.AffectProduct = branchs + sec.WillFixProduct = willFixBrands } func CreateBrandAndTags(accessToken, owner, path string, organizationID int8) []string { diff --git a/cve-vulner-manager/taskhandler/cvrf.go b/cve-vulner-manager/taskhandler/cvrf.go index d15d5cbe9ad0ee9d4ddc215124cbb74cf58f36ec..862002450921274de3930293c9f2ecf2e17c2e5d 100644 --- a/cve-vulner-manager/taskhandler/cvrf.go +++ b/cve-vulner-manager/taskhandler/cvrf.go @@ -161,8 +161,8 @@ type CveNote struct { } type ProductStatuses struct { - XMLName xml.Name `xml:"ProductStatuses,omitempty"` - Status *Status `xml:"Status,omitempty"` + XMLName xml.Name `xml:"ProductStatuses,omitempty"` + Status []*Status `xml:"Status,omitempty"` } type Status struct { @@ -222,6 +222,7 @@ type UnRemediation struct { Description string `xml:"Description"` Date string `xml:"DATE"` ProductId string `xml:"ProductID"` + Reason string `xml:"Reason,omitempty"` } type CveInfo struct { @@ -292,6 +293,7 @@ type UnaffectVulnerability struct { Xmlns string `xml:"xmlns,attr"` CveNotes *CveNotes `xml:"Notes,omitempty"` Cve string `xml:"CVE"` + Threats *Threats `xml:"Threats"` ProductStatuses *ProductStatuses `xml:"ProductStatuses,omitempty"` CvssScoreSets *CVSSScoreSets `xml:"CVSSScoreSets,omitempty"` Remediations *UnRemediations `xml:"Remediations,omitempty"` @@ -432,30 +434,60 @@ func BuildUnaffectVulnerabilitySet(unaffectCvrfsa *UnaffectCvrfSa, v models.Exce func BuildUnaffVulnerabilitySlice(vulnerability []UnaffectVulnerability, v models.ExcelExport, affectBranch string, componentMap map[string]ComponentInfo) []UnaffectVulnerability { cpe := affectBranch + affectType := v.AffectType(cpe) if vulnerability != nil && len(vulnerability) > 0 { cveExist := false for i, vl := range vulnerability { if vl.Cve == v.CveNum && vl.Remediations != nil && len(vl.Remediations.Remediation) > 0 && vl.Remediations.Remediation[0].Description == v.InfluenceComponent { + statusTypeExist := false cpeExist := false - for _, pid := range vl.ProductStatuses.Status.ProductId { - if pid.ProductId == cpe { - cpeExist = true - break + + for si, status := range vl.ProductStatuses.Status { + if status.Type == affectType { + statusTypeExist = true + for _, pid := range status.ProductId { + if pid.ProductId == cpe { + cpeExist = true + break + } + } + + if !cpeExist { + var productId ProductId + productId.ProductId = cpe + vl.ProductStatuses.Status[si].ProductId = append(vl.ProductStatuses.Status[si].ProductId, productId) + var remediation UnRemediation + remediation.Type = status.Type + remediation.Description = v.InfluenceComponent + remediation.Date = common.GetCurDate() + remediation.ProductId = cpe + remediation.Reason = v.GetReasonByVersion(cpe) + vl.Remediations.Remediation = append(vl.Remediations.Remediation, remediation) + vulnerability[i] = vl + } } } - if !cpeExist { + + if !statusTypeExist { + var status Status + status.Type = affectType var productId ProductId productId.ProductId = cpe - vl.ProductStatuses.Status.ProductId = append(vl.ProductStatuses.Status.ProductId, productId) + productIdSlice := make([]ProductId, 0) + productIdSlice = append(productIdSlice, productId) + status.ProductId = productIdSlice + vl.ProductStatuses.Status = append(vl.ProductStatuses.Status, &status) var remediation UnRemediation - remediation.Type = "Unaffected" + remediation.Type = status.Type remediation.Description = v.InfluenceComponent remediation.Date = common.GetCurDate() remediation.ProductId = cpe + remediation.Reason = v.GetReasonByVersion(cpe) vl.Remediations.Remediation = append(vl.Remediations.Remediation, remediation) vulnerability[i] = vl } + cveExist = true break } @@ -478,6 +510,9 @@ func BuildUnaffVulnerabilitySlice(vulnerability []UnaffectVulnerability, v model func BuildUnaffVulnerability(vlLenth int, v models.ExcelExport, componentMap map[string]ComponentInfo, cpe string) []UnaffectVulnerability { vulnerabilitySlice := make([]UnaffectVulnerability, 0) + + affectType := v.AffectType(cpe) + var vulnerability UnaffectVulnerability vulnerability.Xmlns = "http://www.icasi.org/CVRF/schema/vuln/1.1" vulnerability.Ordinal = strconv.Itoa(vlLenth) @@ -492,15 +527,18 @@ func BuildUnaffVulnerability(vlLenth int, v models.ExcelExport, cveNotes.CveNote = &cveNote vulnerability.CveNotes = &cveNotes vulnerability.Cve = v.CveNum + + vulnerability.Threats = &Threats{Threat: &Threat{Type: "Impact", Description: v.CveLevel}} + var productStatuses ProductStatuses var status Status - status.Type = "Unaffected" + status.Type = affectType var productId ProductId productId.ProductId = cpe productIdSlice := make([]ProductId, 0) productIdSlice = append(productIdSlice, productId) status.ProductId = productIdSlice - productStatuses.Status = &status + productStatuses.Status = append(productStatuses.Status, &status) vulnerability.ProductStatuses = &productStatuses var cVSSScoreSets CVSSScoreSets var scoreSet ScoreSet @@ -511,10 +549,11 @@ func BuildUnaffVulnerability(vlLenth int, v models.ExcelExport, var remediations UnRemediations remediationSlice := make([]UnRemediation, 0) var remediation UnRemediation - remediation.Type = "Unaffected" + remediation.Type = affectType remediation.Description = v.InfluenceComponent remediation.Date = common.GetCurDate() remediation.ProductId = cpe + remediation.Reason = v.GetReasonByVersion(cpe) remediationSlice = append(remediationSlice, remediation) remediations.Remediation = remediationSlice vulnerability.Remediations = &remediations @@ -1113,7 +1152,7 @@ func BuildVulnerability(vlLenth int, v models.ExcelExport, productIdSlice := make([]ProductId, 0) productIdSlice = append(productIdSlice, productId) status.ProductId = productIdSlice - productStatuses.Status = &status + productStatuses.Status = append(productStatuses.Status, &status) vulnerability.ProductStatuses = &productStatuses var threats Threats var threat Threat @@ -1162,21 +1201,24 @@ func BuildVulnerabilitySlice(vulnerability []Vulnerability, v models.ExcelExport for _, vl := range vulnerability { if vl.Cve == v.CveNum && strings.Contains(vl.Remediations.Remediation.Description, v.InfluenceComponent) { cpeExist := false - for _, pid := range vl.ProductStatuses.Status.ProductId { - if pid.ProductId == cpe { - cpeExist = true - break + + for si, status := range vl.ProductStatuses.Status { + for _, pid := range status.ProductId { + if pid.ProductId == cpe { + cpeExist = true + break + } } - } - if !cpeExist { - var productId ProductId - productId.ProductId = cpe - if branchFlag == 1 { - vl.ProductStatuses.Status.ProductId = append(vl.ProductStatuses.Status.ProductId, productId) - } else { - productIdSlice := make([]ProductId, 0) - productIdSlice = append(productIdSlice, productId) - vl.ProductStatuses.Status.ProductId = productIdSlice + if !cpeExist { + var productId ProductId + productId.ProductId = cpe + if branchFlag == 1 { + vl.ProductStatuses.Status[si].ProductId = append(vl.ProductStatuses.Status[si].ProductId, productId) + } else { + productIdSlice := make([]ProductId, 0) + productIdSlice = append(productIdSlice, productId) + vl.ProductStatuses.Status[si].ProductId = productIdSlice + } } } cveExist = true diff --git a/cve-vulner-manager/taskhandler/excel.go b/cve-vulner-manager/taskhandler/excel.go index fc12ba7f82f17aa73f9b1b0e163fa218be7cd207..1c2d39976b8ff24b0f426a44b25b87dad2e69e28 100644 --- a/cve-vulner-manager/taskhandler/excel.go +++ b/cve-vulner-manager/taskhandler/excel.go @@ -34,7 +34,7 @@ const UNAFFECTFLAG = 2 var releaseDate map[string]int64 -//CveExcel Excel export client +// CveExcel Excel export client type CveExcel struct { ExcelName string //excel name ExcelHandel *excelize.File //excel File handle @@ -60,10 +60,10 @@ type IssueAndPkg struct { var fillLock sync.Mutex var wgTrigger sync.WaitGroup -//GenerateCveExcel Generate Excel documents based on data. -//param snPrefix means security notice prefix. -//param snSuffix means security notice suffix append start value. -//param forceRewrite means whether to force the document to be rewritten. +// GenerateCveExcel Generate Excel documents based on data. +// param snPrefix means security notice prefix. +// param snSuffix means security notice suffix append start value. +// param forceRewrite means whether to force the document to be rewritten. func GenerateCveExcel(excelName, snPrefix string, snSuffix int64, forceRewrite bool) (err error) { //Query the data to be exported. count := models.GetCanExportVulnCenterCount() @@ -89,7 +89,7 @@ func GenerateCveExcel(excelName, snPrefix string, snSuffix int64, forceRewrite b return ec.Save(mode) } -//GenerateCveExcelByTrigger Generate cve&security notice excel file by trigger +// GenerateCveExcelByTrigger Generate cve&security notice excel file by trigger func GenerateCveExcelByTrigger(affectBranch, excelName, snPrefix, startTime string, snSuffix int64, forceRewrite bool, pkgList []models.ExcelPackage, cvrfFileList map[string][]string, componentMap map[string]ComponentInfo, cvfrFileMap map[string]CvrfSa, cvexml *[]CveXml, @@ -119,7 +119,7 @@ func GenerateCveExcelByTrigger(affectBranch, excelName, snPrefix, startTime stri return ec.Save(mode) } -//Init init excel client +// Init init excel client func (ec *CveExcel) Init(excelName, snPrefix string, snSuffix int64) (err error) { if excelName == "" || !(strings.HasSuffix(excelName, ".xlsx") || strings.HasSuffix(excelName, "xls")) { err = errors.New("excel name illegal") @@ -139,9 +139,9 @@ func (ec *CveExcel) Init(excelName, snPrefix string, snSuffix int64) (err error) return nil } -//InitFileHandle Initialize the file handle. -//param forceRewrite is true it means will create a new file otherwise it means append or new. -//the return value wm is 0 for new creation, and 1 for append. +// InitFileHandle Initialize the file handle. +// param forceRewrite is true it means will create a new file otherwise it means append or new. +// the return value wm is 0 for new creation, and 1 for append. func (ec *CveExcel) InitFileHandle(forceRewrite bool) (wm int8) { if forceRewrite { ec.ExcelHandel = excelize.NewFile() @@ -167,7 +167,7 @@ func (ec *CveExcel) InitFileHandle(forceRewrite bool) (wm int8) { } -//InitSheet init excel sheet +// InitSheet init excel sheet func (ec *CveExcel) InitSheet() { ec.SecNoticeSheetIdx = ec.ExcelHandel.NewSheet(ec.SecNoticeSheetName) ec.InfProductSheetIndex = ec.ExcelHandel.NewSheet(ec.InfProductSheetName) @@ -176,7 +176,7 @@ func (ec *CveExcel) InitSheet() { ec.ExcelHandel.SetSheetName(sn, ec.CveSheetName) } -//FillHeader fill the excel sheet header +// FillHeader fill the excel sheet header func (ec *CveExcel) FillHeader() (err error) { err = ec.ExcelHandel.SetCellValue(ec.CveSheetName, "A1", "CVE编号") if err != nil { @@ -382,7 +382,7 @@ func (ec *CveExcel) FillHeader() (err error) { return nil } -//FillContent fill the excel content +// FillContent fill the excel content func (ec *CveExcel) FillContent(count int64) { pageSize := 50 pageCount := count / int64(pageSize) @@ -632,6 +632,10 @@ func affectBrachRep(xmlp *models.ExcelExport, affectBranch string) bool { func FindUnaffectBrach(xmlp *models.ExcelExport, affectBranch, accessToken, owner string) bool { branchArry, _ := GetBranchesInfo(accessToken, owner, xmlp.OwnedComponent, 1) + if xmlp.IsIssueWithAnalysisVersion() { + return xmlp.IsNotWillFixVersion(affectBranch) + } + affectBool := false if xmlp.AffectedVersion != "" && len(xmlp.AffectedVersion) > 1 { affSlice := strings.Split(xmlp.AffectedVersion, ",") @@ -1063,7 +1067,7 @@ func (ec *CveExcel) fillPackageSheet(row []interface{}) (err error) { return err } -//Save save the excel content to file +// Save save the excel content to file func (ec *CveExcel) Save(md int8) error { if md == 0 { return ec.ExcelHandel.SaveAs(ec.ExcelName) @@ -1072,7 +1076,7 @@ func (ec *CveExcel) Save(md int8) error { } -//ExtractPackageData extract the package data by csv file +// ExtractPackageData extract the package data by csv file func ExtractPackageData(lp string) (pkgList []models.ExcelPackage, err error) { pkgLock.Lock() defer pkgLock.Unlock() @@ -1233,7 +1237,7 @@ func UnaffectIssueProc(affectBranch string, cvrfFileList map[string][]string, } } -//filter existing data +// filter existing data func filterDataInSlice(data string, filterList []string) bool { for _, v := range filterList { if strings.EqualFold(data, v) { @@ -1245,6 +1249,10 @@ func filterDataInSlice(data string, filterList []string) bool { // if cve exist affected and label exist CVE/FIXED return true func filterFixBranch(data *models.ExcelExport, cve, branch string) (has bool) { + if data.IsIssueWithAnalysisVersion() { + return data.IsWillFixVersion(branch) + } + has = false if !strings.Contains(data.IssueLabel, "CVE/FIXED") { return diff --git a/cve-vulner-manager/util/parsepayload.go b/cve-vulner-manager/util/parsepayload.go index 02d27591dba2cb3af166f17a1467aeb9f88a6a05..4ec27eac1ccb53dd497bb733bb9584f1a790bc2d 100644 --- a/cve-vulner-manager/util/parsepayload.go +++ b/cve-vulner-manager/util/parsepayload.go @@ -28,6 +28,8 @@ const ( //KwAbiVersion Keywords of the abi version KwAbiVersion = "修复是否涉及abi变化(是/否):" + KwAnalysisVersion = "原因说明:" + Openeuler = 1 OpenGauss = 2 MindSpore = 3 @@ -53,7 +55,7 @@ var ( IW = "IW" //CommentKeys Keyword parsed by the new version of comments CommentKeys = []string{KwAnalysisDesc, KwOpenEulerScore, KwEffectVersion} - EulerCommentKeys = []string{KwAnalysisDesc, KwOpenEulerScore, KwEffectVersion, KwAbiVersion} + EulerCommentKeys = []string{KwAnalysisDesc, KwOpenEulerScore, KwEffectVersion, KwAbiVersion, KwAnalysisVersion} ) var ( @@ -101,19 +103,29 @@ var ( RegexpDigital = regexp.MustCompile(`(\d){1,}(\.\d+)?`) RegexpSpecialDigital = regexp.MustCompile(`(cvssv3.[0-9]|cvssv2.[0-9]|CVSSV3.[0-9]|CVSSV2.[0-9]|CVSS[::]3.[0-9]|CVSS[::]2.[0-9]|cvss[::]3.[0-9]|cvss[::]2.[0-9]|3.[0-9]/|2.[0-9]/|3.[0-9] /|2.[0-9] /)*`) //^((CVSS:3.0|CVSS:2.0|3.0/|2.0/|3.0 /|2.0 /).)*$ //RegexpSpecialDigital = regexp.MustCompile(`(cvssv[1-9].[0-9]|CVSSV[1-9].[0-9]|CVSS[::][1-9].[0-9]|cvss[::][1-9].[0-9]|[1-9].[0-9]/|[1-9].[0-9] /)*`) //^((CVSS:3.0|CVSS:2.0|3.0/|2.0/|3.0 /|2.0 /).)*$ - RegexpVector = regexp.MustCompile(`AV:[NLAP](?s:(.*?))/A:[LNH]`) - RegexpVectorV2 = regexp.MustCompile(`AV:[LAN](?s:(.*))/Au:[MSN](?s:(.*))/A:[NPC]`) - RegexpScoreTypeV2 = regexp.MustCompile(`(?mi)^CVSS[vV]2.[0-9xX]\s*`) // CVSS V3.0分值: - RegexpScoreTypeV3 = regexp.MustCompile(`(?mi)^CVSS[vV]3.[0-9xX]\s*`) - RegexpIsNewTpl = regexp.MustCompile(`(?mi)^原理分析[::]\s*`) - RegexpIsNewTpl2 = regexp.MustCompile(`(?mi)^规避方案或消减措施[::]\s*`) - regexpEffectVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]受影响`) - regexpNoEffectVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响`) - regexpOtherEffectVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]$`) - regexpEffectAbiVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]是`) - regexpNoEffectAbiVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]否`) - RegexpIsAbiTpl = regexp.MustCompile(`(?mi)^(修复)?是否涉及abi变化\(是/否\)[::]\s*`) - RegexpIsFixTpl = regexp.MustCompile(`(?mi)^三、漏洞修复\s*`) + RegexpVector = regexp.MustCompile(`AV:[NLAP](?s:(.*?))/A:[LNH]`) + RegexpVectorV2 = regexp.MustCompile(`AV:[LAN](?s:(.*))/Au:[MSN](?s:(.*))/A:[NPC]`) + RegexpScoreTypeV2 = regexp.MustCompile(`(?mi)^CVSS[vV]2.[0-9xX]\s*`) // CVSS V3.0分值: + RegexpScoreTypeV3 = regexp.MustCompile(`(?mi)^CVSS[vV]3.[0-9xX]\s*`) + RegexpIsNewTpl = regexp.MustCompile(`(?mi)^原理分析[::]\s*`) + RegexpIsNewTpl2 = regexp.MustCompile(`(?mi)^规避方案或消减措施[::]\s*`) + regexpEffectVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]受影响`) + regexpNoEffectVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响`) + regexpOtherEffectVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]$`) + regexpEffectAbiVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]是`) + regexpNoEffectAbiVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]否`) + regexpWillFixVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]正常修复`) + regexpNoPatchVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]暂不修复-上游无补丁`) + regexpUpgradeVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]暂不修复-待升级版本修复`) + regexpOutScopeVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不修复-超出修复范围`) + regexpNotFixVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不修复-特殊原因导致不再修复`) + regexpComponentNotPresentVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响-组件不存在`) + regexpMitigationsExistVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响-已有消减措施`) + regexpCannotControlledVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响-漏洞代码不能被攻击者触发`) + regexpNotExecuteVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响-漏洞代码不在调用点上`) + regexpCodeNotPresentVersion = regexp.MustCompile(`(?mi)[\d]{1,}\.(.*?)[::]不受影响-漏洞代码不存在`) + RegexpIsAbiTpl = regexp.MustCompile(`(?mi)^(修复)?是否涉及abi变化\(是/否\)[::]\s*`) + RegexpIsFixTpl = regexp.MustCompile(`(?mi)^三、漏洞修复\s*`) //RegexpCveAbiVersionNew new tpl influences version regexp RegexpCveAbiVersionNew = regexp.MustCompile(`受影响版本排查\(受影响/不受影响\)[::](?s:(.*?))(修复)?是否涉及abi变化\(是/否\)[::]`) //RegexpCveAbiNew new tpl influences version regexp @@ -132,14 +144,32 @@ var ( mutex sync.Mutex ) -//CommentAnalysis issue comment analysis keyword and value container +var matchers = []RegexpMatcher{ + {Regexp: regexpWillFixVersion, Analysis: common.AnalysisWillFix}, + {Regexp: regexpNoPatchVersion, Analysis: common.AnalysisNoPatch}, + {Regexp: regexpUpgradeVersion, Analysis: common.AnalysisUpgrade}, + {Regexp: regexpOutScopeVersion, Analysis: common.AnalysisOutScope}, + {Regexp: regexpNotFixVersion, Analysis: common.AnalysisNotFix}, + {Regexp: regexpComponentNotPresentVersion, Analysis: common.AnalysisComponentNotPresent}, + {Regexp: regexpMitigationsExistVersion, Analysis: common.AnalysisMitigationsExist}, + {Regexp: regexpCannotControlledVersion, Analysis: common.AnalysisCannotControlled}, + {Regexp: regexpNotExecuteVersion, Analysis: common.AnalysisNotExecute}, + {Regexp: regexpCodeNotPresentVersion, Analysis: common.AnalysisCodeNotPresent}, +} + +type RegexpMatcher struct { + Regexp *regexp.Regexp + Analysis string +} + +// CommentAnalysis issue comment analysis keyword and value container type CommentAnalysis struct { KeyName string KeyIdx int KeyValue string } -//CaSlice define the CommentAnalysis slice +// CaSlice define the CommentAnalysis slice type CaSlice []CommentAnalysis func (a CaSlice) Len() int { @@ -226,7 +256,7 @@ func init() { VectorMapV2["A"] = mAi } -//GenerateCommentAnalysis Generate analytical entities based on comments. +// GenerateCommentAnalysis Generate analytical entities based on comments. func GenerateCommentAnalysis(content string, organizationID int8) (ca CaSlice) { if content == "" { return @@ -264,7 +294,7 @@ func GenerateCommentAnalysis(content string, organizationID int8) (ca CaSlice) { return ca } -//ParseCommentContent extract comment content based on tags. +// ParseCommentContent extract comment content based on tags. func ParseCommentContent(content string, label string) (res string, ok bool) { ret := regexp.MustCompile(genCommentRegexpStr(label)) sm := ret.FindAllStringSubmatch(content, 1) @@ -275,13 +305,13 @@ func ParseCommentContent(content string, label string) (res string, ok bool) { return } -//ParseCommentVector extract vector from issue comment +// ParseCommentVector extract vector from issue comment func ParseCommentVector(content string) string { sm := RegexpVector.Find([]byte(content)) return string(sm) } -//ExtractVector extract vector from issue body +// ExtractVector extract vector from issue body func ExtractVector(body, scoreType string) string { if body == "" { return body @@ -301,7 +331,7 @@ func ExtractVector(body, scoreType string) string { return "" } -//ReadVMValue get vector v3 value from the vector map by keyword +// ReadVMValue get vector v3 value from the vector map by keyword func ReadVMValue(kStr string) (value string) { if kStr == "" { return "" @@ -322,7 +352,7 @@ func ReadVMValue(kStr string) (value string) { return } -//ReadVMValueV2 get vector v2 value from the vector map by keyword +// ReadVMValueV2 get vector v2 value from the vector map by keyword func ReadVMValueV2(kStr string) (value string) { if kStr == "" { return "" @@ -343,7 +373,7 @@ func ReadVMValueV2(kStr string) (value string) { return } -//VctToMap Convert vector string value to map +// VctToMap Convert vector string value to map func VctToMap(vct string) (vctMap map[string]string, ok bool) { if vct == "" { return nil, false @@ -367,7 +397,7 @@ func VctToMap(vct string) (vctMap map[string]string, ok bool) { } -//ParseCommentWithAllLabel extract comment value with custom label +// ParseCommentWithAllLabel extract comment value with custom label func ParseCommentWithAllLabel(content string) map[string]string { res := make(map[string]string, 0) s, ok := ParseCommentContent(content, IAD) @@ -405,7 +435,7 @@ func ParseCommentWithAllLabel(content string) map[string]string { return res } -//ExtractCommentAnalysisAllValue Extract all value by issue comment +// ExtractCommentAnalysisAllValue Extract all value by issue comment func ExtractCommentAnalysisAllValue(content string, organizationID int8) map[string]string { res := make(map[string]string, 0) ca := GenerateCommentAnalysis(content, organizationID) @@ -435,12 +465,18 @@ func ExtractCommentAnalysisAllValue(content string, organizationID int8) map[str value = ExtractCommentAbiVersion(value) res["abi_version"] = value } + + value, ext = ExtractCommentValue(ca, KwAnalysisVersion) + if ext { + value = ExtractCommentAnalysisVersion(value) + res["analysis_version"] = value + } } } return res } -//ExtractCommentEffectVersion Extract the affected version from the issue comment +// ExtractCommentEffectVersion Extract the affected version from the issue comment func ExtractCommentEffectVersion(str string) string { str = strings.Trim(str, " ") str = strings.ReplaceAll(str, " ", "") @@ -483,7 +519,7 @@ func ExtractCommentEffectVersion(str string) string { return "" } -//ExtractCommentAbiVersion Extract the abi version from the issue comment +// ExtractCommentAbiVersion Extract the abi version from the issue comment func ExtractCommentAbiVersion(str string) string { str = strings.Trim(str, " ") str = strings.ReplaceAll(str, " ", "") @@ -526,7 +562,50 @@ func ExtractCommentAbiVersion(str string) string { return "" } -//ExtractCommentValue Get the value of CaSlice by keyword +// ExtractCommentAnalysisVersion Extract the analysis reason version from the issue comment +func ExtractCommentAnalysisVersion(str string) string { + str = strings.Trim(str, " ") + str = strings.ReplaceAll(str, " ", "") + var res []string + + for _, matcher := range matchers { + matches := matcher.Regexp.FindAllStringSubmatch(str, -1) + if len(matches) > 0 { + matchRes := processMatches(matches, matcher.Analysis) + res = append(res, matchRes...) + } + } + + matchOther := regexpOtherEffectVersion.FindAllStringSubmatch(str, -1) + if len(matchOther) > 0 { + for _, v := range matchOther { + if len(v) > 1 { + tmpV := TrimString(v[1]) + ":" + tmpV = common.BranchVersionRep(tmpV) + res = append(res, tmpV) + } + } + } + if len(res) > 0 { + return strings.Join(res, ",") + } + return "" +} + +func processMatches(matches [][]string, analysisType string) []string { + var matchRes []string + for _, v := range matches { + if len(v) > 1 { + tmpV := TrimString(v[1]) + ":" + analysisType + tmpV = common.BranchVersionRep(tmpV) + matchRes = append(matchRes, tmpV) + } + } + + return matchRes +} + +// ExtractCommentValue Get the value of CaSlice by keyword func ExtractCommentValue(ca CaSlice, keyWord string) (string, bool) { for _, v := range ca { if v.KeyName == keyWord { @@ -536,7 +615,7 @@ func ExtractCommentValue(ca CaSlice, keyWord string) (string, bool) { return "", false } -//ExtractCommentOpenEulerScore Extract openEuler score from issue comment +// ExtractCommentOpenEulerScore Extract openEuler score from issue comment func ExtractCommentOpenEulerScore(str string) (score, vector string) { str = TrimString(str) score = ExtractDigital(str) @@ -556,7 +635,7 @@ func genCommentRegexpStr(label string) string { return fmt.Sprintf(`\[%s\](?s:(.*?))\[/%s\]`, label, label) } -//TrimString Remove the \n \r \t spaces in the string +// TrimString Remove the \n \r \t spaces in the string func TrimString(str string) string { str = strings.Replace(str, " ", "", -1) str = strings.Replace(str, "\n", "", -1) @@ -565,7 +644,7 @@ func TrimString(str string) string { return str } -//TrimStringNR Remove the \n \r in the string +// TrimStringNR Remove the \n \r in the string func TrimStringNR(str string) string { str = strings.Replace(str, "\n", "", -1) str = strings.Replace(str, "\r", "", -1) @@ -573,7 +652,7 @@ func TrimStringNR(str string) string { return str } -//ExtractDigital remove "cvss 3.0" or "cvss 2.0" +// ExtractDigital remove "cvss 3.0" or "cvss 2.0" func RemoveSpecialDigital(body string) string { if body == "" { return body @@ -586,7 +665,7 @@ func RemoveSpecialDigital(body string) string { return "" } -//ExtractDigital Get number in string +// ExtractDigital Get number in string func ExtractDigital(body string) string { if body == "" { return body @@ -605,7 +684,7 @@ func ExtractDigital(body string) string { return "" } -//GetCveNumber Extract cveNum from the issue body cveNumber link +// GetCveNumber Extract cveNum from the issue body cveNumber link func GetCveNumber(ov string) string { if v := regexpCveNumberLink.Find([]byte(ov)); len(v) > 0 { sv := string(v) @@ -616,7 +695,7 @@ func GetCveNumber(ov string) string { return ov } -//GetCveNumber Extract cve package from the issue body whe package is a link +// GetCveNumber Extract cve package from the issue body whe package is a link func GetCvePkg(str string) string { origin := TrimString(str)