2023-04-18 14:08:17 +02:00
package test
import (
"fmt"
"os"
"regexp"
"strings"
"github.com/go-git/go-billy/v5"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
"github.com/kyverno/kyverno/api/kyverno/v1beta1"
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/test/api"
2023-09-01 01:42:08 +02:00
annotationsutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/annotations"
2023-04-18 14:08:17 +02:00
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
2023-08-30 12:24:43 +02:00
filterutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/filter"
2023-08-29 20:20:17 +02:00
pathutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/path"
2023-04-18 14:08:17 +02:00
sanitizederror "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/sanitizedError"
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
2023-08-30 23:42:02 +02:00
unstructuredutils "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/unstructured"
2023-04-18 14:08:17 +02:00
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/clients/dclient"
2023-04-24 18:31:42 +08:00
"github.com/kyverno/kyverno/pkg/config"
2023-04-18 14:08:17 +02:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/openapi"
2023-04-28 21:54:17 +08:00
policyvalidation "github.com/kyverno/kyverno/pkg/validation/policy"
2023-04-18 14:08:17 +02:00
"golang.org/x/exp/slices"
2023-05-10 11:12:53 +03:00
"k8s.io/api/admissionregistration/v1alpha1"
2023-04-18 14:08:17 +02:00
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/log"
)
func applyPoliciesFromPath (
fs billy . Filesystem ,
2023-08-30 18:17:28 +02:00
apiTest * api . Test ,
2023-04-18 14:08:17 +02:00
isGit bool ,
policyResourcePath string ,
rc * resultCounts ,
openApiManager openapi . Manager ,
2023-08-30 12:24:43 +02:00
filter filterutils . Filter ,
2023-04-18 14:08:17 +02:00
auditWarn bool ,
) ( map [ string ] policyreportv1alpha2 . PolicyReportResult , [ ] api . TestResults , error ) {
engineResponses := make ( [ ] engineapi . EngineResponse , 0 )
var dClient dclient . Interface
var resultCounts common . ResultCounts
2023-06-26 22:46:30 +02:00
store . SetLocal ( true )
2023-04-18 14:08:17 +02:00
var filteredResults [ ] api . TestResults
2023-08-30 18:17:28 +02:00
for _ , res := range apiTest . Results {
2023-08-30 12:24:43 +02:00
if filter . Apply ( res ) {
2023-04-18 14:08:17 +02:00
filteredResults = append ( filteredResults , res )
}
}
2023-08-30 18:17:28 +02:00
apiTest . Results = filteredResults
2023-04-18 14:08:17 +02:00
2023-08-30 18:17:28 +02:00
if len ( apiTest . Results ) == 0 {
2023-04-18 14:08:17 +02:00
return nil , nil , nil
}
2023-08-30 18:17:28 +02:00
fmt . Printf ( "\nExecuting %s...\n" , apiTest . Name )
valuesFile := apiTest . Variables
userInfoFile := apiTest . UserInfo
2023-04-18 14:08:17 +02:00
2023-08-30 18:17:28 +02:00
variables , globalValMap , valuesMap , namespaceSelectorMap , subresources , err := common . GetVariable ( nil , apiTest . Values , apiTest . Variables , fs , isGit , policyResourcePath )
2023-04-18 14:08:17 +02:00
if err != nil {
if ! sanitizederror . IsErrorSanitized ( err ) {
return nil , nil , sanitizederror . NewWithError ( "failed to decode yaml" , err )
}
return nil , nil , err
}
// get the user info as request info from a different file
var userInfo v1beta1 . RequestInfo
if userInfoFile != "" {
userInfo , err = common . GetUserInfoFromPath ( fs , userInfoFile , isGit , policyResourcePath )
if err != nil {
fmt . Printf ( "Error: failed to load request info\nCause: %s\n" , err )
os . Exit ( 1 )
}
}
2023-08-30 18:17:28 +02:00
policyFullPath := pathutils . GetFullPaths ( apiTest . Policies , policyResourcePath , isGit )
resourceFullPath := pathutils . GetFullPaths ( apiTest . Resources , policyResourcePath , isGit )
2023-04-18 14:08:17 +02:00
2023-08-30 18:17:28 +02:00
for i , result := range apiTest . Results {
2023-04-18 14:08:17 +02:00
arrPatchedResource := [ ] string { result . PatchedResource }
arrGeneratedResource := [ ] string { result . GeneratedResource }
arrCloneSourceResource := [ ] string { result . CloneSourceResource }
2023-08-29 20:20:17 +02:00
patchedResourceFullPath := pathutils . GetFullPaths ( arrPatchedResource , policyResourcePath , isGit )
generatedResourceFullPath := pathutils . GetFullPaths ( arrGeneratedResource , policyResourcePath , isGit )
CloneSourceResourceFullPath := pathutils . GetFullPaths ( arrCloneSourceResource , policyResourcePath , isGit )
2023-04-18 14:08:17 +02:00
2023-08-30 18:17:28 +02:00
apiTest . Results [ i ] . PatchedResource = patchedResourceFullPath [ 0 ]
apiTest . Results [ i ] . GeneratedResource = generatedResourceFullPath [ 0 ]
apiTest . Results [ i ] . CloneSourceResource = CloneSourceResourceFullPath [ 0 ]
2023-04-18 14:08:17 +02:00
}
2023-05-10 11:12:53 +03:00
policies , validatingAdmissionPolicies , err := common . GetPoliciesFromPaths ( fs , policyFullPath , isGit , policyResourcePath )
2023-04-18 14:08:17 +02:00
if err != nil {
fmt . Printf ( "Error: failed to load policies\nCause: %s\n" , err )
os . Exit ( 1 )
}
var filteredPolicies [ ] kyvernov1 . PolicyInterface
for _ , p := range policies {
2023-08-30 18:17:28 +02:00
for _ , res := range apiTest . Results {
2023-04-18 14:08:17 +02:00
if p . GetName ( ) == res . Policy {
filteredPolicies = append ( filteredPolicies , p )
break
}
}
}
2023-05-10 11:12:53 +03:00
var filteredVAPs [ ] v1alpha1 . ValidatingAdmissionPolicy
for _ , p := range validatingAdmissionPolicies {
2023-08-30 18:17:28 +02:00
for _ , res := range apiTest . Results {
2023-05-10 11:12:53 +03:00
if p . GetName ( ) == res . Policy {
filteredVAPs = append ( filteredVAPs , p )
break
}
}
}
validatingAdmissionPolicies = filteredVAPs
2023-04-18 14:08:17 +02:00
ruleToCloneSourceResource := map [ string ] string { }
for _ , p := range filteredPolicies {
var filteredRules [ ] kyvernov1 . Rule
for _ , rule := range autogen . ComputeRules ( p ) {
2023-08-30 18:17:28 +02:00
for _ , res := range apiTest . Results {
2023-07-28 03:32:30 +03:00
if res . IsValidatingAdmissionPolicy {
2023-05-10 11:12:53 +03:00
continue
}
2023-04-18 14:08:17 +02:00
if rule . Name == res . Rule {
filteredRules = append ( filteredRules , rule )
if rule . HasGenerate ( ) {
ruleUnstr , err := generate . GetUnstrRule ( rule . Generation . DeepCopy ( ) )
if err != nil {
fmt . Printf ( "Error: failed to get unstructured rule\nCause: %s\n" , err )
break
}
genClone , _ , err := unstructured . NestedMap ( ruleUnstr . Object , "clone" )
if err != nil {
fmt . Printf ( "Error: failed to read data\nCause: %s\n" , err )
break
}
if len ( genClone ) != 0 {
ruleToCloneSourceResource [ rule . Name ] = res . CloneSourceResource
}
}
break
}
}
}
p . GetSpec ( ) . SetRules ( filteredRules )
}
policies = filteredPolicies
2023-05-10 11:12:53 +03:00
resources , err := common . GetResourceAccordingToResourcePath ( fs , resourceFullPath , false , policies , validatingAdmissionPolicies , dClient , "" , false , isGit , policyResourcePath )
2023-04-18 14:08:17 +02:00
if err != nil {
fmt . Printf ( "Error: failed to load resources\nCause: %s\n" , err )
os . Exit ( 1 )
}
2023-08-30 18:17:28 +02:00
checkableResources := selectResourcesForCheck ( resources , apiTest )
2023-04-18 14:08:17 +02:00
msgPolicies := "1 policy"
2023-05-10 11:12:53 +03:00
if len ( policies ) + len ( validatingAdmissionPolicies ) > 1 {
msgPolicies = fmt . Sprintf ( "%d policies" , len ( policies ) + len ( validatingAdmissionPolicies ) )
2023-04-18 14:08:17 +02:00
}
msgResources := "1 resource"
if len ( checkableResources ) > 1 {
msgResources = fmt . Sprintf ( "%d resources" , len ( checkableResources ) )
}
if len ( policies ) > 0 && len ( checkableResources ) > 0 {
fmt . Printf ( "applying %s to %s... \n" , msgPolicies , msgResources )
}
for _ , policy := range policies {
2023-04-28 21:54:17 +08:00
_ , err := policyvalidation . Validate ( policy , nil , nil , true , openApiManager , config . KyvernoUserName ( config . KyvernoServiceAccountName ( ) ) )
2023-04-18 14:08:17 +02:00
if err != nil {
log . Log . Error ( err , "skipping invalid policy" , "name" , policy . GetName ( ) )
continue
}
matches := common . HasVariables ( policy )
variable := common . RemoveDuplicateAndObjectVariables ( matches )
if len ( variable ) > 0 {
if len ( variables ) == 0 {
// check policy in variable file
if valuesFile == "" || valuesMap [ policy . GetName ( ) ] == nil {
fmt . Printf ( "test skipped for policy %v (as required variables are not provided by the users) \n \n" , policy . GetName ( ) )
}
}
}
kindOnwhichPolicyIsApplied := common . GetKindsFromPolicy ( policy , subresources , dClient )
for _ , resource := range checkableResources {
thisPolicyResourceValues , err := common . CheckVariableForPolicy ( valuesMap , globalValMap , policy . GetName ( ) , resource . GetName ( ) , resource . GetKind ( ) , variables , kindOnwhichPolicyIsApplied , variable )
if err != nil {
return nil , nil , sanitizederror . NewWithError ( fmt . Sprintf ( "policy `%s` have variables. pass the values for the variables for resource `%s` using set/values_file flag" , policy . GetName ( ) , resource . GetName ( ) ) , err )
}
applyPolicyConfig := common . ApplyPolicyConfig {
Policy : policy ,
Resource : resource ,
MutateLogPath : "" ,
Variables : thisPolicyResourceValues ,
UserInfo : userInfo ,
PolicyReport : true ,
NamespaceSelectorMap : namespaceSelectorMap ,
Rc : & resultCounts ,
RuleToCloneSourceResource : ruleToCloneSourceResource ,
Client : dClient ,
Subresources : subresources ,
}
2023-05-12 16:14:48 +02:00
ers , err := common . ApplyPolicyOnResource ( applyPolicyConfig )
2023-05-10 11:12:53 +03:00
if err != nil {
return nil , nil , sanitizederror . NewWithError ( fmt . Errorf ( "failed to apply policy %v on resource %v" , policy . GetName ( ) , resource . GetName ( ) ) . Error ( ) , err )
}
engineResponses = append ( engineResponses , ers ... )
}
}
validatingAdmissionPolicy := common . ValidatingAdmissionPolicies { }
for _ , policy := range validatingAdmissionPolicies {
for _ , resource := range resources {
applyPolicyConfig := common . ApplyPolicyConfig {
ValidatingAdmissionPolicy : policy ,
Resource : resource ,
PolicyReport : true ,
Rc : & resultCounts ,
Client : dClient ,
Subresources : subresources ,
}
ers , err := validatingAdmissionPolicy . ApplyPolicyOnResource ( applyPolicyConfig )
2023-04-18 14:08:17 +02:00
if err != nil {
return nil , nil , sanitizederror . NewWithError ( fmt . Errorf ( "failed to apply policy %v on resource %v" , policy . GetName ( ) , resource . GetName ( ) ) . Error ( ) , err )
}
engineResponses = append ( engineResponses , ers ... )
}
}
2023-08-30 18:17:28 +02:00
resultsMap , testResults := buildPolicyResults ( engineResponses , apiTest . Results , policyResourcePath , fs , isGit , auditWarn )
2023-04-18 14:08:17 +02:00
return resultsMap , testResults , nil
}
func selectResourcesForCheck ( resources [ ] * unstructured . Unstructured , values * api . Test ) [ ] * unstructured . Unstructured {
res , _ , _ := selectResourcesForCheckInternal ( resources , values )
return res
}
// selectResourcesForCheckInternal internal method to test duplicates and unused
func selectResourcesForCheckInternal ( resources [ ] * unstructured . Unstructured , values * api . Test ) ( [ ] * unstructured . Unstructured , int , int ) {
var duplicates int
var unused int
uniqResources := make ( map [ string ] * unstructured . Unstructured )
for i := range resources {
r := resources [ i ]
key := fmt . Sprintf ( "%s/%s/%s" , r . GetKind ( ) , r . GetName ( ) , r . GetNamespace ( ) )
if _ , ok := uniqResources [ key ] ; ok {
fmt . Println ( "skipping duplicate resource, resource :" , r )
duplicates ++
} else {
uniqResources [ key ] = r
}
}
selectedResources := map [ string ] * unstructured . Unstructured { }
for key := range uniqResources {
r := uniqResources [ key ]
for _ , res := range values . Results {
if res . Kind == r . GetKind ( ) {
for _ , testr := range res . Resources {
if r . GetName ( ) == testr {
selectedResources [ key ] = r
}
}
if r . GetName ( ) == res . Resource {
selectedResources [ key ] = r
}
}
}
}
var checkableResources [ ] * unstructured . Unstructured
for key := range selectedResources {
checkableResources = append ( checkableResources , selectedResources [ key ] )
delete ( uniqResources , key )
}
for _ , r := range uniqResources {
fmt . Println ( "skipping unused resource, resource :" , r )
unused ++
}
return checkableResources , duplicates , unused
}
func buildPolicyResults (
engineResponses [ ] engineapi . EngineResponse ,
testResults [ ] api . TestResults ,
policyResourcePath string ,
fs billy . Filesystem ,
isGit bool ,
auditWarn bool ,
) ( map [ string ] policyreportv1alpha2 . PolicyReportResult , [ ] api . TestResults ) {
results := map [ string ] policyreportv1alpha2 . PolicyReportResult { }
for _ , resp := range engineResponses {
2023-08-15 22:41:43 +03:00
policy := resp . Policy ( )
policyName := policy . GetName ( )
policyNamespace := policy . GetNamespace ( )
2023-09-01 01:42:08 +02:00
scored := annotationsutils . Scored ( policy . GetAnnotations ( ) )
2023-04-18 14:08:17 +02:00
resourceName := resp . Resource . GetName ( )
resourceKind := resp . Resource . GetKind ( )
resourceNamespace := resp . Resource . GetNamespace ( )
var rules [ ] string
for _ , rule := range resp . PolicyResponse . Rules {
rules = append ( rules , rule . Name ( ) )
}
result := policyreportv1alpha2 . PolicyReportResult {
Policy : policyName ,
Resources : [ ] corev1 . ObjectReference {
{
Name : resourceName ,
} ,
} ,
Message : buildMessage ( resp ) ,
}
var patchedResourcePath [ ] string
for i , test := range testResults {
var userDefinedPolicyNamespace string
var userDefinedPolicyName string
found , err := isNamespacedPolicy ( test . Policy )
if err != nil {
log . Log . V ( 3 ) . Info ( "error while checking the policy is namespaced or not" , "policy: " , test . Policy , "error: " , err )
continue
}
if found {
userDefinedPolicyNamespace , userDefinedPolicyName = getUserDefinedPolicyNameAndNamespace ( test . Policy )
test . Policy = userDefinedPolicyName
}
if test . Resources != nil {
if test . Policy == policyName {
// results[].namespace value implicit set same as metadata.namespace until and unless
// user provides explicit values for results[].namespace in test yaml file.
if test . Namespace == "" {
test . Namespace = resourceNamespace
testResults [ i ] . Namespace = resourceNamespace
}
for _ , resource := range test . Resources {
if resource == resourceName {
var resultsKey string
2023-07-28 03:32:30 +03:00
resultsKey = GetResultKeyAccordingToTestResults ( userDefinedPolicyNamespace , test . Policy , test . Rule , test . Namespace , test . Kind , resource , test . IsValidatingAdmissionPolicy )
if ! test . IsValidatingAdmissionPolicy {
2023-05-10 11:12:53 +03:00
if ! slices . Contains ( rules , test . Rule ) {
if ! slices . Contains ( rules , "autogen-" + test . Rule ) {
if ! slices . Contains ( rules , "autogen-cronjob-" + test . Rule ) {
result . Result = policyreportv1alpha2 . StatusSkip
} else {
testResults [ i ] . AutoGeneratedRule = "autogen-cronjob"
test . Rule = "autogen-cronjob-" + test . Rule
2023-07-28 03:32:30 +03:00
resultsKey = GetResultKeyAccordingToTestResults ( userDefinedPolicyNamespace , test . Policy , test . Rule , test . Namespace , test . Kind , resource , test . IsValidatingAdmissionPolicy )
2023-05-10 11:12:53 +03:00
}
2023-04-18 14:08:17 +02:00
} else {
2023-05-10 11:12:53 +03:00
testResults [ i ] . AutoGeneratedRule = "autogen"
test . Rule = "autogen-" + test . Rule
2023-07-28 03:32:30 +03:00
resultsKey = GetResultKeyAccordingToTestResults ( userDefinedPolicyNamespace , test . Policy , test . Rule , test . Namespace , test . Kind , resource , test . IsValidatingAdmissionPolicy )
2023-04-18 14:08:17 +02:00
}
2023-05-10 11:12:53 +03:00
if results [ resultsKey ] . Result == "" {
result . Result = policyreportv1alpha2 . StatusSkip
results [ resultsKey ] = result
}
2023-04-18 14:08:17 +02:00
}
2023-05-10 11:12:53 +03:00
patchedResourcePath = append ( patchedResourcePath , test . PatchedResource )
2023-04-18 14:08:17 +02:00
}
if _ , ok := results [ resultsKey ] ; ! ok {
results [ resultsKey ] = result
}
2023-09-01 01:08:54 +02:00
buildPolicyResultsForGenerate ( resp , test , policyNamespace , policyName , resourceNamespace , resourceKind , resourceName , results , isGit , policyResourcePath , fs )
2023-04-18 14:08:17 +02:00
}
}
}
}
if test . Resource != "" {
if test . Policy == policyName && test . Resource == resourceName {
var resultsKey string
2023-07-28 03:32:30 +03:00
resultsKey = GetResultKeyAccordingToTestResults ( userDefinedPolicyNamespace , test . Policy , test . Rule , test . Namespace , test . Kind , test . Resource , test . IsValidatingAdmissionPolicy )
if ! test . IsValidatingAdmissionPolicy {
2023-05-10 11:12:53 +03:00
if ! slices . Contains ( rules , test . Rule ) {
if ! slices . Contains ( rules , "autogen-" + test . Rule ) {
if ! slices . Contains ( rules , "autogen-cronjob-" + test . Rule ) {
result . Result = policyreportv1alpha2 . StatusSkip
} else {
testResults [ i ] . AutoGeneratedRule = "autogen-cronjob"
test . Rule = "autogen-cronjob-" + test . Rule
2023-07-28 03:32:30 +03:00
resultsKey = GetResultKeyAccordingToTestResults ( userDefinedPolicyNamespace , test . Policy , test . Rule , test . Namespace , test . Kind , test . Resource , test . IsValidatingAdmissionPolicy )
2023-05-10 11:12:53 +03:00
}
2023-04-18 14:08:17 +02:00
} else {
2023-05-10 11:12:53 +03:00
testResults [ i ] . AutoGeneratedRule = "autogen"
test . Rule = "autogen-" + test . Rule
2023-07-28 03:32:30 +03:00
resultsKey = GetResultKeyAccordingToTestResults ( userDefinedPolicyNamespace , test . Policy , test . Rule , test . Namespace , test . Kind , test . Resource , test . IsValidatingAdmissionPolicy )
2023-04-18 14:08:17 +02:00
}
2023-05-10 11:12:53 +03:00
if results [ resultsKey ] . Result == "" {
result . Result = policyreportv1alpha2 . StatusSkip
results [ resultsKey ] = result
}
2023-04-18 14:08:17 +02:00
}
2023-05-10 11:12:53 +03:00
patchedResourcePath = append ( patchedResourcePath , test . PatchedResource )
2023-04-18 14:08:17 +02:00
}
if _ , ok := results [ resultsKey ] ; ! ok {
results [ resultsKey ] = result
}
2023-09-01 01:08:54 +02:00
buildPolicyResultsForGenerate ( resp , test , policyNamespace , policyName , resourceNamespace , resourceKind , resourceName , results , isGit , policyResourcePath , fs )
2023-04-18 14:08:17 +02:00
}
}
for _ , rule := range resp . PolicyResponse . Rules {
if rule . RuleType ( ) != engineapi . Mutation || test . Rule != rule . Name ( ) {
continue
}
var resultsKey [ ] string
var resultKey string
var result policyreportv1alpha2 . PolicyReportResult
2023-07-28 03:32:30 +03:00
resultsKey = GetAllPossibleResultsKey ( policyNamespace , policyName , rule . Name ( ) , resourceNamespace , resourceKind , resourceName , test . IsValidatingAdmissionPolicy )
2023-04-18 14:08:17 +02:00
for _ , key := range resultsKey {
if val , ok := results [ key ] ; ok {
result = val
resultKey = key
} else {
continue
}
if rule . Status ( ) == engineapi . RuleStatusSkip {
result . Result = policyreportv1alpha2 . StatusSkip
} else if rule . Status ( ) == engineapi . RuleStatusError {
result . Result = policyreportv1alpha2 . StatusError
} else {
var x string
for _ , path := range patchedResourcePath {
result . Result = policyreportv1alpha2 . StatusFail
x = getAndCompareResource ( path , resp . PatchedResource , isGit , policyResourcePath , fs , false )
if x == "pass" {
result . Result = policyreportv1alpha2 . StatusPass
break
}
}
}
results [ resultKey ] = result
}
}
for _ , rule := range resp . PolicyResponse . Rules {
2023-07-28 03:32:30 +03:00
if rule . RuleType ( ) != engineapi . Validation && rule . RuleType ( ) != engineapi . ImageVerify || test . Rule != rule . Name ( ) && ! test . IsValidatingAdmissionPolicy {
2023-04-18 14:08:17 +02:00
continue
}
var resultsKey [ ] string
var resultKey string
var result policyreportv1alpha2 . PolicyReportResult
2023-07-28 03:32:30 +03:00
resultsKey = GetAllPossibleResultsKey ( policyNamespace , policyName , rule . Name ( ) , resourceNamespace , resourceKind , resourceName , test . IsValidatingAdmissionPolicy )
2023-04-18 14:08:17 +02:00
for _ , key := range resultsKey {
if val , ok := results [ key ] ; ok {
result = val
resultKey = key
} else {
continue
}
if rule . Status ( ) == engineapi . RuleStatusSkip {
result . Result = policyreportv1alpha2 . StatusSkip
} else if rule . Status ( ) == engineapi . RuleStatusError {
result . Result = policyreportv1alpha2 . StatusError
} else if rule . Status ( ) == engineapi . RuleStatusPass {
result . Result = policyreportv1alpha2 . StatusPass
} else if rule . Status ( ) == engineapi . RuleStatusFail {
2023-09-01 01:42:08 +02:00
if ! scored {
2023-04-18 14:08:17 +02:00
result . Result = policyreportv1alpha2 . StatusWarn
} else if auditWarn && resp . GetValidationFailureAction ( ) . Audit ( ) {
result . Result = policyreportv1alpha2 . StatusWarn
} else {
result . Result = policyreportv1alpha2 . StatusFail
}
} else {
fmt . Println ( rule )
}
results [ resultKey ] = result
}
}
}
}
return results , testResults
}
2023-09-01 01:08:54 +02:00
func buildPolicyResultsForGenerate ( resp engineapi . EngineResponse , test api . TestResults , policyNamespace string , policyName string , resourceNamespace string , resourceKind string , resourceName string , results map [ string ] policyreportv1alpha2 . PolicyReportResult , isGit bool , policyResourcePath string , fs billy . Filesystem ) {
for _ , rule := range resp . PolicyResponse . Rules {
if rule . RuleType ( ) != engineapi . Generation || test . Rule != rule . Name ( ) {
continue
}
var resultsKey [ ] string
var resultKey string
var result policyreportv1alpha2 . PolicyReportResult
resultsKey = GetAllPossibleResultsKey ( policyNamespace , policyName , rule . Name ( ) , resourceNamespace , resourceKind , resourceName , test . IsValidatingAdmissionPolicy )
for _ , key := range resultsKey {
if val , ok := results [ key ] ; ok {
result = val
resultKey = key
} else {
continue
}
if rule . Status ( ) == engineapi . RuleStatusSkip {
result . Result = policyreportv1alpha2 . StatusSkip
} else if rule . Status ( ) == engineapi . RuleStatusError {
result . Result = policyreportv1alpha2 . StatusError
} else {
var x string
result . Result = policyreportv1alpha2 . StatusFail
x = getAndCompareResource ( test . GeneratedResource , rule . GeneratedResource ( ) , isGit , policyResourcePath , fs , true )
if x == "pass" {
result . Result = policyreportv1alpha2 . StatusPass
}
}
results [ resultKey ] = result
}
}
}
2023-07-28 03:32:30 +03:00
func GetAllPossibleResultsKey ( policyNamespace , policy , rule , resourceNamespace , kind , resource string , isVAP bool ) [ ] string {
2023-04-18 14:08:17 +02:00
var resultsKey [ ] string
2023-05-10 11:12:53 +03:00
var resultKey1 , resultKey2 , resultKey3 , resultKey4 string
2023-07-28 03:32:30 +03:00
if isVAP {
2023-05-10 11:12:53 +03:00
resultKey1 = fmt . Sprintf ( "%s-%s-%s" , policy , kind , resource )
resultKey2 = fmt . Sprintf ( "%s-%s-%s-%s" , policy , resourceNamespace , kind , resource )
resultKey3 = fmt . Sprintf ( "%s-%s-%s-%s" , policyNamespace , policy , kind , resource )
resultKey4 = fmt . Sprintf ( "%s-%s-%s-%s-%s" , policyNamespace , policy , resourceNamespace , kind , resource )
} else {
resultKey1 = fmt . Sprintf ( "%s-%s-%s-%s" , policy , rule , kind , resource )
resultKey2 = fmt . Sprintf ( "%s-%s-%s-%s-%s" , policy , rule , resourceNamespace , kind , resource )
resultKey3 = fmt . Sprintf ( "%s-%s-%s-%s-%s" , policyNamespace , policy , rule , kind , resource )
resultKey4 = fmt . Sprintf ( "%s-%s-%s-%s-%s-%s" , policyNamespace , policy , rule , resourceNamespace , kind , resource )
}
2023-04-18 14:08:17 +02:00
resultsKey = append ( resultsKey , resultKey1 , resultKey2 , resultKey3 , resultKey4 )
return resultsKey
}
2023-07-28 03:32:30 +03:00
func GetResultKeyAccordingToTestResults ( policyNs , policy , rule , resourceNs , kind , resource string , isVAP bool ) string {
2023-04-18 14:08:17 +02:00
var resultKey string
2023-07-28 03:32:30 +03:00
if isVAP {
2023-05-10 11:12:53 +03:00
resultKey = fmt . Sprintf ( "%s-%s-%s" , policy , kind , resource )
if policyNs != "" && resourceNs != "" {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s-%s" , policyNs , policy , resourceNs , kind , resource )
} else if policyNs != "" {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s" , policyNs , policy , kind , resource )
} else if resourceNs != "" {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s" , policy , resourceNs , kind , resource )
}
} else {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s" , policy , rule , kind , resource )
if policyNs != "" && resourceNs != "" {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s-%s-%s" , policyNs , policy , rule , resourceNs , kind , resource )
} else if policyNs != "" {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s-%s" , policyNs , policy , rule , kind , resource )
} else if resourceNs != "" {
resultKey = fmt . Sprintf ( "%s-%s-%s-%s-%s" , policy , rule , resourceNs , kind , resource )
}
2023-04-18 14:08:17 +02:00
}
2023-05-10 11:12:53 +03:00
2023-04-18 14:08:17 +02:00
return resultKey
}
func isNamespacedPolicy ( policyNames string ) ( bool , error ) {
return regexp . MatchString ( "^[a-z]*/[a-z]*" , policyNames )
}
// getAndCompareResource --> Get the patchedResource or generatedResource from the path provided by user
// And compare this resource with engine generated resource.
2023-08-31 02:24:41 +02:00
func getAndCompareResource ( path string , actualResource unstructured . Unstructured , isGit bool , policyResourcePath string , fs billy . Filesystem , isGenerate bool ) string {
2023-04-18 14:08:17 +02:00
var status string
resourceType := "patchedResource"
if isGenerate {
resourceType = "generatedResource"
}
2023-08-31 02:24:41 +02:00
expectedResource , err := common . GetResourceFromPath ( fs , path , isGit , policyResourcePath , resourceType )
2023-04-18 14:08:17 +02:00
if err != nil {
2023-08-30 21:37:15 +02:00
fmt . Printf ( "Error: failed to load resources (%s)" , err )
2023-04-18 14:08:17 +02:00
return ""
}
2023-08-30 21:37:15 +02:00
if isGenerate {
2023-08-31 02:24:41 +02:00
unstructuredutils . FixupGenerateLabels ( actualResource )
unstructuredutils . FixupGenerateLabels ( expectedResource )
}
equals , err := unstructuredutils . Compare ( actualResource , expectedResource , true )
if err == nil {
if ! equals {
2023-08-30 21:37:15 +02:00
status = "fail"
2023-08-31 02:24:41 +02:00
} else {
2023-08-30 21:37:15 +02:00
status = "pass"
}
2023-04-18 14:08:17 +02:00
}
return status
}
func buildMessage ( resp engineapi . EngineResponse ) string {
var messages [ ] string
for _ , ruleResp := range resp . PolicyResponse . Rules {
message := strings . TrimSpace ( ruleResp . Message ( ) )
if message != "" {
messages = append ( messages , message )
}
}
return strings . Join ( messages , "," )
}
func getUserDefinedPolicyNameAndNamespace ( policyName string ) ( string , string ) {
if strings . Contains ( policyName , "/" ) {
parts := strings . Split ( policyName , "/" )
namespace := parts [ 0 ]
policy := parts [ 1 ]
return namespace , policy
}
return "" , policyName
}