...

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

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

     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 policy
    16  
    17  import (
    18  	"context"
    19  
    20  	"github.com/pkg/errors"
    21  
    22  	"edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/pull"
    23  
    24  	"edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/approval"
    25  	"edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/common"
    26  	"edge-infra.dev/pkg/f8n/devinfra/repo/owners/policybot/policy/disapproval"
    27  )
    28  
    29  // RemoteConfig allows the use of a remote policy file, rather than a local one. The Remote value
    30  // should follow the format `org/repo`. An example: `palantir/policy-bot`. The Path is optional,
    31  // with the default value being the configured default policy file location. The Ref is optional,
    32  // and the default branch of the Remote repository will be used.
    33  type RemoteConfig struct {
    34  	Remote string `yaml:"remote"`
    35  	Path   string `yaml:"path"`
    36  	Ref    string `yaml:"ref"`
    37  }
    38  
    39  type Config struct {
    40  	Policy        Policy           `yaml:"policy"`
    41  	ApprovalRules []*approval.Rule `yaml:"approval_rules"`
    42  }
    43  
    44  type Policy struct {
    45  	Approval    approval.Policy     `yaml:"approval"`
    46  	Disapproval *disapproval.Policy `yaml:"disapproval"`
    47  }
    48  
    49  func ParsePolicy(c *Config) (common.Evaluator, error) {
    50  	rulesByName := make(map[string]*approval.Rule)
    51  	for _, r := range c.ApprovalRules {
    52  		rulesByName[r.Name] = r
    53  	}
    54  
    55  	evalApproval, err := c.Policy.Approval.Parse(rulesByName)
    56  	if err != nil {
    57  		return nil, errors.WithMessage(err, "failed to parse approval policy")
    58  	}
    59  
    60  	evalDisapproval := c.Policy.Disapproval
    61  	if evalDisapproval == nil {
    62  		evalDisapproval = &disapproval.Policy{}
    63  	}
    64  
    65  	return evaluator{
    66  		approval:    evalApproval,
    67  		disapproval: evalDisapproval,
    68  	}, nil
    69  }
    70  
    71  type evaluator struct {
    72  	approval    common.Evaluator
    73  	disapproval common.Evaluator
    74  }
    75  
    76  func (e evaluator) Trigger() common.Trigger {
    77  	return e.approval.Trigger() | e.disapproval.Trigger()
    78  }
    79  
    80  func (e evaluator) Evaluate(ctx context.Context, prctx pull.Context) (res common.Result) {
    81  	disapproval := e.disapproval.Evaluate(ctx, prctx)
    82  	approval := e.approval.Evaluate(ctx, prctx)
    83  
    84  	res.Name = "policy"
    85  	res.Children = []*common.Result{&approval, &disapproval}
    86  
    87  	for _, r := range res.Children {
    88  		if r.Error != nil {
    89  			res.Error = r.Error
    90  		}
    91  	}
    92  
    93  	switch {
    94  	case res.Error != nil:
    95  	case disapproval.Status == common.StatusDisapproved:
    96  		res.Status = common.StatusDisapproved
    97  		res.StatusDescription = disapproval.StatusDescription
    98  	default:
    99  		res.Status = approval.Status
   100  		res.StatusDescription = approval.StatusDescription
   101  	}
   102  	return
   103  }
   104  

View as plain text