diff --git a/internal/scaffold/add.go b/internal/scaffold/add.go index 3c2b2f7..719a0eb 100644 --- a/internal/scaffold/add.go +++ b/internal/scaffold/add.go @@ -12,6 +12,10 @@ func Add(svcType, svcName string) error { return fmt.Errorf("quikdb.yaml not found. Are you in a quikdb-frame project?") } + if err := validateName(svcName, "service name"); err != nil { + return err + } + fullName := svcType + "-" + svcName if svcType == "web" { fullName = "web-" + svcName diff --git a/internal/scaffold/init.go b/internal/scaffold/init.go index 201b4fb..fa4cad4 100644 --- a/internal/scaffold/init.go +++ b/internal/scaffold/init.go @@ -7,6 +7,10 @@ import ( ) func Init(name, dbType string) error { + if err := validateName(name, "project name"); err != nil { + return err + } + if _, err := os.Stat(name); err == nil { return fmt.Errorf("directory %s already exists", name) } diff --git a/internal/scaffold/validate.go b/internal/scaffold/validate.go new file mode 100644 index 0000000..61993a0 --- /dev/null +++ b/internal/scaffold/validate.go @@ -0,0 +1,18 @@ +package scaffold + +import ( + "fmt" + "regexp" +) + +// validName allows letters, numbers, hyphens, underscores. +// Must start with a letter or number. Max 50 chars. +// Rejects path traversal attempts like ../../etc or /absolute/path. +var validName = regexp.MustCompile(`^[a-zA-Z0-9][a-zA-Z0-9_-]{0,49}$`) + +func validateName(name, label string) error { + if !validName.MatchString(name) { + return fmt.Errorf("invalid %s %q: use letters, numbers, hyphens, and underscores only (no slashes or dots)", label, name) + } + return nil +}