1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package approval
16
17 import (
18 "fmt"
19
20 "github.com/pkg/errors"
21
22 "edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/common"
23 )
24
25 type Policy []interface{}
26
27 func (p Policy) Parse(rules map[string]*Rule) (common.Evaluator, error) {
28 eval := &evaluator{}
29
30 if len(p) == 0 {
31 return eval, nil
32 }
33
34
35 root := map[interface{}]interface{}{
36 "and": []interface{}(p),
37 }
38
39 and, err := parsePolicyR(root, rules, 0)
40 if err != nil {
41 return nil, err
42 }
43
44 eval.root = and
45 return eval, nil
46 }
47
48 func parsePolicyR(policy interface{}, rules map[string]*Rule, depth int) (common.Evaluator, error) {
49 if depth > 10 {
50 return nil, errors.New("reached maximum recursive depth while processing policy")
51 }
52
53
54 if ruleName, ok := policy.(string); ok {
55 if rule, ok := rules[ruleName]; ok {
56 req := &RuleRequirement{
57 rule: rule,
58 }
59 return req, nil
60 }
61 var keys []string
62 for k := range rules {
63 keys = append(keys, k)
64 }
65 return nil, errors.Errorf("policy references undefined rule '%s', allowed values: %v", ruleName, keys)
66 }
67
68
69 if conjunction, ok := policy.(map[interface{}]interface{}); ok {
70 var ops []string
71 for k := range conjunction {
72 ops = append(ops, k.(string))
73 }
74 if len(ops) != 1 {
75 return nil, errors.Errorf("multiple keys found when one was expected: %v", ops)
76 }
77
78 op := ops[0]
79 values, ok := conjunction[op].([]interface{})
80 if !ok {
81 return nil, errors.Errorf("expected list of subconditions, but got %T", conjunction[op])
82 }
83 if len(values) == 0 {
84 return nil, errors.Errorf("empty list of subconditions is not allowed")
85 }
86
87 var subrequirements []common.Evaluator
88 for _, subpolicy := range values {
89 subreq, err := parsePolicyR(subpolicy, rules, depth+1)
90 if err != nil {
91 return nil, errors.WithMessage(err, fmt.Sprintf("failed to parse subpolicies for '%s'", op))
92 }
93 subrequirements = append(subrequirements, subreq)
94 }
95
96 switch op {
97 case "or":
98 return &OrRequirement{requirements: subrequirements}, nil
99 case "and":
100 return &AndRequirement{requirements: subrequirements}, nil
101 default:
102 return nil, errors.Errorf("invalid conjunction '%s', allowed values: [or, and]", op)
103 }
104 }
105
106 return nil, errors.Errorf("malformed policy, expected string or map, but encountered %T", policy)
107 }
108
View as plain text