...

Source file src/edge-infra.dev/pkg/edge/api/services/oi_service_rules.go

Documentation: edge-infra.dev/pkg/edge/api/services

     1  package services
     2  
     3  import (
     4  	"context"
     5  
     6  	"edge-infra.dev/pkg/edge/api/graph/model"
     7  	rulesengine "edge-infra.dev/pkg/sds/emergencyaccess/rules"
     8  )
     9  
    10  // returns a slice of strings containing the names of the privileges. returns nil slice if no privileges are provided.
    11  func extractPrivNames(privileges []*model.OperatorInterventionPrivilegeInput) []string {
    12  	var ret []string
    13  	for _, privilege := range privileges {
    14  		ret = append(ret, privilege.Name)
    15  	}
    16  	return ret
    17  }
    18  
    19  func (o *operatorInterventionService) ReadRules(ctx context.Context, privileges []*model.OperatorInterventionPrivilegeInput) ([]*model.Rule, error) {
    20  	ret, err := o.reng.GetDefaultRules(ctx, extractPrivNames(privileges)...)
    21  
    22  	if err != nil {
    23  		return nil, err
    24  	}
    25  	var rules []*model.Rule
    26  	for _, rule := range ret {
    27  		r := &model.Rule{Privilege: &model.Privilege{Name: rule.Privilege.Name}}
    28  		for _, command := range rule.Commands {
    29  			r.Commands = append(r.Commands, &model.Command{Name: command.Name})
    30  		}
    31  		rules = append(rules, r)
    32  	}
    33  	return rules, nil
    34  }
    35  
    36  // UpdateRules is an all or nothing function to create or update operator intervention rules.
    37  // Will not fail on unique constraint conflict.
    38  func (o *operatorInterventionService) UpdateRules(ctx context.Context, rules []*model.UpdateOperatorInterventionRuleInput) (*model.UpdateOperatorInterventionRuleResponse, error) {
    39  	ruleset, errorResponse := validateRules(rules)
    40  	if len(errorResponse) > 0 {
    41  		return &model.UpdateOperatorInterventionRuleResponse{Errors: errorResponse}, nil
    42  	}
    43  	res, err := o.reng.AddDefaultRulesForPrivileges(ctx, ruleset)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	return &model.UpdateOperatorInterventionRuleResponse{Errors: convertRengErrorsToModel(res.Errors)}, nil
    48  }
    49  
    50  // returns a valid ruleset if the input is valid. returns an error response of len != 0 otherwise.
    51  func validateRules(rules []*model.UpdateOperatorInterventionRuleInput) (rulesengine.RuleSets, []*model.OperatorInterventionErrorResponse) {
    52  	ruleset := rulesengine.RuleSets{}
    53  	errorResponse := []*model.OperatorInterventionErrorResponse{}
    54  	// return early if no rules are provided
    55  	if len(rules) == 0 {
    56  		return ruleset, []*model.OperatorInterventionErrorResponse{
    57  			{
    58  				Type: model.OperatorInterventionErrorTypeInvalidInput,
    59  			},
    60  		}
    61  	}
    62  	// validate rules
    63  	for _, rule := range rules {
    64  		ruleset = append(ruleset, rulesengine.RuleSet{
    65  			Privilege: rule.Privilege.Name,
    66  			Commands: func() []string {
    67  				var ret []string
    68  				for _, command := range rule.Commands {
    69  					ret = append(ret, command.Name)
    70  				}
    71  				return ret
    72  			}(),
    73  		})
    74  
    75  		if rule.Privilege.Name == "" {
    76  			errorResponse = append(errorResponse, &model.OperatorInterventionErrorResponse{
    77  				Type:      model.OperatorInterventionErrorTypeInvalidInput,
    78  				Privilege: &rule.Privilege.Name,
    79  			})
    80  		}
    81  		if len(rule.Commands) == 0 {
    82  			errorResponse = append(errorResponse, &model.OperatorInterventionErrorResponse{
    83  				Type: model.OperatorInterventionErrorTypeInvalidInput,
    84  			})
    85  		}
    86  		for _, command := range rule.Commands {
    87  			if command.Name == "" {
    88  				command := command
    89  				errorResponse = append(errorResponse, &model.OperatorInterventionErrorResponse{
    90  					Type:    model.OperatorInterventionErrorTypeInvalidInput,
    91  					Command: &command.Name,
    92  				})
    93  			}
    94  		}
    95  	}
    96  	return ruleset, errorResponse
    97  }
    98  
    99  func convertRengErrorsToModel(errors []rulesengine.Error) []*model.OperatorInterventionErrorResponse {
   100  	var ret []*model.OperatorInterventionErrorResponse
   101  	for _, err := range errors {
   102  		err := err
   103  		switch err.Type {
   104  		case rulesengine.UnknownCommand:
   105  			ret = append(ret, &model.OperatorInterventionErrorResponse{
   106  				Type:    model.OperatorInterventionErrorTypeUnknownCommand,
   107  				Command: &err.Command,
   108  			})
   109  		case rulesengine.UnknownPrivilege:
   110  			ret = append(ret, &model.OperatorInterventionErrorResponse{
   111  				Type:      model.OperatorInterventionErrorTypeUnknownPrivilege,
   112  				Privilege: &err.Privilege,
   113  			})
   114  		case rulesengine.UnknownRule:
   115  			ret = append(ret, &model.OperatorInterventionErrorResponse{
   116  				Type:      model.OperatorInterventionErrorTypeUnknownRule,
   117  				Privilege: &err.Privilege,
   118  				Command:   &err.Command,
   119  			})
   120  		}
   121  	}
   122  	return ret
   123  }
   124  
   125  func (o *operatorInterventionService) DeleteRule(ctx context.Context, rule model.DeleteOperatorInterventionRuleInput) (*model.DeleteOperatorInterventionRuleResponse, error) {
   126  	if rule.Privilege == "" || rule.Command == "" {
   127  		return &model.DeleteOperatorInterventionRuleResponse{Errors: []*model.OperatorInterventionErrorResponse{
   128  			{
   129  				Type: model.OperatorInterventionErrorTypeInvalidInput,
   130  			},
   131  		}}, nil
   132  	}
   133  
   134  	res, err := o.reng.DeleteDefaultRule(ctx, rule.Command, rule.Privilege)
   135  	if err != nil {
   136  		return nil, err
   137  	}
   138  	return &model.DeleteOperatorInterventionRuleResponse{Errors: convertRengErrorsToModel(res.Errors)}, nil
   139  }
   140  

View as plain text