mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 02:18:15 +00:00
feat(json): unmarshal at decode time (#10700)
Signed-off-by: Khaled Emara <khaled.emara@nirmata.com> Co-authored-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
91ffbb6758
commit
c0cf6c5bf1
19 changed files with 232 additions and 159 deletions
|
@ -658,15 +658,24 @@ type Deny struct {
|
|||
// of conditions (without `any` or `all` statements) is also supported for backwards compatibility
|
||||
// but will be deprecated in the next major release.
|
||||
// See: https://kyverno.io/docs/writing-policies/validate/#deny-rules
|
||||
RawAnyAllConditions *apiextv1.JSON `json:"conditions,omitempty" yaml:"conditions,omitempty"`
|
||||
// +kubebuilder:validation:Schemaless
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
RawAnyAllConditions *ConditionsWrapper `json:"conditions,omitempty" yaml:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Deny) GetAnyAllConditions() apiextensions.JSON {
|
||||
return FromJSON(d.RawAnyAllConditions)
|
||||
func (d *Deny) GetAnyAllConditions() any {
|
||||
if d.RawAnyAllConditions == nil {
|
||||
return nil
|
||||
}
|
||||
return d.RawAnyAllConditions.Conditions
|
||||
}
|
||||
|
||||
func (d *Deny) SetAnyAllConditions(in apiextensions.JSON) {
|
||||
d.RawAnyAllConditions = ToJSON(in)
|
||||
func (d *Deny) SetAnyAllConditions(in any) {
|
||||
var new *ConditionsWrapper
|
||||
if in != nil {
|
||||
new = &ConditionsWrapper{in}
|
||||
}
|
||||
d.RawAnyAllConditions = new
|
||||
}
|
||||
|
||||
// ForEachValidation applies validate rules to a list of sub-elements by creating a context for each entry in the list and looping over it to apply the specified logic.
|
||||
|
|
|
@ -3,8 +3,6 @@ package v1
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
@ -54,9 +52,14 @@ type TargetResourceSpec struct {
|
|||
// will be deprecated in the next major release.
|
||||
// See: https://kyverno.io/docs/writing-policies/preconditions/
|
||||
// +optional
|
||||
RawAnyAllConditions *apiextv1.JSON `json:"preconditions,omitempty" yaml:"preconditions,omitempty"`
|
||||
// +kubebuilder:validation:Schemaless
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
RawAnyAllConditions *ConditionsWrapper `json:"preconditions,omitempty" yaml:"preconditions,omitempty"`
|
||||
}
|
||||
|
||||
func (r *TargetResourceSpec) GetAnyAllConditions() apiextensions.JSON {
|
||||
return FromJSON(r.RawAnyAllConditions)
|
||||
func (r *TargetResourceSpec) GetAnyAllConditions() any {
|
||||
if r.RawAnyAllConditions == nil {
|
||||
return nil
|
||||
}
|
||||
return r.RawAnyAllConditions.Conditions
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/pss/utils"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
@ -76,7 +74,9 @@ type Rule struct {
|
|||
// will be deprecated in the next major release.
|
||||
// See: https://kyverno.io/docs/writing-policies/preconditions/
|
||||
// +optional
|
||||
RawAnyAllConditions *apiextv1.JSON `json:"preconditions,omitempty" yaml:"preconditions,omitempty"`
|
||||
// +kubebuilder:validation:Schemaless
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
RawAnyAllConditions *ConditionsWrapper `json:"preconditions,omitempty" yaml:"preconditions,omitempty"`
|
||||
|
||||
// CELPreconditions are used to determine if a policy rule should be applied by evaluating a
|
||||
// set of CEL conditions. It can only be used with the validate.cel subrule
|
||||
|
@ -186,12 +186,19 @@ func (r *Rule) GetTypeAndSyncAndOrphanDownstream() (_ GenerateType, sync bool, o
|
|||
return r.Generation.GetTypeAndSyncAndOrphanDownstream()
|
||||
}
|
||||
|
||||
func (r *Rule) GetAnyAllConditions() apiextensions.JSON {
|
||||
return FromJSON(r.RawAnyAllConditions)
|
||||
func (r *Rule) GetAnyAllConditions() any {
|
||||
if r.RawAnyAllConditions == nil {
|
||||
return nil
|
||||
}
|
||||
return r.RawAnyAllConditions.Conditions
|
||||
}
|
||||
|
||||
func (r *Rule) SetAnyAllConditions(in apiextensions.JSON) {
|
||||
r.RawAnyAllConditions = ToJSON(in)
|
||||
func (r *Rule) SetAnyAllConditions(in any) {
|
||||
var new *ConditionsWrapper
|
||||
if in != nil {
|
||||
new = &ConditionsWrapper{in}
|
||||
}
|
||||
r.RawAnyAllConditions = new
|
||||
}
|
||||
|
||||
// ValidateRuleType checks only one type of rule is defined per rule
|
||||
|
|
|
@ -2,6 +2,7 @@ package v1
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
@ -77,3 +78,48 @@ func (a *ForEachMutationWrapper) UnmarshalJSON(data []byte) error {
|
|||
a.Items = res
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConditionsWrapper contains either the deprecated list of Conditions or the new AnyAll Conditions.
|
||||
// +k8s:deepcopy-gen=false
|
||||
type ConditionsWrapper struct {
|
||||
// Conditions is a list of conditions that must be satisfied for the rule to be applied.
|
||||
// +optional
|
||||
Conditions any `json:"-"`
|
||||
}
|
||||
|
||||
func (in *ConditionsWrapper) DeepCopyInto(out *ConditionsWrapper) {
|
||||
if err := copier.Copy(out, in); err != nil {
|
||||
panic("deep copy failed")
|
||||
}
|
||||
}
|
||||
|
||||
func (in *ConditionsWrapper) DeepCopy() *ConditionsWrapper {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(ConditionsWrapper)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
func (a *ConditionsWrapper) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.Conditions)
|
||||
}
|
||||
|
||||
func (a *ConditionsWrapper) UnmarshalJSON(data []byte) error {
|
||||
var err error
|
||||
|
||||
var kyvernoOldConditions []Condition
|
||||
if err = json.Unmarshal(data, &kyvernoOldConditions); err == nil {
|
||||
a.Conditions = kyvernoOldConditions
|
||||
return nil
|
||||
}
|
||||
|
||||
var kyvernoAnyAllConditions AnyAllConditions
|
||||
if err = json.Unmarshal(data, &kyvernoAnyAllConditions); err == nil {
|
||||
a.Conditions = kyvernoAnyAllConditions
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("failed to unmarshal Conditions")
|
||||
}
|
||||
|
|
|
@ -506,8 +506,7 @@ func (in *Deny) DeepCopyInto(out *Deny) {
|
|||
*out = *in
|
||||
if in.RawAnyAllConditions != nil {
|
||||
in, out := &in.RawAnyAllConditions, &out.RawAnyAllConditions
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -1324,8 +1323,7 @@ func (in *Rule) DeepCopyInto(out *Rule) {
|
|||
}
|
||||
if in.RawAnyAllConditions != nil {
|
||||
in, out := &in.RawAnyAllConditions, &out.RawAnyAllConditions
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
if in.CELPreconditions != nil {
|
||||
in, out := &in.CELPreconditions, &out.CELPreconditions
|
||||
|
@ -1517,8 +1515,7 @@ func (in *TargetResourceSpec) DeepCopyInto(out *TargetResourceSpec) {
|
|||
}
|
||||
if in.RawAnyAllConditions != nil {
|
||||
in, out := &in.RawAnyAllConditions, &out.RawAnyAllConditions
|
||||
*out = new(apiextensionsv1.JSON)
|
||||
(*in).DeepCopyInto(*out)
|
||||
*out = (*in).DeepCopy()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
"reflect"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
)
|
||||
|
||||
func FixPolicy(policy kyvernov1.PolicyInterface) ([]string, error) {
|
||||
|
@ -38,10 +37,7 @@ func FixPolicy(policy kyvernov1.PolicyInterface) ([]string, error) {
|
|||
}
|
||||
preconditions := rule.GetAnyAllConditions()
|
||||
if preconditions != nil {
|
||||
cond, err := apiutils.ApiextensionsJsonToKyvernoConditions(preconditions)
|
||||
if err != nil {
|
||||
return messages, err
|
||||
}
|
||||
cond := preconditions
|
||||
var newCond *kyvernov1.AnyAllConditions
|
||||
switch typedValue := cond.(type) {
|
||||
case kyvernov1.AnyAllConditions:
|
||||
|
|
|
@ -1324,6 +1324,40 @@ string
|
|||
<p>
|
||||
<p>ConditionOperator is the operation performed on condition key and value.</p>
|
||||
</p>
|
||||
<h3 id="kyverno.io/v1.ConditionsWrapper">ConditionsWrapper
|
||||
</h3>
|
||||
<p>
|
||||
(<em>Appears on:</em>
|
||||
<a href="#kyverno.io/v1.Deny">Deny</a>,
|
||||
<a href="#kyverno.io/v1.Rule">Rule</a>,
|
||||
<a href="#kyverno.io/v1.TargetResourceSpec">TargetResourceSpec</a>)
|
||||
</p>
|
||||
<p>
|
||||
<p>ConditionsWrapper contains either the deprecated list of Conditions or the new AnyAll Conditions.</p>
|
||||
</p>
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>
|
||||
<code>-</code><br/>
|
||||
<em>
|
||||
any
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Conditions is a list of conditions that must be satisfied for the rule to be applied.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h3 id="kyverno.io/v1.ConfigMapReference">ConfigMapReference
|
||||
</h3>
|
||||
<p>
|
||||
|
@ -1542,8 +1576,8 @@ GlobalContextEntryReference
|
|||
<td>
|
||||
<code>conditions</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
|
||||
Kubernetes apiextensions/v1.JSON
|
||||
<a href="#kyverno.io/v1.ConditionsWrapper">
|
||||
ConditionsWrapper
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -3686,8 +3720,8 @@ This config is only valid for verifyImages rules.</p>
|
|||
<td>
|
||||
<code>preconditions</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
|
||||
Kubernetes apiextensions/v1.JSON
|
||||
<a href="#kyverno.io/v1.ConditionsWrapper">
|
||||
ConditionsWrapper
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
@ -4289,8 +4323,8 @@ ResourceSpec
|
|||
<td>
|
||||
<code>preconditions</code><br/>
|
||||
<em>
|
||||
<a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#json-v1-apiextensions">
|
||||
Kubernetes apiextensions/v1.JSON
|
||||
<a href="#kyverno.io/v1.ConditionsWrapper">
|
||||
ConditionsWrapper
|
||||
</a>
|
||||
</em>
|
||||
</td>
|
||||
|
|
|
@ -2712,6 +2712,71 @@ or can be variables declared using JMESPath.</p>
|
|||
|
||||
|
||||
|
||||
<H3 id="kyverno-io-v1-ConditionsWrapper">ConditionsWrapper
|
||||
</H3>
|
||||
|
||||
|
||||
<p>
|
||||
(<em>Appears in:</em>
|
||||
<a href="#kyverno-io-v1-Deny">Deny</a>,
|
||||
<a href="#kyverno-io-v1-Rule">Rule</a>,
|
||||
<a href="#kyverno-io-v1-TargetResourceSpec">TargetResourceSpec</a>)
|
||||
</p>
|
||||
|
||||
|
||||
<p><p>ConditionsWrapper contains either the deprecated list of Conditions or the new AnyAll Conditions.</p>
|
||||
</p>
|
||||
|
||||
|
||||
<table class="table table-striped">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<tr>
|
||||
<td><code>-</code>
|
||||
|
||||
</br>
|
||||
|
||||
|
||||
|
||||
|
||||
<span style="font-family: monospace">any</span>
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
|
||||
<p>Conditions is a list of conditions that must be satisfied for the rule to be applied.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<H3 id="kyverno-io-v1-ConfigMapReference">ConfigMapReference
|
||||
</H3>
|
||||
|
||||
|
@ -3175,7 +3240,9 @@ details.</p>
|
|||
|
||||
|
||||
|
||||
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
|
||||
<a href="#kyverno-io-v1-ConditionsWrapper">
|
||||
<span style="font-family: monospace">ConditionsWrapper</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
|
@ -7289,7 +7356,9 @@ This config is only valid for verifyImages rules.</p>
|
|||
|
||||
|
||||
|
||||
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
|
||||
<a href="#kyverno-io-v1-ConditionsWrapper">
|
||||
<span style="font-family: monospace">ConditionsWrapper</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
|
@ -8605,7 +8674,9 @@ Timestamps (SCTs). If the value is unset, the default behavior by Cosign is used
|
|||
|
||||
|
||||
|
||||
<span style="font-family: monospace">k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1.JSON</span>
|
||||
<a href="#kyverno-io-v1-ConditionsWrapper">
|
||||
<span style="font-family: monospace">ConditionsWrapper</span>
|
||||
</a>
|
||||
|
||||
|
||||
</td>
|
||||
|
|
|
@ -216,7 +216,7 @@ func convertRule(rule kyvernoRule, kind string) (*kyvernov1.Rule, error) {
|
|||
out.Context = *rule.Context
|
||||
}
|
||||
if rule.AnyAllConditions != nil {
|
||||
out.SetAnyAllConditions(*rule.AnyAllConditions)
|
||||
out.SetAnyAllConditions(rule.AnyAllConditions.Conditions)
|
||||
}
|
||||
if rule.Mutation != nil {
|
||||
out.Mutation = *rule.Mutation
|
||||
|
|
|
@ -7,10 +7,8 @@ import (
|
|||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
// the kyvernoRule holds the temporary kyverno rule struct
|
||||
|
@ -27,7 +25,7 @@ type kyvernoRule struct {
|
|||
MatchResources *kyvernov1.MatchResources `json:"match"`
|
||||
ExcludeResources *kyvernov1.MatchResources `json:"exclude,omitempty"`
|
||||
Context *[]kyvernov1.ContextEntry `json:"context,omitempty"`
|
||||
AnyAllConditions *apiextensions.JSON `json:"preconditions,omitempty"`
|
||||
AnyAllConditions *kyvernov1.ConditionsWrapper `json:"preconditions,omitempty"`
|
||||
Mutation *kyvernov1.Mutation `json:"mutate,omitempty"`
|
||||
Validation *kyvernov1.Validation `json:"validate,omitempty"`
|
||||
VerifyImages []kyvernov1.ImageVerification `json:"verifyImages,omitempty" yaml:"verifyImages,omitempty"`
|
||||
|
@ -53,7 +51,7 @@ func createRule(rule *kyvernov1.Rule) *kyvernoRule {
|
|||
if !datautils.DeepEqual(rule.Validation, kyvernov1.Validation{}) {
|
||||
jsonFriendlyStruct.Validation = rule.Validation.DeepCopy()
|
||||
}
|
||||
kyvernoAnyAllConditions, _ := apiutils.ApiextensionsJsonToKyvernoConditions(rule.GetAnyAllConditions())
|
||||
kyvernoAnyAllConditions := rule.GetAnyAllConditions()
|
||||
switch typedAnyAllConditions := kyvernoAnyAllConditions.(type) {
|
||||
case kyvernov1.AnyAllConditions:
|
||||
if !datautils.DeepEqual(typedAnyAllConditions, kyvernov1.AnyAllConditions{}) {
|
||||
|
|
|
@ -19,13 +19,13 @@ limitations under the License.
|
|||
package v1
|
||||
|
||||
import (
|
||||
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
v1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
)
|
||||
|
||||
// DenyApplyConfiguration represents an declarative configuration of the Deny type for use
|
||||
// with apply.
|
||||
type DenyApplyConfiguration struct {
|
||||
RawAnyAllConditions *v1.JSON `json:"conditions,omitempty"`
|
||||
RawAnyAllConditions *v1.ConditionsWrapper `json:"conditions,omitempty"`
|
||||
}
|
||||
|
||||
// DenyApplyConfiguration constructs an declarative configuration of the Deny type for use with
|
||||
|
@ -37,7 +37,7 @@ func Deny() *DenyApplyConfiguration {
|
|||
// WithRawAnyAllConditions sets the RawAnyAllConditions field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the RawAnyAllConditions field is set to the value of the last call.
|
||||
func (b *DenyApplyConfiguration) WithRawAnyAllConditions(value v1.JSON) *DenyApplyConfiguration {
|
||||
func (b *DenyApplyConfiguration) WithRawAnyAllConditions(value v1.ConditionsWrapper) *DenyApplyConfiguration {
|
||||
b.RawAnyAllConditions = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ package v1
|
|||
import (
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
v1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
// RuleApplyConfiguration represents an declarative configuration of the Rule type for use
|
||||
|
@ -32,7 +31,7 @@ type RuleApplyConfiguration struct {
|
|||
MatchResources *MatchResourcesApplyConfiguration `json:"match,omitempty"`
|
||||
ExcludeResources *MatchResourcesApplyConfiguration `json:"exclude,omitempty"`
|
||||
ImageExtractors *kyvernov1.ImageExtractorConfigs `json:"imageExtractors,omitempty"`
|
||||
RawAnyAllConditions *apiextensionsv1.JSON `json:"preconditions,omitempty"`
|
||||
RawAnyAllConditions *kyvernov1.ConditionsWrapper `json:"preconditions,omitempty"`
|
||||
CELPreconditions []v1alpha1.MatchCondition `json:"celPreconditions,omitempty"`
|
||||
Mutation *MutationApplyConfiguration `json:"mutate,omitempty"`
|
||||
Validation *ValidationApplyConfiguration `json:"validate,omitempty"`
|
||||
|
@ -95,7 +94,7 @@ func (b *RuleApplyConfiguration) WithImageExtractors(value kyvernov1.ImageExtrac
|
|||
// WithRawAnyAllConditions sets the RawAnyAllConditions field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the RawAnyAllConditions field is set to the value of the last call.
|
||||
func (b *RuleApplyConfiguration) WithRawAnyAllConditions(value apiextensionsv1.JSON) *RuleApplyConfiguration {
|
||||
func (b *RuleApplyConfiguration) WithRawAnyAllConditions(value kyvernov1.ConditionsWrapper) *RuleApplyConfiguration {
|
||||
b.RawAnyAllConditions = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
|||
package v1
|
||||
|
||||
import (
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
)
|
||||
|
||||
|
@ -28,7 +28,7 @@ import (
|
|||
type TargetResourceSpecApplyConfiguration struct {
|
||||
*ResourceSpecApplyConfiguration `json:"ResourceSpec,omitempty"`
|
||||
Context []ContextEntryApplyConfiguration `json:"context,omitempty"`
|
||||
RawAnyAllConditions *apiextensionsv1.JSON `json:"preconditions,omitempty"`
|
||||
RawAnyAllConditions *kyvernov1.ConditionsWrapper `json:"preconditions,omitempty"`
|
||||
}
|
||||
|
||||
// TargetResourceSpecApplyConfiguration constructs an declarative configuration of the TargetResourceSpec type for use with
|
||||
|
@ -104,7 +104,7 @@ func (b *TargetResourceSpecApplyConfiguration) WithContext(values ...*ContextEnt
|
|||
// WithRawAnyAllConditions sets the RawAnyAllConditions field in the declarative configuration to the given value
|
||||
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
|
||||
// If called multiple times, the RawAnyAllConditions field is set to the value of the last call.
|
||||
func (b *TargetResourceSpecApplyConfiguration) WithRawAnyAllConditions(value apiextensionsv1.JSON) *TargetResourceSpecApplyConfiguration {
|
||||
func (b *TargetResourceSpecApplyConfiguration) WithRawAnyAllConditions(value kyvernov1.ConditionsWrapper) *TargetResourceSpecApplyConfiguration {
|
||||
b.RawAnyAllConditions = &value
|
||||
return b
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@ import (
|
|||
engineutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine/validate"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
stringutils "github.com/kyverno/kyverno/pkg/utils/strings"
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
|
@ -66,7 +65,7 @@ type validator struct {
|
|||
policyContext engineapi.PolicyContext
|
||||
rule kyvernov1.Rule
|
||||
contextEntries []kyvernov1.ContextEntry
|
||||
anyAllConditions apiextensions.JSON
|
||||
anyAllConditions any
|
||||
pattern apiextensions.JSON
|
||||
anyPattern apiextensions.JSON
|
||||
deny *kyvernov1.Deny
|
||||
|
@ -76,7 +75,6 @@ type validator struct {
|
|||
}
|
||||
|
||||
func newValidator(log logr.Logger, contextLoader engineapi.EngineContextLoader, ctx engineapi.PolicyContext, rule kyvernov1.Rule) *validator {
|
||||
anyAllConditions, _ := datautils.ToMap(rule.RawAnyAllConditions)
|
||||
return &validator{
|
||||
log: log,
|
||||
rule: rule,
|
||||
|
@ -85,7 +83,7 @@ func newValidator(log logr.Logger, contextLoader engineapi.EngineContextLoader,
|
|||
pattern: rule.Validation.GetPattern(),
|
||||
anyPattern: rule.Validation.GetAnyPattern(),
|
||||
deny: rule.Validation.Deny,
|
||||
anyAllConditions: anyAllConditions,
|
||||
anyAllConditions: rule.GetAnyAllConditions(),
|
||||
forEach: rule.Validation.ForEachValidation,
|
||||
}
|
||||
}
|
||||
|
@ -98,10 +96,6 @@ func newForEachValidator(
|
|||
ctx engineapi.PolicyContext,
|
||||
log logr.Logger,
|
||||
) (*validator, error) {
|
||||
anyAllConditions, err := datautils.ToMap(foreach.AnyAllConditions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert ruleCopy.Validation.ForEachValidation.AnyAllConditions: %w", err)
|
||||
}
|
||||
var loopItems []kyvernov1.ForEachValidation
|
||||
fev := foreach.GetForEachValidation()
|
||||
if len(fev) > 0 {
|
||||
|
@ -115,7 +109,7 @@ func newForEachValidator(
|
|||
rule: rule,
|
||||
contextLoader: contextLoader,
|
||||
contextEntries: foreach.Context,
|
||||
anyAllConditions: anyAllConditions,
|
||||
anyAllConditions: foreach.AnyAllConditions,
|
||||
pattern: foreach.GetPattern(),
|
||||
anyPattern: foreach.GetAnyPattern(),
|
||||
deny: foreach.Deny,
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -76,12 +75,16 @@ func ApplyPatchNew(resource, patch []byte) ([]byte, error) {
|
|||
}
|
||||
|
||||
func TransformConditions(original apiextensions.JSON) (interface{}, error) {
|
||||
// conditions are currently in the form of []interface{}
|
||||
oldConditions, err := apiutils.ApiextensionsJsonToKyvernoConditions(original)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if original == nil {
|
||||
return kyvernov1.AnyAllConditions{}, nil
|
||||
}
|
||||
switch typedValue := oldConditions.(type) {
|
||||
|
||||
switch typedValue := original.(type) {
|
||||
case *kyvernov1.AnyAllConditions:
|
||||
if typedValue == nil {
|
||||
return kyvernov1.AnyAllConditions{}, nil
|
||||
}
|
||||
return *typedValue.DeepCopy(), nil
|
||||
case kyvernov1.AnyAllConditions:
|
||||
return *typedValue.DeepCopy(), nil
|
||||
case []kyvernov1.Condition: // backwards compatibility
|
||||
|
|
|
@ -30,6 +30,8 @@ func Evaluate(logger logr.Logger, ctx context.EvalInterface, condition kyvernov1
|
|||
// EvaluateConditions evaluates all the conditions present in a slice, in a backwards compatible way
|
||||
func EvaluateConditions(log logr.Logger, ctx context.EvalInterface, conditions interface{}) (bool, string, error) {
|
||||
switch typedConditions := conditions.(type) {
|
||||
case *kyvernov1.AnyAllConditions:
|
||||
return evaluateAnyAllConditions(log, ctx, *typedConditions)
|
||||
case kyvernov1.AnyAllConditions:
|
||||
return evaluateAnyAllConditions(log, ctx, typedConditions)
|
||||
case []kyvernov1.Condition: // backwards compatibility
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
)
|
||||
|
||||
// ApiextensionsJsonToKyvernoConditions takes in user-provided conditions in abstract apiextensions.JSON form
|
||||
// and converts it into []kyverno.Condition or kyverno.AnyAllConditions according to its content.
|
||||
// it also helps in validating the condtions as it returns an error when the conditions are provided wrongfully by the user.
|
||||
func ApiextensionsJsonToKyvernoConditions(in apiextensions.JSON) (interface{}, error) {
|
||||
path := "preconditions/validate.deny.conditions"
|
||||
|
||||
// checks for the existence any other field apart from 'any'/'all' under preconditions/validate.deny.conditions
|
||||
unknownFieldChecker := func(jsonByteArr []byte, path string) error {
|
||||
allowedKeys := map[string]bool{
|
||||
"any": true,
|
||||
"all": true,
|
||||
}
|
||||
var jsonDecoded map[string]interface{}
|
||||
if err := json.Unmarshal(jsonByteArr, &jsonDecoded); err != nil {
|
||||
return fmt.Errorf("error occurred while checking for unknown fields under %s: %+v", path, err)
|
||||
}
|
||||
for k := range jsonDecoded {
|
||||
if !allowedKeys[k] {
|
||||
return fmt.Errorf("unknown field '%s' found under %s", k, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// marshalling the abstract apiextensions.JSON back to JSON form
|
||||
jsonByte, err := json.Marshal(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error occurred while marshalling %s: %+v", path, err)
|
||||
}
|
||||
|
||||
var kyvernoOldConditions []kyvernov1.Condition
|
||||
if err = json.Unmarshal(jsonByte, &kyvernoOldConditions); err == nil {
|
||||
var validConditionOperator bool
|
||||
|
||||
for _, jsonOp := range kyvernoOldConditions {
|
||||
for _, validOp := range kyvernov1.ConditionOperators {
|
||||
if jsonOp.Operator == validOp {
|
||||
validConditionOperator = true
|
||||
}
|
||||
}
|
||||
if !validConditionOperator {
|
||||
return nil, fmt.Errorf("invalid condition operator: %s", jsonOp.Operator)
|
||||
}
|
||||
validConditionOperator = false
|
||||
}
|
||||
|
||||
return kyvernoOldConditions, nil
|
||||
}
|
||||
|
||||
var kyvernoAnyAllConditions kyvernov1.AnyAllConditions
|
||||
if err = json.Unmarshal(jsonByte, &kyvernoAnyAllConditions); err == nil {
|
||||
// checking if unknown fields exist or not
|
||||
err = unknownFieldChecker(jsonByte, path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error occurred while parsing %s: %+v", path, err)
|
||||
}
|
||||
return kyvernoAnyAllConditions, nil
|
||||
}
|
||||
return nil, fmt.Errorf("error occurred while parsing %s: %+v", path, err)
|
||||
}
|
|
@ -7,7 +7,6 @@ import (
|
|||
fuzz "github.com/AdaLogics/go-fuzz-headers"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
|
||||
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
)
|
||||
|
||||
func CreatePolicySpec(ff *fuzz.ConsumeFuzzer) (kyvernov1.Spec, error) {
|
||||
|
@ -194,7 +193,7 @@ func createRule(f *fuzz.ConsumeFuzzer) (*kyvernov1.Rule, error) {
|
|||
return rule, err
|
||||
}
|
||||
if setRawAnyAllConditions {
|
||||
raac := &apiextv1.JSON{}
|
||||
raac := &kyvernov1.ConditionsWrapper{}
|
||||
err = f.GenerateStruct(raac)
|
||||
if err != nil {
|
||||
return rule, err
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/engine/variables/operator"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
apiutils "github.com/kyverno/kyverno/pkg/utils/api"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
vaputils "github.com/kyverno/kyverno/pkg/validatingadmissionpolicy"
|
||||
|
@ -1033,7 +1032,7 @@ func validateMutationForEach(foreach []kyvernov1.ForEachMutation, schemaKey stri
|
|||
// validateConditions validates all the 'conditions' or 'preconditions' of a rule depending on the corresponding 'condition.key'.
|
||||
// As of now, it is validating the 'value' field whether it contains the only allowed set of values or not when 'condition.key' is {{request.operation}}
|
||||
// this is backwards compatible i.e. conditions can be provided in the old manner as well i.e. without 'any' or 'all'
|
||||
func validateConditions(conditions apiextensions.JSON, schemaKey string) (string, error) {
|
||||
func validateConditions(conditions any, schemaKey string) (string, error) {
|
||||
// Conditions can only exist under some specific keys of the policy schema
|
||||
allowedSchemaKeys := map[string]bool{
|
||||
"preconditions": true,
|
||||
|
@ -1043,12 +1042,7 @@ func validateConditions(conditions apiextensions.JSON, schemaKey string) (string
|
|||
return schemaKey, fmt.Errorf("wrong schema key found for validating the conditions. Conditions can only occur under one of ['preconditions', 'conditions'] keys in the policy schema")
|
||||
}
|
||||
|
||||
// conditions are currently in the form of []interface{}
|
||||
kyvernoConditions, err := apiutils.ApiextensionsJsonToKyvernoConditions(conditions)
|
||||
if err != nil {
|
||||
return schemaKey, err
|
||||
}
|
||||
switch typedConditions := kyvernoConditions.(type) {
|
||||
switch typedConditions := conditions.(type) {
|
||||
case kyvernov1.AnyAllConditions:
|
||||
// validating the conditions under 'any', if there are any
|
||||
if !datautils.DeepEqual(typedConditions, kyvernov1.AnyAllConditions{}) && typedConditions.AnyConditions != nil {
|
||||
|
@ -1142,7 +1136,7 @@ func validateAnyAllConditionOperator(c kyvernov1.AnyAllConditions, schemaKey str
|
|||
return "", nil
|
||||
}
|
||||
|
||||
func validateRawJSONConditionOperator(c apiextensions.JSON, schemaKey string) (string, error) {
|
||||
func validateRawJSONConditionOperator(c any, schemaKey string) (string, error) {
|
||||
allowedSchemaKeys := map[string]bool{
|
||||
"preconditions": true,
|
||||
"conditions": true,
|
||||
|
@ -1151,11 +1145,7 @@ func validateRawJSONConditionOperator(c apiextensions.JSON, schemaKey string) (s
|
|||
return schemaKey, fmt.Errorf("wrong schema key found for validating the conditions. Conditions can only occur under one of ['preconditions', 'conditions'] keys in the policy schema")
|
||||
}
|
||||
|
||||
kyvernoConditions, err := apiutils.ApiextensionsJsonToKyvernoConditions(c)
|
||||
if err != nil {
|
||||
return schemaKey, err
|
||||
}
|
||||
switch typedConditions := kyvernoConditions.(type) {
|
||||
switch typedConditions := c.(type) {
|
||||
case kyvernov1.AnyAllConditions:
|
||||
if path, err := validateAnyAllConditionOperator(typedConditions, schemaKey); err != nil {
|
||||
return path, err
|
||||
|
@ -1479,8 +1469,7 @@ func validateWildcard(kinds []string, background bool, rule kyvernov1.Rule) erro
|
|||
}
|
||||
|
||||
if rule.Validation.Deny != nil {
|
||||
kyvernoConditions, _ := apiutils.ApiextensionsJsonToKyvernoConditions(rule.Validation.Deny.GetAnyAllConditions())
|
||||
switch typedConditions := kyvernoConditions.(type) {
|
||||
switch typedConditions := rule.Validation.Deny.GetAnyAllConditions().(type) {
|
||||
case []kyvernov1.Condition: // backwards compatibility
|
||||
for _, condition := range typedConditions {
|
||||
key := condition.GetKey()
|
||||
|
@ -1661,11 +1650,7 @@ func checkDeprecatedAnyAllConditionOperator(c kyvernov1.AnyAllConditions, warnin
|
|||
}
|
||||
|
||||
func checkDeprecatedRawJSONConditionOperator(c apiextensions.JSON, warnings *[]string) {
|
||||
kyvernoConditions, err := apiutils.ApiextensionsJsonToKyvernoConditions(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch typedConditions := kyvernoConditions.(type) {
|
||||
switch typedConditions := c.(type) {
|
||||
case kyvernov1.AnyAllConditions:
|
||||
checkDeprecatedAnyAllConditionOperator(typedConditions, warnings)
|
||||
case []kyvernov1.Condition: // backwards compatibility
|
||||
|
|
Loading…
Add table
Reference in a new issue