2023-08-16 17:42:37 +01:00
package engine
import (
"context"
"encoding/json"
"fmt"
2023-08-23 22:45:01 +01:00
"sync"
2023-08-16 17:42:37 +01:00
"testing"
2023-10-05 17:33:26 +01:00
kyvFuzz "github.com/kyverno/kyverno/pkg/utils/fuzz"
2023-08-16 17:42:37 +01:00
2023-10-05 17:33:26 +01:00
corev1 "k8s.io/api/core/v1"
2023-08-23 22:45:01 +01:00
2023-10-05 17:33:26 +01:00
fuzz "github.com/AdaLogics/go-fuzz-headers"
2023-08-16 17:42:37 +01:00
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine/adapters"
2023-10-05 17:33:26 +01:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2023-08-16 17:42:37 +01:00
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/factories"
"github.com/kyverno/kyverno/pkg/engine/jmespath"
"github.com/kyverno/kyverno/pkg/engine/policycontext"
"github.com/kyverno/kyverno/pkg/imageverifycache"
"github.com/kyverno/kyverno/pkg/registryclient"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
)
var (
fuzzCfg = config . NewDefaultConfiguration ( false )
fuzzMetricsCfg = config . NewDefaultMetricsConfiguration ( )
fuzzJp = jmespath . New ( fuzzCfg )
validateContext = context . Background ( )
regClient = registryclient . NewOrDie ( )
validateEngine = NewEngine (
fuzzCfg ,
config . NewDefaultMetricsConfiguration ( ) ,
fuzzJp ,
nil ,
factories . DefaultRegistryClientFactory ( adapters . RegistryClient ( regClient ) , nil ) ,
imageverifycache . DisabledImageVerifyCache ( ) ,
factories . DefaultContextLoaderFactory ( nil ) ,
nil ,
)
2023-10-05 17:33:26 +01:00
initter sync . Once
2023-08-16 17:42:37 +01:00
)
2023-08-22 23:35:06 +01:00
func buildFuzzContext ( ff * fuzz . ConsumeFuzzer ) ( * PolicyContext , error ) {
2023-10-05 17:33:26 +01:00
cpSpec , err := kyvFuzz . CreatePolicySpec ( ff )
2023-08-16 17:42:37 +01:00
if err != nil {
return nil , err
}
2023-08-22 23:35:06 +01:00
cpol := & kyverno . ClusterPolicy { }
cpol . Spec = cpSpec
2023-08-16 17:42:37 +01:00
2024-04-04 10:09:30 +02:00
if len ( autogen . ComputeRules ( cpol , "" ) ) == 0 {
2023-08-22 23:35:06 +01:00
return nil , fmt . Errorf ( "No rules created" )
}
2023-10-05 17:33:26 +01:00
resourceUnstructured , err := kyvFuzz . CreateUnstructuredObject ( ff , "" )
2023-08-16 17:42:37 +01:00
if err != nil {
return nil , err
}
policyContext , err := policycontext . NewPolicyContext (
fuzzJp ,
* resourceUnstructured ,
kyverno . Create ,
nil ,
fuzzCfg ,
)
if err != nil {
return nil , err
}
policyContext = policyContext .
2023-08-22 23:35:06 +01:00
WithPolicy ( cpol ) .
2023-08-16 17:42:37 +01:00
WithNewResource ( * resourceUnstructured )
2023-08-22 23:35:06 +01:00
addOldResource , err := ff . GetBool ( )
if err != nil {
return nil , err
}
if addOldResource {
2023-10-05 17:33:26 +01:00
oldResourceUnstructured , err := kyvFuzz . CreateUnstructuredObject ( ff , "" )
2023-08-16 17:42:37 +01:00
if err != nil {
return nil , err
}
2023-08-22 23:35:06 +01:00
oldResource , err := json . Marshal ( oldResourceUnstructured )
if err != nil {
return policyContext , nil
}
2023-08-16 17:42:37 +01:00
err = enginecontext . AddOldResource ( policyContext . JSONContext ( ) , oldResource )
if err != nil {
return nil , err
}
policyContext = policyContext . WithOldResource ( * oldResourceUnstructured )
}
return policyContext , nil
}
2023-08-22 23:35:06 +01:00
/ *
VerifyAndPatchImage
* /
2023-08-16 17:42:37 +01:00
func FuzzVerifyImageAndPatchTest ( f * testing . F ) {
2023-08-22 23:35:06 +01:00
f . Fuzz ( func ( t * testing . T , data [ ] byte ) {
ff := fuzz . NewConsumer ( data )
pc , err := buildFuzzContext ( ff )
2023-08-16 17:42:37 +01:00
if err != nil {
return
}
verifyImageAndPatchEngine := NewEngine (
2023-08-17 15:09:08 +01:00
fuzzCfg ,
2023-08-16 17:42:37 +01:00
fuzzMetricsCfg ,
fuzzJp ,
nil ,
factories . DefaultRegistryClientFactory ( adapters . RegistryClient ( registryclient . NewOrDie ( ) ) , nil ) ,
imageverifycache . DisabledImageVerifyCache ( ) ,
factories . DefaultContextLoaderFactory ( nil ) ,
nil ,
)
_ , _ = verifyImageAndPatchEngine . VerifyAndPatchImages (
context . Background ( ) ,
pc ,
)
} )
}
func FuzzEngineValidateTest ( f * testing . F ) {
f . Fuzz ( func ( t * testing . T , data [ ] byte ) {
ff := fuzz . NewConsumer ( data )
2023-10-05 17:33:26 +01:00
cpSpec , err := kyvFuzz . CreatePolicySpec ( ff )
2023-08-16 17:42:37 +01:00
if err != nil {
return
}
policy := & kyverno . ClusterPolicy { }
policy . Spec = cpSpec
2024-04-04 10:09:30 +02:00
if len ( autogen . ComputeRules ( policy , "" ) ) == 0 {
2023-08-16 17:42:37 +01:00
return
}
2023-10-05 17:33:26 +01:00
resourceUnstructured , err := kyvFuzz . CreateUnstructuredObject ( ff , "" )
2023-08-16 17:42:37 +01:00
if err != nil {
return
}
pc , err := NewPolicyContext ( fuzzJp , * resourceUnstructured , kyverno . Create , nil , fuzzCfg )
if err != nil {
2023-10-05 17:33:26 +01:00
return
2023-08-16 17:42:37 +01:00
}
validateEngine . Validate (
validateContext ,
pc . WithPolicy ( policy ) ,
)
} )
}
2023-10-05 17:33:26 +01:00
func getPod ( ff * fuzz . ConsumeFuzzer ) ( * corev1 . Pod , error ) {
pod := & corev1 . Pod { }
err := ff . GenerateStruct ( pod )
pod . Kind = "Pod"
pod . APIVersion = "v1"
return pod , err
2023-08-22 23:35:06 +01:00
}
2023-10-05 17:33:26 +01:00
func FuzzPodBypass ( f * testing . F ) {
f . Fuzz ( func ( t * testing . T , data [ ] byte ) {
initter . Do ( kyvFuzz . InitFuzz )
2023-08-22 23:35:06 +01:00
2023-10-05 17:33:26 +01:00
ff := fuzz . NewConsumer ( data )
policyToCheck , err := ff . GetInt ( )
2023-08-22 23:35:06 +01:00
if err != nil {
2023-10-05 17:33:26 +01:00
return
2023-08-22 23:35:06 +01:00
}
2023-10-05 17:33:26 +01:00
testPolicy := kyvFuzz . Policies [ policyToCheck % 11 ]
pod , err := getPod ( ff )
2023-08-22 23:35:06 +01:00
if err != nil {
2023-10-05 17:33:26 +01:00
return
2023-08-22 23:35:06 +01:00
}
2023-10-05 17:33:26 +01:00
shouldBlock , err := testPolicy . ShouldBlock ( pod )
if err != nil {
return
}
2023-08-22 23:35:06 +01:00
2023-10-05 17:33:26 +01:00
resource , err := json . MarshalIndent ( pod , "" , " " )
if err != nil {
return
}
2023-08-16 17:42:37 +01:00
2023-10-05 17:33:26 +01:00
resourceUnstructured , err := kubeutils . BytesToUnstructured ( resource )
if err != nil {
return
}
2023-08-16 17:42:37 +01:00
2023-10-05 17:33:26 +01:00
pc , err := NewPolicyContext ( fuzzJp , * resourceUnstructured , kyverno . Create , nil , fuzzCfg )
2023-08-16 17:42:37 +01:00
if err != nil {
2023-10-05 17:33:26 +01:00
return
2023-08-16 17:42:37 +01:00
}
2023-10-05 17:33:26 +01:00
er := validateEngine . Validate (
validateContext ,
pc . WithPolicy ( testPolicy . ClusterPolicy ) ,
)
2024-05-30 07:29:24 +08:00
blocked := blockRequest ( [ ] engineapi . EngineResponse { er } )
2023-10-05 17:33:26 +01:00
if blocked != shouldBlock {
panic ( fmt . Sprintf ( "\nDid not block a resource that should be blocked:\n%s\n should have been blocked by \n%+v\n\nshouldBlock was %t\nblocked was %t\n" , string ( resource ) , testPolicy . ClusterPolicy , shouldBlock , blocked ) )
}
} )
}
2024-05-30 07:29:24 +08:00
func blockRequest ( engineResponses [ ] engineapi . EngineResponse ) bool {
2023-10-05 17:33:26 +01:00
for _ , er := range engineResponses {
if er . IsFailed ( ) {
return true
2023-08-16 17:42:37 +01:00
}
}
2023-10-05 17:33:26 +01:00
return false
2023-08-16 17:42:37 +01:00
}
func FuzzMutateTest ( f * testing . F ) {
2023-08-22 23:35:06 +01:00
f . Fuzz ( func ( t * testing . T , data [ ] byte ) {
ff := fuzz . NewConsumer ( data )
//ff.GenerateStruct(policy)
2023-10-05 17:33:26 +01:00
cpSpec , err := kyvFuzz . CreatePolicySpec ( ff )
2023-08-16 17:42:37 +01:00
if err != nil {
return
}
2023-08-22 23:35:06 +01:00
policy := & kyverno . ClusterPolicy { }
policy . Spec = cpSpec
2024-04-04 10:09:30 +02:00
if len ( autogen . ComputeRules ( policy , "" ) ) == 0 {
2023-08-22 23:35:06 +01:00
return
}
2023-10-05 17:33:26 +01:00
resource , err := kyvFuzz . CreateUnstructuredObject ( ff , "" )
2023-08-16 17:42:37 +01:00
if err != nil {
return
}
// create policy context
pc , err := NewPolicyContext (
fuzzJp ,
2023-08-22 23:35:06 +01:00
* resource ,
2023-08-16 17:42:37 +01:00
kyverno . Create ,
nil ,
fuzzCfg ,
)
if err != nil {
t . Skip ( )
}
2023-10-05 17:33:26 +01:00
fuzzInterface := kyvFuzz . FuzzInterface { FF : ff }
2023-08-16 17:42:37 +01:00
e := NewEngine (
fuzzCfg ,
config . NewDefaultMetricsConfiguration ( ) ,
fuzzJp ,
2023-08-23 22:45:01 +01:00
adapters . Client ( fuzzInterface ) ,
2023-08-16 17:42:37 +01:00
factories . DefaultRegistryClientFactory ( adapters . RegistryClient ( nil ) , nil ) ,
imageverifycache . DisabledImageVerifyCache ( ) ,
factories . DefaultContextLoaderFactory ( nil ) ,
nil ,
)
e . Mutate (
context . Background ( ) ,
2023-08-22 23:35:06 +01:00
pc . WithPolicy ( policy ) ,
2023-08-16 17:42:37 +01:00
)
} )
}