From a6ee6127fb840e3ffc5f57d28ba5ae071bf39ffb Mon Sep 17 00:00:00 2001 From: luotianqi777 Date: Thu, 13 Jul 2023 20:58:27 +0800 Subject: [PATCH] add license --- .goreleaser.yml | 68 +++++++++++++++-------------- analyzer/engine/engine.go | 2 +- analyzer/javascript/package_json.go | 6 ++- analyzer/php/composer.go | 2 +- analyzer/python/setup.go | 2 +- util/client/client.go | 15 ++++--- util/model/dependency.go | 20 ++++++--- util/model/vuln.go | 6 +++ util/report/html_tpl | 4 +- util/report/spdx.go | 4 +- util/vuln/server.go | 24 +++++++++- util/vuln/vuln.go | 19 +++++--- 12 files changed, 111 insertions(+), 61 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 69fa2f80..8b246b09 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,33 +1,35 @@ -{ - "project_name": "opensca-cli", - "builds": - [ - { - "env": ["CGO_ENABLED=0"], - "goos": ["linux", "windows", "darwin"], - "goarch": [386, "amd64", "arm", "arm64"], - "goarm": [6, 7], - "id": "opensca-cli", - "dir": ".", - "binary": "opensca-cli", - "main": "./cli/", - }, - ], - "archives": - [ - { - "replacements": - { - "386": "i386", - "darwin": "Darwin", - "linux": "Linux", - "windows": "Windows", - "amd64": "x86_64", - }, - "files": ["LICENSE", "config.json", "README.md"], - "format": "zip", - }, - ], - "checksum": { "name_template": "checksums.txt" }, - "snapshot": { "name_template": "{{.Tag}}" }, -} +project_name: opensca-cli +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + goarch: + - 386 + - amd64 + - arm + - arm64 + goarm: + - 6 + - 7 + id: opensca-cli + dir: . + binary: opensca-cli + main: ./cli/ +archives: + - name_template: >- + {{.ProjectName}}_{{.Tag}}_{{- title .Os}}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else}}{{.Arch}}{{.Arm}}{{end}} + files: + - LICENSE + - config.json + - README.md + format: zip +checksum: + name_template: checksums.txt +snapshot: + name_template: "{{.Tag}}" diff --git a/analyzer/engine/engine.go b/analyzer/engine/engine.go index e3f18453..46ce26ed 100644 --- a/analyzer/engine/engine.go +++ b/analyzer/engine/engine.go @@ -102,7 +102,7 @@ func (e Engine) ParseFile(filepath string) (depRoot *model.DepTree, taskInfo rep // 解析目录树获取依赖树 e.parseDependency(dirRoot, depRoot) // 获取漏洞 - taskInfo.Error = vuln.SearchVuln(depRoot) + taskInfo.Error = vuln.SearchDetail(depRoot) // 是否仅保留漏洞组件 if args.Config.OnlyVuln { root := model.NewDepTree(nil) diff --git a/analyzer/javascript/package_json.go b/analyzer/javascript/package_json.go index 2aec0c4a..2e888952 100644 --- a/analyzer/javascript/package_json.go +++ b/analyzer/javascript/package_json.go @@ -50,7 +50,9 @@ func parsePackage(root *model.DepTree, file *model.FileInfo, simulation bool) (d if pkg.Version != "" { root.Version = model.NewVersion(pkg.Version) } - root.AddLicense(pkg.License) + root.AddLicense(model.LicenseInfo{ + ShortName: pkg.License, + }) root.HomePage = pkg.HomePage // 依赖列表map[name]version depMap := map[string]string{} @@ -145,7 +147,7 @@ func npmSimulation(dep *model.DepTree, exist map[string]struct{}) (subDeps []*mo } info := npm.Versions[latestVersion] dep.Version = model.NewVersion(latestVersion) - dep.AddLicense(info.License) + dep.AddLicense(model.LicenseInfo{ShortName: info.License}) // 解析子依赖 names := []string{} for name := range info.Deps { diff --git a/analyzer/php/composer.go b/analyzer/php/composer.go index 0403888a..908808a7 100644 --- a/analyzer/php/composer.go +++ b/analyzer/php/composer.go @@ -53,7 +53,7 @@ func parseComposer(root *model.DepTree, file *model.FileInfo, simulation bool) ( root.DownloadLocation = composer.Support["source"] // add license if composer.License != "" { - root.AddLicense(composer.License) + root.AddLicense(model.LicenseInfo{ShortName: composer.License}) } // parse direct dependency requires := map[string]string{} diff --git a/analyzer/python/setup.go b/analyzer/python/setup.go index e48dc73f..bce9c1d3 100644 --- a/analyzer/python/setup.go +++ b/analyzer/python/setup.go @@ -57,7 +57,7 @@ func parseSetup(root *model.DepTree, file *model.FileInfo) { } root.Name = dep.Name root.Version = model.NewVersion(dep.Version) - root.Licenses = append(root.Licenses, dep.License) + root.AddLicense(model.LicenseInfo{ShortName: dep.License}) for _, pkg := range [][]string{dep.Packages, dep.InstallRequires, dep.Requires} { for _, p := range pkg { index := strings.IndexAny(p, "=<>") diff --git a/util/client/client.go b/util/client/client.go index c5a76607..e8005dcc 100644 --- a/util/client/client.go +++ b/util/client/client.go @@ -93,7 +93,7 @@ func GetClientId() string { } // Detect 发送任务解析请求 -func Detect(reqbody []byte) (repbody []byte, err error) { +func Detect(dtype string, reqbody []byte) (repbody []byte, err error) { repbody = []byte{} // 获取aes-key key, err := getAesKey() @@ -120,13 +120,16 @@ func Detect(reqbody []byte) (repbody []byte, err error) { return repbody, err } // 发送数据 - rep, err := http.Post(url, "application/json", bytes.NewReader(data)) + req, err := http.NewRequest("POST", url, bytes.NewReader(data)) + req.Header.Add("Content-Type", "application/json") + req.Header.Add("Detect-Type", dtype) + resp, err := http.DefaultClient.Do(req) if err != nil { return repbody, err } - defer rep.Body.Close() - if rep.StatusCode == 200 { - repbody, err = ioutil.ReadAll(rep.Body) + defer resp.Body.Close() + if resp.StatusCode == 200 { + repbody, err = ioutil.ReadAll(resp.Body) if err != nil { logs.Error(err) return @@ -159,7 +162,7 @@ func Detect(reqbody []byte) (repbody []byte, err error) { } } } else { - return repbody, fmt.Errorf("%s status code: %d", url, rep.StatusCode) + return repbody, fmt.Errorf("%s status code: %d", url, resp.StatusCode) } } diff --git a/util/model/dependency.go b/util/model/dependency.go index 3eb8e319..16d75664 100644 --- a/util/model/dependency.go +++ b/util/model/dependency.go @@ -98,7 +98,7 @@ type DepTree struct { IndirectVulnerabilities int `json:"indirect_vulnerabilities,omitempty" xml:"indirect_vulnerabilities,omitempty" ` // 许可证列表 licenseMap map[string]struct{} `json:"-" xml:"-" ` - Licenses []string `json:"licenses,omitempty" xml:"licenses,omitempty" ` + Licenses []LicenseInfo `json:"licenses,omitempty" xml:"licenses,omitempty" ` // spdx相关字段 CopyrightText string `json:"copyrightText,omitempty" xml:"copyrightText,omitempty" ` HomePage string `json:"-" xml:"-" ` @@ -120,7 +120,7 @@ func NewDepTree(parent *DepTree) *DepTree { Parent: parent, Children: []*DepTree{}, licenseMap: map[string]struct{}{}, - Licenses: []string{}, + Licenses: []LicenseInfo{}, CopyrightText: "", } if parent != nil { @@ -130,11 +130,11 @@ func NewDepTree(parent *DepTree) *DepTree { } // AddLicense 添加许可证 -func (dep *DepTree) AddLicense(licName string) { - key := strings.TrimSpace(strings.ToLower(licName)) +func (dep *DepTree) AddLicense(lic LicenseInfo) { + key := strings.TrimSpace(strings.ToLower(lic.ShortName)) if _, ok := dep.licenseMap[key]; !ok { dep.licenseMap[key] = struct{}{} - dep.Licenses = append(dep.Licenses, licName) + dep.Licenses = append(dep.Licenses, lic) } } @@ -183,15 +183,23 @@ func (root *DepTree) String() string { for !stack.Empty() { node := stack.Pop().(*node) dep := node.Dep + vulns := []string{} for _, v := range dep.Vulnerabilities { vulns = append(vulns, v.Id) } + lan := dep.LanguageStr if lan == "" { lan = dep.Language.String() } - 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) + + lics := make([]string, len(dep.Licenses)) + for i, lic := range dep.Licenses { + lics[i] = lic.ShortName + } + + 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:], lics, vulns) for i := len(dep.Children) - 1; i >= 0; i-- { stack.Push(newNode(dep.Children[i], node.Deep+1)) } diff --git a/util/model/vuln.go b/util/model/vuln.go index 92a2db12..b7663af9 100644 --- a/util/model/vuln.go +++ b/util/model/vuln.go @@ -26,3 +26,9 @@ type Vuln struct { func NewVuln() *Vuln { return &Vuln{} } + +// LicenseInfo 许可证 +type LicenseInfo struct { + ShortName string `json:"name"` + // TODO: expand +} diff --git a/util/report/html_tpl b/util/report/html_tpl index ecf65784..36dbaead 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/spdx.go b/util/report/spdx.go index bf04be53..c4d296d9 100644 --- a/util/report/spdx.go +++ b/util/report/spdx.go @@ -194,10 +194,10 @@ func setPkgLicenseCon(dep *model.DepTree) string { lic := "" for _, v := range dep.Licenses { if lic == "" { - lic = v + lic = v.ShortName continue } - lic = lic + " OR " + v + lic = lic + " OR " + v.ShortName } return lic } diff --git a/util/vuln/server.go b/util/vuln/server.go index 5abdefd4..21b78184 100644 --- a/util/vuln/server.go +++ b/util/vuln/server.go @@ -21,7 +21,7 @@ func GetServerVuln(deps []model.Dependency) (vulns [][]*model.Vuln, err error) { logs.Error(err) return } - data, err = client.Detect(data) + data, err = client.Detect("vuln", data) if err != nil { fmt.Printf("\n%s", err.Error()) return vulns, err @@ -34,3 +34,25 @@ func GetServerVuln(deps []model.Dependency) (vulns [][]*model.Vuln, err error) { } return } + +// GetServerLicense 从云服务获取许可证 +func GetServerLicense(deps []model.Dependency) (lics [][]model.LicenseInfo, err error) { + lics = [][]model.LicenseInfo{} + data, err := json.Marshal(deps) + if err != nil { + logs.Error(err) + return + } + data, err = client.Detect("license", data) + if err != nil { + fmt.Printf("\n%s", err.Error()) + return lics, err + } + if len(data) > 0 { + err = json.Unmarshal(data, &lics) + if err != nil { + logs.Error(err) + } + } + return +} diff --git a/util/vuln/vuln.go b/util/vuln/vuln.go index 8b82f7bb..516e21f9 100644 --- a/util/vuln/vuln.go +++ b/util/vuln/vuln.go @@ -11,8 +11,8 @@ import ( "util/model" ) -// SearchVuln 查找漏洞 -func SearchVuln(root *model.DepTree) (err error) { +// SearchDetail 查找组件详情:漏洞/许可证 +func SearchDetail(root *model.DepTree) (err error) { queue := model.NewQueue() queue.Push(root) deps := []*model.DepTree{} @@ -23,17 +23,26 @@ func SearchVuln(root *model.DepTree) (err error) { queue.Push(child) } } - localVulns := [][]*model.Vuln{} - serverVulns := [][]*model.Vuln{} ds := make([]model.Dependency, len(deps)) for i, d := range deps { ds[i] = d.Dependency } + + localVulns := [][]*model.Vuln{} + serverVulns := [][]*model.Vuln{} if args.Config.VulnDB != "" { localVulns = GetLocalVulns(ds) } if args.Config.Url != "" && args.Config.Token != "" { + // vulnerability serverVulns, err = GetServerVuln(ds) + // license + serverLicenses, _ := GetServerLicense(ds) + for i, lics := range serverLicenses { + for _, lic := range lics { + deps[i].AddLicense(lic) + } + } } else if args.Config.VulnDB == "" && args.Config.Url == "" && args.Config.Token != "" { err = errors.New("url is null") } else if args.Config.VulnDB == "" && args.Config.Url != "" && args.Config.Token == "" { @@ -56,8 +65,6 @@ 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 {