diff --git a/cli/main.go b/cli/main.go index b21e870f144154d4566f66b45949630b507ef712..2e3bedad68c08fe6c37c9f642e67354392723eb5 100644 --- a/cli/main.go +++ b/cli/main.go @@ -18,12 +18,14 @@ import ( "util/logs" "util/model" "util/report" + "util/vuln" ) var version string func main() { args.Parse() + vuln.LoadVulnDB(args.Config.VulnDB) if len(args.Config.Path) > 0 { output(engine.NewEngine().ParseFile(args.Config.Path)) } else { @@ -66,7 +68,7 @@ func output(depRoot *model.DepTree, taskInfo report.TaskInfo) { out += ".zip" reportByWriterFunc = report.SwidXml } else { - logs.Warn(fmt.Sprintf("not support report format: %s", out)) + reportFunc = report.Xml } default: reportFunc = report.Json diff --git a/go.work.sum b/go.work.sum index 1c53099f2a25753bc2d3f48e51693ac1666cc11c..615958fc3f165d9e54bd6b21f3969511872ffe65 100644 --- a/go.work.sum +++ b/go.work.sum @@ -1,4 +1 @@ -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= diff --git a/util/model/dependency.go b/util/model/dependency.go index 8e766ea28cceddfebb177c88779df77a3958b112..3eb8e31969e302f1df8a75dbedf50cfc708b38f1 100644 --- a/util/model/dependency.go +++ b/util/model/dependency.go @@ -39,14 +39,14 @@ func getId() int64 { // Dependency 组件依赖 type Dependency struct { - Vendor string `json:"vendor,omitempty"` - Name string `json:"name,omitempty"` - Version *Version `json:"ver,omitempty"` - Language language.Type `json:"lan,omitempty"` + Vendor string `json:"vendor,omitempty" xml:"vendor,omitempty" ` + Name string `json:"name,omitempty" xml:"name,omitempty" ` + Version *Version `json:"ver,omitempty" xml:"-" ` + Language language.Type `json:"lan,omitempty" xml:"-" ` // 仅在生成json时赋值 - VersionStr string `json:"version,omitempty"` - LanguageStr string `json:"language,omitempty"` + VersionStr string `json:"version,omitempty" xml:"version,omitempty" ` + LanguageStr string `json:"language,omitempty" xml:"language,omitempty" ` } // GetVersion 获取版本号 @@ -86,31 +86,27 @@ func (dep Dependency) String() string { type DepTree struct { Dependency // 是否为直接依赖 - Direct bool `json:"direct"` + Direct bool `json:"direct" xml:"direct"` // 依赖路径 - Path string `json:"-"` - Paths []string `json:"paths,omitempty"` + Path string `json:"-" xml:"-"` + Paths []string `json:"paths,omitempty" xml:"paths,omitempty" ` // 唯一的组件id,用来标识不同组件 - ID int64 `json:"-"` + ID int64 `json:"-" xml:"-" ` // 父组件 - Parent *DepTree `json:"-"` - Vulnerabilities []*Vuln `json:"vulnerabilities,omitempty"` - IndirectVulnerabilities int `json:"indirect_vulnerabilities,omitempty"` + Parent *DepTree `json:"-" xml:"-" ` + Vulnerabilities []*Vuln `json:"vulnerabilities,omitempty" xml:"vulnerabilities,omitempty" ` + IndirectVulnerabilities int `json:"indirect_vulnerabilities,omitempty" xml:"indirect_vulnerabilities,omitempty" ` // 许可证列表 - licenseMap map[string]struct{} `json:"-"` - Licenses []string `json:"licenses,omitempty"` + licenseMap map[string]struct{} `json:"-" xml:"-" ` + Licenses []string `json:"licenses,omitempty" xml:"licenses,omitempty" ` // spdx相关字段 - CopyrightText string `json:"copyrightText,omitempty"` - HomePage string `json:"-"` - DownloadLocation string `json:"-"` - CheckSum string `json:"-"` + CopyrightText string `json:"copyrightText,omitempty" xml:"copyrightText,omitempty" ` + HomePage string `json:"-" xml:"-" ` + DownloadLocation string `json:"-" xml:"-" ` + CheckSum string `json:"-" xml:"-" ` // 子组件 - Children []*DepTree `json:"children,omitempty"` - Expand interface{} `json:"-"` -} -type CheckSum struct { - Algorithm string `json:"algorithm,omitempty"` - Value string `json:"value,omitempty"` + Children []*DepTree `json:"children,omitempty" xml:"children,omitempty" ` + Expand interface{} `json:"-" xml:"-" ` } // NewDepTree 创建DepTree @@ -191,15 +187,11 @@ func (root *DepTree) String() string { for _, v := range dep.Vulnerabilities { vulns = append(vulns, v.Id) } - vuln := "" - if len(vulns) > 0 { - vuln = fmt.Sprintf(" %v", vulns) - } lan := dep.LanguageStr if lan == "" { lan = dep.Language.String() } - res += fmt.Sprintf("%s%s<%s>%s%s\n", strings.Repeat("\t", node.Deep), dep.Dependency, lan, dep.Path[strings.Index(dep.Path, "/")+1:], vuln) + res += fmt.Sprintf("%s%s<%s> path:%s license:%v vulns:%v\n", strings.Repeat("\t", node.Deep), dep.Dependency, lan, dep.Path[strings.Index(dep.Path, "/")+1:], dep.Licenses, vulns) for i := len(dep.Children) - 1; i >= 0; i-- { stack.Push(newNode(dep.Children[i], node.Deep+1)) } diff --git a/util/report/format.go b/util/report/format.go index 52ccabdbe9361faed37f6dd4eb0a9e5a050d7dd4..ac0a9bd84f199a97c11d04c43cbffd4e527c53cb 100644 --- a/util/report/format.go +++ b/util/report/format.go @@ -12,14 +12,14 @@ import ( // 任务检查信息 type TaskInfo struct { - ToolVersion string `json:"tool_version"` - AppName string `json:"app_name"` - Size int64 `json:"size"` - StartTime string `json:"start_time"` - EndTime string `json:"end_time"` - CostTime float64 `json:"cost_time"` - Error error `json:"-"` - ErrorString string `json:"error,omitempty"` + ToolVersion string `json:"tool_version" xml:"tool_version" ` + AppName string `json:"app_name" xml:"app_name" ` + Size int64 `json:"size" xml:"size" ` + StartTime string `json:"start_time" xml:"start_time" ` + EndTime string `json:"end_time" xml:"end_time" ` + CostTime float64 `json:"cost_time" xml:"cost_time" ` + Error error `json:"-" xml:"-" ` + ErrorString string `json:"error,omitempty" xml:"error,omitempty" ` } // Format 按照输出内容格式化(不可逆) diff --git a/util/report/html_tpl b/util/report/html_tpl index 4e2853824d2a28069b9d55989d1a496114a728b5..ecf657848c4cd1e1f40a8f0124771012bd3ecd5a 100644 --- a/util/report/html_tpl +++ b/util/report/html_tpl @@ -1,2 +1,2 @@ -OpenSCA开源组件检测报告
\ No newline at end of file +OpenSCA开源组件检测报告
\ No newline at end of file diff --git a/util/report/xml.go b/util/report/xml.go new file mode 100644 index 0000000000000000000000000000000000000000..e5a45c50f32e142ed717cf3a7f1cacae848c57a9 --- /dev/null +++ b/util/report/xml.go @@ -0,0 +1,27 @@ +package report + +import ( + "encoding/xml" + "util/logs" + "util/model" +) + +// Xml 获取xml格式报告数据 +func Xml(dep *model.DepTree, taskInfo TaskInfo) []byte { + if taskInfo.Error != nil { + taskInfo.ErrorString = taskInfo.Error.Error() + } + type report struct { + TaskInfo TaskInfo `xml:"task_info"` + *model.DepTree + } + if data, err := xml.Marshal(report{ + TaskInfo: taskInfo, + DepTree: dep, + }); err != nil { + logs.Error(err) + } else { + return data + } + return []byte{} +} diff --git a/util/vuln/local.go b/util/vuln/local.go index 68ce53ad6e017a6447e9f9031d942c77764419e1..3f8e48ba7f2ba311e364babfc86ce733f58057f7 100644 --- a/util/vuln/local.go +++ b/util/vuln/local.go @@ -9,7 +9,6 @@ import ( "encoding/json" "io/ioutil" "strings" - "util/args" "util/enum/language" "util/logs" "util/model" @@ -26,37 +25,38 @@ type vulnInfo struct { // 漏洞信息 map[language]map[name][]vulninfo var vulnDB map[string]map[string][]vulnInfo -// loadVulnDB 加载本地漏洞 -func loadVulnDB() { +// LoadVulnDB 加载本地漏洞 +func LoadVulnDB(dbpath string) { + if dbpath == "" { + return + } vulnDB = map[string]map[string][]vulnInfo{} - if args.Config.VulnDB != "" { - // 读取本地漏洞数据 - if data, err := ioutil.ReadFile(args.Config.VulnDB); err != nil { + // 读取本地漏洞数据 + if data, err := ioutil.ReadFile(dbpath); err != nil { + logs.Error(err) + } else { + // 解析本地漏洞 + db := []vulnInfo{} + err := json.Unmarshal(data, &db) + if err != nil { logs.Error(err) - } else { - // 解析本地漏洞 - db := []vulnInfo{} - err := json.Unmarshal(data, &db) - if err != nil { - logs.Error(err) + } + for _, info := range db { + if info.Vuln == nil { + continue } - for _, info := range db { - if info.Vuln == nil { - continue - } - // 有中文描述则省略英文描述 - if info.Description != "" { - info.DescriptionEn = "" - } - // 将漏洞信息存到vulnDB中 - name := strings.ToLower(info.Product) - language := strings.ToLower(info.Language) - if _, ok := vulnDB[language]; !ok { - vulnDB[language] = map[string][]vulnInfo{} - } - vulns := vulnDB[language] - vulns[name] = append(vulns[name], info) + // 有中文描述则省略英文描述 + if info.Description != "" { + info.DescriptionEn = "" + } + // 将漏洞信息存到vulnDB中 + name := strings.ToLower(info.Product) + language := strings.ToLower(info.Language) + if _, ok := vulnDB[language]; !ok { + vulnDB[language] = map[string][]vulnInfo{} } + vulns := vulnDB[language] + vulns[name] = append(vulns[name], info) } } } @@ -64,7 +64,7 @@ func loadVulnDB() { // GetLocalVulns 使用本地漏洞库获取漏洞 func GetLocalVulns(deps []model.Dependency) (vulns [][]*model.Vuln) { if vulnDB == nil { - loadVulnDB() + return nil } vulns = make([][]*model.Vuln, len(deps)) for i, dep := range deps { diff --git a/util/vuln/vuln.go b/util/vuln/vuln.go index 032214fb3cf23ccdfafb803a90dd52c41c38a70a..8b82f7bb174eece5b4f9c1c242d62cecd67e2548 100644 --- a/util/vuln/vuln.go +++ b/util/vuln/vuln.go @@ -56,6 +56,8 @@ func SearchVuln(root *model.DepTree) (err error) { if len(serverVulns) != 0 { for _, vuln := range serverVulns[i] { if vuln.Id == "" { + // 约定没有id时按照许可证处理 + dep.AddLicense(vuln.Name) continue } if _, ok := exist[vuln.Id]; !ok {