Skip to content

Commit e025ab4

Browse files
cici37k8s-publishing-bot
authored andcommitted
Adding the feature gates to fix cost for VAP and webhook matchConditions.
Kubernetes-commit: 3d896724760a957e8059ff80e9f399248eacac66
1 parent a30c80f commit e025ab4

File tree

22 files changed

+495
-96
lines changed

22 files changed

+495
-96
lines changed

pkg/admission/plugin/cel/compile.go

+36-28
Original file line numberDiff line numberDiff line change
@@ -222,40 +222,48 @@ func (c compiler) CompileCELExpression(expressionAccessor ExpressionAccessor, op
222222
func mustBuildEnvs(baseEnv *environment.EnvSet) variableDeclEnvs {
223223
requestType := BuildRequestType()
224224
namespaceType := BuildNamespaceType()
225-
envs := make(variableDeclEnvs, 4) // since the number of variable combinations is small, pre-build a environment for each
225+
envs := make(variableDeclEnvs, 8) // since the number of variable combinations is small, pre-build a environment for each
226226
for _, hasParams := range []bool{false, true} {
227227
for _, hasAuthorizer := range []bool{false, true} {
228-
var envOpts []cel.EnvOption
229-
if hasParams {
230-
envOpts = append(envOpts, cel.Variable(ParamsVarName, cel.DynType))
231-
}
232-
if hasAuthorizer {
228+
for _, strictCost := range []bool{false, true} {
229+
var envOpts []cel.EnvOption
230+
if hasParams {
231+
envOpts = append(envOpts, cel.Variable(ParamsVarName, cel.DynType))
232+
}
233+
if hasAuthorizer {
234+
envOpts = append(envOpts,
235+
cel.Variable(AuthorizerVarName, library.AuthorizerType),
236+
cel.Variable(RequestResourceAuthorizerVarName, library.ResourceCheckType))
237+
}
233238
envOpts = append(envOpts,
234-
cel.Variable(AuthorizerVarName, library.AuthorizerType),
235-
cel.Variable(RequestResourceAuthorizerVarName, library.ResourceCheckType))
236-
}
237-
envOpts = append(envOpts,
238-
cel.Variable(ObjectVarName, cel.DynType),
239-
cel.Variable(OldObjectVarName, cel.DynType),
240-
cel.Variable(NamespaceVarName, namespaceType.CelType()),
241-
cel.Variable(RequestVarName, requestType.CelType()))
239+
cel.Variable(ObjectVarName, cel.DynType),
240+
cel.Variable(OldObjectVarName, cel.DynType),
241+
cel.Variable(NamespaceVarName, namespaceType.CelType()),
242+
cel.Variable(RequestVarName, requestType.CelType()))
242243

243-
extended, err := baseEnv.Extend(
244-
environment.VersionedOptions{
245-
// Feature epoch was actually 1.26, but we artificially set it to 1.0 because these
246-
// options should always be present.
247-
IntroducedVersion: version.MajorMinor(1, 0),
248-
EnvOptions: envOpts,
249-
DeclTypes: []*apiservercel.DeclType{
250-
namespaceType,
251-
requestType,
244+
extended, err := baseEnv.Extend(
245+
environment.VersionedOptions{
246+
// Feature epoch was actually 1.26, but we artificially set it to 1.0 because these
247+
// options should always be present.
248+
IntroducedVersion: version.MajorMinor(1, 0),
249+
EnvOptions: envOpts,
250+
DeclTypes: []*apiservercel.DeclType{
251+
namespaceType,
252+
requestType,
253+
},
252254
},
253-
},
254-
)
255-
if err != nil {
256-
panic(fmt.Sprintf("environment misconfigured: %v", err))
255+
)
256+
if err != nil {
257+
panic(fmt.Sprintf("environment misconfigured: %v", err))
258+
}
259+
if strictCost {
260+
extended, err = extended.Extend(environment.StrictCostOpt)
261+
if err != nil {
262+
panic(fmt.Sprintf("environment misconfigured: %v", err))
263+
}
264+
}
265+
envs[OptionalVariableDeclarations{HasParams: hasParams, HasAuthorizer: hasAuthorizer, StrictCost: strictCost}] = extended
257266
}
258-
envs[OptionalVariableDeclarations{HasParams: hasParams, HasAuthorizer: hasAuthorizer}] = extended
259267
}
260268
}
261269
return envs

pkg/admission/plugin/cel/compile_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func TestCompileValidatingPolicyExpression(t *testing.T) {
178178
}
179179

180180
// Include the test library, which includes the test() function in the storage environment during test
181-
base := environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion())
181+
base := environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true)
182182
extended, err := base.Extend(environment.VersionedOptions{
183183
IntroducedVersion: version.MajorMinor(1, 999),
184184
EnvOptions: []celgo.EnvOption{library.Test()},
@@ -254,7 +254,7 @@ func TestCompileValidatingPolicyExpression(t *testing.T) {
254254
}
255255

256256
func BenchmarkCompile(b *testing.B) {
257-
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion()))
257+
compiler := NewCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), true))
258258
b.ResetTimer()
259259
for i := 0; i < b.N; i++ {
260260
options := OptionalVariableDeclarations{HasParams: rand.Int()%2 == 0, HasAuthorizer: rand.Int()%2 == 0}

pkg/admission/plugin/cel/composition_test.go

+41-11
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ func (t *testVariable) GetName() string {
4848

4949
func TestCompositedPolicies(t *testing.T) {
5050
cases := []struct {
51-
name string
52-
variables []NamedExpressionAccessor
53-
expression string
54-
attributes admission.Attributes
55-
expectedResult any
56-
expectErr bool
57-
expectedErrorMessage string
58-
runtimeCostBudget int64
51+
name string
52+
variables []NamedExpressionAccessor
53+
expression string
54+
attributes admission.Attributes
55+
expectedResult any
56+
expectErr bool
57+
expectedErrorMessage string
58+
runtimeCostBudget int64
59+
strictCostEnforcement bool
5960
}{
6061
{
6162
name: "simple",
@@ -185,16 +186,45 @@ func TestCompositedPolicies(t *testing.T) {
185186
expectErr: true,
186187
expectedErrorMessage: "found no matching overload for '_==_' applied to '(string, int)'",
187188
},
189+
{
190+
name: "with strictCostEnforcement on: exceeds cost budget",
191+
variables: []NamedExpressionAccessor{
192+
&testVariable{
193+
name: "dict",
194+
expression: "'abc 123 def 123'.split(' ')",
195+
},
196+
},
197+
attributes: endpointCreateAttributes(),
198+
expression: "size(variables.dict) > 0",
199+
expectErr: true,
200+
expectedErrorMessage: "validation failed due to running out of cost budget, no further validation rules will be run",
201+
runtimeCostBudget: 5,
202+
strictCostEnforcement: true,
203+
},
204+
{
205+
name: "with strictCostEnforcement off: not exceed cost budget",
206+
variables: []NamedExpressionAccessor{
207+
&testVariable{
208+
name: "dict",
209+
expression: "'abc 123 def 123'.split(' ')",
210+
},
211+
},
212+
attributes: endpointCreateAttributes(),
213+
expression: "size(variables.dict) > 0",
214+
expectedResult: true,
215+
runtimeCostBudget: 5,
216+
strictCostEnforcement: false,
217+
},
188218
}
189219
for _, tc := range cases {
190220
t.Run(tc.name, func(t *testing.T) {
191-
compiler, err := NewCompositedCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion()))
221+
compiler, err := NewCompositedCompiler(environment.MustBaseEnvSet(environment.DefaultCompatibilityVersion(), tc.strictCostEnforcement))
192222
if err != nil {
193223
t.Fatal(err)
194224
}
195-
compiler.CompileAndStoreVariables(tc.variables, OptionalVariableDeclarations{HasParams: false, HasAuthorizer: false}, environment.NewExpressions)
225+
compiler.CompileAndStoreVariables(tc.variables, OptionalVariableDeclarations{HasParams: false, HasAuthorizer: false, StrictCost: tc.strictCostEnforcement}, environment.NewExpressions)
196226
validations := []ExpressionAccessor{&condition{Expression: tc.expression}}
197-
f := compiler.Compile(validations, OptionalVariableDeclarations{HasParams: false, HasAuthorizer: false}, environment.NewExpressions)
227+
f := compiler.Compile(validations, OptionalVariableDeclarations{HasParams: false, HasAuthorizer: false, StrictCost: tc.strictCostEnforcement}, environment.NewExpressions)
198228
versionedAttr, err := admission.NewVersionedAttributes(tc.attributes, tc.attributes.GetKind(), newObjectInterfacesForTest())
199229
if err != nil {
200230
t.Fatal(err)

0 commit comments

Comments
 (0)