diff --git a/integration-test/branch-19/target/output.html b/integration-test/branch-19/target/output.html
index 27d28717..a15ccbb6 100644
--- a/integration-test/branch-19/target/output.html
+++ b/integration-test/branch-19/target/output.html
@@ -59,61 +59,13 @@
Argo CD Diff Preview
Summary:
-Modified (6):
-± app-b (+25)
+Modified (4):
± cluster-a-cluster-rbac (-25)
-± cluster-b-cluster-rbac (+12)
± kustomize-build-options (+2|-2)
± owner-a (-12)
± owner-b (+12)
-
-
-app-b (examples/resource-application-boundary/applicationset.yaml)
-
-
-
-
-
-
- +apiVersion: rbac.authorization.k8s.io/v1 |
- +kind: ClusterRole |
- +metadata: |
- + name: app-b-node-reader |
- +rules: |
- +- apiGroups: |
- + - "" |
- + resources: |
- + - nodes |
- + verbs: |
- + - get |
- + - list |
- + - watch |
-
-
-
-
-
-
-
- +apiVersion: rbac.authorization.k8s.io/v1 |
- +kind: ClusterRoleBinding |
- +metadata: |
- + name: app-b-node-reader |
- +roleRef: |
- + apiGroup: rbac.authorization.k8s.io |
- + kind: ClusterRole |
- + name: app-b-node-reader |
- +subjects: |
- +- apiGroup: rbac.authorization.k8s.io |
- + kind: Group |
- + name: app-b-readers |
-
-
-
-
-
cluster-a-cluster-rbac (examples/cluster-rbac-repro/deployment-config/applicationsets/cluster-rbac.yaml)
@@ -160,32 +112,6 @@
-
-
-cluster-b-cluster-rbac (examples/cluster-rbac-repro/deployment-config/applicationsets/cluster-rbac.yaml)
-
-
-
-
-
-
- +apiVersion: rbac.authorization.k8s.io/v1 |
- +kind: ClusterRoleBinding |
- +metadata: |
- + name: sympozium-agent-view |
- +roleRef: |
- + apiGroup: rbac.authorization.k8s.io |
- + kind: ClusterRole |
- + name: view |
- +subjects: |
- +- apiGroup: rbac.authorization.k8s.io |
- + kind: Group |
- + name: oidc:jwt:platform-cluster:system:serviceaccount:automation:automation-agent |
-
-
-
-
-
kustomize-build-options (examples/kustomize-build-options/application.yaml)
diff --git a/integration-test/branch-19/target/output.md b/integration-test/branch-19/target/output.md
index 31f6b74f..85481d0c 100644
--- a/integration-test/branch-19/target/output.md
+++ b/integration-test/branch-19/target/output.md
@@ -2,52 +2,13 @@
Summary:
```yaml
-Modified (6):
-± app-b (+25)
+Modified (4):
± cluster-a-cluster-rbac (-25)
-± cluster-b-cluster-rbac (+12)
± kustomize-build-options (+2|-2)
± owner-a (-12)
± owner-b (+12)
```
-
-app-b (examples/resource-application-boundary/applicationset.yaml)
-
-
-#### ClusterRole: app-b-node-reader
-```diff
-+apiVersion: rbac.authorization.k8s.io/v1
-+kind: ClusterRole
-+metadata:
-+ name: app-b-node-reader
-+rules:
-+- apiGroups:
-+ - ""
-+ resources:
-+ - nodes
-+ verbs:
-+ - get
-+ - list
-+ - watch
-```
-#### ClusterRoleBinding: app-b-node-reader
-```diff
-+apiVersion: rbac.authorization.k8s.io/v1
-+kind: ClusterRoleBinding
-+metadata:
-+ name: app-b-node-reader
-+roleRef:
-+ apiGroup: rbac.authorization.k8s.io
-+ kind: ClusterRole
-+ name: app-b-node-reader
-+subjects:
-+- apiGroup: rbac.authorization.k8s.io
-+ kind: Group
-+ name: app-b-readers
-```
-
-
cluster-a-cluster-rbac (examples/cluster-rbac-repro/deployment-config/applicationsets/cluster-rbac.yaml)
@@ -85,27 +46,6 @@ Modified (6):
```
-
-cluster-b-cluster-rbac (examples/cluster-rbac-repro/deployment-config/applicationsets/cluster-rbac.yaml)
-
-
-#### ClusterRoleBinding: sympozium-agent-view
-```diff
-+apiVersion: rbac.authorization.k8s.io/v1
-+kind: ClusterRoleBinding
-+metadata:
-+ name: sympozium-agent-view
-+roleRef:
-+ apiGroup: rbac.authorization.k8s.io
-+ kind: ClusterRole
-+ name: view
-+subjects:
-+- apiGroup: rbac.authorization.k8s.io
-+ kind: Group
-+ name: oidc:jwt:platform-cluster:system:serviceaccount:automation:automation-agent
-```
-
-
kustomize-build-options (examples/kustomize-build-options/application.yaml)
diff --git a/pkg/extract/extract.go b/pkg/extract/extract.go
index b9e82344..97343056 100644
--- a/pkg/extract/extract.go
+++ b/pkg/extract/extract.go
@@ -430,10 +430,6 @@ func normalizeNamespaces(
clusterScopedResources map[schema.GroupKind]bool,
appName string,
) ([]unstructured.Unstructured, error) {
- if destNamespace == "" {
- return manifests, nil
- }
-
// Convert to pointer slice for DeduplicateTargetObjects
ptrManifests := make([]*unstructured.Unstructured, len(manifests))
for i := range manifests {
diff --git a/pkg/extract/extract_test.go b/pkg/extract/extract_test.go
index a3e47129..f221ad68 100644
--- a/pkg/extract/extract_test.go
+++ b/pkg/extract/extract_test.go
@@ -215,6 +215,29 @@ func TestNormalizeNamespacesPreservesSameNamedUnknownResources(t *testing.T) {
assert.ElementsMatch(t, []string{"ns-a", "ns-b", "ns-c"}, actualNamespaces)
}
+func TestNormalizeNamespacesDeduplicatesClusterScopedResourcesWithoutDestinationNamespace(t *testing.T) {
+ first := unstructured.Unstructured{Object: map[string]any{
+ "apiVersion": "rbac.authorization.k8s.io/v1",
+ "kind": "ClusterRole",
+ "metadata": map[string]any{
+ "name": "node-reader",
+ },
+ "rules": []any{map[string]any{"verbs": []any{"get"}}},
+ }}
+ last := first.DeepCopy()
+ last.Object["rules"] = []any{map[string]any{"verbs": []any{"get", "list"}}}
+
+ result, err := normalizeNamespaces(
+ []unstructured.Unstructured{first, *last},
+ "",
+ map[schema.GroupKind]bool{{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}: true},
+ "test-app",
+ )
+ require.NoError(t, err)
+ require.Len(t, result, 1)
+ assert.Equal(t, last.Object, result[0].Object, "Argo CD deduplication should keep the last resource")
+}
+
func TestResourceInfoProviderDefaultsUnknownKindsToNamespaced(t *testing.T) {
provider := &resourceInfoProvider{clusterScopedByGk: map[schema.GroupKind]bool{
{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}: true,
diff --git a/pkg/reposerverextract/extract.go b/pkg/reposerverextract/extract.go
index db3f6ab2..569a7e29 100644
--- a/pkg/reposerverextract/extract.go
+++ b/pkg/reposerverextract/extract.go
@@ -1264,10 +1264,6 @@ func normalizeNamespaces(
clusterScopedResources map[schema.GroupKind]bool,
appName string,
) ([]unstructured.Unstructured, error) {
- if destNamespace == "" {
- return manifests, nil
- }
-
ptrManifests := make([]*unstructured.Unstructured, len(manifests))
for i := range manifests {
ptrManifests[i] = &manifests[i]
diff --git a/pkg/reposerverextract/extract_test.go b/pkg/reposerverextract/extract_test.go
index 366c056d..3e664750 100644
--- a/pkg/reposerverextract/extract_test.go
+++ b/pkg/reposerverextract/extract_test.go
@@ -35,6 +35,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/yaml"
)
@@ -80,6 +81,29 @@ func assertDefaultProjectFields(t *testing.T, req *repoapiclient.ManifestRequest
assert.Equal(t, []string{"*"}, req.ProjectSourceRepos, "source repos must be permissive so helm build errors are not masked as permission errors")
}
+func TestNormalizeNamespacesDeduplicatesClusterScopedResourcesWithoutDestinationNamespace(t *testing.T) {
+ first := unstructured.Unstructured{Object: map[string]any{
+ "apiVersion": "rbac.authorization.k8s.io/v1",
+ "kind": "ClusterRole",
+ "metadata": map[string]any{
+ "name": "node-reader",
+ },
+ "rules": []any{map[string]any{"verbs": []any{"get"}}},
+ }}
+ last := first.DeepCopy()
+ last.Object["rules"] = []any{map[string]any{"verbs": []any{"get", "list"}}}
+
+ result, err := normalizeNamespaces(
+ []unstructured.Unstructured{first, *last},
+ "",
+ map[schema.GroupKind]bool{{Group: "rbac.authorization.k8s.io", Kind: "ClusterRole"}: true},
+ "test-app",
+ )
+ require.NoError(t, err)
+ require.Len(t, result, 1)
+ assert.Equal(t, last.Object, result[0].Object, "Argo CD deduplication should keep the last resource")
+}
+
func testRepoSelector(t *testing.T, repo string) *repository.Selector {
t.Helper()
selector, err := repository.NewSelector(repo, "")