Skip to content

Commit aadff8b

Browse files
authored
Merge pull request #208 from pohanhuangtw/fix/sbom-platform-awareness
fix: sbom generate with digest not the tag, add other platform into test cases with unify naming style.
2 parents df70856 + fe3e446 commit aadff8b

20 files changed

Lines changed: 17860 additions & 234 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
1717
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
1818
with:
19-
go-version: "1.24.1"
19+
go-version: "1.24.2"
2020
- run: make test
2121
- name: Upload unit-tests coverage to Codecov
2222
uses: codecov/codecov-action@ad3126e916f78f00edff4ed0317cf185271ccc2d # v5.4.2

cmd/storage/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func main() {
4242
log.Fatalln(err)
4343
}
4444

45+
db.SetMaxOpenConns(1)
4546
db.MustExec(storage.CreateImageTableSQL)
4647
db.MustExec(storage.CreateSBOMTableSQL)
4748
db.MustExec(storage.CreateVulnerabilityReportTableSQL)

internal/handlers/generate_sbom.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,10 @@ func (h *GenerateSBOMHandler) Handle(message messaging.Message) error {
9595
"--java-db-repository", "public.ecr.aws/aquasecurity/trivy-java-db",
9696
"--output", sbomFile.Name(),
9797
fmt.Sprintf(
98-
"%s/%s:%s",
98+
"%s/%s@%s",
9999
image.GetImageMetadata().RegistryURI,
100100
image.GetImageMetadata().Repository,
101-
image.GetImageMetadata().Tag,
101+
image.GetImageMetadata().Digest,
102102
),
103103
})
104104

internal/handlers/generate_sbom_test.go

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
"github.com/rancher/sbombastic/pkg/generated/clientset/versioned/scheme"
2323
)
2424

25-
func TestGenerateSBOMHandler_Handle(t *testing.T) {
25+
func generateSBOM(t *testing.T, platform, sha256, expectedSPDXJSON string) {
2626
image := &storagev1alpha1.Image{
2727
ObjectMeta: metav1.ObjectMeta{
2828
Name: "test-image",
@@ -34,8 +34,8 @@ func TestGenerateSBOMHandler_Handle(t *testing.T) {
3434
RegistryURI: "ghcr.io/rancher-sandbox/sbombastic/test-assets",
3535
Repository: "golang",
3636
Tag: "1.12-alpine",
37-
Platform: "linux/amd64",
38-
Digest: "sha256:123",
37+
Platform: platform,
38+
Digest: sha256,
3939
},
4040
},
4141
}
@@ -48,35 +48,34 @@ func TestGenerateSBOMHandler_Handle(t *testing.T) {
4848
WithRuntimeObjects(image).
4949
Build()
5050

51-
spdxPath := filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine.spdx.json")
52-
spdxData, err := os.ReadFile(spdxPath)
53-
require.NoError(t, err)
51+
spdxData, err := os.ReadFile(expectedSPDXJSON)
52+
require.NoError(t, err, "failed to read expected SPDX JSON file %s", expectedSPDXJSON)
5453

5554
expectedSPDX := &spdx.Document{}
5655
err = json.Unmarshal(spdxData, expectedSPDX)
57-
require.NoError(t, err)
56+
require.NoError(t, err, "failed to unmarshal expected SPDX JSON file %s", expectedSPDXJSON)
5857

5958
handler := NewGenerateSBOMHandler(k8sClient, scheme, "/tmp", slog.Default())
6059

6160
err = handler.Handle(&messaging.GenerateSBOM{
6261
ImageName: image.Name,
6362
ImageNamespace: image.Namespace,
6463
})
65-
require.NoError(t, err)
64+
require.NoError(t, err, "failed to generate SBOM, with platform %s", platform)
6665

6766
sbom := &storagev1alpha1.SBOM{}
6867
err = k8sClient.Get(t.Context(), types.NamespacedName{
6968
Name: image.Name,
7069
Namespace: image.Namespace,
7170
}, sbom)
72-
require.NoError(t, err)
71+
require.NoError(t, err, "failed to get SBOM, with platform %s", platform)
7372

7473
assert.Equal(t, image.Spec.ImageMetadata, sbom.Spec.ImageMetadata)
7574
assert.Equal(t, image.UID, sbom.GetOwnerReferences()[0].UID)
7675

7776
generatedSPDX := &spdx.Document{}
7877
err = json.Unmarshal(sbom.Spec.SPDX.Raw, generatedSPDX)
79-
require.NoError(t, err)
78+
require.NoError(t, err, "failed to unmarshal generated SPDX, with platform %s", platform)
8079

8180
// Filter out "DocumentNamespace" and any field named "AnnotationDate" or "Created" regardless of nesting,
8281
// since they contain timestamps and are not deterministic.
@@ -86,5 +85,53 @@ func TestGenerateSBOMHandler_Handle(t *testing.T) {
8685
}, cmp.Ignore())
8786
diff := cmp.Diff(expectedSPDX, generatedSPDX, filter, cmpopts.IgnoreUnexported(spdx.Package{}))
8887

89-
assert.Empty(t, diff)
88+
assert.Empty(t, diff, "SPDX diff mismatch on platform %s\nDiff:\n%s", platform, diff)
89+
}
90+
91+
func TestGenerateSBOMHandler_Handle(t *testing.T) {
92+
for _, test := range []struct {
93+
platform string
94+
sha256 string
95+
expectedSPDXJSON string
96+
}{
97+
{
98+
platform: "linux/amd64",
99+
sha256: "sha256:1782cafde43390b032f960c0fad3def745fac18994ced169003cb56e9a93c028",
100+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-amd64.spdx.json"),
101+
},
102+
{
103+
platform: "linux/arm/v6",
104+
sha256: "sha256:ea95bb81dab31807beac6c62824c048b1ee96b408f6097ea9dd0204e380f00b2",
105+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm-v6.spdx.json"),
106+
},
107+
{
108+
platform: "linux/arm/v7",
109+
sha256: "sha256:ab389e320938f3bd42f45437d381fab28742dadcb892816236801e24a0bef804",
110+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm-v7.spdx.json"),
111+
},
112+
{
113+
platform: "linux/arm64/v8",
114+
sha256: "sha256:1c96d48d06d96929d41e76e8145eb182ce22983f5e3539a655ec2918604835d0",
115+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm64-v8.spdx.json"),
116+
},
117+
{
118+
platform: "linux/386",
119+
sha256: "sha256:d8801b3783dd4e4aee273c1a312cc265c832c7f264056d68e7ea73b8e1dd94b0",
120+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-386.spdx.json"),
121+
},
122+
{
123+
platform: "linux/ppc64le",
124+
sha256: "sha256:216cb428a7a53a75ef7806ed1120c409253e3e65bddc6ae0c21f5cd2faf92324",
125+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-ppc64le.spdx.json"),
126+
},
127+
{
128+
platform: "linux/s390x",
129+
sha256: "sha256:f2475c61ab276da0882a9637b83b2a5710b289d6d80f3daedb71d4a8eaeb1686",
130+
expectedSPDXJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-s390x.spdx.json"),
131+
},
132+
} {
133+
t.Run(test.platform, func(t *testing.T) {
134+
generateSBOM(t, test.platform, test.sha256, test.expectedSPDXJSON)
135+
})
136+
}
90137
}

internal/handlers/scan_sbom_test.go

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,9 @@ import (
2121
"sigs.k8s.io/controller-runtime/pkg/client/fake"
2222
)
2323

24-
func TestScanSBOMHandler_Handle(t *testing.T) {
25-
spdxPath := filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine.spdx.json")
26-
spdxData, err := os.ReadFile(spdxPath)
27-
require.NoError(t, err)
24+
func scanSBOM(t *testing.T, platform, sourceSBOMJSON, expectedReportJSON string) {
25+
spdxData, err := os.ReadFile(sourceSBOMJSON)
26+
require.NoError(t, err, "failed to read source SBOM file %s", sourceSBOMJSON)
2827

2928
sbom := &storagev1alpha1.SBOM{
3029
ObjectMeta: metav1.ObjectMeta{
@@ -44,35 +43,34 @@ func TestScanSBOMHandler_Handle(t *testing.T) {
4443
WithRuntimeObjects(sbom).
4544
Build()
4645

47-
reportPath := filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine.sarif.json")
48-
reportData, err := os.ReadFile(reportPath)
49-
require.NoError(t, err)
46+
reportData, err := os.ReadFile(expectedReportJSON)
47+
require.NoError(t, err, "failed to read expected report file %s", expectedReportJSON)
5048

5149
expectedReport := &sarif.Report{}
5250
err = json.Unmarshal(reportData, expectedReport)
53-
require.NoError(t, err)
51+
require.NoError(t, err, "failed to unmarshal expected report file %s", expectedReportJSON)
5452

5553
handler := NewScanSBOMHandler(k8sClient, scheme, "/tmp", slog.Default())
5654

5755
err = handler.Handle(&messaging.ScanSBOM{
5856
SBOMName: sbom.Name,
5957
SBOMNamespace: sbom.Namespace,
6058
})
61-
require.NoError(t, err)
59+
require.NoError(t, err, "failed to scan SBOM, with platform %s", platform)
6260

6361
vulnerabilityReport := &storagev1alpha1.VulnerabilityReport{}
6462
err = k8sClient.Get(t.Context(), client.ObjectKey{
6563
Name: sbom.Name,
6664
Namespace: sbom.Namespace,
6765
}, vulnerabilityReport)
68-
require.NoError(t, err)
66+
require.NoError(t, err, "failed to get vulnerability report, with platform %s", platform)
6967

7068
assert.Equal(t, sbom.GetImageMetadata(), vulnerabilityReport.GetImageMetadata())
7169
assert.Equal(t, sbom.UID, vulnerabilityReport.GetOwnerReferences()[0].UID)
7270

7371
report := &sarif.Report{}
7472
err = json.Unmarshal(vulnerabilityReport.Spec.SARIF.Raw, report)
75-
require.NoError(t, err)
73+
require.NoError(t, err, "failed to unmarshal vulnerability report, with platform %s", platform)
7674

7775
// Filter out fields containing the file path from the comparison
7876
filter := cmp.FilterPath(func(path cmp.Path) bool {
@@ -87,5 +85,53 @@ func TestScanSBOMHandler_Handle(t *testing.T) {
8785
}))
8886
diff := cmp.Diff(expectedReport, report, filter)
8987

90-
assert.Empty(t, diff)
88+
assert.Empty(t, diff, "diff mismatch on platform %s\nDiff:\n%s", platform, diff)
89+
}
90+
91+
func TestScanSBOMHandler_Handle(t *testing.T) {
92+
for _, test := range []struct {
93+
platform string
94+
sourceSBOMJSON string
95+
expectedReportJSON string
96+
}{
97+
{
98+
platform: "linux/amd64",
99+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-amd64.spdx.json"),
100+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-amd64.sarif.json"),
101+
},
102+
{
103+
platform: "linux/arm/v6",
104+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm-v6.spdx.json"),
105+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm-v6.sarif.json"),
106+
},
107+
{
108+
platform: "linux/arm/v7",
109+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm-v7.spdx.json"),
110+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm-v7.sarif.json"),
111+
},
112+
{
113+
platform: "linux/arm64/v8",
114+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm64-v8.spdx.json"),
115+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-arm64-v8.sarif.json"),
116+
},
117+
{
118+
platform: "linux/386",
119+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-386.spdx.json"),
120+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-386.sarif.json"),
121+
},
122+
{
123+
platform: "linux/ppc64le",
124+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-ppc64le.spdx.json"),
125+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-ppc64le.sarif.json"),
126+
},
127+
{
128+
platform: "linux/s390x",
129+
sourceSBOMJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-s390x.spdx.json"),
130+
expectedReportJSON: filepath.Join("..", "..", "test", "fixtures", "golang-1.12-alpine-s390x.sarif.json"),
131+
},
132+
} {
133+
t.Run(test.platform, func(t *testing.T) {
134+
scanSBOM(t, test.platform, test.sourceSBOMJSON, test.expectedReportJSON)
135+
})
136+
}
91137
}

test/e2e/e2e_suite_test.go

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"github.com/stretchr/testify/assert"
88
"github.com/stretchr/testify/require"
99
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/apimachinery/pkg/labels"
11+
"sigs.k8s.io/e2e-framework/klient/k8s/resources"
1012
"sigs.k8s.io/e2e-framework/klient/wait"
1113
"sigs.k8s.io/e2e-framework/klient/wait/conditions"
1214
"sigs.k8s.io/e2e-framework/pkg/envconf"
@@ -15,21 +17,19 @@ import (
1517

1618
storagev1alpha1 "github.com/rancher/sbombastic/api/storage/v1alpha1"
1719
v1alpha1 "github.com/rancher/sbombastic/api/v1alpha1"
20+
"github.com/rancher/sbombastic/internal/handlers"
1821
)
1922

20-
func EqualReference(img storagev1alpha1.ImageMetadata, registryURI, registryRepository, tag string) bool {
21-
return img.RegistryURI == registryURI &&
22-
img.Repository == registryRepository &&
23-
img.Tag == tag
24-
}
25-
2623
func TestRegistryCreation(t *testing.T) {
2724
releaseName := "sbombastic"
2825
registryName := "test-registry"
2926
registryURI := "ghcr.io"
3027
registryRepository := "rancher-sandbox/sbombastic/test-assets/golang"
28+
totalImages := 7 // Current number of images in the test-assets/golang directory
3129

32-
crName := "dfe56d8371e7df15a3dde25c33a78b84b79766de2ab5a5897032019c878b5932"
30+
labelSelector := labels.FormatLabels(
31+
map[string]string{handlers.LabelManagedByKey: handlers.LabelManagedByValue},
32+
)
3333

3434
f := features.New("Start Registry CR Creation test").
3535
Setup(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
@@ -69,42 +69,36 @@ func TestRegistryCreation(t *testing.T) {
6969
return ctx
7070
}).
7171
Assess("Verify the Image is created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
72-
images := storagev1alpha1.ImageList{
73-
Items: []storagev1alpha1.Image{
74-
{ObjectMeta: metav1.ObjectMeta{Name: crName, Namespace: cfg.Namespace()}},
75-
},
76-
}
72+
images := storagev1alpha1.ImageList{}
73+
err := wait.For(conditions.New(cfg.Client().Resources(cfg.Namespace())).ResourceListN(
74+
&images,
75+
totalImages,
76+
resources.WithLabelSelector(labelSelector)),
77+
)
78+
require.NoError(t, err)
7779

78-
err := wait.For(conditions.New(cfg.Client().Resources()).ResourcesFound(&images))
79-
if err != nil {
80-
t.Error(err)
81-
}
8280
return ctx
8381
}).
8482
Assess("Verify the SPDX SBOM is created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
85-
sboms := storagev1alpha1.SBOMList{
86-
Items: []storagev1alpha1.SBOM{
87-
{ObjectMeta: metav1.ObjectMeta{Name: crName, Namespace: cfg.Namespace()}},
88-
},
89-
}
83+
sboms := storagev1alpha1.SBOMList{}
84+
err := wait.For(conditions.New(cfg.Client().Resources(cfg.Namespace())).ResourceListN(
85+
&sboms,
86+
totalImages,
87+
resources.WithLabelSelector(labelSelector)),
88+
)
89+
require.NoError(t, err)
9090

91-
err := wait.For(conditions.New(cfg.Client().Resources()).ResourcesFound(&sboms))
92-
if err != nil {
93-
t.Error(err)
94-
}
9591
return ctx
9692
}).
9793
Assess("Verify the VulnerabilityReport is created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
98-
vulnReports := storagev1alpha1.VulnerabilityReportList{
99-
Items: []storagev1alpha1.VulnerabilityReport{
100-
{ObjectMeta: metav1.ObjectMeta{Name: crName, Namespace: cfg.Namespace()}},
101-
},
102-
}
94+
vulnReports := storagev1alpha1.VulnerabilityReportList{}
95+
err := wait.For(conditions.New(cfg.Client().Resources(cfg.Namespace())).ResourceListN(
96+
&vulnReports,
97+
totalImages,
98+
resources.WithLabelSelector(labelSelector)),
99+
)
100+
require.NoError(t, err)
103101

104-
err := wait.For(conditions.New(cfg.Client().Resources()).ResourcesFound(&vulnReports))
105-
if err != nil {
106-
t.Error(err)
107-
}
108102
return ctx
109103
}).
110104
Teardown(func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context {

0 commit comments

Comments
 (0)