Reject names that aren't url-safe

Environment names can be used in a number of contexts, and should be
properly escaped for safety. Since most state names are store in path
structures, and often in a URL, use `url.PathEscape` to check for
disallowed characters
This commit is contained in:
James Bardin 2017-03-27 16:16:09 -04:00
parent 3e8a8c5e23
commit 9d118325b3
5 changed files with 68 additions and 1 deletions

View File

@ -1,6 +1,9 @@
package command
import "strings"
import (
"net/url"
"strings"
)
// EnvCommand is a Command Implementation that manipulates local state
// environments.
@ -39,6 +42,13 @@ func (c *EnvCommand) Synopsis() string {
return "Environment management"
}
// validEnvName returns true is this name is valid to use as an environment name.
// Since most named states are accessed via a filesystem path or URL, check if
// escaping the name would be required.
func validEnvName(name string) bool {
return name == url.PathEscape(name)
}
const (
envNotSupported = `Backend does not support environments`
@ -81,5 +91,10 @@ Environment %[1]q is your active environment!
You cannot delete the currently active environment. Please switch
to another environment and try again.
`
envInvalidName = `
The environment name %q is not allowed. The name must contain only URL safe
characters, and no path separators.
`
)

View File

@ -103,6 +103,44 @@ func TestEnv_createAndList(t *testing.T) {
}
}
// Don't allow names that aren't URL safe
func TestEnv_createInvalid(t *testing.T) {
// Create a temporary working directory that is empty
td := tempDir(t)
os.MkdirAll(td, 0755)
defer os.RemoveAll(td)
defer testChdir(t, td)()
newCmd := &EnvNewCommand{}
envs := []string{"test_a*", "test_b/foo", "../../../test_c", "好_d"}
// create multiple envs
for _, env := range envs {
ui := new(cli.MockUi)
newCmd.Meta = Meta{Ui: ui}
if code := newCmd.Run([]string{env}); code == 0 {
t.Fatalf("expected failure: \n%s", ui.OutputWriter)
}
}
// list envs to make sure none were created
listCmd := &EnvListCommand{}
ui := new(cli.MockUi)
listCmd.Meta = Meta{Ui: ui}
if code := listCmd.Run(nil); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
}
actual := strings.TrimSpace(ui.OutputWriter.String())
expected := "* default"
if actual != expected {
t.Fatalf("\nexpected: %q\nactual: %q", expected, actual)
}
}
func TestEnv_createWithState(t *testing.T) {
td := tempDir(t)
os.MkdirAll(td, 0755)

View File

@ -32,6 +32,11 @@ func (c *EnvDeleteCommand) Run(args []string) int {
delEnv := args[0]
if !validEnvName(delEnv) {
c.Ui.Error(fmt.Sprintf(envInvalidName, delEnv))
return 1
}
configPath, err := ModulePath(args[1:])
if err != nil {
c.Ui.Error(err.Error())

View File

@ -35,6 +35,11 @@ func (c *EnvNewCommand) Run(args []string) int {
newEnv := args[0]
if !validEnvName(newEnv) {
c.Ui.Error(fmt.Sprintf(envInvalidName, newEnv))
return 1
}
configPath, err := ModulePath(args[1:])
if err != nil {
c.Ui.Error(err.Error())

View File

@ -39,6 +39,10 @@ func (c *EnvSelectCommand) Run(args []string) int {
}
name := args[0]
if !validEnvName(name) {
c.Ui.Error(fmt.Sprintf(envInvalidName, name))
return 1
}
states, err := b.States()
if err != nil {