Skip to content

Commit

Permalink
feat(sourceNamespace): Separate exactMatch into patternMatch
Browse files Browse the repository at this point in the history
Signed-off-by: Arthur <[email protected]>
  • Loading branch information
ArthurVardevanyan committed Aug 12, 2024
1 parent b9acf0d commit 0fc2753
Show file tree
Hide file tree
Showing 10 changed files with 37 additions and 35 deletions.
2 changes: 1 addition & 1 deletion applicationset/controllers/applicationset_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ func (r *ApplicationSetReconciler) getMinRequeueAfter(applicationSetInfo *argov1
func ignoreNotAllowedNamespaces(namespaces []string) predicate.Predicate {
return predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool {
return glob.MatchStringInList(namespaces, e.Object.GetNamespace(), false)
return glob.MatchStringInList(namespaces, e.Object.GetNamespace(), "glob")
},
}
}
Expand Down
2 changes: 1 addition & 1 deletion controller/appcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2109,7 +2109,7 @@ func (ctrl *ApplicationController) shouldSelfHeal(app *appv1.Application) (bool,
// isAppNamespaceAllowed returns whether the application is allowed in the
// namespace it's residing in.
func (ctrl *ApplicationController) isAppNamespaceAllowed(app *appv1.Application) bool {
return app.Namespace == ctrl.namespace || glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, false)
return app.Namespace == ctrl.namespace || glob.MatchStringInList(ctrl.applicationNamespaces, app.Namespace, "glob")
}

func (ctrl *ApplicationController) canProcessApp(obj interface{}) bool {
Expand Down
5 changes: 1 addition & 4 deletions docs/operator-manual/app-any-namespace.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,7 @@ If an Application in `namespace-two` would set their `.spec.project` to `project

Also, the Argo CD API will enforce these constraints, regardless of the Argo CD RBAC permissions.

The `.spec.sourceNamespaces` field of the `AppProject` is a list that can contain an arbitrary amount of namespaces, each entry supports:

- shell-style wildcard, so that you can allow namespaces with patterns like ```team-one-*```
- regex, requires wrapping the string in ```/```, example to allow all namespaces except a particular one: ```/^((?!not-allowed).)*$/```.
The `.spec.sourceNamespaces` field of the `AppProject` is a list that can contain an arbitrary amount of namespaces, and each entry supports shell-style wildcard, so that you can allow namespaces with patterns like `team-one-*`.

!!! warning
Do not add user controlled namespaces in the `.spec.sourceNamespaces` field of any privileged AppProject like the `default` project. Always make sure that the AppProject follows the principle of granting least required privileges. Never grant access to the `argocd` namespace within the AppProject.
Expand Down
4 changes: 2 additions & 2 deletions notification_controller/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func NewController(

// Check if app is not in the namespace where the controller is in, and also app is not in one of the applicationNamespaces
func checkAppNotInAdditionalNamespaces(app *unstructured.Unstructured, namespace string, applicationNamespaces []string) bool {
return namespace != app.GetNamespace() && !glob.MatchStringInList(applicationNamespaces, app.GetNamespace(), false)
return namespace != app.GetNamespace() && !glob.MatchStringInList(applicationNamespaces, app.GetNamespace(), "glob")
}

func (c *notificationController) alterDestinations(obj v1.Object, destinations services.Destinations, cfg api.Config) services.Destinations {
Expand Down Expand Up @@ -151,7 +151,7 @@ func newInformer(resClient dynamic.ResourceInterface, controllerNamespace string
}
newItems := []unstructured.Unstructured{}
for _, res := range appList.Items {
if controllerNamespace == res.GetNamespace() || glob.MatchStringInList(applicationNamespaces, res.GetNamespace(), false) {
if controllerNamespace == res.GetNamespace() || glob.MatchStringInList(applicationNamespaces, res.GetNamespace(), "glob") {
newItems = append(newItems, res)
}
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/application/v1alpha1/app_project_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -562,5 +562,5 @@ func (p AppProject) IsAppNamespacePermitted(app *Application, controllerNs strin
return true
}

return glob.MatchStringInList(p.Spec.SourceNamespaces, app.Namespace, false)
return glob.MatchStringInList(p.Spec.SourceNamespaces, app.Namespace, "glob")
}
4 changes: 2 additions & 2 deletions util/argo/argo.go
Original file line number Diff line number Diff line change
Expand Up @@ -1131,7 +1131,7 @@ func GetAppEventLabels(app *argoappv1.Application, projLister applicationsv1.App
// Filter out event labels to include
inKeys := settingsManager.GetIncludeEventLabelKeys()
for k, v := range labels {
found := glob.MatchStringInList(inKeys, k, false)
found := glob.MatchStringInList(inKeys, k, "glob")
if found {
eventLabels[k] = v
}
Expand All @@ -1140,7 +1140,7 @@ func GetAppEventLabels(app *argoappv1.Application, projLister applicationsv1.App
// Remove excluded event labels
exKeys := settingsManager.GetExcludeEventLabelKeys()
for k := range eventLabels {
found := glob.MatchStringInList(exKeys, k, false)
found := glob.MatchStringInList(exKeys, k, "glob")
if found {
delete(eventLabels, k)
}
Expand Down
32 changes: 17 additions & 15 deletions util/glob/glob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,28 @@ func Test_Match(t *testing.T) {

func Test_MatchList(t *testing.T) {
tests := []struct {
name string
input string
list []string
exact bool
result bool
name string
input string
list []string
patternMatch string
result bool
}{
{"Exact name in list", "test", []string{"test"}, true, true},
{"Exact name not in list", "test", []string{"other"}, true, false},
{"Exact name not in list, multiple elements", "test", []string{"some", "other"}, true, false},
{"Exact name not in list, list empty", "test", []string{}, true, false},
{"Exact name not in list, empty element", "test", []string{""}, true, false},
{"Glob name in list, but exact wanted", "test", []string{"*"}, true, false},
{"Glob name in list with simple wildcard", "test", []string{"*"}, false, true},
{"Glob name in list without wildcard", "test", []string{"test"}, false, true},
{"Glob name in list, multiple elements", "test", []string{"other*", "te*"}, false, true},
{"Exact name in list", "test", []string{"test"}, "exact", true},
{"Exact name not in list", "test", []string{"other"}, "exact", false},
{"Exact name not in list, multiple elements", "test", []string{"some", "other"}, "exact", false},
{"Exact name not in list, list empty", "test", []string{}, "exact", false},
{"Exact name not in list, empty element", "test", []string{""}, "exact", false},
{"Glob name in list, but exact wanted", "test", []string{"*"}, "exact", false},
{"Glob name in list with simple wildcard", "test", []string{"*"}, "glob", true},
{"Glob name in list without wildcard", "test", []string{"test"}, "glob", true},
{"Glob name in list, multiple elements", "test", []string{"other*", "te*"}, "glob", true},
{"match everything but specified word: fail", "disallowed", []string{"/^((?!disallowed).)*$/"}, "regexp", false},
{"match everything but specified word: pass", "allowed", []string{"/^((?!disallowed).)*$/"}, "regexp", true},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
res := MatchStringInList(tt.list, tt.input, tt.exact)
res := MatchStringInList(tt.list, tt.input, tt.patternMatch)
assert.Equal(t, tt.result, res)
})
}
Expand Down
17 changes: 10 additions & 7 deletions util/glob/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,18 @@ import (
)

// MatchStringInList will return true if item is contained in list. If
// exactMatch is set to false, list may contain globs to be matched.
func MatchStringInList(list []string, item string, exactMatch bool) bool {
// patternMatch; can be set to exact, glob, regexp.
// If patternMatch; is set to exact, the item must be an exact match.
// If patternMatch; is set to glob, the item must match a glob pattern.
// If patternMatch; is set to regexp, the item must match a regular expression or glob.
func MatchStringInList(list []string, item string, patternMatch string) bool {
for _, ll := range list {
// If string is wrapped in "/", assume it is a regular expression.
if !exactMatch && strings.HasPrefix(ll, "/") && strings.HasSuffix(ll, "/") {
if regex.Match(ll[1:len(ll)-1], item) {
return true
}
} else if item == ll || (!exactMatch && Match(ll, item)) {
if patternMatch == "regexp" && strings.HasPrefix(ll, "/") && strings.HasSuffix(ll, "/") && regex.Match(ll[1:len(ll)-1], item) {
return true
} else if (patternMatch == "regexp" || patternMatch == "glob") && Match(ll, item) {
return true
} else if patternMatch == "exact" && item == ll {
return true
}
}
Expand Down
2 changes: 1 addition & 1 deletion util/security/application_namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
)

func IsNamespaceEnabled(namespace string, serverNamespace string, enabledNamespaces []string) bool {
return namespace == serverNamespace || glob.MatchStringInList(enabledNamespaces, namespace, false)
return namespace == serverNamespace || glob.MatchStringInList(enabledNamespaces, namespace, "regexp")
}

func NamespaceNotPermittedError(namespace string) error {
Expand Down
2 changes: 1 addition & 1 deletion util/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func (a *ArgoCDWebhookHandler) HandleEvent(payload interface{}) {
// nor in the list of enabled namespaces.
var filteredApps []v1alpha1.Application
for _, app := range apps.Items {
if app.Namespace == a.ns || glob.MatchStringInList(a.appNs, app.Namespace, false) {
if app.Namespace == a.ns || glob.MatchStringInList(a.appNs, app.Namespace, "glob") {
filteredApps = append(filteredApps, app)
}
}
Expand Down

0 comments on commit 0fc2753

Please sign in to comment.