Skip to content

Commit 35be5e6

Browse files
committed
test: added syft tests
Signed-off-by: Christian Kotzbauer <git@ckotzbauer.de>
1 parent 188dfd9 commit 35be5e6

File tree

11 files changed

+279515
-20
lines changed

11 files changed

+279515
-20
lines changed

internal/syft/fixtures/alpine.cyclonedx

Lines changed: 473 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/alpine.json

Lines changed: 3072 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/alpine.spdx-json

Lines changed: 1490 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/nginx.cyclonedx

Lines changed: 4220 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/nginx.json

Lines changed: 96272 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/nginx.spdx-json

Lines changed: 44022 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/node.cyclonedx

Lines changed: 8329 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/node.json

Lines changed: 78953 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/fixtures/node.spdx-json

Lines changed: 42492 additions & 0 deletions
Large diffs are not rendered by default.

internal/syft/syft.go

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,22 @@ import (
2121
)
2222

2323
type Syft struct {
24-
SbomFormat string
24+
sbomFormat string
25+
resolveVersion func() string
2526
}
2627

2728
func New(sbomFormat string) Syft {
2829
return Syft{
29-
SbomFormat: sbomFormat,
30+
sbomFormat: sbomFormat,
31+
resolveVersion: getSyftVersion,
3032
}
3133
}
3234

35+
func (s Syft) WithVersion(version string) Syft {
36+
s.resolveVersion = func() string { return version }
37+
return s
38+
}
39+
3340
func (s *Syft) ExecuteSyft(img kubernetes.ContainerImage) (string, error) {
3441
logrus.Infof("Processing image %s", img.ImageID)
3542

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

60-
bi, ok := debug.ReadBuildInfo()
61-
if !ok {
62-
logrus.Warnf("failed to read build info")
63-
}
64-
65-
descriptor := sbom.Descriptor{
66-
Name: "syft",
67-
}
68-
69-
for _, dep := range bi.Deps {
70-
if strings.EqualFold("github.com/anchore/syft", dep.Path) {
71-
descriptor.Version = dep.Version
72-
}
73-
}
74-
7567
result := sbom.SBOM{
76-
Source: src.Metadata,
77-
Descriptor: descriptor,
68+
Source: src.Metadata,
69+
Descriptor: sbom.Descriptor{
70+
Name: "syft",
71+
Version: s.resolveVersion(),
72+
},
7873
// TODO: we should have helper functions for getting this built from exported library functions
7974
}
8075

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

9388
// you can use other formats such as format.CycloneDxJSONOption or format.SPDXJSONOption ...
94-
b, err := syft.Encode(result, format.Option(s.SbomFormat))
89+
b, err := syft.Encode(result, format.Option(s.sbomFormat))
9590
if err != nil {
9691
logrus.WithError(err).Error("Encoding of result failed")
9792
return "", err
@@ -121,3 +116,18 @@ func GetFileName(sbomFormat string) string {
121116
return "sbom.json"
122117
}
123118
}
119+
120+
func getSyftVersion() string {
121+
bi, ok := debug.ReadBuildInfo()
122+
if !ok {
123+
logrus.Warnf("failed to read build info")
124+
}
125+
126+
for _, dep := range bi.Deps {
127+
if strings.EqualFold("github.com/anchore/syft", dep.Path) {
128+
return dep.Version
129+
}
130+
}
131+
132+
return ""
133+
}

internal/syft/syft_suite_test.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package syft_test
2+
3+
import (
4+
"encoding/json"
5+
"encoding/xml"
6+
"os"
7+
"testing"
8+
9+
"github.com/ckotzbauer/sbom-operator/internal/kubernetes"
10+
"github.com/ckotzbauer/sbom-operator/internal/syft"
11+
. "github.com/onsi/ginkgo/v2"
12+
. "github.com/onsi/gomega"
13+
)
14+
15+
type syftJsonOutput struct {
16+
Artifacts interface{}
17+
ArtifactRelationships interface{}
18+
Files interface{}
19+
Distro interface{}
20+
}
21+
22+
type syftCyclonedxOutput struct {
23+
Components syftCyclonedxComponents `xml:"components"`
24+
}
25+
26+
type syftCyclonedxComponents struct {
27+
Components string `xml:",innerxml"`
28+
}
29+
30+
type syftSpdxOutput struct {
31+
SpdxVersion string
32+
Packages interface{}
33+
Files interface{}
34+
Relationships interface{}
35+
}
36+
37+
func marshalJson(x interface{}) []byte {
38+
s, err := json.Marshal(x)
39+
Expect(err).NotTo(HaveOccurred())
40+
return s
41+
}
42+
43+
func marshalCyclonedx(x interface{}) []byte {
44+
s, err := xml.Marshal(x)
45+
Expect(err).NotTo(HaveOccurred())
46+
return s
47+
}
48+
49+
func testJsonSbom(name, imageID string) {
50+
format := "json"
51+
s := syft.New(format).WithVersion("v9.9.9")
52+
sbom, err := s.ExecuteSyft(kubernetes.ContainerImage{ImageID: imageID, Auth: []byte{}})
53+
Expect(err).NotTo(HaveOccurred())
54+
55+
var output syftJsonOutput
56+
err = json.Unmarshal([]byte(sbom), &output)
57+
Expect(err).NotTo(HaveOccurred())
58+
59+
data, err := os.ReadFile("./fixtures/" + name + "." + format)
60+
Expect(err).NotTo(HaveOccurred())
61+
62+
var fixture syftJsonOutput
63+
err = json.Unmarshal(data, &fixture)
64+
Expect(err).NotTo(HaveOccurred())
65+
66+
Expect(marshalJson(output.Artifacts)).To(MatchJSON(marshalJson(fixture.Artifacts)))
67+
Expect(marshalJson(output.ArtifactRelationships)).To(MatchJSON(marshalJson(fixture.ArtifactRelationships)))
68+
Expect(marshalJson(output.Files)).To(MatchJSON(marshalJson(fixture.Files)))
69+
Expect(marshalJson(output.Distro)).To(MatchJSON(marshalJson(fixture.Distro)))
70+
}
71+
72+
func testCyclonedxSbom(name, imageID string) {
73+
format := "cyclonedx"
74+
s := syft.New(format).WithVersion("v9.9.9")
75+
sbom, err := s.ExecuteSyft(kubernetes.ContainerImage{ImageID: imageID, Auth: []byte{}})
76+
Expect(err).NotTo(HaveOccurred())
77+
78+
var output syftCyclonedxOutput
79+
err = xml.Unmarshal([]byte(sbom), &output)
80+
Expect(err).NotTo(HaveOccurred())
81+
82+
data, err := os.ReadFile("./fixtures/" + name + "." + format)
83+
Expect(err).NotTo(HaveOccurred())
84+
85+
var fixture syftCyclonedxOutput
86+
err = xml.Unmarshal(data, &fixture)
87+
Expect(err).NotTo(HaveOccurred())
88+
89+
Expect(marshalCyclonedx(output.Components)).To(MatchXML(marshalCyclonedx(fixture.Components)))
90+
}
91+
92+
func testSpdxSbom(name, imageID string) {
93+
format := "spdx-json"
94+
s := syft.New(format).WithVersion("v9.9.9")
95+
sbom, err := s.ExecuteSyft(kubernetes.ContainerImage{ImageID: imageID, Auth: []byte{}})
96+
Expect(err).NotTo(HaveOccurred())
97+
98+
var output syftSpdxOutput
99+
err = json.Unmarshal([]byte(sbom), &output)
100+
Expect(err).NotTo(HaveOccurred())
101+
102+
data, err := os.ReadFile("./fixtures/" + name + "." + format)
103+
Expect(err).NotTo(HaveOccurred())
104+
105+
var fixture syftSpdxOutput
106+
err = json.Unmarshal(data, &fixture)
107+
Expect(err).NotTo(HaveOccurred())
108+
109+
Expect(marshalJson(output.Packages)).To(MatchJSON(marshalJson(fixture.Packages)))
110+
Expect(marshalJson(output.Relationships)).To(MatchJSON(marshalJson(fixture.Relationships)))
111+
Expect(marshalJson(output.Files)).To(MatchJSON(marshalJson(fixture.Files)))
112+
Expect(output.SpdxVersion).To(Equal(fixture.SpdxVersion))
113+
}
114+
115+
func TestSyft(t *testing.T) {
116+
RegisterFailHandler(Fail)
117+
RunSpecs(t, "Syft Suite")
118+
}
119+
120+
var _ = Describe("Syft", func() {
121+
Describe("Catalogues correctly as JSON", func() {
122+
It("alpine", func() {
123+
testJsonSbom("alpine", "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300")
124+
})
125+
126+
It("nginx", func() {
127+
testJsonSbom("nginx", "nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767")
128+
})
129+
130+
It("node", func() {
131+
testJsonSbom("node", "node@sha256:f527a6118422b888c35162e0a7e2fb2febced4c85a23d96e1342f9edc2789fec")
132+
})
133+
})
134+
135+
Describe("Catalogues correctly as Cyclonedx", func() {
136+
It("alpine", func() {
137+
testCyclonedxSbom("alpine", "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300")
138+
})
139+
140+
It("nginx", func() {
141+
testCyclonedxSbom("nginx", "nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767")
142+
})
143+
144+
It("node", func() {
145+
testCyclonedxSbom("node", "node@sha256:f527a6118422b888c35162e0a7e2fb2febced4c85a23d96e1342f9edc2789fec")
146+
})
147+
})
148+
149+
Describe("Catalogues correctly as spdx-json", func() {
150+
It("alpine", func() {
151+
testSpdxSbom("alpine", "alpine@sha256:21a3deaa0d32a8057914f36584b5288d2e5ecc984380bc0118285c70fa8c9300")
152+
})
153+
154+
It("nginx", func() {
155+
testSpdxSbom("nginx", "nginx@sha256:2834dc507516af02784808c5f48b7cbe38b8ed5d0f4837f16e78d00deb7e7767")
156+
})
157+
158+
It("node", func() {
159+
testSpdxSbom("node", "node@sha256:f527a6118422b888c35162e0a7e2fb2febced4c85a23d96e1342f9edc2789fec")
160+
})
161+
})
162+
})

0 commit comments

Comments
 (0)