...

Source file src/edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/approval/parse_test.go

Documentation: edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/approval

     1  // Copyright 2018 Palantir Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package approval
    16  
    17  import (
    18  	"reflect"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/require"
    22  	"gopkg.in/yaml.v2"
    23  
    24  	"edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/common"
    25  )
    26  
    27  func TestParsePolicy(t *testing.T) {
    28  	policyText := `
    29  - rule1
    30  - rule2
    31  - or:
    32     - and:
    33        - rule3
    34        - rule4
    35     - rule5
    36  - and:
    37    - rule6
    38    - rule7
    39  `
    40  
    41  	ruleText := `
    42  - name: rule1
    43    options:
    44      allow_author: true
    45  - name: rule2
    46    options:
    47      allow_author: true
    48      allow_contributor: true
    49  - name: rule3
    50    options:
    51      allow_author: true
    52      allow_contributor: true
    53      # invalidate_on_push: true
    54  - name: rule4
    55    options:
    56      allow_author: true
    57      # invalidate_on_push: true
    58  - name: rule5
    59    options:
    60      allow_contributor: true
    61      # invalidate_on_push: true
    62  - name: rule6
    63    options:
    64      allow_contributor: true
    65  - name: rule7
    66    options:
    67      request_review:
    68        enabled: true
    69    requires:
    70      admins: true
    71  `
    72  
    73  	var policy Policy
    74  	err := yaml.UnmarshalStrict([]byte(policyText), &policy)
    75  	require.NoError(t, err, "failed to unmarshal policy")
    76  
    77  	var rules []*Rule
    78  	err = yaml.UnmarshalStrict([]byte(ruleText), &rules)
    79  	require.NoError(t, err, "failed to unmarshal rules")
    80  
    81  	rulesByName := make(map[string]*Rule)
    82  	for _, r := range rules {
    83  		rulesByName[r.Name] = r
    84  	}
    85  
    86  	req, err := policy.Parse(rulesByName)
    87  	require.NoError(t, err, "failed to parse policy")
    88  
    89  	expected := &evaluator{
    90  		root: &AndRequirement{
    91  			requirements: []common.Evaluator{
    92  				&RuleRequirement{
    93  					rule: rules[0],
    94  				},
    95  				&RuleRequirement{
    96  					rule: rules[1],
    97  				},
    98  				&OrRequirement{
    99  					requirements: []common.Evaluator{
   100  						&AndRequirement{
   101  							requirements: []common.Evaluator{
   102  								&RuleRequirement{
   103  									rule: rules[2],
   104  								},
   105  								&RuleRequirement{
   106  									rule: rules[3],
   107  								},
   108  							},
   109  						},
   110  						&RuleRequirement{
   111  							rule: rules[4],
   112  						},
   113  					},
   114  				},
   115  				&AndRequirement{
   116  					requirements: []common.Evaluator{
   117  						&RuleRequirement{
   118  							rule: rules[5],
   119  						},
   120  						&RuleRequirement{
   121  							rule: rules[6],
   122  						},
   123  					},
   124  				},
   125  			},
   126  		},
   127  	}
   128  
   129  	require.True(t, reflect.DeepEqual(expected, req))
   130  }
   131  
   132  func TestParsePolicyError_empty(t *testing.T) {
   133  	// Empty list
   134  	policy := `
   135  - rule1
   136  - or: []
   137  `
   138  
   139  	rules := `
   140    - name: rule1
   141  `
   142  
   143  	_, err := loadAndParsePolicy(t, policy, rules)
   144  	require.Error(t, err)
   145  }
   146  
   147  func TestParsePolicyError_unknownRule(t *testing.T) {
   148  	// Non-existing rule
   149  	policy := `
   150  - rule1
   151  `
   152  
   153  	rules := `
   154  - name: rule2
   155  `
   156  
   157  	_, err := loadAndParsePolicy(t, policy, rules)
   158  	require.Error(t, err)
   159  }
   160  
   161  func TestParsePolicyError_illegalType(t *testing.T) {
   162  	// Illegal type
   163  	policy := `
   164  - or:
   165    - rule1
   166    - [a, b]
   167  `
   168  
   169  	rules := `
   170  - name: rule1
   171  `
   172  
   173  	_, err := loadAndParsePolicy(t, policy, rules)
   174  	require.Error(t, err)
   175  }
   176  
   177  func TestParsePolicyError_multikey(t *testing.T) {
   178  	// Multiple keys
   179  	policy := `
   180  - or:
   181      - rule1
   182    and:
   183      - rule1
   184  `
   185  
   186  	rules := `
   187  - name: rule1
   188  `
   189  
   190  	_, err := loadAndParsePolicy(t, policy, rules)
   191  	require.Error(t, err)
   192  }
   193  
   194  func TestParsePolicyError_recursiveDepth(t *testing.T) {
   195  	// Recursive depth 10 is allowed
   196  	policy := `
   197  - or:
   198    - or:
   199      - or:
   200        - or:
   201          - or:
   202            - or:
   203              - or:
   204                - or:
   205                  - or:
   206                    - rule1
   207  `
   208  
   209  	rules := `
   210  - name: rule1
   211  `
   212  
   213  	_, err := loadAndParsePolicy(t, policy, rules)
   214  	require.NoError(t, err)
   215  
   216  	// Recursive depth 11 is not allowed
   217  	policy = `
   218  - or:
   219    - or:
   220      - or:
   221        - or:
   222          - or:
   223            - or:
   224              - or:
   225                - or:
   226                  - or:
   227                    - or:
   228                      - rule1
   229  `
   230  
   231  	_, err = loadAndParsePolicy(t, policy, rules)
   232  	require.Error(t, err)
   233  }
   234  
   235  func loadAndParsePolicy(t *testing.T, policyText string, ruleText string) (common.Evaluator, error) {
   236  	var policy Policy
   237  	err := yaml.UnmarshalStrict([]byte(policyText), &policy)
   238  	require.NoError(t, err, "failed to unmarshal policy")
   239  
   240  	var rules []*Rule
   241  	err = yaml.UnmarshalStrict([]byte(ruleText), &rules)
   242  	require.NoError(t, err, "failed to unmarshal rules")
   243  
   244  	rulesByName := make(map[string]*Rule)
   245  	for _, r := range rules {
   246  		rulesByName[r.Name] = r
   247  	}
   248  
   249  	return policy.Parse(rulesByName)
   250  }
   251  

View as plain text