package yaml import ( "encoding/json" "fmt" "strings" kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1" log "github.com/kyverno/kyverno/pkg/logging" "k8s.io/api/admissionregistration/v1alpha1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/yaml" ) // GetPolicy extracts policies from YAML bytes func GetPolicy(bytes []byte) (policies []kyvernov1.PolicyInterface, validatingAdmissionPolicies []v1alpha1.ValidatingAdmissionPolicy, err error) { documents, err := SplitDocuments(bytes) if err != nil { return nil, nil, err } for _, thisPolicyBytes := range documents { policyBytes, err := yaml.ToJSON(thisPolicyBytes) if err != nil { return nil, nil, fmt.Errorf("failed to convert to JSON: %v", err) } us := &unstructured.Unstructured{} if err := json.Unmarshal(policyBytes, us); err != nil { return nil, nil, fmt.Errorf("failed to decode policy: %v", err) } if us.IsList() { list, err := us.ToList() if err != nil { return nil, nil, fmt.Errorf("failed to decode policy list: %v", err) } for i := range list.Items { item := list.Items[i] if policies, validatingAdmissionPolicies, err = addPolicy(policies, validatingAdmissionPolicies, &item); err != nil { return nil, nil, err } } } else { if policies, validatingAdmissionPolicies, err = addPolicy(policies, validatingAdmissionPolicies, us); err != nil { return nil, nil, err } } } return policies, validatingAdmissionPolicies, nil } func addPolicy(policies []kyvernov1.PolicyInterface, validatingAdmissionPolicies []v1alpha1.ValidatingAdmissionPolicy, us *unstructured.Unstructured) ([]kyvernov1.PolicyInterface, []v1alpha1.ValidatingAdmissionPolicy, error) { kind := us.GetKind() if strings.Compare(kind, "ValidatingAdmissionPolicy") == 0 { validatingAdmissionPolicy := &v1alpha1.ValidatingAdmissionPolicy{} if err := runtime.DefaultUnstructuredConverter.FromUnstructured(us.Object, validatingAdmissionPolicy); err != nil { return policies, nil, fmt.Errorf("failed to decode policy: %v", err) } if validatingAdmissionPolicy.Kind == "" { log.V(3).Info("skipping file as ValidatingAdmissionPolicy.Kind not found") return policies, validatingAdmissionPolicies, nil } validatingAdmissionPolicies = append(validatingAdmissionPolicies, *validatingAdmissionPolicy) } else { var policy kyvernov1.PolicyInterface if us.GetKind() == "ClusterPolicy" { policy = &kyvernov1.ClusterPolicy{} } else { policy = &kyvernov1.Policy{} } if err := runtime.DefaultUnstructuredConverter.FromUnstructured(us.Object, policy); err != nil { return nil, validatingAdmissionPolicies, fmt.Errorf("failed to decode policy: %v", err) } if policy.GetKind() == "" { log.V(3).Info("skipping file as policy.TypeMeta.Kind not found") return policies, validatingAdmissionPolicies, nil } if policy.GetKind() != "ClusterPolicy" && policy.GetKind() != "Policy" { return nil, validatingAdmissionPolicies, fmt.Errorf("resource %s/%s is not a Policy or a ClusterPolicy", policy.GetKind(), policy.GetName()) } if policy.GetKind() == "Policy" { if policy.GetNamespace() == "" { policy.SetNamespace("default") } } else { policy.SetNamespace("") } policies = append(policies, policy) } return policies, validatingAdmissionPolicies, nil }