Skip to content

Commit

Permalink
feat: cyclondx sbom custom property support (#4688)
Browse files Browse the repository at this point in the history
* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

* feat: custom property support

Signed-off-by: chenk <hen.keinan@gmail.com>

---------

Signed-off-by: chenk <hen.keinan@gmail.com>
  • Loading branch information
chen-keinan authored Jun 22, 2023
1 parent e1770e0 commit e3d10d2
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 94 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
github.com/aquasecurity/tml v0.6.1
github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230619083756-6eb60789faeb
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230621132350-8e98a8fabf9d
github.com/aws/aws-sdk-go v1.44.245
github.com/aws/aws-sdk-go-v2 v1.18.0
github.com/aws/aws-sdk-go-v2/config v1.18.25
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,8 @@ github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c h1:mFMfHmb5G
github.com/aquasecurity/trivy-db v0.0.0-20230515061101-378ab9ed302c/go.mod h1:s7x7CTxYeiFf6gPOakSsg4mCD93au4dbYplG4h0FGrs=
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 h1:0eS+V7SXHgqoT99tV1mtMW6HL4HdoB9qGLMCb1fZp8A=
github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230619083756-6eb60789faeb h1:5htNYck1farYXZrNfTuAgfULRQJnK73eQ+1Rj1CE8tA=
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230619083756-6eb60789faeb/go.mod h1:GCm7uq++jz7Ij8cA9mAorpKJ9/qSBCl7v6EKYA8DxJ8=
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230621132350-8e98a8fabf9d h1:jcuZYglWR+KQOcb6Tg/vXM3yecMAEJmH9FDIbPRH0JQ=
github.com/aquasecurity/trivy-kubernetes v0.5.7-0.20230621132350-8e98a8fabf9d/go.mod h1:GCm7uq++jz7Ij8cA9mAorpKJ9/qSBCl7v6EKYA8DxJ8=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
Expand Down
62 changes: 47 additions & 15 deletions pkg/k8s/scanner/scanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import (
"bytes"
"context"
"fmt"
"sort"
"strings"

"golang.org/x/xerrors"

ms "github.com/mitchellh/mapstructure"
"github.com/package-url/packageurl-go"
"github.com/samber/lo"

"github.com/aquasecurity/go-version/pkg/version"

Expand All @@ -32,6 +34,13 @@ import (
"github.com/aquasecurity/trivy/pkg/types"
)

const (
k8sCoreComponentNamespace = core.Namespace + "k8s:component" + ":"
k8sComponentType = "Type"
k8sComponentName = "Name"
k8sComponentNode = "node"
)

type Scanner struct {
cluster string
runner cmd.Runner
Expand Down Expand Up @@ -215,16 +224,16 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact, clusterName
Type: cdx.ComponentTypeContainer,
Name: name,
Version: cDigest,
Properties: map[string]string{
cyc.PropertyPkgID: fmt.Sprintf("%s:%s", name, version),
cyc.PropertyPkgType: oci,
Properties: []core.Property{
{Name: cyc.PropertyPkgID, Value: fmt.Sprintf("%s:%s", name, version)},
{Name: cyc.PropertyPkgType, Value: oci},
},
})
}
rootComponent := &core.Component{
Name: comp.Name,
Type: cdx.ComponentTypeApplication,
Properties: comp.Properties,
Properties: toProperties(comp.Properties, k8sCoreComponentNamespace),
Components: imageComponents,
}
coreComponents = append(coreComponents, rootComponent)
Expand Down Expand Up @@ -289,34 +298,41 @@ func nodeComponent(nf bom.NodeInfo) *core.Component {
osName, osVersion := osNameVersion(nf.OsImage)
runtimeName, runtimeVersion := runtimeNameVersion(nf.ContainerRuntimeVersion)
kubeletVersion := sanitizedVersion(nf.KubeletVersion)
properties := toProperties(nf.Properties, "")
properties = append(properties, toProperties(map[string]string{
k8sComponentType: k8sComponentNode,
k8sComponentName: nf.NodeName,
}, k8sCoreComponentNamespace)...)
return &core.Component{
Type: cdx.ComponentTypeContainer,
Name: nf.NodeName,
Properties: nf.Properties,
Properties: properties,
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: osName,
Version: osVersion,
Properties: map[string]string{
"Class": types.ClassOSPkg,
"Type": osName,
Properties: []core.Property{
{Name: "Class", Value: types.ClassOSPkg},
{Name: "Type", Value: osName},
},
},
{
Type: cdx.ComponentTypeApplication,
Name: nodeCoreComponents,
Properties: map[string]string{
"Class": types.ClassLangPkg,
"Type": golang,
Properties: []core.Property{
{Name: "Class", Value: types.ClassLangPkg},
{Name: "Type", Value: golang},
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: kubelet,
Version: kubeletVersion,
Properties: map[string]string{
cyc.PropertyPkgType: golang,
Properties: []core.Property{
{Name: k8sComponentType, Value: k8sComponentNode, Namespace: k8sCoreComponentNamespace},
{Name: k8sComponentName, Value: kubelet, Namespace: k8sCoreComponentNamespace},
{Name: cyc.PropertyPkgType, Value: golang},
},
PackageURL: &purl.PackageURL{
PackageURL: *packageurl.NewPackageURL(golang, "", kubelet, kubeletVersion, packageurl.Qualifiers{}, ""),
Expand All @@ -326,8 +342,10 @@ func nodeComponent(nf bom.NodeInfo) *core.Component {
Type: cdx.ComponentTypeLibrary,
Name: runtimeName,
Version: runtimeVersion,
Properties: map[string]string{
cyc.PropertyPkgType: golang,
Properties: []core.Property{
{Name: k8sComponentType, Value: k8sComponentNode, Namespace: k8sCoreComponentNamespace},
{Name: k8sComponentName, Value: runtimeName, Namespace: k8sCoreComponentNamespace},
{Name: cyc.PropertyPkgType, Value: golang},
},
PackageURL: &purl.PackageURL{
PackageURL: *packageurl.NewPackageURL(golang, "", runtimeName, runtimeVersion, packageurl.Qualifiers{}, ""),
Expand All @@ -338,3 +356,17 @@ func nodeComponent(nf bom.NodeInfo) *core.Component {
},
}
}

func toProperties(props map[string]string, namespace string) []core.Property {
properties := lo.MapToSlice(props, func(k, v string) core.Property {
return core.Property{
Name: k,
Value: v,
Namespace: namespace,
}
})
sort.Slice(properties, func(i, j int) bool {
return properties[i].Name < properties[j].Name
})
return properties
}
48 changes: 27 additions & 21 deletions pkg/k8s/scanner/scanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ func TestK8sClusterInfoReport(t *testing.T) {
{
Type: cdx.ComponentTypeApplication,
Name: "kube-apiserver-kind-control-plane",
Properties: map[string]string{
"ControlPlaneComponents": "kube-apiserver",
Properties: []core.Property{
{Name: "ControlPlaneComponents", Value: "kube-apiserver", Namespace: k8sCoreComponentNamespace},
},
Components: []*core.Component{
{
Expand All @@ -102,47 +102,51 @@ func TestK8sClusterInfoReport(t *testing.T) {
},
},
},
Properties: map[string]string{
cyc.PropertyPkgID: "k8s.gcr.io/kube-apiserver:1.21.1",
cyc.PropertyPkgType: "oci",
Properties: []core.Property{
{Name: cyc.PropertyPkgID, Value: "k8s.gcr.io/kube-apiserver:1.21.1"},
{Name: cyc.PropertyPkgType, Value: "oci"},
},
},
},
},
{
Type: cdx.ComponentTypeContainer,
Name: "kind-control-plane",
Properties: map[string]string{
"Architecture": "arm64",
"HostName": "kind-control-plane",
"KernelVersion": "6.2.15-300.fc38.aarch64",
"NodeRole": "master",
"OperatingSystem": "linux",
Properties: []core.Property{
{Name: "Architecture", Value: "arm64"},
{Name: "HostName", Value: "kind-control-plane"},
{Name: "KernelVersion", Value: "6.2.15-300.fc38.aarch64"},
{Name: "NodeRole", Value: "master"},
{Name: "OperatingSystem", Value: "linux"},
{Name: k8sComponentName, Value: "kind-control-plane", Namespace: k8sCoreComponentNamespace},
{Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace},
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: "ubuntu",
Version: "21.04",
Properties: map[string]string{
"Class": "os-pkgs",
"Type": "ubuntu",
Properties: []core.Property{
{Name: "Class", Value: "os-pkgs", Namespace: ""},
{Name: "Type", Value: "ubuntu", Namespace: ""},
},
},
{
Type: cdx.ComponentTypeApplication,
Name: "node-core-components",
Properties: map[string]string{
"Class": "lang-pkgs",
"Type": "golang",
Properties: []core.Property{
{Name: "Class", Value: "lang-pkgs", Namespace: ""},
{Name: "Type", Value: "golang", Namespace: ""},
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: "k8s.io/kubelet",
Version: "1.21.1",
Properties: map[string]string{
"PkgType": "golang",
Properties: []core.Property{
{Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace},
{Name: k8sComponentName, Value: "k8s.io/kubelet", Namespace: k8sCoreComponentNamespace},
{Name: "PkgType", Value: "golang", Namespace: ""},
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Expand All @@ -157,8 +161,10 @@ func TestK8sClusterInfoReport(t *testing.T) {
Type: cdx.ComponentTypeLibrary,
Name: "github.com/containerd/containerd",
Version: "1.5.2",
Properties: map[string]string{
cyc.PropertyPkgType: "golang",
Properties: []core.Property{
{Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace},
{Name: k8sComponentName, Value: "github.com/containerd/containerd", Namespace: k8sCoreComponentNamespace},
{Name: "PkgType", Value: "golang", Namespace: ""},
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Expand Down
32 changes: 22 additions & 10 deletions pkg/sbom/cyclonedx/core/cyclonedx.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,18 @@ type Component struct {
Licenses []string
Hashes []digest.Digest
Supplier string
Properties map[string]string
Properties []Property

Components []*Component
Vulnerabilities []types.DetectedVulnerability
}

type Property struct {
Name string
Value string
Namespace string
}

func NewCycloneDX(version string, opts ...Option) *CycloneDX {
c := &CycloneDX{
appVersion: version,
Expand Down Expand Up @@ -291,17 +297,23 @@ func (c *CycloneDX) Licenses(licenses []string) *cdx.Licenses {
return lo.ToPtr(cdx.Licenses(choices))
}

func (c *CycloneDX) Properties(props map[string]string) []cdx.Property {
properties := lo.MapToSlice(props, func(k, v string) cdx.Property {
return cdx.Property{
Name: Namespace + k,
Value: v,
func (c *CycloneDX) Properties(properties []Property) []cdx.Property {
cdxProps := make([]cdx.Property, 0, len(properties))
for _, property := range properties {
namespace := Namespace
if len(property.Namespace) > 0 {
namespace = property.Namespace
}
cdxProps = append(cdxProps,
cdx.Property{
Name: namespace + property.Name,
Value: property.Value,
})
}
sort.Slice(cdxProps, func(i, j int) bool {
return cdxProps[i].Name < cdxProps[j].Name
})
sort.Slice(properties, func(i, j int) bool {
return properties[i].Name < properties[j].Name
})
return properties
return cdxProps
}

func IsTrivySBOM(c *cdx.BOM) bool {
Expand Down
42 changes: 21 additions & 21 deletions pkg/sbom/cyclonedx/core/cyclonedx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ func TestMarshaler_CoreComponent(t *testing.T) {
{
Type: cdx.ComponentTypeApplication,
Name: "kube-apiserver-kind-control-plane",
Properties: map[string]string{
"control_plane_components": "kube-apiserver",
Properties: []core.Property{
{Name: "control_plane_components", Value: "kube-apiserver"},
},
Components: []*core.Component{
{
Expand All @@ -57,47 +57,47 @@ func TestMarshaler_CoreComponent(t *testing.T) {
},
},
Hashes: []digest.Digest{"sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f"},
Properties: map[string]string{
"PkgID": "k8s.gcr.io/kube-apiserver:1.21.1",
"PkgType": "oci",
Properties: []core.Property{
{Name: "PkgID", Value: "k8s.gcr.io/kube-apiserver:1.21.1"},
{Name: "PkgType", Value: "oci"},
},
},
},
},
{
Type: cdx.ComponentTypeContainer,
Name: "kind-control-plane",
Properties: map[string]string{
"architecture": "arm64",
"host_name": "kind-control-plane",
"kernel_version": "6.2.13-300.fc38.aarch64",
"node_role": "master",
"operating_system": "linux",
Properties: []core.Property{
{Name: "architecture", Value: "arm64"},
{Name: "host_name", Value: "kind-control-plane"},
{Name: "kernel_version", Value: "6.2.13-300.fc38.aarch64"},
{Name: "node_role", Value: "master"},
{Name: "operating_system", Value: "linux"},
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeOS,
Name: "ubuntu",
Version: "21.04",
Properties: map[string]string{
"Class": "os-pkgs",
"Type": "ubuntu",
Properties: []core.Property{
{Name: "Class", Value: "os-pkgs"},
{Name: "Type", Value: "ubuntu"},
},
},
{
Type: cdx.ComponentTypeApplication,
Name: "node-core-components",
Properties: map[string]string{
"Class": "lang-pkgs",
"Type": "golang",
Properties: []core.Property{
{Name: "Class", Value: "lang-pkgs"},
{Name: "Type", Value: "golang"},
},
Components: []*core.Component{
{
Type: cdx.ComponentTypeLibrary,
Name: "kubelet",
Version: "1.21.1",
Properties: map[string]string{
"PkgType": "golang",
Properties: []core.Property{
{Name: "PkgType", Value: "golang"},
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Expand All @@ -112,8 +112,8 @@ func TestMarshaler_CoreComponent(t *testing.T) {
Type: cdx.ComponentTypeLibrary,
Name: "containerd",
Version: "1.5.2",
Properties: map[string]string{
"PkgType": "golang",
Properties: []core.Property{
{Name: "PkgType", Value: "golang"},
},
PackageURL: &purl.PackageURL{
PackageURL: packageurl.PackageURL{
Expand Down
Loading

0 comments on commit e3d10d2

Please sign in to comment.