Skip to content

Commit

Permalink
Support Variable Depths and improve regex (#118)
Browse files Browse the repository at this point in the history
* Make the service path variable depth

* Update validation to support .

* Support different validation for CHAMBER_NO_PATHS

* Add tests for validations
  • Loading branch information
pecigonzalo authored and nickatsegment committed Sep 10, 2018
1 parent 46a6dcb commit d9c77ea
Show file tree
Hide file tree
Showing 5 changed files with 210 additions and 14 deletions.
11 changes: 5 additions & 6 deletions cmd/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,12 @@ func list(cmd *cobra.Command, args []string) error {

func key(s string) string {
_, noPaths := os.LookupEnv("CHAMBER_NO_PATHS")
if !noPaths {
tokens := strings.Split(s, "/")
secretKey := tokens[2]
return secretKey
sep := "/"
if noPaths {
sep = "."
}

tokens := strings.Split(s, ".")
secretKey := tokens[1]
tokens := strings.Split(s, sep)
secretKey := tokens[len(tokens)-1]
return secretKey
}
19 changes: 14 additions & 5 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import (

// Regex's used to validate service and key names
var (
validKeyFormat = regexp.MustCompile(`^[A-Za-z0-9-_]+$`)
validServiceFormat = regexp.MustCompile(`^[A-Za-z0-9-_]+$`)
validKeyFormat = regexp.MustCompile(`^[\w\-\.]+$`)
validServiceFormat = regexp.MustCompile(`^[\w\-\.]+$`)
validServicePathFormat = regexp.MustCompile(`^[\w\-\.]+(\/[\w\-\.]+)*$`)

verbose bool
numRetries int
Expand Down Expand Up @@ -62,15 +63,23 @@ func Execute(vers string) {
}

func validateService(service string) error {
if !validServiceFormat.MatchString(service) {
return fmt.Errorf("Failed to validate service name '%s'. Only alphanumeric, dashes, and underscores are allowed for service names", service)
_, noPaths := os.LookupEnv("CHAMBER_NO_PATHS")
if noPaths {
if !validServiceFormat.MatchString(service) {
return fmt.Errorf("Failed to validate service name '%s'. Only alphanumeric, dashes, fullstops and underscores are allowed for service names", service)
}
} else {
if !validServicePathFormat.MatchString(service) {
return fmt.Errorf("Failed to validate service name '%s'. Only alphanumeric, dashes, forwardslashes, fullstops and underscores are allowed for service names", service)
}
}

return nil
}

func validateKey(key string) error {
if !validKeyFormat.MatchString(key) {
return fmt.Errorf("Failed to validate key name '%s'. Only alphanumeric, dashes, and underscores are allowed for key names", key)
return fmt.Errorf("Failed to validate key name '%s'. Only alphanumeric, dashes, fullstops and underscores are allowed for key names", key)
}
return nil
}
Expand Down
110 changes: 110 additions & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package cmd

import (
"os"
"testing"

"github.com/stretchr/testify/assert"
)

func TestValidations(t *testing.T) {

// Test Key formats
validKeyFormat := []string{
"foo",
"foo.bar",
"foo.",
".foo",
"foo-bar",
}

for _, k := range validKeyFormat {
t.Run("Key validation should return Nil", func(t *testing.T) {
result := validateKey(k)
assert.Nil(t, result)
})
}

invalidKeyFormat := []string{
"/foo",
"foo//bar",
"foo/bar",
}

for _, k := range invalidKeyFormat {
t.Run("Key validation should return Error", func(t *testing.T) {
result := validateKey(k)
assert.Error(t, result)
})
}

// Test Service format with PATH
validServicePathFormat := []string{
"foo",
"foo.",
".foo",
"foo.bar",
"foo-bar",
"foo/bar",
"foo.bar/foo",
"foo-bar/foo",
"foo-bar/foo-bar",
"foo/bar/foo",
"foo/bar/foo-bar",
}

for _, k := range validServicePathFormat {
t.Run("Service with PATH validation should return Nil", func(t *testing.T) {
result := validateService(k)
assert.Nil(t, result)
})
}

invalidServicePathFormat := []string{
"foo/",
"/foo",
"foo//bar",
}

for _, k := range invalidServicePathFormat {
t.Run("Service with PATH validation should return Error", func(t *testing.T) {
result := validateService(k)
assert.Error(t, result)
})
}

// Test Service format without PATH
os.Setenv("CHAMBER_NO_PATHS", "true")
validServiceNoPathFormat := []string{
"foo",
"foo.",
".foo",
"foo.bar",
"foo-bar",
"foo-bar.foo",
"foo-bar.foo-bar",
"foo.bar.foo",
"foo.bar.foo-bar",
}

for _, k := range validServiceNoPathFormat {
t.Run("Service without PATH validation should return Nil", func(t *testing.T) {
result := validateService(k)
assert.Nil(t, result)
})
}

invalidServiceNoPathFormat := []string{
"/foo",
"foo//bar",
"foo/bar",
}

for _, k := range invalidServiceNoPathFormat {
t.Run("Service without PATH validation should return Error", func(t *testing.T) {
result := validateService(k)
assert.Error(t, result)
})
}
os.Unsetenv("CHAMBER_NO_PATHS")
}
7 changes: 4 additions & 3 deletions store/ssmstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ const (

// validPathKeyFormat is the format that is expected for key names inside parameter store
// when using paths
var validPathKeyFormat = regexp.MustCompile(`^\/[A-Za-z0-9-_]+\/[A-Za-z0-9-_]+$`)
var validPathKeyFormat = regexp.MustCompile(`^(\/[\w\-\.]+)+$`)

// validKeyFormat is the format that is expected for key names inside parameter store when
// not using paths
var validKeyFormat = regexp.MustCompile(`^[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$`)
var validKeyFormat = regexp.MustCompile(`^[\w\-\.]+$`)

// ensure SSMStore confirms to Store interface
var _ Store = &SSMStore{}
Expand Down Expand Up @@ -484,7 +484,8 @@ func basePath(key string) string {
if len(pathParts) == 1 {
return pathParts[0]
}
return "/" + pathParts[1]
end := len(pathParts) - 1
return strings.Join(pathParts[0:end], "/")
}

func parameterMetaToSecretMeta(p *ssm.ParameterMetadata) SecretMetadata {
Expand Down
77 changes: 77 additions & 0 deletions store/ssmstore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,83 @@ func TestDelete(t *testing.T) {
})
}

func TestValidations(t *testing.T) {
mock := &mockSSMClient{parameters: map[string]mockParameter{}}
pathStore := NewTestSSMStore(mock)
pathStore.usePaths = true

validPathFormat := []string{
"/foo",
"/foo.",
"/.foo",
"/foo.bar",
"/foo-bar",
"/foo/bar",
"/foo.bar/foo",
"/foo-bar/foo",
"/foo-bar/foo-bar",
"/foo/bar/foo",
"/foo/bar/foo-bar",
}

for _, k := range validPathFormat {
t.Run("Path Validation should return true", func(t *testing.T) {
result := pathStore.validateName(k)
assert.True(t, result)
})
}

invalidPathFormat := []string{
"/foo//bar",
"foo//bar",
"foo/bar",
"foo/b",
"foo",
}

for _, k := range invalidPathFormat {
t.Run("Path Validation should return false", func(t *testing.T) {
result := pathStore.validateName(k)
assert.False(t, result)
})
}

noPathStore := NewTestSSMStore(mock)
noPathStore.usePaths = false

validNoPathFormat := []string{
"foo",
"foo.",
".foo",
"foo.bar",
"foo-bar",
"foo-bar.foo",
"foo-bar.foo-bar",
"foo.bar.foo",
"foo.bar.foo-bar",
}

for _, k := range validNoPathFormat {
t.Run("Validation should return true", func(t *testing.T) {
result := noPathStore.validateName(k)
assert.True(t, result)
})
}

invalidNoPathFormat := []string{
"/foo",
"foo/bar",
"foo//bar",
}

for _, k := range invalidNoPathFormat {
t.Run("Validation should return false", func(t *testing.T) {
result := noPathStore.validateName(k)
assert.False(t, result)
})
}
}

type ByKey []Secret

func (a ByKey) Len() int { return len(a) }
Expand Down

0 comments on commit d9c77ea

Please sign in to comment.