99 "path/filepath"
1010 "sort"
1111 "strings"
12+ "time"
1213
1314 "github.com/stolostron/policy-generator-plugin/internal/types"
1415 "gopkg.in/yaml.v3"
@@ -222,23 +223,85 @@ func getDefaultBool(config map[string]interface{}, key string) (value bool, set
222223func getPolicyBool (
223224 config map [string ]interface {}, policyIndex int , key string ,
224225) (value bool , set bool ) {
226+ policy := getPolicy (config , policyIndex )
227+ if policy == nil {
228+ return false , false
229+ }
230+
231+ value , set = policy [key ].(bool )
232+
233+ return
234+ }
235+
236+ // getPolicy will return a policy at the specified index in the Policy Generator configuration YAML.
237+ func getPolicy (config map [string ]interface {}, policyIndex int ) map [string ]interface {} {
225238 policies , ok := config ["policies" ].([]interface {})
226239 if ! ok {
227- return false , false
240+ return nil
228241 }
229242
230243 if len (policies )- 1 < policyIndex {
231- return false , false
244+ return nil
232245 }
233246
234247 policy , ok := policies [policyIndex ].(map [string ]interface {})
235248 if ! ok {
236- return false , false
249+ return nil
237250 }
238251
239- value , set = policy [key ].(bool )
252+ return policy
253+ }
240254
241- return
255+ // getEvaluationInterval will return the evaluation interval of specified policy in the Policy Generator configuration
256+ // YAML.
257+ func isEvaluationIntervalSet (config map [string ]interface {}, policyIndex int , complianceType string ) bool {
258+ policy := getPolicy (config , policyIndex )
259+ if policy == nil {
260+ return false
261+ }
262+
263+ evaluationInterval , ok := policy ["evaluationInterval" ].(map [string ]interface {})
264+ if ! ok {
265+ return false
266+ }
267+
268+ _ , set := evaluationInterval [complianceType ].(string )
269+
270+ return set
271+ }
272+
273+ // isEvaluationIntervalSetManifest will return the evaluation interval of the specified manifest of the specified policy
274+ // in the Policy Generator configuration YAML.
275+ func isEvaluationIntervalSetManifest (
276+ config map [string ]interface {}, policyIndex int , manifestIndex int , complianceType string ,
277+ ) bool {
278+ policy := getPolicy (config , policyIndex )
279+ if policy == nil {
280+ return false
281+ }
282+
283+ manifests , ok := policy ["manifests" ].([]interface {})
284+ if ! ok {
285+ return false
286+ }
287+
288+ if len (manifests )- 1 < manifestIndex {
289+ return false
290+ }
291+
292+ manifest , ok := manifests [manifestIndex ].(map [string ]interface {})
293+ if ! ok {
294+ return false
295+ }
296+
297+ evaluationInterval , ok := manifest ["evaluationInterval" ].(map [string ]interface {})
298+ if ! ok {
299+ return false
300+ }
301+
302+ _ , set := evaluationInterval [complianceType ].(string )
303+
304+ return set
242305}
243306
244307// applyDefaults applies any missing defaults under Policy.PlacementBindingDefaults,
@@ -333,6 +396,21 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
333396 policy .Controls = p .PolicyDefaults .Controls
334397 }
335398
399+ // Only use the policyDefault evaluationInterval value when it's not explicitly set on the policy.
400+ if policy .EvaluationInterval .Compliant == "" {
401+ set := isEvaluationIntervalSet (unmarshaledConfig , i , "compliant" )
402+ if ! set {
403+ policy .EvaluationInterval .Compliant = p .PolicyDefaults .EvaluationInterval .Compliant
404+ }
405+ }
406+
407+ if policy .EvaluationInterval .NonCompliant == "" {
408+ set := isEvaluationIntervalSet (unmarshaledConfig , i , "noncompliant" )
409+ if ! set {
410+ policy .EvaluationInterval .NonCompliant = p .PolicyDefaults .EvaluationInterval .NonCompliant
411+ }
412+ }
413+
336414 if policy .PolicySets == nil {
337415 policy .PolicySets = p .PolicyDefaults .PolicySets
338416 }
@@ -409,9 +487,32 @@ func (p *Plugin) applyDefaults(unmarshaledConfig map[string]interface{}) {
409487 policy .Standards = p .PolicyDefaults .Standards
410488 }
411489
412- for i := range policy .Manifests {
413- if policy .Manifests [i ].ComplianceType == "" {
414- policy .Manifests [i ].ComplianceType = policy .ComplianceType
490+ for j := range policy .Manifests {
491+ manifest := & policy .Manifests [j ]
492+
493+ if manifest .ComplianceType == "" {
494+ manifest .ComplianceType = policy .ComplianceType
495+ }
496+
497+ // If the manifests are consolidated to a single ConfigurationPolicy object, don't set
498+ // the evaluation interval per manifest.
499+ if policy .ConsolidateManifests {
500+ continue
501+ }
502+
503+ // Only use the policy's evaluationInterval value when it's not explicitly set in the manifest.
504+ if manifest .EvaluationInterval .Compliant == "" {
505+ set := isEvaluationIntervalSetManifest (unmarshaledConfig , i , j , "compliant" )
506+ if ! set {
507+ manifest .EvaluationInterval .Compliant = policy .EvaluationInterval .Compliant
508+ }
509+ }
510+
511+ if manifest .EvaluationInterval .NonCompliant == "" {
512+ set := isEvaluationIntervalSetManifest (unmarshaledConfig , i , j , "noncompliant" )
513+ if ! set {
514+ manifest .EvaluationInterval .NonCompliant = policy .EvaluationInterval .NonCompliant
515+ }
415516 }
416517 }
417518
@@ -507,13 +608,33 @@ func (p *Plugin) assertValidConfig() error {
507608 p .PolicyDefaults .Namespace , policy .Name )
508609 }
509610
611+ if policy .EvaluationInterval .Compliant != "" && policy .EvaluationInterval .Compliant != "never" {
612+ _ , err := time .ParseDuration (policy .EvaluationInterval .Compliant )
613+ if err != nil {
614+ return fmt .Errorf (
615+ "the policy %s has an invalid policy.evaluationInterval.compliant value: %w" , policy .Name , err ,
616+ )
617+ }
618+ }
619+
620+ if policy .EvaluationInterval .NonCompliant != "" && policy .EvaluationInterval .NonCompliant != "never" {
621+ _ , err := time .ParseDuration (policy .EvaluationInterval .NonCompliant )
622+ if err != nil {
623+ return fmt .Errorf (
624+ "the policy %s has an invalid policy.evaluationInterval.noncompliant value: %w" , policy .Name , err ,
625+ )
626+ }
627+ }
628+
510629 if len (policy .Manifests ) == 0 {
511630 return fmt .Errorf (
512631 "each policy must have at least one manifest, but found none in policy %s" , policy .Name ,
513632 )
514633 }
515634
516- for _ , manifest := range policy .Manifests {
635+ for j := range policy .Manifests {
636+ manifest := & policy .Manifests [j ]
637+
517638 if manifest .Path == "" {
518639 return fmt .Errorf (
519640 "each policy manifest entry must have path set, but did not find a path in policy %s" ,
@@ -532,6 +653,40 @@ func (p *Plugin) assertValidConfig() error {
532653 if err != nil {
533654 return err
534655 }
656+
657+ evalInterval := & manifest .EvaluationInterval
658+ if policy .ConsolidateManifests && (evalInterval .Compliant != "" || evalInterval .NonCompliant != "" ) {
659+ return fmt .Errorf (
660+ "the policy %s has the evaluationInterval value set on manifest[%d] but " +
661+ "consolidateManifests is true" ,
662+ policy .Name ,
663+ j ,
664+ )
665+ }
666+
667+ if evalInterval .Compliant != "" && evalInterval .Compliant != "never" {
668+ _ , err := time .ParseDuration (evalInterval .Compliant )
669+ if err != nil {
670+ return fmt .Errorf (
671+ "the policy %s has an invalid policy.evaluationInterval.manifest[%d].compliant value: %w" ,
672+ policy .Name ,
673+ j ,
674+ err ,
675+ )
676+ }
677+ }
678+
679+ if evalInterval .NonCompliant != "" && evalInterval .NonCompliant != "never" {
680+ _ , err := time .ParseDuration (evalInterval .NonCompliant )
681+ if err != nil {
682+ return fmt .Errorf (
683+ "the policy %s has an invalid policy.evaluationInterval.manifest[%d].noncompliant value: %w" ,
684+ policy .Name ,
685+ j ,
686+ err ,
687+ )
688+ }
689+ }
535690 }
536691
537692 // Validate policy Placement settings
0 commit comments