Skip to content

Commit d314838

Browse files
authored
fix: Set namespace for AppProjects and repositories (#571)
Signed-off-by: jannfis <jann@mistrust.net>
1 parent 33e7dff commit d314838

File tree

4 files changed

+417
-0
lines changed

4 files changed

+417
-0
lines changed

agent/inbound.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ func (a *Agent) processIncomingApplication(ev *event.Event) error {
105105
return err
106106
}
107107

108+
// Applications must exist in the same namespace as the agent
109+
incomingApp.SetNamespace(a.namespace)
110+
108111
var exists, sourceUIDMatch bool
109112

110113
if a.mode == types.AgentModeManaged {
@@ -196,6 +199,9 @@ func (a *Agent) processIncomingAppProject(ev *event.Event) error {
196199
return err
197200
}
198201

202+
// AppProjects must exist in the same namespace as the agent
203+
incomingAppProject.SetNamespace(a.namespace)
204+
199205
exists, sourceUIDMatch, err := a.projectManager.CompareSourceUID(a.context, incomingAppProject)
200206
if err != nil {
201207
return fmt.Errorf("failed to validate source UID of appProject: %w", err)
@@ -277,6 +283,9 @@ func (a *Agent) processIncomingRepository(ev *event.Event) error {
277283
return err
278284
}
279285

286+
// Repository secrets must exist in the same namespace as the agent
287+
incomingRepo.SetNamespace(a.namespace)
288+
280289
var exists, sourceUIDMatch bool
281290

282291
// Source UID annotation is not present for repos on the autonomous agent since it is the source of truth.
@@ -422,7 +431,9 @@ func (a *Agent) processIncomingResourceResyncEvent(ev *event.Event) error {
422431
// createApplication creates an Application upon an event in the agent's work
423432
// queue.
424433
func (a *Agent) createApplication(incoming *v1alpha1.Application) (*v1alpha1.Application, error) {
434+
// Applications must exist in the same namespace as the agent
425435
incoming.SetNamespace(a.namespace)
436+
426437
logCtx := log().WithFields(logrus.Fields{
427438
"method": "CreateApplication",
428439
"app": incoming.QualifiedName(),
@@ -472,7 +483,9 @@ func (a *Agent) createApplication(incoming *v1alpha1.Application) (*v1alpha1.App
472483
}
473484

474485
func (a *Agent) updateApplication(incoming *v1alpha1.Application) (*v1alpha1.Application, error) {
486+
// Applications must exist in the same namespace as the agent
475487
incoming.SetNamespace(a.namespace)
488+
476489
logCtx := log().WithFields(logrus.Fields{
477490
"method": "UpdateApplication",
478491
"app": incoming.QualifiedName(),
@@ -513,7 +526,9 @@ func (a *Agent) updateApplication(incoming *v1alpha1.Application) (*v1alpha1.App
513526
}
514527

515528
func (a *Agent) deleteApplication(app *v1alpha1.Application) error {
529+
// Applications must exist in the same namespace as the agent
516530
app.SetNamespace(a.namespace)
531+
517532
logCtx := log().WithFields(logrus.Fields{
518533
"method": "DeleteApplication",
519534
"app": app.QualifiedName(),
@@ -556,6 +571,9 @@ func (a *Agent) deleteApplication(app *v1alpha1.Application) error {
556571
// createAppProject creates an AppProject upon an event in the agent's work
557572
// queue.
558573
func (a *Agent) createAppProject(incoming *v1alpha1.AppProject) (*v1alpha1.AppProject, error) {
574+
// AppProjects must exist in the same namespace as the agent
575+
incoming.SetNamespace(a.namespace)
576+
559577
logCtx := log().WithFields(logrus.Fields{
560578
"method": "CreateAppProject",
561579
"appProject": incoming.Name,
@@ -591,6 +609,9 @@ func (a *Agent) createAppProject(incoming *v1alpha1.AppProject) (*v1alpha1.AppPr
591609
}
592610

593611
func (a *Agent) updateAppProject(incoming *v1alpha1.AppProject) (*v1alpha1.AppProject, error) {
612+
// AppProjects must exist in the same namespace as the agent
613+
incoming.SetNamespace(a.namespace)
614+
594615
logCtx := log().WithFields(logrus.Fields{
595616
"method": "UpdateAppProject",
596617
"appProject": incoming.Name,
@@ -617,6 +638,9 @@ func (a *Agent) updateAppProject(incoming *v1alpha1.AppProject) (*v1alpha1.AppPr
617638
}
618639

619640
func (a *Agent) deleteAppProject(project *v1alpha1.AppProject) error {
641+
// AppProjects must exist in the same namespace as the agent
642+
project.SetNamespace(a.namespace)
643+
620644
logCtx := log().WithFields(logrus.Fields{
621645
"method": "DeleteAppProject",
622646
"appProject": project.Name,
@@ -650,6 +674,9 @@ func (a *Agent) deleteAppProject(project *v1alpha1.AppProject) error {
650674

651675
// createRepository creates a Repository upon an event in the agent's work queue.
652676
func (a *Agent) createRepository(incoming *corev1.Secret) (*corev1.Secret, error) {
677+
// Repository secrets must exist in the same namespace as the agent
678+
incoming.SetNamespace(a.namespace)
679+
653680
logCtx := log().WithFields(logrus.Fields{
654681
"method": "CreateRepository",
655682
"repo": incoming.Name,
@@ -688,7 +715,9 @@ func (a *Agent) createRepository(incoming *corev1.Secret) (*corev1.Secret, error
688715
}
689716

690717
func (a *Agent) updateRepository(incoming *corev1.Secret) (*corev1.Secret, error) {
718+
// Repository secrets must exist in the same namespace as the agent
691719
incoming.SetNamespace(a.namespace)
720+
692721
logCtx := log().WithFields(logrus.Fields{
693722
"method": "UpdateRepository",
694723
"repo": incoming.Name,
@@ -713,7 +742,9 @@ func (a *Agent) updateRepository(incoming *corev1.Secret) (*corev1.Secret, error
713742
}
714743

715744
func (a *Agent) deleteRepository(repo *corev1.Secret) error {
745+
// Repository secrets must exist in the same namespace as the agent
716746
repo.SetNamespace(a.namespace)
747+
717748
logCtx := log().WithFields(logrus.Fields{
718749
"method": "DeleteRepository",
719750
"repo": repo.Name,

agent/inbound_test.go

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,185 @@ func Test_UpdateAppProject(t *testing.T) {
900900
require.Empty(t, napp.OwnerReferences, "OwnerReferences should not be applied on managed app project")
901901
})
902902

903+
// Namespace handling tests
904+
t.Run("CreateAppProject sets correct namespace", func(t *testing.T) {
905+
agentNamespace := "agent-namespace"
906+
a, _ := newAgent(t)
907+
a.namespace = agentNamespace
908+
a.mode = types.AgentModeManaged
909+
910+
be := backend_mocks.NewAppProject(t)
911+
var err error
912+
a.projectManager, err = appproject.NewAppProjectManager(be, agentNamespace, appproject.WithAllowUpsert(true))
913+
require.NoError(t, err)
914+
915+
project := &v1alpha1.AppProject{
916+
ObjectMeta: v1.ObjectMeta{
917+
Name: "test-project",
918+
Namespace: "wrong-namespace", // This should be overridden
919+
},
920+
Spec: v1alpha1.AppProjectSpec{
921+
SourceNamespaces: []string{"default"},
922+
},
923+
}
924+
925+
// Mock the backend Create method and capture the project passed to it
926+
var capturedProject *v1alpha1.AppProject
927+
createMock := be.On("Create", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
928+
capturedProject = args[1].(*v1alpha1.AppProject)
929+
}).Return(&v1alpha1.AppProject{}, nil)
930+
defer createMock.Unset()
931+
932+
_, err = a.createAppProject(project)
933+
require.NoError(t, err)
934+
935+
// Verify that the namespace was set correctly
936+
require.NotNil(t, capturedProject, "Project should have been passed to backend")
937+
assert.Equal(t, agentNamespace, capturedProject.Namespace, "Project namespace should be set to agent namespace")
938+
assert.Equal(t, "test-project", capturedProject.Name, "Project name should remain unchanged")
939+
})
940+
941+
t.Run("UpdateAppProject sets correct namespace", func(t *testing.T) {
942+
agentNamespace := "agent-namespace"
943+
a, _ := newAgent(t)
944+
a.namespace = agentNamespace
945+
a.mode = types.AgentModeManaged
946+
947+
be := backend_mocks.NewAppProject(t)
948+
var err error
949+
a.projectManager, err = appproject.NewAppProjectManager(be, agentNamespace,
950+
appproject.WithAllowUpsert(true),
951+
appproject.WithMode(manager.ManagerModeManaged),
952+
appproject.WithRole(manager.ManagerRoleAgent))
953+
require.NoError(t, err)
954+
955+
project := &v1alpha1.AppProject{
956+
ObjectMeta: v1.ObjectMeta{
957+
Name: "test-project",
958+
Namespace: "wrong-namespace", // This should be overridden
959+
ResourceVersion: "12345",
960+
},
961+
Spec: v1alpha1.AppProjectSpec{
962+
SourceNamespaces: []string{"default"},
963+
},
964+
}
965+
966+
// Set up project as managed
967+
a.projectManager.Manage(project.Name)
968+
defer a.projectManager.Unmanage(project.Name)
969+
970+
// Mock the backend methods
971+
getMock := be.On("Get", mock.Anything, mock.Anything, mock.Anything).Return(&v1alpha1.AppProject{}, nil)
972+
defer getMock.Unset()
973+
974+
supportsPatchMock := be.On("SupportsPatch").Return(true)
975+
defer supportsPatchMock.Unset()
976+
977+
// Capture the namespace passed to Patch method
978+
var capturedNamespace string
979+
patchMock := be.On("Patch", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
980+
capturedNamespace = args[2].(string)
981+
}).Return(&v1alpha1.AppProject{}, nil)
982+
defer patchMock.Unset()
983+
984+
_, err = a.updateAppProject(project)
985+
require.NoError(t, err)
986+
987+
// Verify that the namespace was set correctly in the patch call
988+
assert.Equal(t, agentNamespace, capturedNamespace, "Patch should use agent namespace")
989+
})
990+
991+
t.Run("DeleteAppProject sets correct namespace", func(t *testing.T) {
992+
agentNamespace := "agent-namespace"
993+
a, _ := newAgent(t)
994+
a.namespace = agentNamespace
995+
a.mode = types.AgentModeManaged
996+
997+
be := backend_mocks.NewAppProject(t)
998+
var err error
999+
a.projectManager, err = appproject.NewAppProjectManager(be, agentNamespace, appproject.WithAllowUpsert(true))
1000+
require.NoError(t, err)
1001+
1002+
project := &v1alpha1.AppProject{
1003+
ObjectMeta: v1.ObjectMeta{
1004+
Name: "test-project",
1005+
Namespace: "wrong-namespace", // This should be overridden
1006+
},
1007+
Spec: v1alpha1.AppProjectSpec{
1008+
SourceNamespaces: []string{"default"},
1009+
},
1010+
}
1011+
1012+
// Set up project as managed
1013+
a.projectManager.Manage(project.Name)
1014+
1015+
// Mock the backend Delete method and capture the namespace passed to it
1016+
var capturedNamespace string
1017+
deleteMock := be.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
1018+
capturedNamespace = args[2].(string)
1019+
}).Return(nil)
1020+
defer deleteMock.Unset()
1021+
1022+
err = a.deleteAppProject(project)
1023+
require.NoError(t, err)
1024+
1025+
// Verify that the namespace was set correctly
1026+
assert.Equal(t, agentNamespace, capturedNamespace, "Delete should use agent namespace")
1027+
})
1028+
1029+
t.Run("AppProject operations with custom agent namespace", func(t *testing.T) {
1030+
customAgentNamespace := "custom-agent-ns"
1031+
a, _ := newAgent(t)
1032+
a.namespace = customAgentNamespace
1033+
a.mode = types.AgentModeManaged
1034+
1035+
be := backend_mocks.NewAppProject(t)
1036+
var err error
1037+
a.projectManager, err = appproject.NewAppProjectManager(be, customAgentNamespace, appproject.WithAllowUpsert(true))
1038+
require.NoError(t, err)
1039+
1040+
project := &v1alpha1.AppProject{
1041+
ObjectMeta: v1.ObjectMeta{
1042+
Name: "test-project",
1043+
Namespace: "principal-namespace", // Different from agent
1044+
},
1045+
Spec: v1alpha1.AppProjectSpec{
1046+
SourceNamespaces: []string{"default"},
1047+
},
1048+
}
1049+
1050+
// Test Create
1051+
var capturedCreateProject *v1alpha1.AppProject
1052+
createMock := be.On("Create", mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
1053+
capturedCreateProject = args[1].(*v1alpha1.AppProject)
1054+
}).Return(&v1alpha1.AppProject{}, nil)
1055+
1056+
_, err = a.createAppProject(project)
1057+
require.NoError(t, err)
1058+
createMock.Unset()
1059+
1060+
// Verify that the namespace was overridden to agent namespace
1061+
require.NotNil(t, capturedCreateProject, "Project should have been passed to backend")
1062+
assert.Equal(t, customAgentNamespace, capturedCreateProject.Namespace, "Project namespace should be set to custom agent namespace")
1063+
assert.NotEqual(t, "principal-namespace", capturedCreateProject.Namespace, "Project namespace should not remain as principal namespace")
1064+
1065+
// Test Delete
1066+
a.projectManager.Manage(project.Name)
1067+
1068+
var capturedDeleteNamespace string
1069+
deleteMock := be.On("Delete", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Run(func(args mock.Arguments) {
1070+
capturedDeleteNamespace = args[2].(string)
1071+
}).Return(nil)
1072+
1073+
err = a.deleteAppProject(project)
1074+
require.NoError(t, err)
1075+
deleteMock.Unset()
1076+
1077+
// Verify that the namespace was overridden to agent namespace
1078+
assert.Equal(t, customAgentNamespace, capturedDeleteNamespace, "Delete should use custom agent namespace")
1079+
assert.NotEqual(t, "principal-namespace", capturedDeleteNamespace, "Delete should not use principal namespace")
1080+
})
1081+
9031082
}
9041083

9051084
func Test_ProcessIncomingRepositoryWithUIDMismatch(t *testing.T) {

principal/event.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ func (s *Server) processAppProjectEvent(ctx context.Context, agentName string, e
333333
// AppProject creation event will only be processed in autonomous mode
334334
case event.Create.String():
335335
if agentMode.IsAutonomous() {
336+
incoming.SetNamespace(s.namespace)
336337
_, err := s.projectManager.Create(ctx, incoming)
337338
if err != nil {
338339
return fmt.Errorf("could not create app-project %s: %w", incoming.Name, err)
@@ -348,6 +349,8 @@ func (s *Server) processAppProjectEvent(ctx context.Context, agentName string, e
348349
return event.NewEventNotAllowedErr("event type not allowed when mode is not autonomous")
349350
}
350351

352+
incoming.SetNamespace(s.namespace)
353+
351354
_, err := s.projectManager.UpdateAppProject(ctx, incoming)
352355
if err != nil {
353356
return fmt.Errorf("could not update app-project %s: %w", incoming.Name, err)
@@ -359,6 +362,8 @@ func (s *Server) processAppProjectEvent(ctx context.Context, agentName string, e
359362
return event.NewEventNotAllowedErr("event type not allowed when mode is not autonomous")
360363
}
361364

365+
incoming.SetNamespace(s.namespace)
366+
362367
deletionPropagation := backend.DeletePropagationForeground
363368
err := s.projectManager.Delete(ctx, incoming, &deletionPropagation)
364369
if err != nil {

0 commit comments

Comments
 (0)