diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf31259..d848e8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,7 +31,8 @@ jobs: - uses: actions/setup-go@v5 with: - go-version: '1.21' + # Force version to solve cache restore issue: https://github.com/actions/setup-go/issues/506 + go-version: 1.23.2 check-latest: true # https://github.com/actions/setup-go#check-latest-version cache: true # https://github.com/actions/setup-go#caching-dependency-files-and-build-outputs @@ -51,11 +52,11 @@ jobs: - name: Grype scan id: scan - uses: anchore/scan-action@v3 + uses: anchore/scan-action@v5 with: path: "." fail-build: true - severity-cutoff: negligible + severity-cutoff: medium output-format: sarif - name: Upload SARIF report diff --git a/cmd/cyclonexdx.go b/cmd/cyclonexdx.go index 927d63b..2e0928f 100644 --- a/cmd/cyclonexdx.go +++ b/cmd/cyclonexdx.go @@ -249,6 +249,13 @@ func transformToCycloneDXBOM(kbom *model.KBOM) *cyclonedx.BOM { //nolint:funlen }, } + if version, ok := res.AdditionalProperties["version"]; ok { + properties = append(properties, cyclonedx.Property{ + Name: RADPrefix + K8sComponentVersion, + Value: version, + }) + } + if resList.Namespaced { properties = append(properties, cyclonedx.Property{ Name: RADPrefix + "k8s:component:namespace", diff --git a/cmd/generate_test.go b/cmd/generate_test.go index 2e42b05..1626ee4 100644 --- a/cmd/generate_test.go +++ b/cmd/generate_test.go @@ -217,10 +217,12 @@ func TestGenerateKBOM(t *testing.T) { ResourcesCount: 2, Resources: []model.Resource{ { - Name: "backend", + Name: "backend", + AdditionalProperties: map[string]string{"version": "v1.0.0"}, }, { - Name: "frontend", + Name: "frontend", + AdditionalProperties: map[string]string{"version": "v2.0.0"}, }, }, }, @@ -630,10 +632,16 @@ var expectedOutJSON = `{ "count": 2, "resources": [ { - "name": "backend" + "name": "backend", + "additional_properties": { + "version": "v1.0.0" + } }, { - "name": "frontend" + "name": "frontend", + "additional_properties": { + "version": "v2.0.0" + } } ] } diff --git a/cmd/schema_test.go b/cmd/schema_test.go index a7418de..ec56b1f 100644 --- a/cmd/schema_test.go +++ b/cmd/schema_test.go @@ -293,6 +293,12 @@ var expectedSchema = `{ }, "namespace": { "type": "string" + }, + "additional_properties": { + "additionalProperties": { + "type": "string" + }, + "type": "object" } }, "additionalProperties": false, diff --git a/go.mod b/go.mod index 8126c09..76f1244 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,6 @@ module github.com/rad-security/kbom -go 1.22.0 - -toolchain go1.22.3 +go 1.23 require ( github.com/CycloneDX/cyclonedx-go v0.7.2 diff --git a/internal/kube/kube.go b/internal/kube/kube.go index 3ddb109..742e254 100644 --- a/internal/kube/kube.go +++ b/internal/kube/kube.go @@ -14,6 +14,7 @@ import ( "github.com/rs/zerolog/log" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" @@ -370,10 +371,13 @@ func (k *k8sDB) AllResources(ctx context.Context, full bool, namespaceFilter []s if full { for _, item := range resourceList.Items { res := model.Resource{ - Name: item.GetName(), - Namespace: item.GetNamespace(), + Name: item.GetName(), + Namespace: item.GetNamespace(), + AdditionalProperties: map[string]string{}, + } + if version, ok := getVersion(item); ok { + res.AdditionalProperties["version"] = version } - val := resourceMap[gvr.String()] val.Resources = append(val.Resources, res) resourceMap[gvr.String()] = val @@ -385,6 +389,22 @@ func (k *k8sDB) AllResources(ctx context.Context, full bool, namespaceFilter []s return resourceMap, nil } +func getVersion(item unstructured.Unstructured) (version string, ok bool) { + + obj := item.Object + if obj == nil { + return "", false + } + + spec, ok := obj["spec"].(map[string]interface{}) + if !ok { + return "", false + } + + version, ok = spec["version"].(string) + return +} + func getLabelValue(labels map[string]string, key string) string { for k, v := range labels { if k == key { diff --git a/internal/model/kbom.go b/internal/model/kbom.go index d08d0df..584e043 100644 --- a/internal/model/kbom.go +++ b/internal/model/kbom.go @@ -63,10 +63,11 @@ type Components struct { } type Resource struct { - Kind string `json:"kind,omitempty"` - APIVersion string `json:"api_version,omitempty"` - Name string `json:"name"` - Namespace string `json:"namespace,omitempty"` + Kind string `json:"kind,omitempty"` + APIVersion string `json:"api_version,omitempty"` + Name string `json:"name"` + Namespace string `json:"namespace,omitempty"` + AdditionalProperties map[string]string `json:"additional_properties,omitempty"` } type ResourceList struct {