Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions internal/validators/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var (
ErrInvalidNamedArgumentName = errors.New("invalid named argument name format")
ErrArgumentValueStartsWithName = errors.New("argument value cannot start with the argument name")
ErrArgumentDefaultStartsWithName = errors.New("argument default cannot start with the argument name")
ErrValueHintOnNamedArgument = errors.New("valueHint is only valid for positional arguments, not named arguments")

// Server name validation errors
ErrMultipleSlashesInServerName = errors.New("server name cannot contain multiple slashes")
Expand Down
14 changes: 14 additions & 0 deletions internal/validators/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,20 @@ func validateArgument(ctx *ValidationContext, obj *model.Argument) *ValidationRe
// Validate value and default don't start with the name
valueResult := validateArgumentValueFields(ctx, obj.Name, obj.Value, obj.Default)
result.Merge(valueResult)

// valueHint names a positional slot for transport URL variable
// substitution, so it only makes sense on positional arguments. The
// schema allows it on named arguments (the union branches don't set
// additionalProperties: false), so reject it here instead.
if obj.ValueHint != "" {
issue := NewValidationIssueFromError(
ValidationIssueTypeSemantic,
ctx.Field("valueHint").String(),
ErrValueHintOnNamedArgument,
"valuehint-on-named-argument",
)
result.AddIssue(issue)
}
}
return result
}
Expand Down
28 changes: 28 additions & 0 deletions internal/validators/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,34 @@ func TestValidateArgument_InvalidNamedArgumentNames(t *testing.T) {
}
}

func TestValidateArgument_ValueHintOnNamedArgument(t *testing.T) {
// valueHint identifies a positional slot, so a named argument must not carry
// one. The schema misses this (the argument union branches allow extra
// properties), so the semantic validator is the enforcement point.
t.Run("named_with_valueHint_rejected", func(t *testing.T) {
arg := model.Argument{
Type: model.ArgumentTypeNamed,
Name: "--port",
ValueHint: "port_number",
}
server := createValidServerWithArgument(arg)
result := validators.ValidateServerJSON(&server, validators.ValidationSchemaVersionAndSemantic)
assert.Error(t, result.FirstError(), "named argument carrying valueHint should be rejected")
})

// A positional argument with a valueHint stays valid (no regression).
t.Run("positional_with_valueHint_valid", func(t *testing.T) {
arg := model.Argument{
InputWithVariables: model.InputWithVariables{Input: model.Input{Value: "/etc/config.json"}},
Type: model.ArgumentTypePositional,
ValueHint: "config_path",
}
server := createValidServerWithArgument(arg)
result := validators.ValidateServerJSON(&server, validators.ValidationSchemaVersionAndSemantic)
assert.NoError(t, result.FirstError(), "positional argument with valueHint should remain valid")
})
}

func TestValidateArgument_InvalidValueFields(t *testing.T) {
invalidValueCases := []struct {
name string
Expand Down
Loading