k8s.io/apiserver@v0.31.1/pkg/audit/context_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package audit 18 19 import ( 20 "context" 21 "fmt" 22 "sync" 23 "testing" 24 25 auditinternal "k8s.io/apiserver/pkg/apis/audit" 26 27 "github.com/stretchr/testify/assert" 28 ) 29 30 func TestEnabled(t *testing.T) { 31 tests := []struct { 32 name string 33 ctx *AuditContext 34 expectEnabled bool 35 }{{ 36 name: "nil context", 37 expectEnabled: false, 38 }, { 39 name: "empty context", 40 ctx: &AuditContext{}, 41 expectEnabled: true, // An AuditContext should be considered enabled before the level is set 42 }, { 43 name: "level None", 44 ctx: &AuditContext{RequestAuditConfig: RequestAuditConfig{Level: auditinternal.LevelNone}}, 45 expectEnabled: false, 46 }, { 47 name: "level Metadata", 48 ctx: &AuditContext{RequestAuditConfig: RequestAuditConfig{Level: auditinternal.LevelMetadata}}, 49 expectEnabled: true, 50 }, { 51 name: "level RequestResponse", 52 ctx: &AuditContext{RequestAuditConfig: RequestAuditConfig{Level: auditinternal.LevelRequestResponse}}, 53 expectEnabled: true, 54 }} 55 56 for _, test := range tests { 57 t.Run(test.name, func(t *testing.T) { 58 assert.Equal(t, test.expectEnabled, test.ctx.Enabled()) 59 }) 60 } 61 } 62 63 func TestAddAuditAnnotation(t *testing.T) { 64 const ( 65 annotationKeyTemplate = "test-annotation-%d" 66 annotationValue = "test-annotation-value" 67 annotationExtraValue = "test-existing-annotation" 68 numAnnotations = 10 69 ) 70 71 expectAnnotations := func(t *testing.T, annotations map[string]string) { 72 assert.Len(t, annotations, numAnnotations) 73 } 74 75 ctxWithAnnotation := withAuditContextAndLevel(context.Background(), auditinternal.LevelMetadata) 76 AddAuditAnnotation(ctxWithAnnotation, fmt.Sprintf(annotationKeyTemplate, 0), annotationExtraValue) 77 78 tests := []struct { 79 description string 80 ctx context.Context 81 validator func(t *testing.T, ctx context.Context) 82 }{{ 83 description: "no audit", 84 ctx: context.Background(), 85 validator: func(_ *testing.T, _ context.Context) {}, 86 }, { 87 description: "context initialized, policy not evaluated", 88 // Audit context is initialized, but the policy has not yet been evaluated (no level). 89 // Annotations should be retained. 90 ctx: WithAuditContext(context.Background()), 91 validator: func(t *testing.T, ctx context.Context) { 92 ev := AuditContextFrom(ctx).Event 93 expectAnnotations(t, ev.Annotations) 94 }, 95 }, { 96 description: "with metadata level", 97 ctx: withAuditContextAndLevel(context.Background(), auditinternal.LevelMetadata), 98 validator: func(t *testing.T, ctx context.Context) { 99 ev := AuditContextFrom(ctx).Event 100 expectAnnotations(t, ev.Annotations) 101 }, 102 }, { 103 description: "with none level", 104 ctx: withAuditContextAndLevel(context.Background(), auditinternal.LevelNone), 105 validator: func(t *testing.T, ctx context.Context) { 106 ev := AuditContextFrom(ctx).Event 107 assert.Empty(t, ev.Annotations) 108 }, 109 }, { 110 description: "with overlapping annotations", 111 ctx: ctxWithAnnotation, 112 validator: func(t *testing.T, ctx context.Context) { 113 ev := AuditContextFrom(ctx).Event 114 expectAnnotations(t, ev.Annotations) 115 // Verify that the pre-existing annotation is not overwritten. 116 assert.Equal(t, annotationExtraValue, ev.Annotations[fmt.Sprintf(annotationKeyTemplate, 0)]) 117 }, 118 }} 119 120 for _, test := range tests { 121 t.Run(test.description, func(t *testing.T) { 122 var wg sync.WaitGroup 123 wg.Add(numAnnotations) 124 for i := 0; i < numAnnotations; i++ { 125 go func(i int) { 126 AddAuditAnnotation(test.ctx, fmt.Sprintf(annotationKeyTemplate, i), annotationValue) 127 wg.Done() 128 }(i) 129 } 130 wg.Wait() 131 132 test.validator(t, test.ctx) 133 }) 134 } 135 } 136 137 func TestAuditAnnotationsWithAuditLoggingSetup(t *testing.T) { 138 // No audit context data in the request context 139 ctx := context.Background() 140 AddAuditAnnotation(ctx, "nil", "0") 141 142 // initialize audit context, policy not evaluated yet 143 ctx = WithAuditContext(ctx) 144 AddAuditAnnotation(ctx, "before-evaluation", "1") 145 146 // policy evaluated, audit logging enabled 147 if ac := AuditContextFrom(ctx); ac != nil { 148 ac.RequestAuditConfig.Level = auditinternal.LevelMetadata 149 } 150 AddAuditAnnotation(ctx, "after-evaluation", "2") 151 152 expected := map[string]string{ 153 "before-evaluation": "1", 154 "after-evaluation": "2", 155 } 156 actual := AuditContextFrom(ctx).Event.Annotations 157 assert.Equal(t, expected, actual) 158 } 159 160 func withAuditContextAndLevel(ctx context.Context, l auditinternal.Level) context.Context { 161 ctx = WithAuditContext(ctx) 162 ac := AuditContextFrom(ctx) 163 ac.RequestAuditConfig.Level = l 164 return ctx 165 }