From d4a540b5a5314abc5e810bc3091ffdf1891d0949 Mon Sep 17 00:00:00 2001 From: aman Date: Mon, 3 Aug 2026 14:19:05 +0530 Subject: [PATCH] fix(resource): use resource title as audit record target name Audit records for resource creation stored the resource's unique name, which callers often set to an ID. Store the title instead and fall back to the name when the title is empty. Co-Authored-By: Claude Fable 5 --- core/resource/service.go | 6 ++++- core/resource/service_test.go | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/core/resource/service.go b/core/resource/service.go index 5a0be64976..6d78b7ec6e 100644 --- a/core/resource/service.go +++ b/core/resource/service.go @@ -152,6 +152,10 @@ func (s Service) Create(ctx context.Context, res Resource) (Resource, error) { } func (s Service) createAuditRecord(ctx context.Context, event pkgauditrecord.Event, res Resource, proj project.Project) { + targetName := res.Title + if targetName == "" { + targetName = res.Name + } if _, err := s.auditRecordRepository.Create(ctx, auditmodels.AuditRecord{ Event: event, Resource: auditmodels.Resource{ @@ -162,7 +166,7 @@ func (s Service) createAuditRecord(ctx context.Context, event pkgauditrecord.Eve Target: &auditmodels.Target{ ID: res.ID, Type: pkgauditrecord.EntityType(res.NamespaceID), - Name: res.Name, + Name: targetName, }, OrgID: proj.Organization.ID, OrgName: proj.Organization.Title, diff --git a/core/resource/service_test.go b/core/resource/service_test.go index 0ec4a3cc89..90a8606d9d 100644 --- a/core/resource/service_test.go +++ b/core/resource/service_test.go @@ -420,6 +420,56 @@ func TestCreate(t *testing.T) { assert.Equal(t, schema.UserPrincipal, got.PrincipalType) }) + t.Run("audit record target name uses title when set", func(t *testing.T) { + repo, relationSvc, _, projectSvc, _, _, auditRepo, _, svc := newTestService(t) + userID := uuid.New().String() + + projectSvc.EXPECT().Get(mock.Anything, testProject.ID).Return(testProject, nil) + + repo.EXPECT().Create(mock.Anything, mock.Anything).Return(resource.Resource{ + ID: uuid.New().String(), Name: "aoi-uuid-1", Title: "My AOI", NamespaceID: "resource/item", + ProjectID: testProject.ID, PrincipalID: userID, PrincipalType: schema.UserPrincipal, + }, nil) + + relationSvc.EXPECT().Delete(mock.Anything, mock.Anything).Return(nil) + relationSvc.EXPECT().Create(mock.Anything, mock.Anything).Return(relation.Relation{}, nil).Times(2) + + auditRepo.EXPECT().Create(mock.Anything, mock.MatchedBy(func(r auditmodels.AuditRecord) bool { + return r.Target != nil && r.Target.Name == "My AOI" + })).Return(auditmodels.AuditRecord{}, nil) + + _, err := svc.Create(ctx, resource.Resource{ + Name: "aoi-uuid-1", Title: "My AOI", NamespaceID: "resource/item", ProjectID: testProject.ID, + PrincipalID: userID, PrincipalType: schema.UserPrincipal, + }) + assert.NoError(t, err) + }) + + t.Run("audit record target name falls back to name when title empty", func(t *testing.T) { + repo, relationSvc, _, projectSvc, _, _, auditRepo, _, svc := newTestService(t) + userID := uuid.New().String() + + projectSvc.EXPECT().Get(mock.Anything, testProject.ID).Return(testProject, nil) + + repo.EXPECT().Create(mock.Anything, mock.Anything).Return(resource.Resource{ + ID: uuid.New().String(), Name: "res-slug", NamespaceID: "resource/item", + ProjectID: testProject.ID, PrincipalID: userID, PrincipalType: schema.UserPrincipal, + }, nil) + + relationSvc.EXPECT().Delete(mock.Anything, mock.Anything).Return(nil) + relationSvc.EXPECT().Create(mock.Anything, mock.Anything).Return(relation.Relation{}, nil).Times(2) + + auditRepo.EXPECT().Create(mock.Anything, mock.MatchedBy(func(r auditmodels.AuditRecord) bool { + return r.Target != nil && r.Target.Name == "res-slug" + })).Return(auditmodels.AuditRecord{}, nil) + + _, err := svc.Create(ctx, resource.Resource{ + Name: "res-slug", NamespaceID: "resource/item", ProjectID: testProject.ID, + PrincipalID: userID, PrincipalType: schema.UserPrincipal, + }) + assert.NoError(t, err) + }) + t.Run("explicit principal skips authn lookup", func(t *testing.T) { repo, relationSvc, _, projectSvc, _, _, auditRepo, _, svc := newTestService(t) userID := uuid.New().String()