Skip to content

Commit 20a5789

Browse files
committed
Scope oauth tokens by org, replace flat project list with org-keyed map
1 parent e97132e commit 20a5789

11 files changed

Lines changed: 203 additions & 208 deletions

File tree

apps/code/src/main/services/agent/service.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,14 @@ describe("AgentService", () => {
343343
it("recordActivity resets the timeout on subsequent calls", () => {
344344
injectSession(service, "run-1");
345345
service.recordActivity("run-1");
346-
const firstDeadline = getIdleTimeouts(service).get("run-1")?.deadline;
346+
const firstDeadline =
347+
getIdleTimeouts(service).get("run-1")?.deadline ?? 0;
347348

348349
vi.advanceTimersByTime(5 * 60 * 1000);
349350
service.recordActivity("run-1");
350351
const secondDeadline = getIdleTimeouts(service).get("run-1")?.deadline;
351352

352-
expect(secondDeadline).toBeGreaterThan(firstDeadline!);
353+
expect(secondDeadline).toBeGreaterThan(firstDeadline);
353354
});
354355

355356
it("kills idle session after timeout expires", () => {

apps/code/src/main/services/oauth/schemas.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ export const oAuthTokenResponse = z.object({
2424
token_type: z.string(),
2525
scope: z.string().optional().default(""),
2626
refresh_token: z.string(),
27-
scoped_teams: z.array(z.number()).optional(),
2827
scoped_organizations: z.array(z.string()).optional(),
2928
});
3029
export type OAuthTokenResponse = z.infer<typeof oAuthTokenResponse>;

apps/code/src/renderer/api/posthogClient.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ export class PostHogAPIClient {
132132
}
133133
}
134134

135-
setTeamId(teamId: number): void {
136-
this._teamId = teamId;
135+
setTeamId(teamId: number | null | undefined): void {
136+
this._teamId = teamId ?? null;
137137
}
138138

139139
private async getTeamId(): Promise<number> {
@@ -167,6 +167,32 @@ export class PostHogAPIClient {
167167
});
168168
}
169169

170+
async listOrgProjects(
171+
orgId: string,
172+
): Promise<{ id: number; name: string }[]> {
173+
const url = new URL(
174+
`${this.api.baseUrl}/api/organizations/${orgId}/projects/`,
175+
);
176+
const response = await this.api.fetcher.fetch({
177+
method: "get",
178+
url,
179+
path: `/api/organizations/${orgId}/projects/`,
180+
});
181+
182+
if (!response.ok) {
183+
throw new Error(
184+
`Failed to fetch projects for org ${orgId}: ${response.statusText}`,
185+
);
186+
}
187+
188+
const data = await response.json();
189+
const results = data.results ?? data ?? [];
190+
return results.map((p: { id: number; name?: string }) => ({
191+
id: p.id,
192+
name: p.name ?? `Project ${p.id}`,
193+
}));
194+
}
195+
170196
async getProject(projectId: number) {
171197
//@ts-expect-error this is not in the generated client
172198
const data = await this.api.get("/api/projects/{project_id}/", {

apps/code/src/renderer/features/auth/stores/authStore.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { beforeEach, describe, expect, it, vi } from "vitest";
22

33
const mockGetCurrentUser = vi.fn();
4+
const mockListOrgProjects = vi.fn();
45

56
const { getItem, setItem } = vi.hoisted(() => ({
67
getItem: vi.fn(),
@@ -69,6 +70,7 @@ vi.mock("@renderer/api/posthogClient", () => ({
6970
this: Record<string, unknown>,
7071
) {
7172
this.getCurrentUser = mockGetCurrentUser;
73+
this.listOrgProjects = mockListOrgProjects;
7274
this.setTeamId = vi.fn();
7375
}),
7476
}));
@@ -88,7 +90,6 @@ function makeStoredTokens(overrides: Record<string, unknown> = {}) {
8890
refreshToken: "test-refresh-token",
8991
expiresAt: Date.now() + 3600 * 1000,
9092
cloudRegion: "us" as const,
91-
scopedTeams: [1],
9293
scopeVersion: OAUTH_SCOPE_VERSION,
9394
...overrides,
9495
};
@@ -107,6 +108,7 @@ describe("authStore - scope version", () => {
107108
getItem.mockResolvedValue(null);
108109
setItem.mockResolvedValue(undefined);
109110
mockGetCurrentUser.mockResolvedValue(mockUser);
111+
mockListOrgProjects.mockResolvedValue([]);
110112

111113
useAuthStore.setState({
112114
oauthAccessToken: null,
@@ -118,8 +120,7 @@ describe("authStore - scope version", () => {
118120
isAuthenticated: false,
119121
client: null,
120122
projectId: null,
121-
availableProjectIds: [],
122-
availableOrgIds: [],
123+
orgProjectsMap: {},
123124
needsProjectSelection: false,
124125
needsScopeReauth: false,
125126
});
@@ -186,7 +187,6 @@ describe("authStore - scope version", () => {
186187
access_token: "new-access-token",
187188
refresh_token: "new-refresh-token",
188189
expires_in: 3600,
189-
scoped_teams: [1],
190190
scoped_organizations: ["org-1"],
191191
},
192192
});
@@ -215,7 +215,7 @@ describe("authStore - scope version", () => {
215215
access_token: "new-access-token",
216216
refresh_token: "new-refresh-token",
217217
expires_in: 3600,
218-
scoped_teams: [1],
218+
scoped_organizations: ["org-1"],
219219
},
220220
});
221221

@@ -242,7 +242,7 @@ describe("authStore - scope version", () => {
242242
access_token: "new-access-token",
243243
refresh_token: "new-refresh-token",
244244
expires_in: 3600,
245-
scoped_teams: [1],
245+
scoped_organizations: ["org-1"],
246246
},
247247
});
248248

0 commit comments

Comments
 (0)