diff --git a/src/pkg/path/path.go b/src/pkg/path/path.go index 758beef77..6e9c7cd11 100644 --- a/src/pkg/path/path.go +++ b/src/pkg/path/path.go @@ -185,11 +185,7 @@ func BuildPrefix( }, nil } -// FromDataLayerPath parses the escaped path p, validates the elements in p -// match a resource-specific path format, and returns a Path struct for that -// resource-specific type. If p does not match any resource-specific paths or -// is malformed returns an error. -func FromDataLayerPath(p string, isItem bool) (Path, error) { +func pathFromDataLayerPath(p string, isItem bool, minElements int) (Path, error) { p = TrimTrailingSlash(p) // If p was just the path separator then it will be empty now. if len(p) == 0 { @@ -202,15 +198,21 @@ func FromDataLayerPath(p string, isItem bool) (Path, error) { return nil, clues.Stack(errParsingPath, err).With("path_string", p) } - if len(pb.elements) < 5 { - return nil, clues.New("path has too few segments").With("path_string", p) + if len(pb.elements) < minElements { + return nil, clues.New( + "missing required tenant, service, category, protected resource ID, or non-prefix segment"). + With("path_string", pb) } service, category, err := validateServiceAndCategoryStrings( pb.elements[1], pb.elements[3]) if err != nil { - return nil, clues.Stack(errParsingPath, err).With("path_string", p) + return nil, clues.Stack(errParsingPath, err).With("path_string", pb) + } + + if err := verifyInputValues(pb.elements[0], pb.elements[2]); err != nil { + return nil, clues.Stack(err).With("path_string", pb) } return &dataLayerResourcePath{ @@ -221,6 +223,20 @@ func FromDataLayerPath(p string, isItem bool) (Path, error) { }, nil } +func PrefixOrPathFromDataLayerPath(p string, isItem bool) (Path, error) { + res, err := pathFromDataLayerPath(p, isItem, 4) + return res, clues.Stack(err).OrNil() +} + +// FromDataLayerPath parses the escaped path p, validates the elements in p +// match a resource-specific path format, and returns a Path struct for that +// resource-specific type. If p does not match any resource-specific paths or +// is malformed returns an error. +func FromDataLayerPath(p string, isItem bool) (Path, error) { + res, err := pathFromDataLayerPath(p, isItem, 5) + return res, clues.Stack(err).OrNil() +} + // TrimTrailingSlash takes an escaped path element and returns an escaped path // element with the trailing path separator character(s) removed if they were not // escaped. If there were no trailing path separator character(s) or the separator(s) diff --git a/src/pkg/path/path_test.go b/src/pkg/path/path_test.go index b9bb44c17..d71a30f07 100644 --- a/src/pkg/path/path_test.go +++ b/src/pkg/path/path_test.go @@ -426,6 +426,26 @@ func (suite *PathUnitSuite) TestFromDataLayerPath() { } } +func (suite *PathUnitSuite) TestPrefixOrPathFromDataLayerPath() { + t := suite.T() + input := fmt.Sprintf( + "%s/%s/%s/%s", + "tenant", + ExchangeService.String(), + "user", + EmailCategory.String()) + + // Check that we can make a valid prefix path. + p, err := PrefixOrPathFromDataLayerPath(input, false) + assert.NoError(t, err, clues.ToCore(err)) + assert.Equal(t, input, p.String()) + + // Check we can't make a regular path with the same input since it doesn't + // have enough segments. + _, err = FromDataLayerPath(input, false) + assert.Error(t, err) +} + func (suite *PathUnitSuite) TestBuildPrefix() { table := []struct { name string