package sbom
import (
"encoding/json"
"encoding/xml"
"io"
"github.com/CycloneDX/cyclonedx-go"
"github.com/xmirrorsecurity/opensca-cli/v3/opensca/model"
)
func ParseCdxJson(f *model.File) *model.DepGraph {
bom := &cyclonedx.BOM{}
f.OpenReader(func(reader io.Reader) {
json.NewDecoder(reader).Decode(&bom)
})
return parseCdxBom(f, bom)
}
func ParseCdxXml(f *model.File) *model.DepGraph {
bom := &cyclonedx.BOM{}
f.OpenReader(func(reader io.Reader) {
xml.NewDecoder(reader).Decode(&bom)
})
return parseCdxBom(f, bom)
}
func parseCdxBom(f *model.File, bom *cyclonedx.BOM) *model.DepGraph {
if bom == nil {
return nil
}
if bom.BOMFormat == "" && bom.XMLNS == "" {
return nil
}
if bom.Components == nil || len(*bom.Components) == 0 {
return nil
}
depRefMap := map[string]*model.DepGraph{}
_dep := model.NewDepGraphMap(func(s ...string) string {
return s[0]
}, func(s ...string) *model.DepGraph {
return &model.DepGraph{
Vendor: s[1],
Name: s[2],
Version: s[3],
}
}).LoadOrStore
for _, d := range *bom.Components {
if d.PackageURL != "" {
vendor, name, version, language := model.ParsePurl(d.PackageURL)
if name != "" {
dep := _dep(d.BOMRef, vendor, name, version)
dep.Language = language
depRefMap[d.BOMRef] = dep
continue
}
}
if d.Name != "" {
depRefMap[d.BOMRef] = _dep(d.BOMRef, d.Author, d.Name, d.Version)
}
}
if bom.Dependencies != nil {
for _, d := range *bom.Dependencies {
dep, ok := depRefMap[d.Ref]
if !ok || d.Dependencies == nil {
continue
}
for _, subRef := range *d.Dependencies {
dep.AppendChild(depRefMap[subRef])
}
}
}
root := &model.DepGraph{Path: f.Relpath()}
for _, dep := range depRefMap {
if len(dep.Parents) == 0 {
root.AppendChild(dep)
}
}
return root
}