Skip to content

Commit 6f11cbb

Browse files
AlexTugarevroboquat
authored andcommitted
[server][github] fix selection of user for prebuilds
1 parent 07e013e commit 6f11cbb

File tree

1 file changed

+53
-30
lines changed

1 file changed

+53
-30
lines changed

components/server/ee/src/prebuilds/github-app.ts

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -166,14 +166,16 @@ export class GithubApp {
166166
try {
167167
const installationId = ctx.payload.installation?.id;
168168
const cloneURL = ctx.payload.repository.clone_url;
169-
const owner = installationId && (await this.findProjectOwner(cloneURL) || (await this.findInstallationOwner(installationId)));
170-
if (!owner) {
171-
log.info(`Did not find user for installation. Probably an incomplete app installation.`, { repo: ctx.payload.repository, installationId });
169+
const installationOwner = installationId ? await this.findInstallationOwner(installationId) : undefined;
170+
const project = await this.projectDB.findProjectByCloneUrl(cloneURL);
171+
const user = await this.selectUserForPrebuild(installationOwner, project);
172+
if (!user) {
173+
log.info(`Did not find user for installation. Probably an incomplete app installation.`, { repo: ctx.payload.repository, installationId, project });
172174
return;
173175
}
174-
const logCtx: LogContext = { userId: owner.user.id };
176+
const logCtx: LogContext = { userId: user.id };
175177

176-
if (!!owner.user.blocked) {
178+
if (!!user.blocked) {
177179
log.info(logCtx, `Blocked user tried to start prebuild`, { repo: ctx.payload.repository });
178180
return;
179181
}
@@ -190,15 +192,15 @@ export class GithubApp {
190192
const contextURL = `${repo.html_url}/tree/${branch}`;
191193
span.setTag('contextURL', contextURL);
192194

193-
let config = await this.prebuildManager.fetchConfig({ span }, owner.user, contextURL);
195+
let config = await this.prebuildManager.fetchConfig({ span }, user, contextURL);
194196
const runPrebuild = this.appRules.shouldRunPrebuild(config, branch == repo.default_branch, false, false);
195197
if (!runPrebuild) {
196198
const reason = `Not running prebuild, the user did not enable it for this context`;
197199
log.debug(logCtx, reason, { contextURL });
198200
span.log({ "not-running": reason, "config": config });
199201
return;
200202
}
201-
const { user, project } = owner;
203+
202204
this.prebuildManager.startPrebuild({ span }, { user, contextURL, cloneURL: repo.clone_url, commit: pl.after, branch, project})
203205
.catch(err => log.error(logCtx, "Error while starting prebuild", err, { contextURL }));
204206
} catch (e) {
@@ -225,17 +227,19 @@ export class GithubApp {
225227
try {
226228
const installationId = ctx.payload.installation?.id;
227229
const cloneURL = ctx.payload.repository.clone_url;
228-
const owner = installationId && (await this.findProjectOwner(cloneURL) || (await this.findInstallationOwner(installationId)));
229-
if (!owner) {
230-
log.info("Did not find user for installation. Probably an incomplete app installation.", { repo: ctx.payload.repository, installationId });
230+
const installationOwner = installationId ? await this.findInstallationOwner(installationId) : undefined;
231+
const project = await this.projectDB.findProjectByCloneUrl(cloneURL);
232+
const user = await this.selectUserForPrebuild(installationOwner, project);
233+
if (!user) {
234+
log.info("Did not find user for installation. Probably an incomplete app installation.", { repo: ctx.payload.repository, installationId, project });
231235
return;
232236
}
233237

234238
const pr = ctx.payload.pull_request;
235239
const contextURL = pr.html_url;
236-
const config = await this.prebuildManager.fetchConfig({ span }, owner.user, contextURL);
240+
const config = await this.prebuildManager.fetchConfig({ span }, user, contextURL);
237241

238-
const prebuildStartPromise = this.onPrStartPrebuild({ span }, config, owner, ctx);
242+
const prebuildStartPromise = this.onPrStartPrebuild({ span }, ctx, config, user, project);
239243
this.onPrAddCheck({ span }, config, ctx, prebuildStartPromise).catch(() => {/** ignore */});
240244
this.onPrAddBadge(config, ctx);
241245
this.onPrAddComment(config, ctx).catch(() => {/** ignore */});
@@ -282,8 +286,7 @@ export class GithubApp {
282286
}
283287
}
284288

285-
protected onPrStartPrebuild(tracecContext: TraceContext, config: WorkspaceConfig | undefined, owner: {user: User, project?: Project}, ctx: Context<'pull_request.opened' | 'pull_request.synchronize' | 'pull_request.reopened'>): Promise<StartPrebuildResult> | undefined {
286-
const { user, project } = owner;
289+
protected onPrStartPrebuild(tracecContext: TraceContext, ctx: Context<'pull_request.opened' | 'pull_request.synchronize' | 'pull_request.reopened'>, config: WorkspaceConfig | undefined, user: User, project?: Project): Promise<StartPrebuildResult> | undefined {
287290
const pr = ctx.payload.pull_request;
288291
const pr_head = pr.head;
289292
const contextURL = pr.html_url;
@@ -298,7 +301,7 @@ export class GithubApp {
298301
prebuildStartPromise.catch(err => log.error(err, "Error while starting prebuild", { contextURL }));
299302
return prebuildStartPromise;
300303
} else {
301-
log.debug({ userId: owner.user.id }, `Not running prebuild, the user did not enable it for this context`, { contextURL, owner });
304+
log.debug({ userId: user.id }, `Not running prebuild, the user did not enable it for this context`, { contextURL, user, project });
302305
return;
303306
}
304307
}
@@ -349,24 +352,44 @@ export class GithubApp {
349352
return this.config.hostUrl.with({ pathname: '/button/open-in-gitpod.svg' }).toString();
350353
}
351354

352-
protected async findProjectOwner(cloneURL: string): Promise<{user: User, project?: Project} | undefined> {
353-
// Project mode
354-
//
355-
const project = await this.projectDB.findProjectByCloneUrl(cloneURL);
356-
if (project) {
357-
const owner = !!project.userId
358-
? { userId: project.userId }
359-
: (await this.teamDB.findMembersByTeam(project.teamId || '')).filter(m => m.role === "owner")[0];
360-
if (owner) {
361-
const user = await this.userDB.findUserById(owner.userId);
362-
if (user) {
363-
return { user, project}
364-
}
355+
/**
356+
* Finds the relevant user account to create a prebuild with.
357+
*
358+
* First it tries to find the installer of the GitHub App installation
359+
* among the members of the project team. As a fallback, it tries so pick
360+
* any of the team members which also has a github.com connection.
361+
*
362+
* For projects under a personal account, it simply returns the installer.
363+
*
364+
* @param installationOwner given user account of the GitHub App installation
365+
* @param project the project associated with the `cloneURL`
366+
* @returns a promise that resolves to a `User` or undefined
367+
*/
368+
protected async selectUserForPrebuild(installationOwner?: User, project?: Project): Promise<User | undefined> {
369+
if (!project) {
370+
return installationOwner;
371+
}
372+
if (!project.teamId) {
373+
return installationOwner;
374+
}
375+
const teamMembers = await this.teamDB.findMembersByTeam(project.teamId);
376+
if (!!installationOwner && teamMembers.some(t => t.userId === installationOwner.id)) {
377+
return installationOwner;
378+
}
379+
for (const teamMember of teamMembers) {
380+
const user = await this.userDB.findUserById(teamMember.userId);
381+
if (user && user.identities.some(i => i.authProviderId === "Public-GitHub")) {
382+
return user;
365383
}
366384
}
367385
}
368386

369-
protected async findInstallationOwner(installationId: number): Promise<{user: User, project?: Project} | undefined> {
387+
/**
388+
*
389+
* @param installationId read from webhook event
390+
* @returns the user account of the GitHub App installation
391+
*/
392+
protected async findInstallationOwner(installationId: number): Promise<User | undefined> {
370393
// Legacy mode
371394
//
372395
const installation = await this.appInstallationDB.findInstallation("github", String(installationId));
@@ -380,7 +403,7 @@ export class GithubApp {
380403
return;
381404
}
382405

383-
return { user };
406+
return user;
384407
}
385408
}
386409

0 commit comments

Comments
 (0)