implement message expression.

This commit is contained in:
Jiahui Feng
2023-03-08 17:36:11 -08:00
parent f4ee476a3c
commit d8be7aa9ca
10 changed files with 545 additions and 66 deletions

View File

@@ -782,26 +782,24 @@ func validateValidation(v *admissionregistration.Validation, paramKind *admissio
var allErrors field.ErrorList
trimmedExpression := strings.TrimSpace(v.Expression)
trimmedMsg := strings.TrimSpace(v.Message)
trimmedMessageExpression := strings.TrimSpace(v.MessageExpression)
if len(trimmedExpression) == 0 {
allErrors = append(allErrors, field.Required(fldPath.Child("expression"), "expression is not specified"))
} else {
result := plugincel.CompileCELExpression(&validatingadmissionpolicy.ValidationCondition{
Expression: trimmedExpression,
Message: v.Message,
Reason: v.Reason,
}, plugincel.OptionalVariableDeclarations{HasParams: paramKind != nil, HasAuthorizer: true}, celconfig.PerCallLimit)
if result.Error != nil {
switch result.Error.Type {
case cel.ErrorTypeRequired:
allErrors = append(allErrors, field.Required(fldPath.Child("expression"), result.Error.Detail))
case cel.ErrorTypeInvalid:
allErrors = append(allErrors, field.Invalid(fldPath.Child("expression"), v.Expression, result.Error.Detail))
case cel.ErrorTypeInternal:
allErrors = append(allErrors, field.InternalError(fldPath.Child("expression"), result.Error))
default:
allErrors = append(allErrors, field.InternalError(fldPath.Child("expression"), fmt.Errorf("unsupported error type: %w", result.Error)))
}
}
allErrors = append(allErrors, validateCELExpression(v.Expression, plugincel.OptionalVariableDeclarations{
HasParams: paramKind != nil,
HasAuthorizer: true,
}, fldPath.Child("expression"))...)
}
if len(v.MessageExpression) > 0 && len(trimmedMessageExpression) == 0 {
allErrors = append(allErrors, field.Invalid(fldPath.Child("messageExpression"), v.MessageExpression, "must be non-empty if specified"))
} else if len(trimmedMessageExpression) != 0 {
// use v.MessageExpression instead of trimmedMessageExpression so that
// the compiler output shows the correct column.
allErrors = append(allErrors, validateCELExpression(v.MessageExpression, plugincel.OptionalVariableDeclarations{
HasParams: paramKind != nil,
HasAuthorizer: false,
}, fldPath.Child("messageExpression"))...)
}
if len(v.Message) > 0 && len(trimmedMsg) == 0 {
allErrors = append(allErrors, field.Invalid(fldPath.Child("message"), v.Message, "message must be non-empty if specified"))
@@ -816,6 +814,26 @@ func validateValidation(v *admissionregistration.Validation, paramKind *admissio
return allErrors
}
func validateCELExpression(expression string, variables plugincel.OptionalVariableDeclarations, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
result := plugincel.CompileCELExpression(&validatingadmissionpolicy.ValidationCondition{
Expression: expression,
}, variables, celconfig.PerCallLimit)
if result.Error != nil {
switch result.Error.Type {
case cel.ErrorTypeRequired:
allErrors = append(allErrors, field.Required(fldPath, result.Error.Detail))
case cel.ErrorTypeInvalid:
allErrors = append(allErrors, field.Invalid(fldPath, expression, result.Error.Detail))
case cel.ErrorTypeInternal:
allErrors = append(allErrors, field.InternalError(fldPath, result.Error))
default:
allErrors = append(allErrors, field.InternalError(fldPath, fmt.Errorf("unsupported error type: %w", result.Error)))
}
}
return allErrors
}
func validateAuditAnnotation(meta metav1.ObjectMeta, v *admissionregistration.AuditAnnotation, paramKind *admissionregistration.ParamKind, fldPath *field.Path) field.ErrorList {
var allErrors field.ErrorList
if len(meta.GetName()) != 0 {

View File

@@ -2564,7 +2564,38 @@ func TestValidateValidatingAdmissionPolicy(t *testing.T) {
},
},
},
expectedError: `spec.validations[0].expression: Invalid value: "object.x in [1, 2, ": compilation failed: ERROR: <input>:1:19: Syntax error: missing ']' at '<EOF>`,
expectedError: `spec.validations[0].expression: Invalid value: "object.x in [1, 2, ": compilation failed: ERROR: <input>:1:20: Syntax error: missing ']' at '<EOF>`,
},
{
name: "invalid messageExpression",
config: &admissionregistration.ValidatingAdmissionPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "config",
},
Spec: admissionregistration.ValidatingAdmissionPolicySpec{
Validations: []admissionregistration.Validation{
{
Expression: "true",
MessageExpression: "object.x in [1, 2, ",
},
},
MatchConstraints: &admissionregistration.MatchResources{
ResourceRules: []admissionregistration.NamedRuleWithOperations{
{
RuleWithOperations: admissionregistration.RuleWithOperations{
Operations: []admissionregistration.OperationType{"CREATE"},
Rule: admissionregistration.Rule{
APIGroups: []string{"a"},
APIVersions: []string{"a"},
Resources: []string{"*/*"},
},
},
},
},
},
},
},
expectedError: `spec.validations[0].messageExpression: Invalid value: "object.x in [1, 2, ": compilation failed: ERROR: <input>:1:20: Syntax error: missing ']' at '<EOF>`,
},
{
name: "invalid auditAnnotations key due to key name",