github.com/zntrio/harp/v2@v2.0.9/pkg/bundle/ruleset/engine/rego/engine.go (about) 1 // Licensed to Elasticsearch B.V. under one or more contributor 2 // license agreements. See the NOTICE file distributed with 3 // this work for additional information regarding copyright 4 // ownership. Elasticsearch B.V. licenses this file to you under 5 // the Apache License, Version 2.0 (the "License"); you may 6 // not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 package rego 19 20 import ( 21 "context" 22 "errors" 23 "fmt" 24 "io" 25 26 "github.com/open-policy-agent/opa/rego" 27 28 bundlev1 "github.com/zntrio/harp/v2/api/gen/go/harp/bundle/v1" 29 "github.com/zntrio/harp/v2/pkg/bundle/ruleset/engine" 30 ) 31 32 const ( 33 maxPolicySize = 5 * 1024 * 1025 // 5MB 34 ) 35 36 func New(ctx context.Context, r io.Reader) (engine.PackageLinter, error) { 37 // Read all policy content 38 policy, err := io.ReadAll(io.LimitReader(r, maxPolicySize)) 39 if err != nil { 40 return nil, fmt.Errorf("unable to read the policy content: %w", err) 41 } 42 43 // Parse and prepare the policy 44 query, err := rego.New( 45 rego.Query("data.harp.compliant"), 46 rego.Module("harp.rego", string(policy)), 47 ).PrepareForEval(ctx) 48 if err != nil { 49 return nil, fmt.Errorf("unable to prepare for eval: %w", err) 50 } 51 52 // Return engine 53 return &ruleEngine{ 54 query: query, 55 }, nil 56 } 57 58 // ----------------------------------------------------------------------------- 59 60 type ruleEngine struct { 61 query rego.PreparedEvalQuery 62 } 63 64 func (re *ruleEngine) EvaluatePackage(ctx context.Context, p *bundlev1.Package) error { 65 // Check arguments 66 if p == nil { 67 return errors.New("unable to evaluate nil package") 68 } 69 70 // Evaluation with the given package 71 results, err := re.query.Eval(ctx, rego.EvalInput(p)) 72 if err != nil { 73 return fmt.Errorf("unable to evaluate the policy: %w", err) 74 } else if len(results) == 0 { 75 // Handle undefined result. 76 return nil 77 } 78 79 for _, result := range results { 80 for _, expression := range result.Expressions { 81 // Extract result 82 compliant, ok := expression.Value.(bool) 83 if !ok { 84 // Handle unexpected result type. 85 return errors.New("the policy must return boolean") 86 } 87 88 // Check package compliance 89 if !compliant { 90 return engine.ErrRuleNotValid 91 } 92 } 93 } 94 95 // Package validated 96 return nil 97 }