add support of variables for Type Checking.
This commit is contained in:
		@@ -188,7 +188,7 @@ func (c *TypeChecker) compiler(ctx *TypeCheckingContext, typeOverwrite typeOverw
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	compiler := &plugincel.CompositedCompiler{
 | 
						compiler := &plugincel.CompositedCompiler{
 | 
				
			||||||
		Compiler:       &typeCheckingCompiler{typeOverwrite: typeOverwrite},
 | 
							Compiler:       &typeCheckingCompiler{typeOverwrite: typeOverwrite, compositionEnv: env},
 | 
				
			||||||
		CompositionEnv: env,
 | 
							CompositionEnv: env,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return compiler, nil
 | 
						return compiler, nil
 | 
				
			||||||
@@ -449,6 +449,7 @@ func createVariableOpts(declType *apiservercel.DeclType, variables ...string) []
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type typeCheckingCompiler struct {
 | 
					type typeCheckingCompiler struct {
 | 
				
			||||||
 | 
						compositionEnv *plugincel.CompositionEnv
 | 
				
			||||||
	typeOverwrite  typeOverwrite
 | 
						typeOverwrite  typeOverwrite
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -468,20 +469,18 @@ func (c *typeCheckingCompiler) CompileCELExpression(expressionAccessor plugincel
 | 
				
			|||||||
			ExpressionAccessor: expressionAccessor,
 | 
								ExpressionAccessor: expressionAccessor,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	envSet, err := buildEnvSet(options.HasParams, options.HasAuthorizer, c.typeOverwrite)
 | 
						env, err := c.compositionEnv.Env(mode)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return resultError(fmt.Sprintf("fail to build env set: %v", err), apiservercel.ErrorTypeInternal)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	env, err := envSet.Env(mode)
 | 
					 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return resultError(fmt.Sprintf("fail to build env: %v", err), apiservercel.ErrorTypeInternal)
 | 
							return resultError(fmt.Sprintf("fail to build env: %v", err), apiservercel.ErrorTypeInternal)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	_, issues := env.Compile(expressionAccessor.GetExpression())
 | 
						ast, issues := env.Compile(expressionAccessor.GetExpression())
 | 
				
			||||||
	if issues != nil {
 | 
						if issues != nil {
 | 
				
			||||||
		return resultError(issues.String(), apiservercel.ErrorTypeInvalid)
 | 
							return resultError(issues.String(), apiservercel.ErrorTypeInvalid)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// type checker does not require the program, an empty result indicates successful compilation.
 | 
						// type checker does not require the program, however the type must still be set.
 | 
				
			||||||
	return plugincel.CompilationResult{}
 | 
						return plugincel.CompilationResult{
 | 
				
			||||||
 | 
							OutputType: ast.OutputType(),
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var _ plugincel.Compiler = (*typeCheckingCompiler)(nil)
 | 
					var _ plugincel.Compiler = (*typeCheckingCompiler)(nil)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -413,6 +413,95 @@ func TestTypeCheck(t *testing.T) {
 | 
				
			|||||||
				toContain("found no matching overload for 'allowed' applied to 'kubernetes.authorization.Authorizer"),
 | 
									toContain("found no matching overload for 'allowed' applied to 'kubernetes.authorization.Authorizer"),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "variables valid",
 | 
				
			||||||
 | 
								policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{
 | 
				
			||||||
 | 
									Variables: []v1beta1.Variable{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:       "works",
 | 
				
			||||||
 | 
											Expression: "true",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Validations: []v1beta1.Validation{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Expression: "variables.works",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									MatchConstraints: deploymentPolicy.Spec.MatchConstraints,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								schemaToReturn: &spec.Schema{
 | 
				
			||||||
 | 
									SchemaProps: spec.SchemaProps{
 | 
				
			||||||
 | 
										Type: []string{"object"},
 | 
				
			||||||
 | 
										Properties: map[string]spec.Schema{
 | 
				
			||||||
 | 
											"foo": *spec.Int64Property(),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								assertions: []assertionFunc{toHaveLengthOf(0)},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "variables missing field",
 | 
				
			||||||
 | 
								policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{
 | 
				
			||||||
 | 
									Variables: []v1beta1.Variable{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:       "works",
 | 
				
			||||||
 | 
											Expression: "true",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Validations: []v1beta1.Validation{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Expression: "variables.nonExisting",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									MatchConstraints: deploymentPolicy.Spec.MatchConstraints,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								schemaToReturn: &spec.Schema{
 | 
				
			||||||
 | 
									SchemaProps: spec.SchemaProps{
 | 
				
			||||||
 | 
										Type: []string{"object"},
 | 
				
			||||||
 | 
										Properties: map[string]spec.Schema{
 | 
				
			||||||
 | 
											"foo": *spec.Int64Property(),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								assertions: []assertionFunc{
 | 
				
			||||||
 | 
									toHaveLengthOf(1),
 | 
				
			||||||
 | 
									toHaveFieldRef("spec.validations[0].expression"),
 | 
				
			||||||
 | 
									toContain("undefined field 'nonExisting'"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "variables field wrong type",
 | 
				
			||||||
 | 
								policy: &v1beta1.ValidatingAdmissionPolicy{Spec: v1beta1.ValidatingAdmissionPolicySpec{
 | 
				
			||||||
 | 
									Variables: []v1beta1.Variable{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Name:       "name",
 | 
				
			||||||
 | 
											Expression: "'something'",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Validations: []v1beta1.Validation{
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											Expression: "variables.name == object.foo", // foo is int64
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									MatchConstraints: deploymentPolicy.Spec.MatchConstraints,
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								schemaToReturn: &spec.Schema{
 | 
				
			||||||
 | 
									SchemaProps: spec.SchemaProps{
 | 
				
			||||||
 | 
										Type: []string{"object"},
 | 
				
			||||||
 | 
										Properties: map[string]spec.Schema{
 | 
				
			||||||
 | 
											"foo": *spec.Int64Property(),
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								assertions: []assertionFunc{
 | 
				
			||||||
 | 
									toHaveLengthOf(1),
 | 
				
			||||||
 | 
									toHaveFieldRef("spec.validations[0].expression"),
 | 
				
			||||||
 | 
									toContain("found no matching overload for '_==_' applied to '(string, int)"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
	} {
 | 
						} {
 | 
				
			||||||
		t.Run(tc.name, func(t *testing.T) {
 | 
							t.Run(tc.name, func(t *testing.T) {
 | 
				
			||||||
			typeChecker := buildTypeChecker(tc.schemaToReturn)
 | 
								typeChecker := buildTypeChecker(tc.schemaToReturn)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user