diff --git a/pkg/api/kyverno/v1/policy_types.go b/pkg/api/kyverno/v1/policy_types.go index 4cecc0bdd9..9229358cf4 100755 --- a/pkg/api/kyverno/v1/policy_types.go +++ b/pkg/api/kyverno/v1/policy_types.go @@ -215,6 +215,14 @@ const ( LessThanOrEquals ConditionOperator = "LessThanOrEquals" // LessThan evaluates if the key (numeric) is less than the value (numeric). LessThan ConditionOperator = "LessThan" + // DurationGreaterThanOrEquals evaluates if the key (duration) is greater than or equal to the value (duration) + DurationGreaterThanOrEquals ConditionOperator = "DurationGreaterThanOrEquals" + // DurationGreaterThan evaluates if the key (duration) is greater than the value (duration) + DurationGreaterThan ConditionOperator = "DurationGreaterThan" + // DurationLessThanOrEquals evaluates if the key (duration) is less than or equal to the value (duration) + DurationLessThanOrEquals ConditionOperator = "DurationLessThanOrEquals" + // DurationLessThan evaluates if the key (duration) is greater than the value (duration) + DurationLessThan ConditionOperator = "DurationLessThan" ) // MatchResources is used to specify resource and admission review request data for diff --git a/pkg/engine/variables/evaluate_test.go b/pkg/engine/variables/evaluate_test.go index 90cf38423f..d4823d7874 100644 --- a/pkg/engine/variables/evaluate_test.go +++ b/pkg/engine/variables/evaluate_test.go @@ -211,6 +211,150 @@ func Test_Eval_LessThan_Const_string_Fail(t *testing.T) { } } +func Test_Eval_DurationGreaterThanOrEquals_Const_string_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_string_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_string_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "2h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_string_Equal_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationGreaterThan, + Value: "2h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_string_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationGreaterThan, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThan_Const_string_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationGreaterThan, + Value: "2h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_string_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationLessThanOrEquals, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_string_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationLessThanOrEquals, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_string_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.LessThanOrEquals, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_string_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationLessThan, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_string_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationLessThan, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThan_Const_string_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationLessThan, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + //Bool func Test_Eval_Equal_Const_Bool_Pass(t *testing.T) { @@ -470,6 +614,150 @@ func Test_Eval_LessThan_Const_int_Fail(t *testing.T) { } } +func Test_Eval_DurationGreaterThanOrEquals_Const_int_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationGreaterThanOrEquals, + Value: 3600, + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_int_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationGreaterThanOrEquals, + Value: 3600, + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_int_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationGreaterThanOrEquals, + Value: 7200, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_int_Equal_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600, + Operator: kyverno.DurationGreaterThan, + Value: 7200, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_int_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationGreaterThan, + Value: 3600, + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThan_Const_int_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600, + Operator: kyverno.DurationGreaterThan, + Value: 7200, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_int_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "2h", + Operator: kyverno.DurationLessThanOrEquals, + Value: 7200, + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_int_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationLessThanOrEquals, + Value: 7200, + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_int_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200, + Operator: kyverno.LessThanOrEquals, + Value: 3600, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_int_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600, + Operator: kyverno.DurationLessThan, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_int_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600, + Operator: kyverno.DurationLessThan, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThan_Const_int_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200, + Operator: kyverno.DurationLessThan, + Value: 3600, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + // int64 func Test_Eval_Equal_Const_int64_Pass(t *testing.T) { ctx := context.NewContext() @@ -527,6 +815,150 @@ func Test_Eval_NoEqual_Const_int64_Fail(t *testing.T) { } } +func Test_Eval_DurationGreaterThanOrEquals_Const_int64_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_int64_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(7200), + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_int64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationGreaterThanOrEquals, + Value: int64(7200), + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_int64_Equal_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationGreaterThan, + Value: int64(7200), + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_int64_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(7200), + Operator: kyverno.DurationGreaterThan, + Value: int64(3600), + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThan_Const_int64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationGreaterThan, + Value: int64(7200), + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_int64_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(7200), + Operator: kyverno.DurationLessThanOrEquals, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_int64_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationLessThanOrEquals, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_int64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(7200), + Operator: kyverno.LessThanOrEquals, + Value: int64(3600), + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_int64_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationLessThan, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_int64_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(3600), + Operator: kyverno.DurationLessThan, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThan_Const_int64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: int64(7200), + Operator: kyverno.DurationLessThan, + Value: int64(3600), + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + //float64 func Test_Eval_Equal_Const_float64_Pass(t *testing.T) { @@ -729,6 +1161,150 @@ func Test_Eval_LessThan_Const_float64_Fail(t *testing.T) { } } +func Test_Eval_DurationGreaterThanOrEquals_Const_float64_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600.0, + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_float64_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200.0, + Operator: kyverno.DurationGreaterThanOrEquals, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThanOrEquals_Const_float64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600.0, + Operator: kyverno.DurationGreaterThanOrEquals, + Value: 7200.0, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_float64_Equal_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600.0, + Operator: kyverno.DurationGreaterThan, + Value: 7200.0, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationGreaterThan_Const_float64_Greater_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200.0, + Operator: kyverno.DurationGreaterThan, + Value: "1h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationGreaterThan_Const_float64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600.0, + Operator: kyverno.DurationGreaterThan, + Value: 7200.0, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_float64_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200.0, + Operator: kyverno.DurationLessThanOrEquals, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_float64_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600.0, + Operator: kyverno.DurationLessThanOrEquals, + Value: "2h", + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThanOrEquals_Const_float64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200.0, + Operator: kyverno.LessThanOrEquals, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_float64_Equal_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 3600.0, + Operator: kyverno.DurationLessThan, + Value: "1h", + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + +func Test_Eval_DurationLessThan_Const_float64_Less_Pass(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: "1h", + Operator: kyverno.DurationLessThan, + Value: 7200.0, + } + if !Evaluate(log.Log, ctx, condition) { + t.Error("expected to pass") + } +} + +func Test_Eval_DurationLessThan_Const_float64_Fail(t *testing.T) { + ctx := context.NewContext() + condition := kyverno.Condition{ + Key: 7200.0, + Operator: kyverno.DurationLessThan, + Value: 3600.0, + } + if Evaluate(log.Log, ctx, condition) { + t.Error("expected to fail") + } +} + //object/map[string]interface func Test_Eval_Equal_Const_object_Pass(t *testing.T) { diff --git a/pkg/engine/variables/operator/duration.go b/pkg/engine/variables/operator/duration.go new file mode 100644 index 0000000000..ce86bec3c6 --- /dev/null +++ b/pkg/engine/variables/operator/duration.go @@ -0,0 +1,139 @@ +package operator + +import ( + "fmt" + "time" + + "github.com/go-logr/logr" + kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" + "github.com/kyverno/kyverno/pkg/engine/context" +) + +//NewDurationOperatorHandler returns handler to manage the provided duration operations (>, >=, <=, <) +func NewDurationOperatorHandler(log logr.Logger, ctx context.EvalInterface, op kyverno.ConditionOperator) OperatorHandler { + return DurationOperatorHandler{ + ctx: ctx, + log: log, + condition: op, + } +} + +//DurationOperatorHandler provides implementation to handle Duration Operations associated with policies +type DurationOperatorHandler struct { + ctx context.EvalInterface + log logr.Logger + condition kyverno.ConditionOperator +} + +// durationCompareByCondition compares a time.Duration key with a time.Duration value on the basis of the provided operator +func durationCompareByCondition(key time.Duration, value time.Duration, op kyverno.ConditionOperator, log *logr.Logger) bool { + switch op { + case kyverno.DurationGreaterThanOrEquals: + return key >= value + case kyverno.DurationGreaterThan: + return key > value + case kyverno.DurationLessThanOrEquals: + return key <= value + case kyverno.DurationLessThan: + return key < value + default: + (*log).Info(fmt.Sprintf("Expected operator, one of [DurationGreaterThanOrEquals, DurationGreaterThan, DurationLessThanOrEquals, DurationLessThan], found %s", op)) + return false + } +} + +func (doh DurationOperatorHandler) Evaluate(key, value interface{}) bool { + switch typedKey := key.(type) { + case int: + return doh.validateValueWithIntPattern(int64(typedKey), value) + case int64: + return doh.validateValueWithIntPattern(typedKey, value) + case float64: + return doh.validateValueWithFloatPattern(typedKey, value) + case string: + return doh.validateValueWithStringPattern(typedKey, value) + default: + doh.log.Info("Unsupported type", "value", typedKey, "type", fmt.Sprintf("%T", typedKey)) + return false + } +} + +func (doh DurationOperatorHandler) validateValueWithIntPattern(key int64, value interface{}) bool { + switch typedValue := value.(type) { + case int: + return durationCompareByCondition(time.Duration(key)*time.Second, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case int64: + return durationCompareByCondition(time.Duration(key)*time.Second, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case float64: + return durationCompareByCondition(time.Duration(key)*time.Second, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case string: + duration, err := time.ParseDuration(typedValue) + if err == nil { + return durationCompareByCondition(time.Duration(key)*time.Second, duration, doh.condition, &doh.log) + } + doh.log.Error(fmt.Errorf("Parse Error: "), "Failed to parse time duration from the string value") + return false + default: + doh.log.Info("Unexpected type", "value", value, "type", fmt.Sprintf("%T", value)) + return false + } +} + +func (doh DurationOperatorHandler) validateValueWithFloatPattern(key float64, value interface{}) bool { + switch typedValue := value.(type) { + case int: + return durationCompareByCondition(time.Duration(key)*time.Second, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case int64: + return durationCompareByCondition(time.Duration(key)*time.Second, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case float64: + return durationCompareByCondition(time.Duration(key)*time.Second, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case string: + duration, err := time.ParseDuration(typedValue) + if err == nil { + return durationCompareByCondition(time.Duration(key)*time.Second, duration, doh.condition, &doh.log) + } + doh.log.Error(fmt.Errorf("Parse Error: "), "Failed to parse time duration from the string value") + return false + default: + doh.log.Info("Unexpected type", "value", value, "type", fmt.Sprintf("%T", value)) + return false + } +} + +func (doh DurationOperatorHandler) validateValueWithStringPattern(key string, value interface{}) bool { + duration, err := time.ParseDuration(key) + if err != nil { + doh.log.Error(err, "Failed to parse time duration from the string key") + return false + } + switch typedValue := value.(type) { + case int: + return durationCompareByCondition(duration, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case int64: + return durationCompareByCondition(duration, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case float64: + return durationCompareByCondition(duration, time.Duration(typedValue)*time.Second, doh.condition, &doh.log) + case string: + durationValue, err := time.ParseDuration(typedValue) + if err == nil { + return durationCompareByCondition(duration, durationValue, doh.condition, &doh.log) + } + doh.log.Error(fmt.Errorf("Parse Error: "), "Failed to parse time duration from the string value") + return false + default: + doh.log.Info("Unexpected type", "value", value, "type", fmt.Sprintf("%T", value)) + return false + } +} + +// the following functions are unreachable because the key is strictly supposed to be a duration +// still the following functions are just created to make DurationOperatorHandler struct implement OperatorHandler interface +func (doh DurationOperatorHandler) validateValueWithBoolPattern(key bool, value interface{}) bool { + return false +} +func (doh DurationOperatorHandler) validateValueWithMapPattern(key map[string]interface{}, value interface{}) bool { + return false +} +func (doh DurationOperatorHandler) validateValueWithSlicePattern(key []interface{}, value interface{}) bool { + return false +} diff --git a/pkg/engine/variables/operator/operator.go b/pkg/engine/variables/operator/operator.go index 561ea9ac00..51fd490240 100644 --- a/pkg/engine/variables/operator/operator.go +++ b/pkg/engine/variables/operator/operator.go @@ -51,6 +51,12 @@ func CreateOperatorHandler(log logr.Logger, ctx context.EvalInterface, op kyvern strings.ToLower(string(kyverno.LessThan)): return NewNumericOperatorHandler(log, ctx, op) + case strings.ToLower(string(kyverno.DurationGreaterThanOrEquals)), + strings.ToLower(string(kyverno.DurationGreaterThan)), + strings.ToLower(string(kyverno.DurationLessThanOrEquals)), + strings.ToLower(string(kyverno.DurationLessThan)): + return NewDurationOperatorHandler(log, ctx, op) + default: log.Info("operator not supported", "operator", str) }