fix: AppProject finalizer should consider apps in all allowed namespaces (#24347) (cherry-pick #26416 for 3.3) (#26480)

Signed-off-by: Dhruvang Makadia <dhruvang1@users.noreply.github.com>
Co-authored-by: Dhruvang Makadia <dhruvang1@users.noreply.github.com>
This commit is contained in:
argo-cd-cherry-pick-bot[bot]
2026-02-17 23:15:37 -10:00
committed by GitHub
parent 4b0a2c0ef2
commit e464f6ae43
2 changed files with 89 additions and 2 deletions

View File

@@ -1137,13 +1137,13 @@ func (ctrl *ApplicationController) processProjectQueueItem() (processNext bool)
}
func (ctrl *ApplicationController) finalizeProjectDeletion(proj *appv1.AppProject) error {
apps, err := ctrl.appLister.Applications(ctrl.namespace).List(labels.Everything())
apps, err := ctrl.appLister.List(labels.Everything())
if err != nil {
return fmt.Errorf("error listing applications: %w", err)
}
appsCount := 0
for i := range apps {
if apps[i].Spec.GetProject() == proj.Name {
if apps[i].Spec.GetProject() == proj.Name && ctrl.isAppNamespaceAllowed(apps[i]) && proj.IsAppNamespacePermitted(apps[i], ctrl.namespace) {
appsCount++
}
}

View File

@@ -2302,6 +2302,93 @@ func TestFinalizeProjectDeletion_DoesNotHaveApplications(t *testing.T) {
}, receivedPatch)
}
func TestFinalizeProjectDeletion_HasApplicationInOtherNamespace(t *testing.T) {
app := newFakeApp()
app.Namespace = "team-a"
proj := &v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace},
Spec: v1alpha1.AppProjectSpec{
SourceNamespaces: []string{"team-a"},
},
}
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
applicationNamespaces: []string{"team-a"},
}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
patched := false
fakeAppCs.PrependReactor("patch", "*", func(_ kubetesting.Action) (handled bool, ret runtime.Object, err error) {
patched = true
return true, &v1alpha1.AppProject{}, nil
})
err := ctrl.finalizeProjectDeletion(proj)
require.NoError(t, err)
assert.False(t, patched)
}
func TestFinalizeProjectDeletion_IgnoresAppsInUnmonitoredNamespace(t *testing.T) {
app := newFakeApp()
app.Namespace = "team-b"
proj := &v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace},
}
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
applicationNamespaces: []string{"team-a"},
}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
if patchAction, ok := action.(kubetesting.PatchAction); ok {
require.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
}
return true, &v1alpha1.AppProject{}, nil
})
err := ctrl.finalizeProjectDeletion(proj)
require.NoError(t, err)
assert.Equal(t, map[string]any{
"metadata": map[string]any{
"finalizers": nil,
},
}, receivedPatch)
}
func TestFinalizeProjectDeletion_IgnoresAppsNotPermittedByProject(t *testing.T) {
app := newFakeApp()
app.Namespace = "team-b"
proj := &v1alpha1.AppProject{
ObjectMeta: metav1.ObjectMeta{Name: "default", Namespace: test.FakeArgoCDNamespace},
Spec: v1alpha1.AppProjectSpec{
SourceNamespaces: []string{"team-a"},
},
}
ctrl := newFakeController(t.Context(), &fakeData{
apps: []runtime.Object{app, proj},
applicationNamespaces: []string{"team-a", "team-b"},
}, nil)
fakeAppCs := ctrl.applicationClientset.(*appclientset.Clientset)
receivedPatch := map[string]any{}
fakeAppCs.PrependReactor("patch", "*", func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) {
if patchAction, ok := action.(kubetesting.PatchAction); ok {
require.NoError(t, json.Unmarshal(patchAction.GetPatch(), &receivedPatch))
}
return true, &v1alpha1.AppProject{}, nil
})
err := ctrl.finalizeProjectDeletion(proj)
require.NoError(t, err)
assert.Equal(t, map[string]any{
"metadata": map[string]any{
"finalizers": nil,
},
}, receivedPatch)
}
func TestProcessRequestedAppOperation_FailedNoRetries(t *testing.T) {
app := newFakeApp()
app.Spec.Project = "default"