Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion central/sensor/service/pipeline/nodescansv2/pipeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (p *pipelineImpl) Run(ctx context.Context, clusterID string, msg *central.M
}

// TODO(ROX-12240, ROX-13053): Do something meaningful with the nodeInventory
log.Infof("Central received NodeInventory: %+v", nodeInventory)
log.Debugf("Central received NodeInventory: %+v", nodeInventory)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see you already incorporated the feedback regarding loglevels. Great job!

That said, we're keeping the pipeline only until #3757 is merged, as NodeInventory is still an independent message here, and we depend on this pipeline to print the inventory, correct?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, no changes to the pipeline here as it affects the decision that we need to do in #3757.

The nodescanv2 pipeline is a dud and does nothing except of printing the debug log message. Moreover, it is guarded by the feature-flag - see here


return nil
}
Expand Down
47 changes: 32 additions & 15 deletions compliance/collection/nodeinventorizer/fake_nodeinventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
timestamp "github.com/gogo/protobuf/types"
"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/rox/pkg/logging"
scannerV1 "github.com/stackrox/scanner/generated/scanner/api/v1"
)

var (
Expand All @@ -19,33 +18,51 @@ type FakeNodeInventorizer struct {
func (f *FakeNodeInventorizer) Scan(nodeName string) (*storage.NodeInventory, error) {
log.Infof("Generating fake scan result message...")
msg := &storage.NodeInventory{
NodeId: "",
NodeName: nodeName,
ScanTime: timestamp.TimestampNow(),
Components: &scannerV1.Components{
Namespace: "Testme OS",
RhelComponents: []*scannerV1.RHELComponent{
Components: &storage.NodeInventory_Components{
Namespace: "rhcos:4.11",
RhelComponents: []*storage.NodeInventory_Components_RHELComponent{
{
Id: int64(0),
Name: "vim-minimal",
Namespace: "rhel:8",
Version: "2:7.4.629-6.el8.x86_64",
Version: "2:7.4.629-6.el8",
Arch: "x86_64",
Module: "FakeMod",
Cpes: []string{"cpe:/a:redhat:enterprise_linux:8::baseos"},
AddedBy: "FakeLayer",
Module: "",
AddedBy: "FakeNodeScanner",
},
{
Name: "libsolv",
Id: int64(1),
Name: "tar",
Namespace: "rhel:8",
Version: "0.7.7-1.el8.x86_64",
Version: "1.27.1.el8",
Arch: "x86_64",
Module: "FakeMod",
AddedBy: "FakeLayer",
Module: "",
AddedBy: "FakeNodeScanner",
},
{
Id: int64(2),
Name: "lz4-libs",
Namespace: "rhel:8",
Version: "1.8.3-3.el8_4",
Arch: "x86_64",
Module: "",
AddedBy: "FakeNodeScanner",
},
{
Id: int64(3),
Name: "libksba",
Namespace: "rhel:8",
Version: "1.3.5-7.el8",
Arch: "x86_64",
Module: "",
AddedBy: "FakeNodeScanner",
},
},
LanguageComponents: nil,
RhelContentSets: []string{"rhel-8-for-x86_64-appstream-rpms", "rhel-8-for-x86_64-baseos-rpms"},
},
Notes: []scannerV1.Note{scannerV1.Note_LANGUAGE_CVES_UNAVAILABLE},
Notes: []storage.NodeInventory_Note{storage.NodeInventory_LANGUAGE_CVES_UNAVAILABLE},
}
return msg, nil
}
49 changes: 36 additions & 13 deletions compliance/collection/nodeinventorizer/nodeinventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ func (n *NodeInventoryCollector) Scan(nodeName string) (*storage.NodeInventory,
NodeName: nodeName,
ScanTime: timestamp.TimestampNow(),
Components: protoComponents,
Notes: []scannerV1.Note{scannerV1.Note_LANGUAGE_CVES_UNAVAILABLE},
Notes: []storage.NodeInventory_Note{storage.NodeInventory_LANGUAGE_CVES_UNAVAILABLE},
}

return m, nil
}

func protoComponentsFromScanComponents(c *nodes.Components) *scannerV1.Components {
func protoComponentsFromScanComponents(c *nodes.Components) *storage.NodeInventory_Components {
if c == nil {
return nil
}
Expand All @@ -66,33 +66,36 @@ func protoComponentsFromScanComponents(c *nodes.Components) *scannerV1.Component
// For now, we only care about RHEL components, but this must be extended once we support non-RHCOS
rhelComponents := convertAndDedupRHELComponents(c.CertifiedRHELComponents)

protoComponents := &scannerV1.Components{
Namespace: namespace,
OsComponents: nil,
RhelComponents: rhelComponents,
LanguageComponents: nil,
protoComponents := &storage.NodeInventory_Components{
Namespace: namespace,
RhelComponents: rhelComponents,
}
return protoComponents
}

func convertAndDedupRHELComponents(rc *database.RHELv2Components) []*scannerV1.RHELComponent {
func convertAndDedupRHELComponents(rc *database.RHELv2Components) []*storage.NodeInventory_Components_RHELComponent {
if rc == nil || rc.Packages == nil {
log.Warn("No RHEL packages found in scan result")
return nil
}

convertedComponents := make(map[string]*scannerV1.RHELComponent, 0)
convertedComponents := make(map[string]*storage.NodeInventory_Components_RHELComponent, 0)
for i, rhelc := range rc.Packages {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth adding a guard here for the case where rhelc is a nil pointer.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in fdbd8cd

comp := &scannerV1.RHELComponent{
if rhelc == nil {
continue
}
comp := &storage.NodeInventory_Components_RHELComponent{
// The loop index is used as ID, as this field only needs to be unique for each NodeInventory result slice
Id: int64(i),
Name: rhelc.Name,
Namespace: rc.Dist,
Version: rhelc.Version,
Arch: rhelc.Arch,
Module: rhelc.Module,
Cpes: rc.CPEs,
Executables: rhelc.Executables,
Executables: nil,
}
if rhelc.Executables != nil {
comp.Executables = convertExecutables(rhelc.Executables)
}
compKey := makeComponentKey(comp)
if compKey != "" {
Expand All @@ -108,6 +111,26 @@ func convertAndDedupRHELComponents(rc *database.RHELv2Components) []*scannerV1.R
return maps.Values(convertedComponents)
}

func makeComponentKey(component *scannerV1.RHELComponent) string {
func convertExecutables(exe []*scannerV1.Executable) []*storage.NodeInventory_Components_RHELComponent_Executable {
arr := make([]*storage.NodeInventory_Components_RHELComponent_Executable, len(exe))
for i, executable := range exe {
arr[i] = &storage.NodeInventory_Components_RHELComponent_Executable{
Path: executable.GetPath(),
RequiredFeatures: nil,
}
if executable.GetRequiredFeatures() != nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for switchting to getters here, as discussed in the sync review!

arr[i].RequiredFeatures = make([]*storage.NodeInventory_Components_RHELComponent_Executable_FeatureNameVersion, len(executable.GetRequiredFeatures()))
for i2, fnv := range executable.GetRequiredFeatures() {
arr[i].RequiredFeatures[i2] = &storage.NodeInventory_Components_RHELComponent_Executable_FeatureNameVersion{
Name: fnv.GetName(),
Version: fnv.GetVersion(),
}
}
}
}
return arr
}

func makeComponentKey(component *storage.NodeInventory_Components_RHELComponent) string {
return component.Name + ":" + component.Version + ":" + component.Arch + ":" + component.Module
}
88 changes: 79 additions & 9 deletions compliance/collection/nodeinventorizer/nodeinventory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package nodeinventorizer
import (
"testing"

"github.com/stackrox/rox/generated/storage"
"github.com/stackrox/scanner/database"
scannerV1 "github.com/stackrox/scanner/generated/scanner/api/v1"
"github.com/stretchr/testify/suite"
Expand All @@ -19,12 +20,12 @@ type NodeInventorizerTestSuite struct {
func (s *NodeInventorizerTestSuite) TestConvertRHELComponentIDs() {
testCases := map[string]struct {
inComponents []*database.RHELv2Package
outComponents []*scannerV1.RHELComponent
outComponents []*storage.NodeInventory_Components_RHELComponent
expectedLen int
}{
"nil-inComponents": {
inComponents: nil,
outComponents: make([]*scannerV1.RHELComponent, 0),
outComponents: make([]*storage.NodeInventory_Components_RHELComponent, 0),
},
"one-component": {
inComponents: []*database.RHELv2Package{
Expand All @@ -38,7 +39,7 @@ func (s *NodeInventorizerTestSuite) TestConvertRHELComponentIDs() {
},
},
},
outComponents: []*scannerV1.RHELComponent{
outComponents: []*storage.NodeInventory_Components_RHELComponent{
{
Id: 0,
Name: "zlib",
Expand Down Expand Up @@ -66,7 +67,7 @@ func (s *NodeInventorizerTestSuite) TestConvertRHELComponentIDs() {
Arch: "x86_64",
},
},
outComponents: []*scannerV1.RHELComponent{
outComponents: []*storage.NodeInventory_Components_RHELComponent{
{
Id: 0,
Name: "zlib",
Expand Down Expand Up @@ -97,7 +98,7 @@ func (s *NodeInventorizerTestSuite) TestConvertRHELComponentIDs() {
Arch: "x86_64",
},
},
outComponents: []*scannerV1.RHELComponent{
outComponents: []*storage.NodeInventory_Components_RHELComponent{
{
Id: 0,
Name: "redhat-release",
Expand Down Expand Up @@ -129,11 +130,11 @@ func (s *NodeInventorizerTestSuite) TestConvertRHELComponentIDs() {

func (s *NodeInventorizerTestSuite) TestMakeComponentKey() {
testcases := map[string]struct {
component *scannerV1.RHELComponent
component *storage.NodeInventory_Components_RHELComponent
expected string
}{
"Full component": {
component: &scannerV1.RHELComponent{
component: &storage.NodeInventory_Components_RHELComponent{
Id: 0,
Name: "Name",
Version: "1.2.3",
Expand All @@ -143,7 +144,7 @@ func (s *NodeInventorizerTestSuite) TestMakeComponentKey() {
expected: "Name:1.2.3:x42:Mod",
},
"Missing part": {
component: &scannerV1.RHELComponent{
component: &storage.NodeInventory_Components_RHELComponent{
Id: 0,
Version: "1.2.3",
Arch: "x42",
Expand All @@ -152,7 +153,7 @@ func (s *NodeInventorizerTestSuite) TestMakeComponentKey() {
expected: ":1.2.3:x42:Mod",
},
"Internationalized": {
component: &scannerV1.RHELComponent{
component: &storage.NodeInventory_Components_RHELComponent{
Id: 0,
Name: "日本語",
Version: "1.2.3",
Expand All @@ -169,3 +170,72 @@ func (s *NodeInventorizerTestSuite) TestMakeComponentKey() {
})
}
}

func (s *NodeInventorizerTestSuite) TestConvertExecutable() {
testcases := map[string]struct {
exe []*scannerV1.Executable
expected []*storage.NodeInventory_Components_RHELComponent_Executable
}{
"RequiredFeatures not empty": {
exe: []*scannerV1.Executable{
{
Path: "/root/1",
RequiredFeatures: []*scannerV1.FeatureNameVersion{
{
Name: "name1",
Version: "version1",
},
},
},
},
expected: []*storage.NodeInventory_Components_RHELComponent_Executable{
{
Path: "/root/1",
RequiredFeatures: []*storage.NodeInventory_Components_RHELComponent_Executable_FeatureNameVersion{
{
Name: "name1",
Version: "version1",
},
},
},
},
},
"RequiredFeatures empty": {
exe: []*scannerV1.Executable{
{
Path: "/root/1",
RequiredFeatures: []*scannerV1.FeatureNameVersion{},
},
},
expected: []*storage.NodeInventory_Components_RHELComponent_Executable{
{
Path: "/root/1",
RequiredFeatures: []*storage.NodeInventory_Components_RHELComponent_Executable_FeatureNameVersion{},
},
},
},
"RequiredFeatures nil": {
exe: []*scannerV1.Executable{
{
Path: "/root/1",
RequiredFeatures: nil,
},
},
expected: []*storage.NodeInventory_Components_RHELComponent_Executable{
{
Path: "/root/1",
RequiredFeatures: nil,
},
},
},
}

for testName, testCase := range testcases {
s.Run(testName, func() {
for i, got := range convertExecutables(testCase.exe) {
s.Equal(testCase.expected[i].GetPath(), got.GetPath())
s.Equal(testCase.expected[i].GetRequiredFeatures(), got.GetRequiredFeatures())
}
})
}
}
Loading