diff --git a/syft/formats/common/cyclonedxhelpers/decoder.go b/syft/formats/common/cyclonedxhelpers/decoder.go index 36d99e26014e..e224ea6043eb 100644 --- a/syft/formats/common/cyclonedxhelpers/decoder.go +++ b/syft/formats/common/cyclonedxhelpers/decoder.go @@ -2,6 +2,7 @@ package cyclonedxhelpers import ( "fmt" + "github.com/anchore/packageurl-go" "io" "github.com/CycloneDX/cyclonedx-go" @@ -88,6 +89,10 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str case cyclonedx.ComponentTypeApplication, cyclonedx.ComponentTypeFramework, cyclonedx.ComponentTypeLibrary: p := decodeComponent(component) idMap[component.BOMRef] = p + syftID := extractSyftPacakgeID(component.BOMRef) + if syftID != "" { + idMap[syftID] = p + } // TODO there must be a better way than needing to call this manually: p.SetID() s.Artifacts.PackageCatalog.Add(*p) @@ -100,6 +105,19 @@ func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[str } } +func extractSyftPacakgeID(i string) string { + instance, err := packageurl.FromString(i) + if err != nil { + return "" + } + for _, q := range instance.Qualifiers { + if q.Key == "package-id" { + return q.Value + } + } + return "" +} + func linuxReleaseFromComponents(components []cyclonedx.Component) *linux.Release { for i := range components { component := &components[i] @@ -188,21 +206,25 @@ func collectRelationships(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]int return } for _, d := range *bom.Dependencies { - from, fromOk := idMap[d.Ref].(artifact.Identifiable) - if fromOk { - if d.Dependencies == nil { + from, fromExists := idMap[d.Ref].(artifact.Identifiable) + if !fromExists { + continue + } + + if d.Dependencies == nil { + continue + } + + for _, t := range *d.Dependencies { + to, toExists := idMap[t.Ref].(artifact.Identifiable) + if !toExists { continue } - for _, t := range *d.Dependencies { - to, toOk := idMap[t.Ref].(artifact.Identifiable) - if toOk { - s.Relationships = append(s.Relationships, artifact.Relationship{ - From: from, - To: to, - Type: artifact.DependencyOfRelationship, // FIXME this information is lost - }) - } - } + s.Relationships = append(s.Relationships, artifact.Relationship{ + From: from, + To: to, + Type: artifact.DependencyOfRelationship, // FIXME this information is lost + }) } } } diff --git a/syft/formats/common/cyclonedxhelpers/format.go b/syft/formats/common/cyclonedxhelpers/format.go index a22b191b2d11..c5c408b25689 100644 --- a/syft/formats/common/cyclonedxhelpers/format.go +++ b/syft/formats/common/cyclonedxhelpers/format.go @@ -1,6 +1,7 @@ package cyclonedxhelpers import ( + "github.com/anchore/syft/syft/pkg" "time" "github.com/CycloneDX/cyclonedx-go" @@ -141,10 +142,21 @@ func toDependencies(relationships []artifact.Relationship) []cyclonedx.Dependenc continue } + // we only capture package-to-package relationships for now + fromPkg, ok := r.From.(*pkg.Package) + if !ok { + continue + } + + toPkg, ok := r.To.(*pkg.Package) + if !ok { + continue + } + innerDeps := []cyclonedx.Dependency{} - innerDeps = append(innerDeps, cyclonedx.Dependency{Ref: string(r.From.ID())}) + innerDeps = append(innerDeps, cyclonedx.Dependency{Ref: deriveBomRef(*fromPkg)}) result = append(result, cyclonedx.Dependency{ - Ref: string(r.To.ID()), + Ref: deriveBomRef(*toPkg), Dependencies: &innerDeps, }) } diff --git a/test/integration/encode_decode_cycle_test.go b/test/integration/encode_decode_cycle_test.go index 2681bfe6a561..19a8bd9f0a00 100644 --- a/test/integration/encode_decode_cycle_test.go +++ b/test/integration/encode_decode_cycle_test.go @@ -2,7 +2,6 @@ package integration import ( "bytes" - "encoding/json" "fmt" "regexp" "testing" @@ -48,13 +47,13 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) { // unstable values in = regexp.MustCompile(`"(timestamp|serialNumber|bom-ref)": "[^"]+",`).ReplaceAll(in, []byte{}) - // dependencies are not supported (edge types cannot be encoded or inferred during decoding) - var det map[string]interface{} - require.NoError(t, json.Unmarshal(in, &det)) - delete(det, "dependencies") - inCopy, err := json.Marshal(det) - require.NoError(t, err) - in = inCopy + //// dependencies are not supported (edge types cannot be encoded or inferred during decoding) + //var det map[string]interface{} + //require.NoError(t, json.Unmarshal(in, &det)) + //delete(det, "dependencies") + //inCopy, err := json.Marshal(det) + //require.NoError(t, err) + //in = inCopy return in }, @@ -65,19 +64,9 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) { redactor: func(in []byte) []byte { // unstable values in = regexp.MustCompile(`(serialNumber|bom-ref)="[^"]+"`).ReplaceAll(in, []byte{}) - in = regexp.MustCompile("[^<]+").ReplaceAll(in, []byte{}) + in = regexp.MustCompile(`[^<]+`).ReplaceAll(in, []byte{}) + //in = regexp.MustCompile(`(?m:(\n\s+)*[\s\S]*?)`).ReplaceAll(in, []byte{}) - // dependencies are not supported (edge types cannot be encoded or inferred during decoding) - start := bytes.Index(in, []byte(" ")) // important: mind the prefix whitespace - endVal := "\n" // important: mind the postfix whitespace - stop := bytes.Index(in, []byte(endVal)) - if start != -1 && stop != -1 { - stopAfterVal := stop + len(endVal) - inCopy := make([]byte, 0) - inCopy = append(inCopy, in[:start]...) - inCopy = append(inCopy, in[stopAfterVal:]...) - in = inCopy - } return in }, },