Skip to content

Commit

Permalink
[wip] fix relationship encoding for cyclonedx
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Goodman <[email protected]>
  • Loading branch information
wagoodman committed Oct 7, 2022
1 parent ce27c16 commit e98f483
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 35 deletions.
48 changes: 35 additions & 13 deletions syft/formats/common/cyclonedxhelpers/decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cyclonedxhelpers

import (
"fmt"
"github.com/anchore/packageurl-go"
"io"

"github.com/CycloneDX/cyclonedx-go"
Expand Down Expand Up @@ -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)
Expand All @@ -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]
Expand Down Expand Up @@ -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
})
}
}
}
Expand Down
16 changes: 14 additions & 2 deletions syft/formats/common/cyclonedxhelpers/format.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cyclonedxhelpers

import (
"github.com/anchore/syft/syft/pkg"
"time"

"github.com/CycloneDX/cyclonedx-go"
Expand Down Expand Up @@ -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,
})
}
Expand Down
29 changes: 9 additions & 20 deletions test/integration/encode_decode_cycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package integration

import (
"bytes"
"encoding/json"
"fmt"
"regexp"
"testing"
Expand Down Expand Up @@ -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
},
Expand All @@ -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("<timestamp>[^<]+</timestamp>").ReplaceAll(in, []byte{})
in = regexp.MustCompile(`<timestamp>[^<]+</timestamp>`).ReplaceAll(in, []byte{})
//in = regexp.MustCompile(`(?m:(\n\s+)*<dependencies>[\s\S]*?</dependencies>)`).ReplaceAll(in, []byte{})

// dependencies are not supported (edge types cannot be encoded or inferred during decoding)
start := bytes.Index(in, []byte(" <dependencies>")) // important: mind the prefix whitespace
endVal := "</dependencies>\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
},
},
Expand Down

0 comments on commit e98f483

Please sign in to comment.