Skip to content

Commit

Permalink
test: added syft tests
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Kotzbauer <git@ckotzbauer.de>
  • Loading branch information
ckotzbauer committed Jan 29, 2022
1 parent 188dfd9 commit 35be5e6
Show file tree
Hide file tree
Showing 11 changed files with 279,515 additions and 20 deletions.
473 changes: 473 additions & 0 deletions internal/syft/fixtures/alpine.cyclonedx

Large diffs are not rendered by default.

3,072 changes: 3,072 additions & 0 deletions internal/syft/fixtures/alpine.json

Large diffs are not rendered by default.

1,490 changes: 1,490 additions & 0 deletions internal/syft/fixtures/alpine.spdx-json

Large diffs are not rendered by default.

4,220 changes: 4,220 additions & 0 deletions internal/syft/fixtures/nginx.cyclonedx

Large diffs are not rendered by default.

96,272 changes: 96,272 additions & 0 deletions internal/syft/fixtures/nginx.json

Large diffs are not rendered by default.

44,022 changes: 44,022 additions & 0 deletions internal/syft/fixtures/nginx.spdx-json

Large diffs are not rendered by default.

8,329 changes: 8,329 additions & 0 deletions internal/syft/fixtures/node.cyclonedx

Large diffs are not rendered by default.

78,953 changes: 78,953 additions & 0 deletions internal/syft/fixtures/node.json

Large diffs are not rendered by default.

42,492 changes: 42,492 additions & 0 deletions internal/syft/fixtures/node.spdx-json

Large diffs are not rendered by default.

50 changes: 30 additions & 20 deletions internal/syft/syft.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,22 @@ import (
)

type Syft struct {
SbomFormat string
sbomFormat string
resolveVersion func() string
}

func New(sbomFormat string) Syft {
return Syft{
SbomFormat: sbomFormat,
sbomFormat: sbomFormat,
resolveVersion: getSyftVersion,
}
}

func (s Syft) WithVersion(version string) Syft {
s.resolveVersion = func() string { return version }
return s
}

func (s *Syft) ExecuteSyft(img kubernetes.ContainerImage) (string, error) {
logrus.Infof("Processing image %s", img.ImageID)

Expand Down Expand Up @@ -57,24 +64,12 @@ func (s *Syft) ExecuteSyft(img kubernetes.ContainerImage) (string, error) {
defer cleanup()
}

bi, ok := debug.ReadBuildInfo()
if !ok {
logrus.Warnf("failed to read build info")
}

descriptor := sbom.Descriptor{
Name: "syft",
}

for _, dep := range bi.Deps {
if strings.EqualFold("github.com/anchore/syft", dep.Path) {
descriptor.Version = dep.Version
}
}

result := sbom.SBOM{
Source: src.Metadata,
Descriptor: descriptor,
Source: src.Metadata,
Descriptor: sbom.Descriptor{
Name: "syft",
Version: s.resolveVersion(),
},
// TODO: we should have helper functions for getting this built from exported library functions
}

Expand All @@ -91,7 +86,7 @@ func (s *Syft) ExecuteSyft(img kubernetes.ContainerImage) (string, error) {
result.Relationships = relationships

// you can use other formats such as format.CycloneDxJSONOption or format.SPDXJSONOption ...
b, err := syft.Encode(result, format.Option(s.SbomFormat))
b, err := syft.Encode(result, format.Option(s.sbomFormat))
if err != nil {
logrus.WithError(err).Error("Encoding of result failed")
return "", err
Expand Down Expand Up @@ -121,3 +116,18 @@ func GetFileName(sbomFormat string) string {
return "sbom.json"
}
}

func getSyftVersion() string {
bi, ok := debug.ReadBuildInfo()
if !ok {
logrus.Warnf("failed to read build info")
}

for _, dep := range bi.Deps {
if strings.EqualFold("github.com/anchore/syft", dep.Path) {
return dep.Version
}
}

return ""
}
162 changes: 162 additions & 0 deletions internal/syft/syft_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package syft_test

import (
"encoding/json"
"encoding/xml"
"os"
"testing"

"github.com/ckotzbauer/sbom-operator/internal/kubernetes"
"github.com/ckotzbauer/sbom-operator/internal/syft"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

type syftJsonOutput struct {
Artifacts interface{}
ArtifactRelationships interface{}
Files interface{}
Distro interface{}
}

type syftCyclonedxOutput struct {
Components syftCyclonedxComponents `xml:"components"`
}

type syftCyclonedxComponents struct {
Components string `xml:",innerxml"`
}

type syftSpdxOutput struct {
SpdxVersion string
Packages interface{}
Files interface{}
Relationships interface{}
}

func marshalJson(x interface{}) []byte {
s, err := json.Marshal(x)
Expect(err).NotTo(HaveOccurred())
return s
}

func marshalCyclonedx(x interface{}) []byte {
s, err := xml.Marshal(x)
Expect(err).NotTo(HaveOccurred())
return s
}

func testJsonSbom(name, imageID string) {
format := "json"
s := syft.New(format).WithVersion("v9.9.9")
sbom, err := s.ExecuteSyft(kubernetes.ContainerImage{ImageID: imageID, Auth: []byte{}})
Expect(err).NotTo(HaveOccurred())

var output syftJsonOutput
err = json.Unmarshal([]byte(sbom), &output)
Expect(err).NotTo(HaveOccurred())

data, err := os.ReadFile("./fixtures/" + name + "." + format)
Expect(err).NotTo(HaveOccurred())

var fixture syftJsonOutput
err = json.Unmarshal(data, &fixture)
Expect(err).NotTo(HaveOccurred())

Expect(marshalJson(output.Artifacts)).To(MatchJSON(marshalJson(fixture.Artifacts)))
Expect(marshalJson(output.ArtifactRelationships)).To(MatchJSON(marshalJson(fixture.ArtifactRelationships)))
Expect(marshalJson(output.Files)).To(MatchJSON(marshalJson(fixture.Files)))
Expect(marshalJson(output.Distro)).To(MatchJSON(marshalJson(fixture.Distro)))
}

func testCyclonedxSbom(name, imageID string) {
format := "cyclonedx"
s := syft.New(format).WithVersion("v9.9.9")
sbom, err := s.ExecuteSyft(kubernetes.ContainerImage{ImageID: imageID, Auth: []byte{}})
Expect(err).NotTo(HaveOccurred())

var output syftCyclonedxOutput
err = xml.Unmarshal([]byte(sbom), &output)
Expect(err).NotTo(HaveOccurred())

data, err := os.ReadFile("./fixtures/" + name + "." + format)
Expect(err).NotTo(HaveOccurred())

var fixture syftCyclonedxOutput
err = xml.Unmarshal(data, &fixture)
Expect(err).NotTo(HaveOccurred())

Expect(marshalCyclonedx(output.Components)).To(MatchXML(marshalCyclonedx(fixture.Components)))
}

func testSpdxSbom(name, imageID string) {
format := "spdx-json"
s := syft.New(format).WithVersion("v9.9.9")
sbom, err := s.ExecuteSyft(kubernetes.ContainerImage{ImageID: imageID, Auth: []byte{}})
Expect(err).NotTo(HaveOccurred())

var output syftSpdxOutput
err = json.Unmarshal([]byte(sbom), &output)
Expect(err).NotTo(HaveOccurred())

data, err := os.ReadFile("./fixtures/" + name + "." + format)
Expect(err).NotTo(HaveOccurred())

var fixture syftSpdxOutput
err = json.Unmarshal(data, &fixture)
Expect(err).NotTo(HaveOccurred())

Expect(marshalJson(output.Packages)).To(MatchJSON(marshalJson(fixture.Packages)))
Expect(marshalJson(output.Relationships)).To(MatchJSON(marshalJson(fixture.Relationships)))
Expect(marshalJson(output.Files)).To(MatchJSON(marshalJson(fixture.Files)))
Expect(output.SpdxVersion).To(Equal(fixture.SpdxVersion))
}

func TestSyft(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Syft Suite")
}

var _ = Describe("Syft", func() {
Describe("Catalogues correctly as JSON", func() {
It("alpine", func() {
testJsonSbom("alpine", "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300")
})

It("nginx", func() {
testJsonSbom("nginx", "nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767")
})

It("node", func() {
testJsonSbom("node", "node@sha256:f527a6118422b888c35162e0a7e2fb2febced4c85a23d96e1342f9edc2789fec")
})
})

Describe("Catalogues correctly as Cyclonedx", func() {
It("alpine", func() {
testCyclonedxSbom("alpine", "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300")
})

It("nginx", func() {
testCyclonedxSbom("nginx", "nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767")
})

It("node", func() {
testCyclonedxSbom("node", "node@sha256:f527a6118422b888c35162e0a7e2fb2febced4c85a23d96e1342f9edc2789fec")
})
})

Describe("Catalogues correctly as spdx-json", func() {
It("alpine", func() {
testSpdxSbom("alpine", "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300")
})

It("nginx", func() {
testSpdxSbom("nginx", "nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767")
})

It("node", func() {
testSpdxSbom("node", "node@sha256:f527a6118422b888c35162e0a7e2fb2febced4c85a23d96e1342f9edc2789fec")
})
})
})

0 comments on commit 35be5e6

Please sign in to comment.