Skip to content

Commit f208adf

Browse files
committed
add logic for skip-gc behavior of ImageManifestVuln
1 parent 4ec43ee commit f208adf

File tree

5 files changed

+70
-12
lines changed

5 files changed

+70
-12
lines changed

deploy/manifests/container-security-operator/1.0.1/container-security-operator.v1.0.1.clusterserviceversion.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,20 @@ metadata:
99
description: Identify image vulnerabilities in Kubernetes pods
1010
repository: https://github.com/quay/container-security-operator
1111
tectonic-visibility: ocs
12+
alm-examples: |-
13+
[
14+
{
15+
"apiVersion": "secscan.quay.redhat.com/v1alpha1",
16+
"kind": "ImageManifestVuln",
17+
"metadata": {
18+
"name": "example",
19+
"annotations": {
20+
"imagemanifestvuln.skip-gc": "true"
21+
}
22+
},
23+
"spec": {}
24+
}
25+
]
1226
name: container-security-operator.v1.0.1
1327
namespace: placeholder
1428
spec:

labeller/labeller.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package labeller
33
import (
44
"errors"
55
"fmt"
6+
"reflect"
67
"strings"
78
"time"
89

@@ -37,6 +38,8 @@ var (
3738
Defcon1Label = "Defcon1"
3839
)
3940

41+
const skipGCAnnotation = "imagemanifestvuln.skip-gc"
42+
4043
type Labeller struct {
4144
kclient kubernetes.Interface
4245
sclient secscanclient.Interface
@@ -251,6 +254,8 @@ func (l *Labeller) handleAddImageManifestVuln(obj interface{}) {
251254
level.Debug(l.logger).Log("msg", "ImageManifestVuln added", "key", key)
252255
prometheus.PromImageManifestVulnEventsTotal.WithLabelValues("add", imgmanifestvuln.Namespace).Inc()
253256
}
257+
258+
l.handleNoGC(imgmanifestvuln, &secscanv1alpha1.ImageManifestVuln{Spec: secscanv1alpha1.ImageManifestVulnSpec{Image: "none"}})
254259
}
255260

256261
func (l *Labeller) handleDeleteImageManifestVuln(obj interface{}) {
@@ -273,6 +278,8 @@ func (l *Labeller) handleUpdateImageManifestVuln(oldObj, newObj interface{}) {
273278
level.Debug(l.logger).Log("msg", "ImageManifestVuln updated", "key", key)
274279
prometheus.PromImageManifestVulnEventsTotal.WithLabelValues("update", imgmanifestvuln.Namespace).Inc()
275280
}
281+
282+
l.handleNoGC(imgmanifestvuln, oldObj.(*secscanv1alpha1.ImageManifestVuln))
276283
}
277284

278285
func (l *Labeller) waitForCacheSync(stopc <-chan struct{}) error {
@@ -506,3 +513,12 @@ func (l *Labeller) podInNamespaces(pod *corev1.Pod) bool {
506513
}
507514
return false
508515
}
516+
517+
func (l *Labeller) handleNoGC(obj, oldObj *secscanv1alpha1.ImageManifestVuln) {
518+
if _, ok := obj.GetAnnotations()[skipGCAnnotation]; ok && !reflect.DeepEqual(obj.Spec, oldObj.Spec) {
519+
_, err := l.sclient.SecscanV1alpha1().ImageManifestVulns(obj.GetNamespace()).UpdateStatus(updateImageManifestVulnLastUpdate(obj))
520+
if err != nil {
521+
level.Error(l.logger).Log("msg", "Error updating noop ImageManifestVuln", "err", err)
522+
}
523+
}
524+
}

labeller/labeller_test.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ func newFakeLabeller(ctx context.Context, c *testClient, config *Config) *Labell
120120
resyncThreshold: config.ResyncThreshold,
121121
wellKnownEndpoint: config.WellknownEndpoint,
122122
prometheus: prometheus.NewServer(config.PrometheusAddr),
123-
vulnerabilities: NewLockableVulnerabilites(),
124123

125124
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "fakeLabeller"),
126125
}
@@ -229,7 +228,7 @@ func TestSkipNonRunningPod(t *testing.T) {
229228
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
230229

231230
for _, pod := range pods {
232-
err := fakeLabeller.SecurityLabelPod(pod.Namespace + "/" + pod.Name)
231+
err := fakeLabeller.Reconcile(pod.Namespace + "/" + pod.Name)
233232
if assert.Error(t, err) {
234233
if pod.Status.Phase == corev1.PodRunning {
235234
assert.Equal(t, err, fmt.Errorf("Pod condition not ready"))
@@ -259,7 +258,7 @@ func TestNonVulnerablePod(t *testing.T) {
259258
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
260259

261260
// Scan the pod
262-
err := fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
261+
err := fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
263262
assert.NoError(t, err)
264263
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
265264

@@ -289,7 +288,7 @@ func TestVulnerablePodCreateImageManifestVuln(t *testing.T) {
289288
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
290289

291290
// Scan the pod
292-
err := fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
291+
err := fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
293292
assert.NoError(t, err)
294293
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
295294

@@ -319,7 +318,7 @@ func TestVulnerablePodUpdateImageManifestVuln(t *testing.T) {
319318
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
320319

321320
// Scan the pod
322-
err := fakeLabeller.SecurityLabelPod(runningPod1.Namespace + "/" + runningPod1.Name)
321+
err := fakeLabeller.Reconcile(runningPod1.Namespace + "/" + runningPod1.Name)
323322
assert.NoError(t, err)
324323
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
325324

@@ -332,7 +331,7 @@ func TestVulnerablePodUpdateImageManifestVuln(t *testing.T) {
332331
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
333332

334333
// Scan the pod
335-
err = fakeLabeller.SecurityLabelPod(runningPod2.Namespace + "/" + runningPod2.Name)
334+
err = fakeLabeller.Reconcile(runningPod2.Namespace + "/" + runningPod2.Name)
336335
assert.NoError(t, err)
337336
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
338337

@@ -364,7 +363,7 @@ func TestForcedResyncThreshold(t *testing.T) {
364363
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
365364

366365
// Scan the pod
367-
err := fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
366+
err := fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
368367
assert.NoError(t, err)
369368
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
370369

@@ -374,7 +373,7 @@ func TestForcedResyncThreshold(t *testing.T) {
374373
initialTimestamp, _ := lastManfestUpdateTime(manifest)
375374

376375
// Resyncing a pod too early should have no effects
377-
err = fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
376+
err = fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
378377
assert.NoError(t, err)
379378
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
380379

@@ -390,7 +389,7 @@ func TestForcedResyncThreshold(t *testing.T) {
390389
assert.NoError(t, err)
391390

392391
// Rescan the pod and check for new lastUpdate
393-
err = fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
392+
err = fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
394393
assert.NoError(t, err)
395394
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
396395

@@ -419,7 +418,7 @@ func TestGarbageCollectManifest(t *testing.T) {
419418
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
420419

421420
// Scan the pod
422-
err := fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
421+
err := fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
423422
assert.NoError(t, err)
424423
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
425424

@@ -434,7 +433,7 @@ func TestGarbageCollectManifest(t *testing.T) {
434433
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
435434

436435
// Delete event reconciliation
437-
err = fakeLabeller.SecurityLabelPod(runningPod.Namespace + "/" + runningPod.Name)
436+
err = fakeLabeller.Reconcile(runningPod.Namespace + "/" + runningPod.Name)
438437
assert.NoError(t, err)
439438
assert.NoError(t, fakeLabeller.waitForCacheSync(ctx.Done()))
440439

labeller/manifest.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,10 @@ func garbageCollectManifests(podclient corev1.PodInterface, manifestclient secsc
279279
}
280280

281281
for _, manifest := range manifestList.Items {
282+
if _, ok := manifest.GetAnnotations()[skipGCAnnotation]; ok {
283+
return nil
284+
}
285+
282286
var (
283287
updated bool
284288
updatedManifest *secscanv1alpha1.ImageManifestVuln

labeller/manifest_test.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222

2323
"k8s.io/client-go/kubernetes"
2424
"k8s.io/client-go/kubernetes/fake"
25-
"k8s.io/client-go/kubernetes/typed/core/v1"
25+
v1 "k8s.io/client-go/kubernetes/typed/core/v1"
2626
)
2727

2828
func randString(n int) string {
@@ -396,6 +396,31 @@ func TestGarbageCollectManifestDeletion(t *testing.T) {
396396
assert.Equal(t, sortedPodKeysFromPods(testPods), sortedAffectedPodsKeys(manifests[0]))
397397
}
398398

399+
func TestGarbageCollectManifestNoop(t *testing.T) {
400+
ns := generateNamespaceForTest(t)
401+
402+
c := newTestClient()
403+
404+
noopManifest := &secscanv1alpha1.ImageManifestVuln{}
405+
noopManifest.SetLabels(map[string]string{"imagemanifestvuln.example": "true"})
406+
if _, err := c.imageManifestVulnsClient(ns).Create(noopManifest); err != nil {
407+
t.Fatal(err)
408+
}
409+
410+
// Garbage collecting manifest with noop label should not delete anything
411+
err := garbageCollectManifests(c.podsClient(ns), c.imageManifestVulnsClient(ns))
412+
if err != nil {
413+
t.Fatal(err)
414+
}
415+
416+
// Check that the number of manifests if the same
417+
manifestList, err := c.imageManifestVulnsClient(ns).List(metav1.ListOptions{})
418+
if err != nil {
419+
t.Fatal(err)
420+
}
421+
assert.Len(t, manifestList.Items, 1)
422+
}
423+
399424
func TestGarbageCollectManifestDanglingPods(t *testing.T) {
400425
ns := generateNamespaceForTest(t)
401426
testImageID := "quay.io/test/redis@sha256:94033a42da840b970fd9d2b04dae5fec56add2714ca674a758d030ce5acba27e"

0 commit comments

Comments
 (0)