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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

Expand Down Expand Up @@ -56,6 +57,10 @@ type fakeProfileClient struct {

var _ storage.ProfileClient = (*fakeProfileClient)(nil)

func (f *fakeProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (f *fakeProfileClient) GetContainerProfile(_ context.Context, _, name string) (*v1beta1.ContainerProfile, error) {
f.getCPCalls++
// Name-keyed authored CPs take precedence: this is how a multi-container pod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// hostEventContainer builds the host pseudo-container event
Expand Down Expand Up @@ -131,6 +132,10 @@ type signallingProfileClient struct {

var _ storage.ProfileClient = (*signallingProfileClient)(nil)

func (c *signallingProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (c *signallingProfileClient) GetContainerProfile(_ context.Context, _, _ string) (*v1beta1.ContainerProfile, error) {
c.once.Do(func() { close(c.reached) })
return c.cp, nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/kubescape/node-agent/pkg/storage"
"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

Expand Down Expand Up @@ -60,6 +61,10 @@ func newFakeStorage(cp *v1beta1.ContainerProfile) *stubStorage {
return &stubStorage{cp: cp}
}

func (s *stubStorage) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (s *stubStorage) GetContainerProfile(_ context.Context, _, _ string) (*v1beta1.ContainerProfile, error) {
s.mu.RLock()
defer s.mu.RUnlock()
Expand Down
17 changes: 17 additions & 0 deletions pkg/objectcache/containerprofilecache/reconciler_checksum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

Expand Down Expand Up @@ -54,6 +55,10 @@ type checksumRecordingClient struct {

var _ storage.ProfileClient = (*checksumRecordingClient)(nil)

func (c *checksumRecordingClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (c *checksumRecordingClient) GetContainerProfile(ctx context.Context, _, name string) (*v1beta1.ContainerProfile, error) {
c.mu.Lock()
c.fetches = append(c.fetches, recordedFetch{name: name, checksum: storage.KnownChecksumFromContext(ctx)})
Expand Down Expand Up @@ -387,6 +392,10 @@ type blockingSpecProfileClient struct {

var _ storage.ProfileClient = (*blockingSpecProfileClient)(nil)

func (c *blockingSpecProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (c *blockingSpecProfileClient) GetContainerProfile(ctx context.Context, _, _ string) (*v1beta1.ContainerProfile, error) {
select {
case c.entered <- struct{}{}:
Expand Down Expand Up @@ -509,6 +518,10 @@ type conditionalChecksumClient struct {

var _ storage.ProfileClient = (*conditionalChecksumClient)(nil)

func (c *conditionalChecksumClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (c *conditionalChecksumClient) GetContainerProfile(ctx context.Context, _, _ string) (*v1beta1.ContainerProfile, error) {
c.mu.Lock()
defer c.mu.Unlock()
Expand Down Expand Up @@ -966,6 +979,10 @@ type blockingFetchClient struct {

var _ storage.ProfileClient = (*blockingFetchClient)(nil)

func (c *blockingFetchClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (c *blockingFetchClient) GetContainerProfile(ctx context.Context, _, name string) (*v1beta1.ContainerProfile, error) {
active := c.active.Add(1)
defer c.active.Add(-1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

Expand All @@ -18,6 +19,10 @@ type scriptedProfileClient struct {
errByName map[string]error
}

func (s *scriptedProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (s *scriptedProfileClient) GetContainerProfile(_ context.Context, _, name string) (*v1beta1.ContainerProfile, error) {
if err, ok := s.errByName[name]; ok {
return nil, err
Expand Down
17 changes: 17 additions & 0 deletions pkg/objectcache/containerprofilecache/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
)
Expand Down Expand Up @@ -76,6 +77,10 @@ type countingProfileClient struct {

var _ storage.ProfileClient = (*countingProfileClient)(nil)

func (f *countingProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (f *countingProfileClient) GetContainerProfile(_ context.Context, _, name string) (*v1beta1.ContainerProfile, error) {
f.cpCalls.Add(1)
if f.userCP != nil && name == f.userCP.Name {
Expand Down Expand Up @@ -568,6 +573,10 @@ type userCPErrorClient struct {

var _ storage.ProfileClient = (*userCPErrorClient)(nil)

func (o *userCPErrorClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (o *userCPErrorClient) GetContainerProfile(_ context.Context, _, name string) (*v1beta1.ContainerProfile, error) {
if name == o.userName {
return nil, o.userCPErr
Expand Down Expand Up @@ -613,6 +622,10 @@ type failingProfileClient struct {

var _ storage.ProfileClient = (*failingProfileClient)(nil)

func (f *failingProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return nil, f.cpErr
}

func (f *failingProfileClient) GetContainerProfile(_ context.Context, _, _ string) (*v1beta1.ContainerProfile, error) {
return nil, f.cpErr
}
Expand Down Expand Up @@ -687,6 +700,10 @@ type blockingProfileClient struct {

var _ storage.ProfileClient = (*blockingProfileClient)(nil)

func (b *blockingProfileClient) ListContainerProfiles(_ context.Context, _ string, _ metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return &v1beta1.ContainerProfileList{}, nil
}

func (b *blockingProfileClient) GetContainerProfile(ctx context.Context, _, _ string) (*v1beta1.ContainerProfile, error) {
b.blocked <- struct{}{} // buffered(1): stored if reader hasn't arrived yet
select {
Expand Down
4 changes: 4 additions & 0 deletions pkg/storage/storage_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import (

type ProfileClient interface {
GetContainerProfile(ctx context.Context, namespace, name string) (*v1beta1.ContainerProfile, error)
// ListContainerProfiles lists ContainerProfiles in a namespace, optionally
// filtered by a label selector — used to gather the fragments of a signed
// bundle (label signature.kubescape.io/bundle=<name>).
ListContainerProfiles(ctx context.Context, namespace string, opts metav1.ListOptions) (*v1beta1.ContainerProfileList, error)
}

// ProfileCreator defines the interface for creating container profiles
Expand Down
21 changes: 21 additions & 0 deletions pkg/storage/storage_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
spdxv1beta1 "github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
beta1 "github.com/kubescape/storage/pkg/generated/clientset/versioned/typed/softwarecomposition/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/watch"
)

Expand Down Expand Up @@ -77,6 +78,26 @@ func (sc *StorageHttpClientMock) GetContainerProfile(_ context.Context, namespac
return nil, nil
}

func (sc *StorageHttpClientMock) ListContainerProfiles(_ context.Context, namespace string, opts metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
sc.containerProfilesMu.Lock()
defer sc.containerProfilesMu.Unlock()
sel, err := labels.Parse(opts.LabelSelector)
if err != nil {
return nil, err
}
out := &v1beta1.ContainerProfileList{}
for _, p := range sc.ContainerProfiles {
if p == nil || (namespace != metav1.NamespaceAll && p.Namespace != namespace) {
continue
}
if !sel.Matches(labels.Set(p.Labels)) {
continue
}
out.Items = append(out.Items, *p)
}
return out, nil
}

func (sc *StorageHttpClientMock) GetSBOMMeta(_ string) (*v1beta1.SBOMSyft, error) {
return sc.mockSBOM, nil
}
Expand Down
87 changes: 87 additions & 0 deletions pkg/storage/storage_mock_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package storage

import (
"context"
"testing"

"github.com/kubescape/storage/pkg/apis/softwarecomposition/v1beta1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func TestStorageHttpClientMock_ListContainerProfiles(t *testing.T) {
mock := &StorageHttpClientMock{
ContainerProfiles: []*v1beta1.ContainerProfile{
{
ObjectMeta: metav1.ObjectMeta{
Name: "cp-1",
Namespace: "default",
Labels: map[string]string{
"app": "frontend",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "cp-2",
Namespace: "default",
Labels: map[string]string{
"app": "backend",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "cp-3",
Namespace: "other",
Labels: map[string]string{
"app": "frontend",
},
},
},
},
}

// 1. List all in default namespace
list, err := mock.ListContainerProfiles(context.Background(), "default", metav1.ListOptions{})
require.NoError(t, err)
assert.Len(t, list.Items, 2)

// 2. List with label selector in default namespace
list, err = mock.ListContainerProfiles(context.Background(), "default", metav1.ListOptions{
LabelSelector: "app=frontend",
})
require.NoError(t, err)
require.Len(t, list.Items, 1)
assert.Equal(t, "cp-1", list.Items[0].Name)

// 3. List in other namespace
list, err = mock.ListContainerProfiles(context.Background(), "other", metav1.ListOptions{})
require.NoError(t, err)
require.Len(t, list.Items, 1)
assert.Equal(t, "cp-3", list.Items[0].Name)

// 4. List in non-existent namespace
list, err = mock.ListContainerProfiles(context.Background(), "nonexistent", metav1.ListOptions{})
require.NoError(t, err)
assert.Empty(t, list.Items)

// 5. List cluster-wide across all namespaces (metav1.NamespaceAll / "")
list, err = mock.ListContainerProfiles(context.Background(), metav1.NamespaceAll, metav1.ListOptions{})
require.NoError(t, err)
assert.Len(t, list.Items, 3)

// 6. List cluster-wide with label selector
list, err = mock.ListContainerProfiles(context.Background(), metav1.NamespaceAll, metav1.ListOptions{
LabelSelector: "app=frontend",
})
require.NoError(t, err)
assert.Len(t, list.Items, 2)

// 7. Invalid label selector returns error
_, err = mock.ListContainerProfiles(context.Background(), "default", metav1.ListOptions{
LabelSelector: "invalid===selector",
})
require.Error(t, err)
}
6 changes: 6 additions & 0 deletions pkg/storage/v1/containerprofile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ func (sc *Storage) GetContainerProfile(ctx context.Context, namespace, name stri
return sc.storageClient.ContainerProfiles(namespace).Get(ctx, name, metav1.GetOptions{})
}

// ListContainerProfiles lists ContainerProfiles in a namespace with the given
// options (typically a LabelSelector) — used to gather signed bundle fragments.
func (sc *Storage) ListContainerProfiles(ctx context.Context, namespace string, opts metav1.ListOptions) (*v1beta1.ContainerProfileList, error) {
return sc.storageClient.ContainerProfiles(namespace).List(ctx, opts)
}

// CreateContainerProfileDirect directly creates the profile without queuing.
// This implements the ProfileCreator interface.
func (sc *Storage) CreateContainerProfileDirect(profile *v1beta1.ContainerProfile) error {
Expand Down
Loading