8000 chore: handle deleted organizations in idp sync by Emyrk · Pull Request #17405 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

chore: handle deleted organizations in idp sync #17405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Apr 16, 2025
Merged
Prev Previous commit
Next Next commit
add test to go to zero orgs
  • Loading branch information
Emyrk committed Apr 15, 2025
commit 47e76f13f97a7eeba84a00f4690c000cb0033332
9 changes: 6 additions & 3 deletions coderd/database/dbmem/dbmem.go
Original file line number Diff line number Diff line change
Expand Up @@ -2357,10 +2357,13 @@ func (q *FakeQuerier) DeleteOrganizationMember(ctx context.Context, arg database
q.mutex.Lock()
defer q.mutex.Unlock()

deleted := slices.DeleteFunc(q.data.organizationMembers, func(member database.OrganizationMember) bool {
return member.OrganizationID == arg.OrganizationID && member.UserID == arg.UserID
deleted := false
q.data.organizationMembers = slices.DeleteFunc(q.data.organizationMembers, func(member database.OrganizationMember) bool {
match := member.OrganizationID == arg.OrganizationID && member.UserID == arg.UserID
deleted = deleted || match
return match
})
if len(deleted) == 0 {
if !deleted {
Comment on lines +2360 to +2366
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A dbmem bug I found

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh this is nasty, took me a minute to realize what the bug was. 💀

if you want, rather than track deleted yourself, you could do something like

	newMembers := slices.DeleteFunc(q.data.organizationMembers, func(member database.OrganizationMember) bool {
		return member.OrganizationID == arg.OrganizationID && member.UserID == arg.UserID
	})
	if len(newMembers) == len(q.data.organizationMembers) {
		return sql.ErrNoRows
	}
	q.data.organizationMembers = newMembers

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had thought about that as well. That felt a bit less direct and less intuitive to me though, so I went with the crude and simple lol

return sql.ErrNoRows
}

Expand Down
40 changes: 40 additions & 0 deletions coderd/idpsync/organizations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ func TestSyncOrganizations(t *testing.T) {
// This test creates some deleted organizations and checks the behavior is
// correct.
t.Run("SyncUserToDeletedOrg", func(t *testing.T) {
t.Parallel()

ctx := testutil.Context(t, testutil.WaitMedium)
db, _ := dbtestutil.NewDB(t)
user := dbgen.User(t, db, database.User{})
Expand Down Expand Up @@ -108,4 +110,42 @@ func TestSyncOrganizations(t *testing.T) {
})
require.ElementsMatch(t, []uuid.UUID{stays.Org.ID, joins.Org.ID}, inIDs)
})

t.Run("UserToZeroOrgs", func(t *testing.T) {
t.Parallel()

ctx := testutil.Context(t, testutil.WaitMedium)
db, _ := dbtestutil.NewDB(t)
user := dbgen.User(t, db, database.User{})

deletedLeaves := dbfake.Organization(t, db).Members(user).Deleted(true).Do()

// Now sync the user to the deleted organization
s := idpsync.NewAGPLSync(
slogtest.Make(t, &slogtest.Options{}),
runtimeconfig.NewManager(),
idpsync.DeploymentSyncSettings{
OrganizationField: "orgs",
OrganizationMapping: map[string][]uuid.UUID{
"leave": {deletedLeaves.Org.ID},
},
OrganizationAssignDefault: false,
},
)

err := s.SyncOrganizations(ctx, db, user, idpsync.OrganizationParams{
SyncEntitled: true,
MergedClaims: map[string]interface{}{
"orgs": []string{},
},
})
require.NoError(t, err)

orgs, err := db.GetOrganizationsByUserID(ctx, database.GetOrganizationsByUserIDParams{
UserID: user.ID,
Deleted: sql.NullBool{},
})
require.NoError(t, err)
require.Len(t, orgs, 0)
})
}
0