Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add stricter func name validation #544

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
15 changes: 8 additions & 7 deletions commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"

"github.com/fnproject/cli/common"
Expand Down Expand Up @@ -397,14 +398,14 @@ func (a *initFnCmd) bindFn(fn *modelsV2.Fn) {
}
}

// ValidateFuncName checks if the func name is valid, the name can't contain a colon and
// must be all lowercase
// ValidateFuncName checks if the func name is valid, the name can only contain alphanumerical
// lowercase characters, separated by ., _ or -.
func ValidateFuncName(name string) error {
if strings.Contains(name, ":") {
return errors.New("Function name cannot contain a colon")
}
if strings.ToLower(name) != name {
return errors.New("Function name must be lowercase")
// Match multiple groups of lowercase charaters and numbers, followed by 0 or 1 instances
// of the separators; the string also needs to end with a character or a number (not separator)
isValid := regexp.MustCompile(`^([a-z0-9]+[._-]?)*[a-z0-9]$`).MatchString
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should compile this at init time and have a global var to use just to call MatchString, regex compile is slow and this func may have repeated invocations (eg in deploy --all)

if !isValid(name) {
return errors.New("Function name cannot contain spaces, start with separators or contain uppercase letters")
}
return nil
}
Expand Down
115 changes: 104 additions & 11 deletions init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,110 @@ func TestInit(t *testing.T) {
}
}

func funcNameValidation(name string, t *testing.T) {
err := commands.ValidateFuncName("fooFunc")
if err == nil {
t.Error("Expected validation error for function name")
func TestFuncNameValidation(t *testing.T) {
tc := []struct {
name string
value string
errExpected bool
}{
{
name: "strings only",
value: "somename",
errExpected: false,
},
{
name: "numbers only",
value: "12345",
errExpected: false,
},
{
name: "uppercase letters",
value: "HelloFuncName",
errExpected: true,
},
{
name: "starts with separator",
value: ".myfunc",
errExpected: true,
},
{
name: "starts with separator (*)",
value: "*myfunc",
errExpected: true,
},
{
name: "starts with separator (-)",
value: "-myfunc",
errExpected: true,
},
{
name: "ends with separator",
value: "myfunc-",
errExpected: true,
},
{
name: "ends with separator (.)",
value: "myfunc.",
errExpected: true,
},
{
name: "ends with separator (*)",
value: "myfunc*",
errExpected: true,
},
{
name: "contains spaces",
value: "my func blah",
errExpected: true,
},
{
name: "hypen in name",
value: "my-func-blah",
errExpected: false,
},
{
name: "underscore in name",
value: "my_funcblah",
errExpected: false,
},
{
name: "dot in name",
value: "my.funcblah",
errExpected: false,
},
{
name: "multiple separators in row",
value: "my___funcblah",
errExpected: true,
},
{
name: "multiple different separators in row",
value: "my_.funcblah",
errExpected: true,
},
{
name: "multiple separators in the name",
value: "my_func-blah.test",
errExpected: false,
},
peterj marked this conversation as resolved.
Show resolved Hide resolved
}
}

func TestFuncNameWithUpperCase(t *testing.T) {
funcNameValidation("fooMyFunc", t)
}

func TestFuncNameWithColon(t *testing.T) {
funcNameValidation("foo:myfunc", t)
t.Log("Test func name validation")
{
for i, tst := range tc {
t.Logf("\tTest %d: \t%s", i, tst.name)
{
err := commands.ValidateFuncName(tst.value)
if err != nil {
if !tst.errExpected {
t.Fatalf("\tValidateFuncName failed : got unexpected error [%v]\n", err)
}
} else {
if tst.errExpected {
t.Fatalf("\tValidateFuncName failed : error expected for value '%s' but was nil\n", tst.value)
}
}
}
}
}
}