event/cmdschema: don't allow flags after tail parameter

This commit is contained in:
Tulir Asokan 2026-01-11 23:54:10 +02:00
commit e034c16753
4 changed files with 66 additions and 24 deletions

View file

@ -69,7 +69,8 @@ func (ec *EventContent) Equals(other *EventContent) bool {
return ec.Command == other.Command &&
slices.Equal(ec.Aliases, other.Aliases) &&
slices.EqualFunc(ec.Parameters, other.Parameters, (*Parameter).Equals) &&
ec.Description.Equals(other.Description)
ec.Description.Equals(other.Description) &&
ec.TailParam == other.TailParam
}
func init() {

View file

@ -92,7 +92,7 @@ func (ec *EventContent) ParseArguments(input string) (json.RawMessage, error) {
retErr = err
}
}
processParameter := func(param *Parameter, isLast, isNamed bool) {
processParameter := func(param *Parameter, isLast, isTail, isNamed bool) {
origInput := input
var nextVal string
var wasQuoted bool
@ -135,8 +135,8 @@ func (ec *EventContent) ParseArguments(input string) (json.RawMessage, error) {
args[param.Key] = collector
} else {
nextVal, input, wasQuoted = parseQuoted(input)
if isLast && !wasQuoted && len(input) > 0 && !strings.Contains(input, "--") {
// If the last argument is not quoted and doesn't have flags, just treat the rest of the string
if (isLast || isTail) && !wasQuoted && len(input) > 0 {
// If the last argument is not quoted, just treat the rest of the string
// as the argument without escapes (arguments with escapes should be quoted).
nextVal += " " + input
input = ""
@ -175,7 +175,7 @@ func (ec *EventContent) ParseArguments(input string) (json.RawMessage, error) {
// Trim the equals sign, but leave spaces alone to let parseQuoted treat it as empty input
input = strings.TrimPrefix(input[nameEndIdx:], "=")
skipParams[paramIdx] = true
processParameter(overrideParam, false, true)
processParameter(overrideParam, false, false, true)
} else {
break
}
@ -184,7 +184,7 @@ func (ec *EventContent) ParseArguments(input string) (json.RawMessage, error) {
if skipParams[i] || (param.Optional && !isTail) {
continue
}
processParameter(param, i == len(ec.Parameters)-1 || isTail, false)
processParameter(param, i == len(ec.Parameters)-1, isTail, false)
}
jsonArgs, marshalErr := json.Marshal(args)
if marshalErr != nil {

View file

@ -93,24 +93,6 @@
"woof": false
}
},
{
"name": "named flag at end",
"input": "/flag mrrp @user:example.com --woof=yes",
"output": {
"meow": "mrrp",
"user": "@user:example.com",
"woof": true
}
},
{
"name": "named flag at end without value",
"input": "/flag mrrp @user:example.com --woof",
"output": {
"meow": "mrrp",
"user": "@user:example.com",
"woof": true
}
},
{
"name": "all variables named",
"input": "/flag --woof=no --meow=mrrp --user=@user:example.com",

View file

@ -0,0 +1,59 @@
{
"spec": {
"command": "tail",
"source": "@testbot",
"parameters": [
{
"key": "meow",
"schema": {
"schema_type": "primitive",
"type": "string"
}
},
{
"key": "reason",
"schema": {
"schema_type": "primitive",
"type": "string"
},
"optional": true
},
{
"key": "woof",
"schema": {
"schema_type": "primitive",
"type": "boolean"
},
"optional": true
}
],
"fi.mau.tail_parameter": "reason"
},
"tests": [
{
"name": "no tail or flag",
"input": "/tail mrrp",
"output": {
"meow": "mrrp",
"reason": ""
}
},
{
"name": "tail, no flag",
"input": "/tail mrrp meow meow",
"output": {
"meow": "mrrp",
"reason": "meow meow"
}
},
{
"name": "flag before tail",
"input": "/tail mrrp --woof meow meow",
"output": {
"meow": "mrrp",
"reason": "meow meow",
"woof": true
}
}
]
}