From 562239258a465a28b8b1d10fc1b6311df6cfc465 Mon Sep 17 00:00:00 2001 From: Dimitri Kennedy Date: Mon, 23 Mar 2026 14:50:51 -0400 Subject: [PATCH] fix(auth): restore team-scoped authorization --- .../auth-broker/src/modules/orgs/service.ts | 20 +++++++---------- .../tests/org-team-membership.test.ts | 22 ++++++------------- 2 files changed, 15 insertions(+), 27 deletions(-) diff --git a/services/auth-broker/src/modules/orgs/service.ts b/services/auth-broker/src/modules/orgs/service.ts index 88f4bd4f..ffc716f2 100644 --- a/services/auth-broker/src/modules/orgs/service.ts +++ b/services/auth-broker/src/modules/orgs/service.ts @@ -233,15 +233,6 @@ export class InMemoryOrgTeamsStore implements OrgTeamsStore { readonly orgKey: string | null; readonly actorUserId: string; }): MaybePromise { - const allowedOrgIds = new Set( - [...this.activeMemberships.values()] - .filter( - (membership) => - membership.scope === "organization" && - membership.userId === input.actorUserId - ) - .map((membership) => membership.organizationId) - ); const organization = input.orgKey ? this.findOrganization({ orgKey: input.orgKey }) : null; @@ -249,7 +240,12 @@ export class InMemoryOrgTeamsStore implements OrgTeamsStore { if (organization && team.organizationId !== organization.id) { return false; } - return allowedOrgIds.has(team.organizationId); + return [...this.activeMemberships.values()].some( + (membership) => + membership.scope === "team" && + membership.teamId === team.id && + membership.userId === input.actorUserId + ); }); } @@ -267,8 +263,8 @@ export class InMemoryOrgTeamsStore implements OrgTeamsStore { } const allowed = [...this.activeMemberships.values()].some( (membership) => - membership.scope === "organization" && - membership.organizationId === team.organizationId && + membership.scope === "team" && + membership.teamId === team.id && membership.userId === input.actorUserId ); return allowed ? team : null; diff --git a/services/auth-broker/tests/org-team-membership.test.ts b/services/auth-broker/tests/org-team-membership.test.ts index 96943972..49c34232 100644 --- a/services/auth-broker/tests/org-team-membership.test.ts +++ b/services/auth-broker/tests/org-team-membership.test.ts @@ -249,7 +249,7 @@ describe("org and team membership broker routes", () => { expect(listMembersResponse.status).toBe(404); }); - test("active org members can administer teams without direct team membership", async () => { + test("active org members cannot administer teams without direct team membership", async () => { const store = new InMemoryOrgTeamsStore(); const ownerApp = createAuthBrokerApp({ config: createTestConfig(), @@ -300,27 +300,27 @@ describe("org and team membership broker routes", () => { }) ); - const orgAdminApp = createAuthBrokerApp({ + const orgMemberApp = createAuthBrokerApp({ config: createTestConfig(), betterAuthRuntime: createBetterAuthRuntimeWithSession( createSession({ userId: "user-456", - email: "org-admin@example.com", + email: "org-member@example.com", }) ), orgTeamsStore: store, }); - const listTeamsResponse = await orgAdminApp.handle( + const listTeamsResponse = await orgMemberApp.handle( new Request("http://localhost/v1/auth/teams?org=hack") ); expect(listTeamsResponse.status).toBe(200); const listedTeams = (await listTeamsResponse.json()) as { readonly teams?: ReadonlyArray<{ readonly slug?: string }>; }; - expect(listedTeams.teams?.map((team) => team.slug)).toEqual(["cli"]); + expect(listedTeams.teams).toEqual([]); - const addTeamMemberResponse = await orgAdminApp.handle( + const addTeamMemberResponse = await orgMemberApp.handle( new Request("http://localhost/v1/auth/teams/cli/members/add", { method: "POST", headers: { "content-type": "application/json" }, @@ -330,15 +330,7 @@ describe("org and team membership broker routes", () => { }), }) ); - expect(addTeamMemberResponse.status).toBe(200); - const addedMembership = (await addTeamMemberResponse.json()) as { - readonly membership?: { - readonly scope?: string; - readonly state?: string; - }; - }; - expect(addedMembership.membership?.scope).toBe("team"); - expect(addedMembership.membership?.state).toBe("active"); + expect(addTeamMemberResponse.status).toBe(404); }); test("team membership changes require an active parent org membership", async () => {