...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/rules/request_payloads.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/rules

     1  package rulesengine
     2  
     3  // request payloads represent any datatype being sent to the rules engine.
     4  // these will often have a validation method.
     5  import (
     6  	"errors"
     7  	"fmt"
     8  
     9  	"github.com/google/uuid"
    10  )
    11  
    12  var (
    13  	ErrInvalidCommandNil = errors.New("command was nil")
    14  	ErrInvalidBannerID   = errors.New("bannerid was not a valid uuid")
    15  )
    16  
    17  type PostCommandPayload struct {
    18  	Name string `json:"name"`
    19  }
    20  
    21  func (pc PostCommandPayload) Validate() error {
    22  	if pc.Name == "" {
    23  		return fmt.Errorf("empty command name")
    24  	}
    25  	return nil
    26  }
    27  
    28  type PostPrivilegePayload struct {
    29  	Name string `json:"name"`
    30  }
    31  
    32  func (pp PostPrivilegePayload) Validate() error {
    33  	if pp.Name == "" {
    34  		return fmt.Errorf("empty privilege name")
    35  	}
    36  	return nil
    37  }
    38  
    39  type ValidateCommandPayload struct {
    40  	Identity Identity `json:"identity"`
    41  	Command  Command  `json:"command"`
    42  	Target   Target   `json:"target"`
    43  }
    44  
    45  func (vc ValidateCommandPayload) Validate() error {
    46  	if vc.Command.Name == "" {
    47  		return ErrInvalidCommandNil
    48  	}
    49  
    50  	if vc.Command.Type == "" {
    51  		// Only check for emptiness - the db may be aware of valid request types
    52  		// that we are not yet aware of. If a request type is supplied which the
    53  		// db is not aware of, this is considered an error and the db will
    54  		// return an error
    55  		return errors.New("command type was empty")
    56  	}
    57  
    58  	_, err := uuid.Parse(vc.Target.BannerID)
    59  	if err != nil {
    60  		return ErrInvalidBannerID
    61  	}
    62  
    63  	return nil
    64  }
    65  
    66  type WriteRule struct {
    67  	Command    string   `json:"command"`
    68  	Privileges []string `json:"privileges"`
    69  }
    70  
    71  func (pr WriteRule) Validate() error {
    72  	if pr.Command == "" {
    73  		return fmt.Errorf("empty command name")
    74  	}
    75  
    76  	if len(pr.Privileges) == 0 {
    77  		return fmt.Errorf("empty privilege list")
    78  	}
    79  
    80  	for i, privilege := range pr.Privileges {
    81  		if privilege == "" {
    82  			return fmt.Errorf("empty privilege name in array at %d", i)
    83  		}
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  type WriteRules []WriteRule
    90  
    91  func (pr WriteRules) Validate() error {
    92  	if len(pr) == 0 {
    93  		return fmt.Errorf("empty rules list")
    94  	}
    95  
    96  	for i, rule := range pr {
    97  		if err := rule.Validate(); err != nil {
    98  			return fmt.Errorf("invalid rule at %d: %w", i, err)
    99  		}
   100  	}
   101  	return nil
   102  }
   103  
   104  type RuleSet struct {
   105  	Privilege string
   106  	Commands  []string
   107  }
   108  
   109  func (rs RuleSet) Validate() error {
   110  	if rs.Privilege == "" {
   111  		return fmt.Errorf("empty privilege name")
   112  	}
   113  
   114  	if len(rs.Commands) == 0 {
   115  		return fmt.Errorf("empty command list")
   116  	}
   117  
   118  	for i, command := range rs.Commands {
   119  		if command == "" {
   120  			return fmt.Errorf("empty command name in array at %d", i)
   121  		}
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  type RuleSets []RuleSet
   128  
   129  func (rs RuleSets) Validate() error {
   130  	if len(rs) == 0 {
   131  		return fmt.Errorf("empty rules list")
   132  	}
   133  	// Protect database from a massive bulk write attempt
   134  	// Rather than validating the number of rules, validate against the sum
   135  	// total number of commands added to each rule. Otherwise it would be
   136  	// possible to add an unbounded number of commands to a single rule, or add
   137  	// many commands to many rules, resulting in an insert of size O(n^2).
   138  	numCommands := 0
   139  	for _, ruleSet := range rs {
   140  		numCommands += len(ruleSet.Commands)
   141  	}
   142  	if numCommands > maxRules {
   143  		return fmt.Errorf("total number of commands in rules %d exceeds max %d", numCommands, maxRules)
   144  	}
   145  	var retErr error
   146  	for i, rule := range rs {
   147  		if err := rule.Validate(); err != nil {
   148  			retErr = errors.Join(retErr, fmt.Errorf("invalid rule at %d: %w", i, err))
   149  		}
   150  	}
   151  	return retErr
   152  }
   153  

View as plain text