Skip to content

Commit d38b01c

Browse files
authored
Clean up SCM connections of installation admin (#19601)
1 parent 949af13 commit d38b01c

File tree

4 files changed

+54
-1
lines changed

4 files changed

+54
-1
lines changed

components/server/src/auth/authenticator.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* See License.AGPL.txt in the project root for license information.
55
*/
66

7-
import { TeamDB } from "@gitpod/gitpod-db/lib";
7+
import { BUILTIN_INSTLLATION_ADMIN_USER_ID, TeamDB } from "@gitpod/gitpod-db/lib";
88
import { User } from "@gitpod/gitpod-protocol";
99
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
1010
import express from "express";
@@ -221,6 +221,13 @@ export class Authenticator {
221221
res.redirect(this.getSorryUrl(`Not authenticated. Please login.`));
222222
return;
223223
}
224+
if (user.id === BUILTIN_INSTLLATION_ADMIN_USER_ID) {
225+
log.info(`Authorization is not permitted for admin user.`);
226+
res.redirect(
227+
this.getSorryUrl(`Authorization is not permitted for admin user. Please login with a user account.`),
228+
);
229+
return;
230+
}
224231
const returnTo: string | undefined = req.query.returnTo?.toString();
225232
const host: string | undefined = req.query.host?.toString();
226233
const scopes: string = req.query.scopes?.toString() || "";

components/server/src/container-module.ts

+2
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ import { ScmService } from "./scm/scm-service";
132132
import { ContextService } from "./workspace/context-service";
133133
import { RateLimitter } from "./rate-limitter";
134134
import { AnalyticsController } from "./analytics-controller";
135+
import { InstallationAdminCleanup } from "./jobs/installation-admin-cleanup";
135136

136137
export const productionContainerModule = new ContainerModule(
137138
(bind, unbind, isBound, rebind, unbindAsync, onActivation, onDeactivation) => {
@@ -371,6 +372,7 @@ export const productionContainerModule = new ContainerModule(
371372
bind(SnapshotsJob).toSelf().inSingletonScope();
372373
bind(JobRunner).toSelf().inSingletonScope();
373374
bind(RelationshipUpdateJob).toSelf().inSingletonScope();
375+
bind(InstallationAdminCleanup).toSelf().inSingletonScope();
374376

375377
// Redis
376378
bind(Redis).toDynamicValue((ctx) => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* Copyright (c) 2024 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License.AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { BUILTIN_INSTLLATION_ADMIN_USER_ID, UserDB } from "@gitpod/gitpod-db/lib";
8+
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
9+
import { inject, injectable } from "inversify";
10+
import { Job } from "./runner";
11+
12+
@injectable()
13+
export class InstallationAdminCleanup implements Job {
14+
@inject(UserDB) protected readonly userDb: UserDB;
15+
16+
public name = "installation-admin-cleanup";
17+
public frequencyMs = 5 * 60 * 1000; // every 5 minutes
18+
19+
public async run(): Promise<void> {
20+
try {
21+
const installationAdmin = await this.userDb.findUserById(BUILTIN_INSTLLATION_ADMIN_USER_ID);
22+
if (!installationAdmin) {
23+
return;
24+
}
25+
26+
let cleanupRequired = false;
27+
for (const identity of installationAdmin.identities) {
28+
cleanupRequired = true;
29+
identity.deleted = true;
30+
await this.userDb.deleteTokens(identity);
31+
}
32+
if (cleanupRequired) {
33+
await this.userDb.storeUser(installationAdmin);
34+
log.info("Cleaned up SCM connections of installation admin.");
35+
}
36+
} catch (err) {
37+
log.error("Failed to clean up SCM connections of installation admin.", err);
38+
throw err;
39+
}
40+
}
41+
}

components/server/src/jobs/runner.ts

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { RelationshipUpdateJob } from "../authorization/relationship-updater-job
2020
import { WorkspaceStartController } from "../workspace/workspace-start-controller";
2121
import { runWithRequestContext } from "../util/request-context";
2222
import { SYSTEM_USER } from "../authorization/authorizer";
23+
import { InstallationAdminCleanup } from "./installation-admin-cleanup";
2324

2425
export const Job = Symbol("Job");
2526

@@ -42,6 +43,7 @@ export class JobRunner {
4243
@inject(SnapshotsJob) private readonly snapshotsJob: SnapshotsJob,
4344
@inject(RelationshipUpdateJob) private readonly relationshipUpdateJob: RelationshipUpdateJob,
4445
@inject(WorkspaceStartController) private readonly workspaceStartController: WorkspaceStartController,
46+
@inject(InstallationAdminCleanup) private readonly installationAdminCleanup: InstallationAdminCleanup,
4547
) {}
4648

4749
public start(): DisposableCollection {
@@ -56,6 +58,7 @@ export class JobRunner {
5658
this.snapshotsJob,
5759
this.relationshipUpdateJob,
5860
this.workspaceStartController,
61+
this.installationAdminCleanup,
5962
];
6063

6164
for (const job of jobs) {

0 commit comments

Comments
 (0)