Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add effective scan config to assetScan annotations #739

Merged
merged 10 commits into from
Oct 6, 2023
2 changes: 1 addition & 1 deletion cmd/vmclarity-cli/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ var ScanCmd = &cobra.Command{
families.SetMountPointsForFamiliesInput(mountPoints, config)
}

err = cli.MarkInProgress(ctx)
err = cli.MarkInProgress(ctx, config)
if err != nil {
return fmt.Errorf("failed to inform server %v scan has started: %w", server, err)
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apiserver/database/gorm/odata.go
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ var schemaMetas = map[string]odatasql.SchemaMeta{
"scansCount": odatasql.FieldMeta{FieldType: odatasql.NumberFieldType},
"assetInfo": odatasql.FieldMeta{
FieldType: odatasql.ComplexFieldType,
ComplexFieldSchemas: []string{"VMInfo", "ContainerInfo", "ContainerImageInfo"},
ComplexFieldSchemas: []string{"VMInfo", "DirInfo", "ContainerInfo", "ContainerImageInfo"},
DiscriminatorProperty: "objectType",
},
"summary": odatasql.FieldMeta{
Expand Down
3 changes: 2 additions & 1 deletion pkg/cli/state/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package state
import (
"context"

"github.com/openclarity/vmclarity/pkg/shared/families"
"github.com/openclarity/vmclarity/pkg/shared/families/types"
"github.com/openclarity/vmclarity/pkg/shared/log"
)
Expand All @@ -28,7 +29,7 @@ func (l *LocalState) WaitForReadyState(context.Context) error {
return nil
}

func (l *LocalState) MarkInProgress(ctx context.Context) error {
func (l *LocalState) MarkInProgress(ctx context.Context, _ *families.Config) error {
logger := log.GetLoggerFromContextOrDiscard(ctx)
logger.Info("Scanning is in progress")
return nil
Expand Down
3 changes: 2 additions & 1 deletion pkg/cli/state/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ package state
import (
"context"

"github.com/openclarity/vmclarity/pkg/shared/families"
"github.com/openclarity/vmclarity/pkg/shared/families/types"
)

type Manager interface {
WaitForReadyState(context.Context) error
MarkInProgress(context.Context) error
MarkInProgress(context.Context, *families.Config) error
MarkFamilyScanInProgress(context.Context, types.FamilyType) error
MarkDone(context.Context, []error) error
IsAborted(ctx context.Context) (bool, error)
Expand Down
33 changes: 31 additions & 2 deletions pkg/cli/state/vmclarity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@ package state

import (
"context"
"encoding/json"
"errors"
"fmt"
"time"

"github.com/openclarity/vmclarity/api/models"
"github.com/openclarity/vmclarity/pkg/shared/backendclient"
"github.com/openclarity/vmclarity/pkg/shared/families"
"github.com/openclarity/vmclarity/pkg/shared/families/types"
"github.com/openclarity/vmclarity/pkg/shared/log"
"github.com/openclarity/vmclarity/pkg/shared/utils"
)

const (
DefaultWaitForVolRetryInterval = 15 * time.Second
DefaultWaitForVolRetryInterval = 15 * time.Second
effectiveScanConfigAnnotationKey = "openclarity.io/vmclarity-scanner/config"
)

type AssetScanID = models.AssetScanID
Expand Down Expand Up @@ -75,7 +78,7 @@ func (v *VMClarityState) WaitForReadyState(ctx context.Context) error {
}
}

func (v *VMClarityState) MarkInProgress(ctx context.Context) error {
func (v *VMClarityState) MarkInProgress(ctx context.Context, config *families.Config) error {
assetScan, err := v.client.GetAssetScan(ctx, v.assetScanID, models.GetAssetScansAssetScanIDParams{})
if err != nil {
return fmt.Errorf("failed to get asset scan: %w", err)
Expand All @@ -100,6 +103,11 @@ func (v *VMClarityState) MarkInProgress(ctx context.Context) error {
assetScan.Status.General.State = &state
assetScan.Status.General.LastTransitionTime = utils.PointerTo(time.Now())

assetScan.Annotations, err = appendEffectiveScanConfigAnnotation(assetScan.Annotations, config)
if err != nil {
return fmt.Errorf("failed to add effective scan config annotation: %w", err)
}

err = v.client.PatchAssetScan(ctx, assetScan, v.assetScanID)
if err != nil {
return fmt.Errorf("failed to patch asset scan: %w", err)
Expand Down Expand Up @@ -407,3 +415,24 @@ func NewVMClarityState(client *backendclient.BackendClient, id AssetScanID) (*VM
assetScanID: id,
}, nil
}

func appendEffectiveScanConfigAnnotation(annotations *models.Annotations, config *families.Config) (*models.Annotations, error) {
configJSON, err := json.Marshal(config)
if err != nil {
return nil, fmt.Errorf("failed to marshal effective families config: %w", err)
}
effectiveScanConfigAnnotations := models.Annotations{
{
Key: utils.PointerTo(effectiveScanConfigAnnotationKey),
Value: utils.PointerTo(string(configJSON)),
},
}

if annotations == nil {
return &effectiveScanConfigAnnotations, nil
}
newAnnotations := *annotations
newAnnotations = append(newAnnotations, effectiveScanConfigAnnotations...)
Tehsmash marked this conversation as resolved.
Show resolved Hide resolved

return &newAnnotations, nil
}
Tehsmash marked this conversation as resolved.
Show resolved Hide resolved
159 changes: 159 additions & 0 deletions pkg/cli/state/vmclarity_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Copyright © 2023 Cisco Systems, Inc. and its affiliates.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package state

import (
"reflect"
"testing"

"github.com/openclarity/kubeclarity/shared/pkg/config"

"github.com/openclarity/vmclarity/api/models"
"github.com/openclarity/vmclarity/pkg/shared/families"
"github.com/openclarity/vmclarity/pkg/shared/families/sbom"
"github.com/openclarity/vmclarity/pkg/shared/families/types"
"github.com/openclarity/vmclarity/pkg/shared/utils"
)

var effectiveScanConfigJSON = `{"sbom":{"Enabled":true,"AnalyzersList":["syft"],"Inputs":[{"StripPathFromResult":null,"Input":"test","InputType":"dir"}],"MergeWith":null,"AnalyzersConfig":{"Registry":null,"Analyzer":{"OutputFormat":"","AnalyzerList":["syft"],"Scope":"","TrivyConfig":{"Timeout":0,"CacheDir":"","TempDir":""}},"Scanner":null,"LocalImageScan":false}},"vulnerabilities":{"Enabled":false,"ScannersList":null,"Inputs":null,"InputFromSbom":false,"ScannersConfig":null},"secrets":{"Enabled":false,"ScannersList":null,"StripInputPaths":false,"Inputs":null,"ScannersConfig":null},"rootkits":{"Enabled":false,"ScannersList":null,"StripInputPaths":false,"Inputs":null,"ScannersConfig":null},"malware":{"Enabled":false,"ScannersList":null,"StripInputPaths":false,"Inputs":null,"ScannersConfig":null},"misconfiguration":{"enabled":false,"ScannersList":null,"StripInputPaths":false,"Inputs":null,"ScannersConfig":{"Lynis":{"InstallPath":""}}},"infofinder":{"enabled":false,"ScannersList":null,"StripInputPaths":false,"Inputs":null,"ScannersConfig":{"SSHTopology":{}}},"exploits":{"enabled":false,"ScannersList":null,"Inputs":null,"InputFromVuln":false,"ScannersConfig":null}}`
chrisgacsal marked this conversation as resolved.
Show resolved Hide resolved

func Test_appendEffectiveScanConfigAnnotation(t *testing.T) {
type args struct {
annotations *models.Annotations
config *families.Config
}
tests := []struct {
name string
args args
want *models.Annotations
wantErr bool
}{
{
name: "annotations is nil",
args: args{
annotations: nil,
config: &families.Config{
SBOM: sbom.Config{
Enabled: true,
AnalyzersList: []string{"syft"},
Inputs: []types.Input{
{
Input: "test",
InputType: "dir",
},
},
AnalyzersConfig: &config.Config{
Analyzer: &config.Analyzer{
AnalyzerList: []string{"syft"},
},
},
},
},
},
want: &models.Annotations{
{
Key: utils.PointerTo(effectiveScanConfigAnnotationKey),
Value: utils.PointerTo(effectiveScanConfigJSON),
},
},
},
{
name: "annotations is empty list",
args: args{
annotations: &models.Annotations{},
config: &families.Config{
SBOM: sbom.Config{
Enabled: true,
AnalyzersList: []string{"syft"},
Inputs: []types.Input{
{
Input: "test",
InputType: "dir",
},
},
AnalyzersConfig: &config.Config{
Analyzer: &config.Analyzer{
AnalyzerList: []string{"syft"},
},
},
},
},
},
want: &models.Annotations{
{
Key: utils.PointerTo(effectiveScanConfigAnnotationKey),
Value: utils.PointerTo(effectiveScanConfigJSON),
},
},
},
{
name: "annotations is not empty",
args: args{
annotations: &models.Annotations{
{
Key: utils.PointerTo("test"),
Value: utils.PointerTo("test"),
},
},
config: &families.Config{
SBOM: sbom.Config{
Enabled: true,
AnalyzersList: []string{"syft"},
Inputs: []types.Input{
{
Input: "test",
InputType: "dir",
},
},
AnalyzersConfig: &config.Config{
Analyzer: &config.Analyzer{
AnalyzerList: []string{"syft"},
},
},
},
},
},
want: &models.Annotations{
{
Key: utils.PointerTo("test"),
Value: utils.PointerTo("test"),
},
{
Key: utils.PointerTo(effectiveScanConfigAnnotationKey),
Value: utils.PointerTo(effectiveScanConfigJSON),
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := appendEffectiveScanConfigAnnotation(tt.args.annotations, tt.args.config)
if (err != nil) != tt.wantErr {
t.Errorf("appendEffectiveScanConfigAnnotation() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Error("appendEffectiveScanConfigAnnotation() test failed")
for _, g := range *got {
t.Errorf("got key = %s, value = %s", *g.Key, *g.Value)
}
for _, w := range *tt.want {
t.Errorf("want key = %s, value = %s", *w.Key, *w.Value)
}
}
})
}
}