From 6165bb55fb8bd79e05dd9560f2bfcccdcd9dfc8f Mon Sep 17 00:00:00 2001 From: Keepers Date: Mon, 5 Dec 2022 13:57:36 -0700 Subject: [PATCH] add missing any/none target check for paths (#1689) ## Description the new pathFilterFactory now properly cleans the inputs and checks for all-pass and all-fail conditions. ## Type of change - [x] :bug: Bugfix ## Issue(s) * #1616 ## Test Plan - [x] :zap: Unit test --- src/pkg/selectors/selectors.go | 68 +++++++++++++++++++++------- src/pkg/selectors/sharepoint_test.go | 35 ++++++++++++++ 2 files changed, 86 insertions(+), 17 deletions(-) diff --git a/src/pkg/selectors/selectors.go b/src/pkg/selectors/selectors.go index 09ba46dff..00640cf19 100644 --- a/src/pkg/selectors/selectors.go +++ b/src/pkg/selectors/selectors.go @@ -512,23 +512,42 @@ func filterize(sc scopeConfig, s ...string) filters.Filter { return filters.Contains(join(s...)) } -type filterFunc func(string) filters.Filter +type ( + filterFunc func(string) filters.Filter + sliceFilterFunc func([]string) filters.Filter +) // pathFilterFactory returns the appropriate path filter // (contains, prefix, or suffix) for the provided options. // If multiple options are flagged, Prefix takes priority. // If no options are provided, returns PathContains. -func pathFilterFactory(opts ...option) func([]string) filters.Filter { +func pathFilterFactory(opts ...option) sliceFilterFunc { sc := &scopeConfig{} sc.populate(opts...) + var ff sliceFilterFunc + switch true { case sc.usePrefixFilter: - return filters.PathPrefix + ff = filters.PathPrefix case sc.useSuffixFilter: - return filters.PathSuffix + ff = filters.PathSuffix default: - return filters.PathContains + ff = filters.PathContains + } + + return wrapSliceFilter(ff) +} + +func wrapSliceFilter(ff sliceFilterFunc) sliceFilterFunc { + return func(s []string) filters.Filter { + s = clean(s) + + if f, ok := isAnyOrNone(s); ok { + return f + } + + return ff(s) } } @@ -537,22 +556,37 @@ func pathFilterFactory(opts ...option) func([]string) filters.Filter { // - normalizes the cleaned input (returns anyFail if empty, allFail if *) // - joins the string // - and generates a filter with the joined input. -func wrapFilter(ff filterFunc) func([]string) filters.Filter { +func wrapFilter(ff filterFunc) sliceFilterFunc { return func(s []string) filters.Filter { s = clean(s) - if len(s) == 1 { - if s[0] == AnyTgt { - return passAny - } - - if s[0] == NoneTgt { - return failAny - } + if f, ok := isAnyOrNone(s); ok { + return f } - ss := join(s...) - - return ff(ss) + return ff(join(s...)) } } + +// returns (, true) if s is len==1 and s[0] is +// anyTgt or noneTgt, implying that the caller should use +// the returned filter. On (, false), the caller +// can ignore the returned filter. +// a special case exists for len(s)==0, interpreted as +// "noneTgt" +func isAnyOrNone(s []string) (filters.Filter, bool) { + switch len(s) { + case 0: + return failAny, true + + case 1: + switch s[0] { + case AnyTgt: + return passAny, true + case NoneTgt: + return failAny, true + } + } + + return failAny, false +} diff --git a/src/pkg/selectors/sharepoint_test.go b/src/pkg/selectors/sharepoint_test.go index b6e27e07d..c8e54bd0d 100644 --- a/src/pkg/selectors/sharepoint_test.go +++ b/src/pkg/selectors/sharepoint_test.go @@ -140,6 +140,41 @@ func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_WebURLs() { } } +func (suite *SharePointSelectorSuite) TestSharePointSelector_Include_WebURLs_anyNone() { + table := []struct { + name string + in []string + expect string + }{ + { + name: "any", + in: []string{AnyTgt}, + expect: AnyTgt, + }, + { + name: "none", + in: []string{NoneTgt}, + expect: NoneTgt, + }, + } + for _, test := range table { + suite.T().Run(test.name, func(t *testing.T) { + sel := NewSharePointRestore() + sel.Include(sel.WebURL(test.in)) + scopes := sel.Includes + require.Len(t, scopes, 1) + + for _, sc := range scopes { + scopeMustHave( + t, + SharePointScope(sc), + map[categorizer]string{SharePointWebURL: test.expect}, + ) + } + }) + } +} + func (suite *SharePointSelectorSuite) TestSharePointSelector_Exclude_WebURLs() { t := suite.T() sel := NewSharePointRestore()