api_justification.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package api
  2. import (
  3. "fmt"
  4. "strings"
  5. "connectrpc.com/connect"
  6. apiv1 "github.com/OliveTin/OliveTin/gen/olivetin/api/v1"
  7. authpublic "github.com/OliveTin/OliveTin/internal/auth/authpublic"
  8. "github.com/OliveTin/OliveTin/internal/config"
  9. "github.com/OliveTin/OliveTin/internal/entities"
  10. "github.com/OliveTin/OliveTin/internal/executor"
  11. "github.com/OliveTin/OliveTin/internal/tpl"
  12. log "github.com/sirupsen/logrus"
  13. )
  14. func validateJustificationRequired(action *config.Action, justification string, user *authpublic.AuthenticatedUser) error {
  15. if !actionRequiresJustificationConfig(action) || justificationProvided(justification, user) {
  16. return nil
  17. }
  18. return fmt.Errorf("justification is required for this action")
  19. }
  20. func actionRequiresJustificationConfig(action *config.Action) bool {
  21. return action != nil && action.RequiresJustification()
  22. }
  23. func justificationProvided(justification string, user *authpublic.AuthenticatedUser) bool {
  24. return strings.TrimSpace(justification) != "" || executor.IsSystemExecution(user)
  25. }
  26. func connectInvalidJustification(err error) error {
  27. return connect.NewError(connect.CodeInvalidArgument, err)
  28. }
  29. func startActionArgumentsFromProto(args []*apiv1.StartActionArgument) map[string]string {
  30. result := make(map[string]string, len(args))
  31. for _, arg := range args {
  32. result[arg.Name] = arg.Value
  33. }
  34. return result
  35. }
  36. func resolveStartJustification(action *config.Action, binding *executor.ActionBinding, clientJustification string, args map[string]string) string {
  37. if strings.TrimSpace(clientJustification) != "" {
  38. return clientJustification
  39. }
  40. return resolveJustificationFromTemplate(action, binding, clientJustification, args)
  41. }
  42. func resolveJustificationFromTemplate(action *config.Action, binding *executor.ActionBinding, fallback string, args map[string]string) string {
  43. templateText := action.JustificationTemplateText()
  44. if templateText == "" {
  45. return fallback
  46. }
  47. resolved, err := tpl.ParseTemplateWithActionContext(templateText, bindingEntity(binding), args)
  48. if err != nil {
  49. log.WithFields(log.Fields{
  50. "template": templateText,
  51. "entity": bindingEntity(binding),
  52. "error": err,
  53. }).Warn("Failed to resolve justification template")
  54. return fallback
  55. }
  56. return resolved
  57. }
  58. func bindingEntity(binding *executor.ActionBinding) *entities.Entity {
  59. if binding == nil {
  60. return nil
  61. }
  62. return binding.Entity
  63. }
  64. func restartRequiresJustificationError() error {
  65. return connect.NewError(connect.CodeInvalidArgument, fmt.Errorf("justification is required for this action; use StartAction with a justification instead"))
  66. }