mirror of
https://github.com/OliveTin/OliveTin
synced 2025-12-12 09:05:39 +00:00
fmt: fmt
This commit is contained in:
@@ -86,7 +86,7 @@ func UserFromContext(ctx context.Context, cfg *config.Config) *AuthenticatedUser
|
|||||||
buildUserAcls(cfg, ret)
|
buildUserAcls(cfg, ret)
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
log.WithFields(log.Fields{
|
||||||
"username": ret.Username,
|
"username": ret.Username,
|
||||||
"usergroup": ret.Usergroup,
|
"usergroup": ret.Usergroup,
|
||||||
}).Infof("UserFromContext")
|
}).Infof("UserFromContext")
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ type Action struct {
|
|||||||
|
|
||||||
// ActionArgument objects appear on Actions.
|
// ActionArgument objects appear on Actions.
|
||||||
type ActionArgument struct {
|
type ActionArgument struct {
|
||||||
Name string
|
Name string
|
||||||
Title string
|
Title string
|
||||||
Description string
|
Description string
|
||||||
Type string
|
Type string
|
||||||
Default string
|
Default string
|
||||||
Choices []ActionArgumentChoice
|
Choices []ActionArgumentChoice
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActionArgumentChoice represents a predefined choice for an argument.
|
// ActionArgumentChoice represents a predefined choice for an argument.
|
||||||
|
|||||||
121
internal/executor/arguments.go
Normal file
121
internal/executor/arguments.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
config "github.com/OliveTin/OliveTin/internal/config"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"errors"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
typecheckRegex = map[string]string{
|
||||||
|
"very_dangerous_raw_string": "",
|
||||||
|
"int": "^[\\d]+$",
|
||||||
|
"ascii": "^[a-zA-Z0-9]+$",
|
||||||
|
"ascii_identifier": "^[a-zA-Z0-9\\-\\.\\_]+$",
|
||||||
|
"ascii_sentence": "^[a-zA-Z0-9 \\,\\.]+$",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseActionArguments(rawShellCommand string, values map[string]string, action *config.Action) (string, error) {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"cmd": rawShellCommand,
|
||||||
|
}).Infof("Before Parse Args")
|
||||||
|
|
||||||
|
r := regexp.MustCompile("{{ *?([a-zA-Z0-9_]+?) *?}}")
|
||||||
|
matches := r.FindAllStringSubmatch(rawShellCommand, -1)
|
||||||
|
|
||||||
|
for _, match := range matches {
|
||||||
|
argValue, argProvided := values[match[1]]
|
||||||
|
|
||||||
|
if !argProvided {
|
||||||
|
log.Infof("%v", values)
|
||||||
|
return "", errors.New("Required arg not provided: " + match[1])
|
||||||
|
}
|
||||||
|
|
||||||
|
err := typecheckActionArgument(match[1], argValue, action)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"name": match[1],
|
||||||
|
"value": argValue,
|
||||||
|
}).Debugf("Arg assigned")
|
||||||
|
|
||||||
|
rawShellCommand = strings.ReplaceAll(rawShellCommand, match[0], argValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"cmd": rawShellCommand,
|
||||||
|
}).Infof("After Parse Args")
|
||||||
|
|
||||||
|
return rawShellCommand, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func typecheckActionArgument(name string, value string, action *config.Action) error {
|
||||||
|
arg := action.FindArg(name)
|
||||||
|
|
||||||
|
if arg == nil {
|
||||||
|
return errors.New("Action arg not defined: " + name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(arg.Choices) > 0 {
|
||||||
|
return typecheckChoice(value, arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return TypeSafetyCheck(name, value, arg.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func typecheckChoice(value string, arg *config.ActionArgument) error {
|
||||||
|
for _, choice := range arg.Choices {
|
||||||
|
if value == choice.Value {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.New("argument value is not one of the predefined choices")
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeSafetyCheck checks argument values match a specific type. The types are
|
||||||
|
// defined in typecheckRegex, and, you guessed it, uses regex to check for allowed
|
||||||
|
// characters.
|
||||||
|
func TypeSafetyCheck(name string, value string, argumentType string) error {
|
||||||
|
if argumentType == "url" {
|
||||||
|
return typeSafetyCheckUrl(name, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return typeSafetyCheckRegex(name, value, argumentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeSafetyCheckRegex(name string, value string, argumentType string) error {
|
||||||
|
pattern, found := typecheckRegex[argumentType]
|
||||||
|
|
||||||
|
if !found {
|
||||||
|
return errors.New("argument type not implemented " + argumentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
matches, _ := regexp.MatchString(pattern, value)
|
||||||
|
|
||||||
|
if !matches {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"name": name,
|
||||||
|
"value": value,
|
||||||
|
"type": argumentType,
|
||||||
|
}).Warn("Arg type check safety failure")
|
||||||
|
|
||||||
|
return errors.New("invalid argument, doesn't match " + argumentType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeSafetyCheckUrl(name string, value string) error {
|
||||||
|
_, err := url.ParseRequestURI(value)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
69
internal/executor/arguments_test.go
Normal file
69
internal/executor/arguments_test.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package executor
|
||||||
|
|
||||||
|
import (
|
||||||
|
config "github.com/OliveTin/OliveTin/internal/config"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSanitizeUnsafe(t *testing.T) {
|
||||||
|
assert.Nil(t, TypeSafetyCheck("", "_zomg_ c:/ haxxor ' bobby tables && rm -rf ", "very_dangerous_raw_string"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSanitizeUnimplemented(t *testing.T) {
|
||||||
|
err := TypeSafetyCheck("", "I am a happy little argument", "greeting_type")
|
||||||
|
|
||||||
|
assert.NotNil(t, err, "Test an argument type that does not exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArgumentNameNumbers(t *testing.T) {
|
||||||
|
a1 := config.Action{
|
||||||
|
Title: "Do some tickles",
|
||||||
|
Shell: "echo 'Tickling {{ person1name }}'",
|
||||||
|
Arguments: []config.ActionArgument{
|
||||||
|
{
|
||||||
|
Name: "person1name",
|
||||||
|
Type: "ascii",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
values := map[string]string{
|
||||||
|
"person1name": "Fred",
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := parseActionArguments(a1.Shell, values, &a1)
|
||||||
|
|
||||||
|
assert.Equal(t, "echo 'Tickling Fred'", out)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestArgumentNotProvided(t *testing.T) {
|
||||||
|
a1 := config.Action{
|
||||||
|
Title: "Do some tickles",
|
||||||
|
Shell: "echo 'Tickling {{ personName }}'",
|
||||||
|
Arguments: []config.ActionArgument{
|
||||||
|
{
|
||||||
|
Name: "person",
|
||||||
|
Type: "ascii",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
values := map[string]string{}
|
||||||
|
|
||||||
|
out, err := parseActionArguments(a1.Shell, values, &a1)
|
||||||
|
|
||||||
|
assert.Equal(t, "", out)
|
||||||
|
assert.Equal(t, err.Error(), "Required arg not provided: personName")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTypeSafetyCheckUrl(t *testing.T) {
|
||||||
|
assert.Nil(t, TypeSafetyCheck("test1", "http://google.com", "url"), "Test URL: google.com")
|
||||||
|
assert.Nil(t, TypeSafetyCheck("test2", "http://technowax.net:80?foo=bar", "url"), "Test URL: technowax.net with query arguments")
|
||||||
|
assert.Nil(t, TypeSafetyCheck("test3", "http://localhost:80?foo=bar", "url"), "Test URL: localhost with query arguments")
|
||||||
|
assert.NotNil(t, TypeSafetyCheck("test4", "http://lo host:80", "url"), "Test a badly formed URL")
|
||||||
|
assert.NotNil(t, TypeSafetyCheck("test5", "12345", "url"), "Test a badly formed URL")
|
||||||
|
assert.NotNil(t, TypeSafetyCheck("test6", "_!23;", "url"), "Test a badly formed URL")
|
||||||
|
}
|
||||||
@@ -8,23 +8,21 @@ import (
|
|||||||
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// ExecutionRequest is a request to execute an action. It's passed to an
|
||||||
typecheckRegex = map[string]string{
|
// Executor. They're created from the grpcapi.
|
||||||
"very_dangerous_raw_string": "",
|
type ExecutionRequest struct {
|
||||||
"int": "^[\\d]+$",
|
ActionName string
|
||||||
"ascii": "^[a-zA-Z0-9]+$",
|
Arguments map[string]string
|
||||||
"ascii_identifier": "^[a-zA-Z0-9\\-\\.\\_]+$",
|
action *config.Action
|
||||||
"ascii_sentence": "^[a-zA-Z0-9 \\,\\.]+$",
|
Cfg *config.Config
|
||||||
}
|
AuthenticatedUser *acl.AuthenticatedUser
|
||||||
)
|
logEntry *InternalLogEntry
|
||||||
|
finalParsedCommand string
|
||||||
|
}
|
||||||
|
|
||||||
// InternalLogEntry objects are created by an Executor, and represent the final
|
// InternalLogEntry objects are created by an Executor, and represent the final
|
||||||
// state of execution (even if the command is not executed). It's designed to be
|
// state of execution (even if the command is not executed). It's designed to be
|
||||||
@@ -45,71 +43,14 @@ type InternalLogEntry struct {
|
|||||||
ActionIcon string
|
ActionIcon string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecutionRequest is a request to execute an action. It's passed to an
|
type executorStepFunc func(*ExecutionRequest) bool
|
||||||
// Executor. They're created from the grpcapi.
|
|
||||||
type ExecutionRequest struct {
|
|
||||||
ActionName string
|
|
||||||
Arguments map[string]string
|
|
||||||
action *config.Action
|
|
||||||
Cfg *config.Config
|
|
||||||
AuthenticatedUser *acl.AuthenticatedUser
|
|
||||||
logEntry *InternalLogEntry
|
|
||||||
finalParsedCommand string
|
|
||||||
}
|
|
||||||
|
|
||||||
type executorStep interface {
|
|
||||||
Exec(*ExecutionRequest) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executor represents a helper class for executing commands. It's main method
|
// Executor represents a helper class for executing commands. It's main method
|
||||||
// is ExecRequest
|
// is ExecRequest
|
||||||
type Executor struct {
|
type Executor struct {
|
||||||
Logs []InternalLogEntry
|
Logs []InternalLogEntry
|
||||||
|
|
||||||
chainOfCommand []executorStep
|
chainOfCommand []executorStepFunc
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultExecutor returns an Executor, with a sensible "chain of command" for
|
|
||||||
// executing actions.
|
|
||||||
func DefaultExecutor() *Executor {
|
|
||||||
e := Executor{}
|
|
||||||
e.chainOfCommand = []executorStep{
|
|
||||||
stepFindAction{},
|
|
||||||
stepACLCheck{},
|
|
||||||
stepParseArgs{},
|
|
||||||
stepLogStart{},
|
|
||||||
stepExec{},
|
|
||||||
stepLogFinish{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return &e
|
|
||||||
}
|
|
||||||
|
|
||||||
type stepFindAction struct{}
|
|
||||||
|
|
||||||
func (s stepFindAction) Exec(req *ExecutionRequest) bool {
|
|
||||||
actualAction := req.Cfg.FindAction(req.ActionName)
|
|
||||||
|
|
||||||
if actualAction == nil {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"actionName": req.ActionName,
|
|
||||||
}).Warnf("Action not found")
|
|
||||||
|
|
||||||
req.logEntry.Stderr = "Action not found"
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
req.action = actualAction
|
|
||||||
req.logEntry.ActionIcon = actualAction.Icon
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
type stepACLCheck struct{}
|
|
||||||
|
|
||||||
func (s stepACLCheck) Exec(req *ExecutionRequest) bool {
|
|
||||||
return acl.IsAllowedExec(req.Cfg, req.AuthenticatedUser, req.action)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecRequest processes an ExecutionRequest
|
// ExecRequest processes an ExecutionRequest
|
||||||
@@ -123,7 +64,7 @@ func (e *Executor) ExecRequest(req *ExecutionRequest) *pb.StartActionResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, step := range e.chainOfCommand {
|
for _, step := range e.chainOfCommand {
|
||||||
if !step.Exec(req) {
|
if !step(req) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,34 +84,46 @@ func (e *Executor) ExecRequest(req *ExecutionRequest) *pb.StartActionResponse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type stepLogStart struct{}
|
// DefaultExecutor returns an Executor, with a sensible "chain of command" for
|
||||||
|
// executing actions.
|
||||||
|
func DefaultExecutor() *Executor {
|
||||||
|
e := Executor{}
|
||||||
|
e.chainOfCommand = []executorStepFunc{
|
||||||
|
stepFindAction,
|
||||||
|
stepACLCheck,
|
||||||
|
stepParseArgs,
|
||||||
|
stepLogStart,
|
||||||
|
stepExec,
|
||||||
|
stepLogFinish,
|
||||||
|
}
|
||||||
|
|
||||||
func (e stepLogStart) Exec(req *ExecutionRequest) bool {
|
return &e
|
||||||
log.WithFields(log.Fields{
|
}
|
||||||
"title": req.action.Title,
|
|
||||||
"timeout": req.action.Timeout,
|
func stepFindAction(req *ExecutionRequest) bool {
|
||||||
}).Infof("Action starting")
|
actualAction := req.Cfg.FindAction(req.ActionName)
|
||||||
|
|
||||||
|
if actualAction == nil {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"actionName": req.ActionName,
|
||||||
|
}).Warnf("Action not found")
|
||||||
|
|
||||||
|
req.logEntry.Stderr = "Action not found"
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
req.action = actualAction
|
||||||
|
req.logEntry.ActionIcon = actualAction.Icon
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type stepLogFinish struct{}
|
func stepACLCheck(req *ExecutionRequest) bool {
|
||||||
|
return acl.IsAllowedExec(req.Cfg, req.AuthenticatedUser, req.action)
|
||||||
func (e stepLogFinish) Exec(req *ExecutionRequest) bool {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"title": req.action.Title,
|
|
||||||
"stdout": req.logEntry.Stdout,
|
|
||||||
"stderr": req.logEntry.Stderr,
|
|
||||||
"timedOut": req.logEntry.TimedOut,
|
|
||||||
"exit": req.logEntry.ExitCode,
|
|
||||||
}).Infof("Action finished")
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stepParseArgs struct{}
|
func stepParseArgs(req *ExecutionRequest) bool {
|
||||||
|
|
||||||
func (e stepParseArgs) Exec(req *ExecutionRequest) bool {
|
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
req.finalParsedCommand, err = parseActionArguments(req.action.Shell, req.Arguments, req.action)
|
req.finalParsedCommand, err = parseActionArguments(req.action.Shell, req.Arguments, req.action)
|
||||||
@@ -186,9 +139,28 @@ func (e stepParseArgs) Exec(req *ExecutionRequest) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
type stepExec struct{}
|
func stepLogStart(req *ExecutionRequest) bool {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"title": req.action.Title,
|
||||||
|
"timeout": req.action.Timeout,
|
||||||
|
}).Infof("Action starting")
|
||||||
|
|
||||||
func (e stepExec) Exec(req *ExecutionRequest) bool {
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func stepLogFinish(req *ExecutionRequest) bool {
|
||||||
|
log.WithFields(log.Fields{
|
||||||
|
"title": req.action.Title,
|
||||||
|
"stdout": req.logEntry.Stdout,
|
||||||
|
"stderr": req.logEntry.Stderr,
|
||||||
|
"timedOut": req.logEntry.TimedOut,
|
||||||
|
"exit": req.logEntry.ExitCode,
|
||||||
|
}).Infof("Action finished")
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func stepExec(req *ExecutionRequest) bool {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.action.Timeout)*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(req.action.Timeout)*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
@@ -215,103 +187,3 @@ func (e stepExec) Exec(req *ExecutionRequest) bool {
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseActionArguments(rawShellCommand string, values map[string]string, action *config.Action) (string, error) {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"cmd": rawShellCommand,
|
|
||||||
}).Infof("Before Parse Args")
|
|
||||||
|
|
||||||
r := regexp.MustCompile("{{ *?([a-zA-Z0-9_]+?) *?}}")
|
|
||||||
matches := r.FindAllStringSubmatch(rawShellCommand, -1)
|
|
||||||
|
|
||||||
for _, match := range matches {
|
|
||||||
argValue, argProvided := values[match[1]]
|
|
||||||
|
|
||||||
if !argProvided {
|
|
||||||
log.Infof("%v", values)
|
|
||||||
return "", errors.New("Required arg not provided: " + match[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
err := typecheckActionArgument(match[1], argValue, action)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"name": match[1],
|
|
||||||
"value": argValue,
|
|
||||||
}).Debugf("Arg assigned")
|
|
||||||
|
|
||||||
rawShellCommand = strings.ReplaceAll(rawShellCommand, match[0], argValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"cmd": rawShellCommand,
|
|
||||||
}).Infof("After Parse Args")
|
|
||||||
|
|
||||||
return rawShellCommand, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func typecheckActionArgument(name string, value string, action *config.Action) error {
|
|
||||||
arg := action.FindArg(name)
|
|
||||||
|
|
||||||
if arg == nil {
|
|
||||||
return errors.New("Action arg not defined: " + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(arg.Choices) > 0 {
|
|
||||||
return typecheckChoice(value, arg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return TypeSafetyCheck(name, value, arg.Type)
|
|
||||||
}
|
|
||||||
|
|
||||||
func typecheckChoice(value string, arg *config.ActionArgument) error {
|
|
||||||
for _, choice := range arg.Choices {
|
|
||||||
if value == choice.Value {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New("argument value is not one of the predefined choices")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TypeSafetyCheck checks argument values match a specific type. The types are
|
|
||||||
// defined in typecheckRegex, and, you guessed it, uses regex to check for allowed
|
|
||||||
// characters.
|
|
||||||
func TypeSafetyCheck(name string, value string, argumentType string) error {
|
|
||||||
if argumentType == "url" {
|
|
||||||
return typeSafetyCheckUrl(name, value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return typeSafetyCheckRegex(name, value, argumentType)
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeSafetyCheckRegex(name string, value string, argumentType string) error {
|
|
||||||
pattern, found := typecheckRegex[argumentType]
|
|
||||||
|
|
||||||
if !found {
|
|
||||||
return errors.New("argument type not implemented " + argumentType)
|
|
||||||
}
|
|
||||||
|
|
||||||
matches, _ := regexp.MatchString(pattern, value)
|
|
||||||
|
|
||||||
if !matches {
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"name": name,
|
|
||||||
"value": value,
|
|
||||||
"type": argumentType,
|
|
||||||
}).Warn("Arg type check safety failure")
|
|
||||||
|
|
||||||
return errors.New("invalid argument, doesn't match " + argumentType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func typeSafetyCheckUrl(name string, value string) error {
|
|
||||||
_, err := url.ParseRequestURI(value)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -8,17 +8,6 @@ import (
|
|||||||
config "github.com/OliveTin/OliveTin/internal/config"
|
config "github.com/OliveTin/OliveTin/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSanitizeUnsafe(t *testing.T) {
|
|
||||||
assert.Nil(t, TypeSafetyCheck("", "_zomg_ c:/ haxxor ' bobby tables && rm -rf ", "very_dangerous_raw_string"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestSanitizeUnimplemented(t *testing.T) {
|
|
||||||
err := TypeSafetyCheck("", "I am a happy little argument", "greeting_type")
|
|
||||||
|
|
||||||
assert.NotNil(t, err, "Test an argument type that does not exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func testingExecutor() (*Executor, *config.Config) {
|
func testingExecutor() (*Executor, *config.Config) {
|
||||||
e := DefaultExecutor()
|
e := DefaultExecutor()
|
||||||
|
|
||||||
@@ -119,54 +108,3 @@ func TestArgumentNameSnakeCase(t *testing.T) {
|
|||||||
assert.Equal(t, "echo 'Tickling Fred'", out)
|
assert.Equal(t, "echo 'Tickling Fred'", out)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestArgumentNameNumbers(t *testing.T) {
|
|
||||||
a1 := config.Action{
|
|
||||||
Title: "Do some tickles",
|
|
||||||
Shell: "echo 'Tickling {{ person1name }}'",
|
|
||||||
Arguments: []config.ActionArgument{
|
|
||||||
{
|
|
||||||
Name: "person1name",
|
|
||||||
Type: "ascii",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
values := map[string]string{
|
|
||||||
"person1name": "Fred",
|
|
||||||
}
|
|
||||||
|
|
||||||
out, err := parseActionArguments(a1.Shell, values, &a1)
|
|
||||||
|
|
||||||
assert.Equal(t, "echo 'Tickling Fred'", out)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestArgumentNotProvided(t *testing.T) {
|
|
||||||
a1 := config.Action{
|
|
||||||
Title: "Do some tickles",
|
|
||||||
Shell: "echo 'Tickling {{ personName }}'",
|
|
||||||
Arguments: []config.ActionArgument{
|
|
||||||
{
|
|
||||||
Name: "person",
|
|
||||||
Type: "ascii",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
values := map[string]string{}
|
|
||||||
|
|
||||||
out, err := parseActionArguments(a1.Shell, values, &a1)
|
|
||||||
|
|
||||||
assert.Equal(t, "", out)
|
|
||||||
assert.Equal(t, err.Error(), "Required arg not provided: personName")
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestTypeSafetyCheckUrl(t *testing.T) {
|
|
||||||
assert.Nil(t, TypeSafetyCheck("test1", "http://google.com", "url"), "Test URL: google.com")
|
|
||||||
assert.Nil(t, TypeSafetyCheck("test2", "http://technowax.net:80?foo=bar", "url"), "Test URL: technowax.net with query arguments")
|
|
||||||
assert.Nil(t, TypeSafetyCheck("test3", "http://localhost:80?foo=bar", "url"), "Test URL: localhost with query arguments")
|
|
||||||
assert.NotNil(t, TypeSafetyCheck("test4", "http://lo host:80", "url"), "Test a badly formed URL")
|
|
||||||
assert.NotNil(t, TypeSafetyCheck("test5", "12345", "url"), "Test a badly formed URL")
|
|
||||||
assert.NotNil(t, TypeSafetyCheck("test6", "_!23;", "url"), "Test a badly formed URL")
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user