package services import ( "context" "edge-infra.dev/pkg/edge/api/graph/model" rulesengine "edge-infra.dev/pkg/sds/emergencyaccess/rules" ) // returns a slice of strings containing the names of the privileges. returns nil slice if no privileges are provided. func extractPrivNames(privileges []*model.OperatorInterventionPrivilegeInput) []string { var ret []string for _, privilege := range privileges { ret = append(ret, privilege.Name) } return ret } func (o *operatorInterventionService) ReadRules(ctx context.Context, privileges []*model.OperatorInterventionPrivilegeInput) ([]*model.Rule, error) { ret, err := o.reng.GetDefaultRules(ctx, extractPrivNames(privileges)...) if err != nil { return nil, err } var rules []*model.Rule for _, rule := range ret { r := &model.Rule{Privilege: &model.Privilege{Name: rule.Privilege.Name}} for _, command := range rule.Commands { r.Commands = append(r.Commands, &model.Command{Name: command.Name}) } rules = append(rules, r) } return rules, nil } // UpdateRules is an all or nothing function to create or update operator intervention rules. // Will not fail on unique constraint conflict. func (o *operatorInterventionService) UpdateRules(ctx context.Context, rules []*model.UpdateOperatorInterventionRuleInput) (*model.UpdateOperatorInterventionRuleResponse, error) { ruleset, errorResponse := validateRules(rules) if len(errorResponse) > 0 { return &model.UpdateOperatorInterventionRuleResponse{Errors: errorResponse}, nil } res, err := o.reng.AddDefaultRulesForPrivileges(ctx, ruleset) if err != nil { return nil, err } return &model.UpdateOperatorInterventionRuleResponse{Errors: convertRengErrorsToModel(res.Errors)}, nil } // returns a valid ruleset if the input is valid. returns an error response of len != 0 otherwise. func validateRules(rules []*model.UpdateOperatorInterventionRuleInput) (rulesengine.RuleSets, []*model.OperatorInterventionErrorResponse) { ruleset := rulesengine.RuleSets{} errorResponse := []*model.OperatorInterventionErrorResponse{} // return early if no rules are provided if len(rules) == 0 { return ruleset, []*model.OperatorInterventionErrorResponse{ { Type: model.OperatorInterventionErrorTypeInvalidInput, }, } } // validate rules for _, rule := range rules { ruleset = append(ruleset, rulesengine.RuleSet{ Privilege: rule.Privilege.Name, Commands: func() []string { var ret []string for _, command := range rule.Commands { ret = append(ret, command.Name) } return ret }(), }) if rule.Privilege.Name == "" { errorResponse = append(errorResponse, &model.OperatorInterventionErrorResponse{ Type: model.OperatorInterventionErrorTypeInvalidInput, Privilege: &rule.Privilege.Name, }) } if len(rule.Commands) == 0 { errorResponse = append(errorResponse, &model.OperatorInterventionErrorResponse{ Type: model.OperatorInterventionErrorTypeInvalidInput, }) } for _, command := range rule.Commands { if command.Name == "" { command := command errorResponse = append(errorResponse, &model.OperatorInterventionErrorResponse{ Type: model.OperatorInterventionErrorTypeInvalidInput, Command: &command.Name, }) } } } return ruleset, errorResponse } func convertRengErrorsToModel(errors []rulesengine.Error) []*model.OperatorInterventionErrorResponse { var ret []*model.OperatorInterventionErrorResponse for _, err := range errors { err := err switch err.Type { case rulesengine.UnknownCommand: ret = append(ret, &model.OperatorInterventionErrorResponse{ Type: model.OperatorInterventionErrorTypeUnknownCommand, Command: &err.Command, }) case rulesengine.UnknownPrivilege: ret = append(ret, &model.OperatorInterventionErrorResponse{ Type: model.OperatorInterventionErrorTypeUnknownPrivilege, Privilege: &err.Privilege, }) case rulesengine.UnknownRule: ret = append(ret, &model.OperatorInterventionErrorResponse{ Type: model.OperatorInterventionErrorTypeUnknownRule, Privilege: &err.Privilege, Command: &err.Command, }) } } return ret } func (o *operatorInterventionService) DeleteRule(ctx context.Context, rule model.DeleteOperatorInterventionRuleInput) (*model.DeleteOperatorInterventionRuleResponse, error) { if rule.Privilege == "" || rule.Command == "" { return &model.DeleteOperatorInterventionRuleResponse{Errors: []*model.OperatorInterventionErrorResponse{ { Type: model.OperatorInterventionErrorTypeInvalidInput, }, }}, nil } res, err := o.reng.DeleteDefaultRule(ctx, rule.Command, rule.Privilege) if err != nil { return nil, err } return &model.DeleteOperatorInterventionRuleResponse{Errors: convertRengErrorsToModel(res.Errors)}, nil }