From 630879e30afc32e0a59551a8ba5ce17520a1df9a Mon Sep 17 00:00:00 2001 From: David Caravello <119438707+dcaravel@users.noreply.github.com> Date: Mon, 9 Dec 2024 18:07:09 -0600 Subject: [PATCH] add more tests --- database/pgsql/rhelv2_layer_test.go | 121 ++++++++++++++++++++++++++-- e2etests/testcase_test.go | 43 ++++++++++ 2 files changed, 158 insertions(+), 6 deletions(-) diff --git a/database/pgsql/rhelv2_layer_test.go b/database/pgsql/rhelv2_layer_test.go index 7bdb3c7ce..1da1ba5c3 100644 --- a/database/pgsql/rhelv2_layer_test.go +++ b/database/pgsql/rhelv2_layer_test.go @@ -8,6 +8,7 @@ import ( "github.com/stackrox/scanner/database" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestInsertRHELv2Layer(t *testing.T) { @@ -181,16 +182,12 @@ func TestGetRHELv2Layers(t *testing.T) { assert.Len(t, layers, 3) layer = layers[2] assert.Equal(t, "sha256:howdyhowdyhowdy", layer.Hash) - for _, pkg := range layer.Pkgs { - pkg.ID = 0 - } + resetPackageIDs(layer) assert.Equal(t, layer2Pkgs, layer.Pkgs) assert.Equal(t, layer2CPEs, layer.CPEs) layer = layers[1] assert.Equal(t, "sha256:howdyhowdy", layer.Hash) - for _, pkg := range layer.Pkgs { - pkg.ID = 0 - } + resetPackageIDs(layer) assert.Equal(t, layer1Pkgs, layer.Pkgs) assert.Equal(t, layer1CPEs, layer.CPEs) layer = layers[0] @@ -198,3 +195,115 @@ func TestGetRHELv2Layers(t *testing.T) { assert.Empty(t, layer.Pkgs) assert.Empty(t, layer.CPEs) } + +// TestRHELv2LayerLineage verifies that data for duplicate layers with different parent +// layers (lineage) is pulled correctly. +func TestRHELv2LayerLineage(t *testing.T) { + + datastore, err := openDatabaseForTest("RHELv2LayerLineage", false) + if err != nil { + t.Error(err) + return + } + defer datastore.Close() + + // Two 'fake' images will be created, each with 3 layers, the DB will resemble: + // id | hash | parent_hash | dist | cpes | lineage | parent_lineage + // ----+-----------------+-----------------+--------+----------------+-----------+---------------- + // 1 | sha256:base | | rhel:8 | | | + // 2 | sha256:layer1-a | sha256:base | rhel:8 | {cpe-a,cpe2-a} | lineage | + // 3 | sha256:layer1-b | sha256:base | rhel:8 | {cpe-b,cpe2-b} | lineage | + // 4 | sha256:leaf | sha256:layer1-a | rhel:8 | | lineage-a | lineage + // 5 | sha256:leaf | sha256:layer1-b | rhel:8 | | lineage-b | lineage + + // base layers + base := &database.RHELv2Layer{ + Hash: "sha256:base", + Dist: "rhel:8", + } + + err = datastore.InsertRHELv2Layer(base) + require.NoError(t, err) + + layer1a := &database.RHELv2Layer{ + Hash: "sha256:layer1-a", + Lineage: "lineage", + ParentHash: "sha256:base", + ParentLineage: "", + Dist: "rhel:8", + Pkgs: []*database.RHELv2Package{ + {Name: "pkg", Version: "v1-a", Arch: "x86_64"}, + {Name: "pkg2", Version: "v2-a", Module: "module", Arch: "i686"}, + }, + CPEs: []string{"cpe-a", "cpe2-a"}, + } + + layer1b := &database.RHELv2Layer{ + Hash: "sha256:layer1-b", + Lineage: "lineage", + ParentHash: "sha256:base", + ParentLineage: "", + Dist: "rhel:8", + Pkgs: []*database.RHELv2Package{ + {Name: "pkg", Version: "v1-b", Arch: "x86_64"}, + {Name: "pkg2", Version: "v2-b", Module: "module", Arch: "i686"}, + }, + CPEs: []string{"cpe-b", "cpe2-b"}, + } + + err = datastore.InsertRHELv2Layer(layer1a) + require.NoError(t, err) + err = datastore.InsertRHELv2Layer(layer1b) + require.NoError(t, err) + + leafa := &database.RHELv2Layer{ + Hash: "sha256:leaf", // for this test all leafs should have same digest + Lineage: "lineage-a", // lineage is specific to layer A + ParentHash: "sha256:layer1-a", + ParentLineage: "lineage", + Dist: "rhel:8", + } + + var leafb = new(database.RHELv2Layer) + *leafb = *leafa + leafb.Lineage = "lineage-b" + leafb.ParentHash = "sha256:layer1-b" + + err = datastore.InsertRHELv2Layer(leafa) + require.NoError(t, err) + err = datastore.InsertRHELv2Layer(leafb) + require.NoError(t, err) + + assertLayersEqual := func(t *testing.T, expected, actual *database.RHELv2Layer) { + resetPackageIDs(actual) + assert.Equal(t, expected.Hash, actual.Hash, "Hash mismatch") + assert.Equal(t, expected.Lineage, actual.Lineage, "Lineage mismatch") + assert.Equal(t, expected.CPEs, actual.CPEs, "CPEs mistmatch") + assert.Equal(t, expected.Pkgs, actual.Pkgs, "Pkgs mismatch") + } + + layers, err := datastore.GetRHELv2Layers("sha256:leaf", "lineage-a") + require.NoError(t, err) + require.Len(t, layers, 3) + + assertLayersEqual(t, base, layers[0]) + assertLayersEqual(t, layer1a, layers[1]) + assertLayersEqual(t, leafa, layers[2]) + + layers, err = datastore.GetRHELv2Layers("sha256:leaf", "lineage-b") + require.NoError(t, err) + require.Len(t, layers, 3) + + assertLayersEqual(t, base, layers[0]) + assertLayersEqual(t, layer1b, layers[1]) + assertLayersEqual(t, leafb, layers[2]) +} + +// resetPackageIDs sets all package IDs to 0. Package IDs are DB sequence numbers +// that will not be deterministic (depending on how tests are written), therefore +// set the IDs to 0 to allow tests pass. +func resetPackageIDs(layer *database.RHELv2Layer) { + for _, pkg := range layer.Pkgs { + pkg.ID = 0 + } +} diff --git a/e2etests/testcase_test.go b/e2etests/testcase_test.go index 5a9cb18e0..cffcf19f3 100644 --- a/e2etests/testcase_test.go +++ b/e2etests/testcase_test.go @@ -4785,4 +4785,47 @@ All OpenShift Container Platform 4.10 users are advised to upgrade to these upda }, }, }, + // START: Lineage Tests + // The order of the next tests is important, the intent is to reproduce the conditions described in ROX-26604 + // in which differing parent layers were not properly handled leading to inaccuracies. These images share top + // and bottom layers, middle layers differ. + // Dockerfiles at: github.com/stackrox/stackrox/qa-tests-backend/test-images/lineage + { + image: "quay.io/rhacs-eng/qa:lineage-jdk-17.0.11", + registry: "https://quay.io", + source: "Red Hat", + username: os.Getenv("QUAY_RHACS_ENG_RO_USERNAME"), + password: os.Getenv("QUAY_RHACS_ENG_RO_PASSWORD"), + onlyCheckSpecifiedVulns: true, + namespace: "rhel:8", + expectedFeatures: []apiV1.Feature{ + { + Name: "java-17-openjdk-headless", + NamespaceName: "rhel:8", + VersionFormat: "rpm", + Version: "1:17.0.11.0.9-2.el8.x86_64", + FixedBy: "1:17.0.13.0.11-3.el8", + AddedBy: "sha256:06c7a3d491f551a56296ccb9bee8a68c83776991e73a9005e8b5ebb533002097", + }, + }, + }, + { + image: "quay.io/rhacs-eng/qa:lineage-jdk-17.0.13", + registry: "https://quay.io", + source: "Red Hat", + username: os.Getenv("QUAY_RHACS_ENG_RO_USERNAME"), + password: os.Getenv("QUAY_RHACS_ENG_RO_PASSWORD"), + onlyCheckSpecifiedVulns: true, + namespace: "rhel:8", + expectedFeatures: []apiV1.Feature{ + { + Name: "java-17-openjdk-headless", + NamespaceName: "rhel:8", + VersionFormat: "rpm", + Version: "1:17.0.13.0.11-3.el8.x86_64", + AddedBy: "sha256:2f7b9495af5ddc85b0be7ca9411fddb54f37999ea73b03cbf1115dd0c5bd4f95", + }, + }, + }, + // END: Lineage Tests }