Skip to content

Commit

Permalink
[server] Removes unused RepositoryService.canInstall (#19112)
Browse files Browse the repository at this point in the history
* [server] Remove obsolete branch from `createWorkspace`

We're no longer supporting `/prebuild` in context parser, thus this is obsolete.

* [server] remove unused `RepositoryService.canInstallAutomatedPrebuilds`
  • Loading branch information
AlexTugarev authored Nov 22, 2023
1 parent 9374be9 commit 0fba169
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 166 deletions.
32 changes: 0 additions & 32 deletions components/server/src/prebuilds/bitbucket-server-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,38 +89,6 @@ class TestBitbucketServerService {
};
}

@test async test_canInstallAutomatedPrebuilds_unauthorized() {
const result = await this.service.canInstallAutomatedPrebuilds(
this.user,
"https://bitbucket.gitpod-self-hosted.com/users/jldec/repos/test-repo",
);
expect(result).to.be.false;
}

@test async test_canInstallAutomatedPrebuilds_in_project_ok() {
const result = await this.service.canInstallAutomatedPrebuilds(
this.user,
"https://bitbucket.gitpod-self-hosted.com/projects/jldec/repos/jldec-repo-march-30",
);
expect(result).to.be.true;
}

@test async test_canInstallAutomatedPrebuilds_ok() {
const result = await this.service.canInstallAutomatedPrebuilds(
this.user,
"https://bitbucket.gitpod-self-hosted.com/projects/FOO/repos/repo123",
);
expect(result).to.be.true;
}

@test async test_canInstallAutomatedPrebuilds_users_project_ok() {
const result = await this.service.canInstallAutomatedPrebuilds(
this.user,
"https://bitbucket.gitpod-self-hosted.com/scm/~alextugarev/yolo.git",
);
expect(result).to.be.true;
}

@test async test_installAutomatedPrebuilds_ok() {
try {
await this.service.installAutomatedPrebuilds(
Expand Down
37 changes: 8 additions & 29 deletions components/server/src/prebuilds/bitbucket-server-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { RepositoryService } from "../repohost/repo-service";
import { ProviderRepository, User } from "@gitpod/gitpod-protocol";
import { inject, injectable } from "inversify";
import { BitbucketServerApi } from "../bitbucket-server/bitbucket-server-api";
import { AuthProviderParams } from "../auth/auth-provider";
import { BitbucketServerContextParser } from "../bitbucket-server/bitbucket-server-context-parser";
import { Config } from "../config";
import { TokenService } from "../user/token-service";
Expand All @@ -19,11 +18,14 @@ import { CancellationToken } from "vscode-jsonrpc";
export class BitbucketServerService extends RepositoryService {
static PREBUILD_TOKEN_SCOPE = "prebuilds";

@inject(BitbucketServerApi) protected api: BitbucketServerApi;
@inject(Config) protected readonly config: Config;
@inject(AuthProviderParams) protected authProviderConfig: AuthProviderParams;
@inject(TokenService) protected tokenService: TokenService;
@inject(BitbucketServerContextParser) protected contextParser: BitbucketServerContextParser;
constructor(
@inject(BitbucketServerApi) private readonly api: BitbucketServerApi,
@inject(Config) private readonly config: Config,
@inject(TokenService) private readonly tokenService: TokenService,
@inject(BitbucketServerContextParser) private readonly contextParser: BitbucketServerContextParser,
) {
super();
}

async getRepositoriesForAutomatedPrebuilds(
user: User,
Expand All @@ -44,29 +46,6 @@ export class BitbucketServerService extends RepositoryService {
});
}

async canInstallAutomatedPrebuilds(user: User, cloneUrl: string): Promise<boolean> {
const { host, repoKind, owner, repoName } = await this.contextParser.parseURL(user, cloneUrl);
if (host !== this.authProviderConfig.host) {
return false;
}

const identity = user.identities.find((i) => i.authProviderId === this.authProviderConfig.id);
if (!identity) {
console.error(`BBS: no identity found.`, { host: this.authProviderConfig.host, userId: user.id, cloneUrl });
return false;
}

try {
await this.api.getWebhooks(user, { repoKind, repositorySlug: repoName, owner });
// reading webhooks to check if admin scope is provided
} catch (error) {
console.log(`BBS: could not read webhooks.`, error, { error, cloneUrl });
return false;
}
// return true once it can get webhooks, fallback to let SCM itself to check permission
return true;
}

async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
const { owner, repoName, repoKind } = await this.contextParser.parseURL(user, cloneUrl);

Expand Down
26 changes: 7 additions & 19 deletions components/server/src/prebuilds/bitbucket-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { RepositoryService } from "../repohost/repo-service";
import { User } from "@gitpod/gitpod-protocol";
import { inject, injectable } from "inversify";
import { BitbucketApiFactory } from "../bitbucket/bitbucket-api-factory";
import { AuthProviderParams } from "../auth/auth-provider";
import { BitbucketApp } from "./bitbucket-app";
import { Config } from "../config";
import { TokenService } from "../user/token-service";
Expand All @@ -18,24 +17,13 @@ import { BitbucketContextParser } from "../bitbucket/bitbucket-context-parser";
export class BitbucketService extends RepositoryService {
static PREBUILD_TOKEN_SCOPE = "prebuilds";

@inject(BitbucketApiFactory) protected api: BitbucketApiFactory;
@inject(Config) protected readonly config: Config;
@inject(AuthProviderParams) protected authProviderConfig: AuthProviderParams;
@inject(TokenService) protected tokenService: TokenService;
@inject(BitbucketContextParser) protected bitbucketContextParser: BitbucketContextParser;

async canInstallAutomatedPrebuilds(user: User, cloneUrl: string): Promise<boolean> {
const { host, owner, repoName } = await this.bitbucketContextParser.parseURL(user, cloneUrl);
if (host !== this.authProviderConfig.host) {
return false;
}

// only admins may install webhooks on repositories
const api = await this.api.create(user);
const response = await api.user.listPermissionsForRepos({
q: `repository.full_name="${owner}/${repoName}"`,
});
return !!response.data?.values && response.data.values[0]?.permission === "admin";
constructor(
@inject(BitbucketApiFactory) private readonly api: BitbucketApiFactory,
@inject(Config) private readonly config: Config,
@inject(TokenService) private readonly tokenService: TokenService,
@inject(BitbucketContextParser) private readonly bitbucketContextParser: BitbucketContextParser,
) {
super();
}

async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
Expand Down
41 changes: 9 additions & 32 deletions components/server/src/prebuilds/github-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { RepositoryService } from "../repohost/repo-service";
import { inject, injectable } from "inversify";
import { GitHubGraphQlEndpoint, GitHubRestApi } from "../github/api";
import { GitHubEnterpriseApp } from "./github-enterprise-app";
import { AuthProviderParams } from "../auth/auth-provider";
import { GithubContextParser } from "../github/github-context-parser";
import { ProviderRepository, User } from "@gitpod/gitpod-protocol";
import { Config } from "../config";
Expand All @@ -18,12 +17,15 @@ import { TokenService } from "../user/token-service";
export class GitHubService extends RepositoryService {
static PREBUILD_TOKEN_SCOPE = "prebuilds";

@inject(GitHubGraphQlEndpoint) protected readonly githubQueryApi: GitHubGraphQlEndpoint;
@inject(GitHubRestApi) protected readonly githubApi: GitHubRestApi;
@inject(Config) protected readonly config: Config;
@inject(AuthProviderParams) protected authProviderConfig: AuthProviderParams;
@inject(TokenService) protected tokenService: TokenService;
@inject(GithubContextParser) protected githubContextParser: GithubContextParser;
constructor(
@inject(GitHubGraphQlEndpoint) protected readonly githubQueryApi: GitHubGraphQlEndpoint,
@inject(GitHubRestApi) protected readonly githubApi: GitHubRestApi,
@inject(Config) private readonly config: Config,
@inject(TokenService) private readonly tokenService: TokenService,
@inject(GithubContextParser) private readonly githubContextParser: GithubContextParser,
) {
super();
}

// TODO: consider refactoring this to either use GH Search API w/ typeahead search only OR
// return results in a stream, appending pages as being fetched (via callback below) OR
Expand Down Expand Up @@ -53,31 +55,6 @@ export class GitHubService extends RepositoryService {
return repositories;
}

async canInstallAutomatedPrebuilds(user: User, cloneUrl: string): Promise<boolean> {
const { host, owner, repoName: repo } = await this.githubContextParser.parseURL(user, cloneUrl);
if (host !== this.authProviderConfig.host) {
return false;
}
try {
// You need "ADMIN" permission on a repository to be able to install a webhook.
// Ref: https://docs.github.com/en/organizations/managing-access-to-your-organizations-repositories/repository-roles-for-an-organization#permissions-for-each-role
// Ref: https://docs.github.com/en/graphql/reference/enums#repositorypermission
const result: any = await this.githubQueryApi.runQuery(
user,
`
query {
repository(name: "${repo}", owner: "${owner}") {
viewerPermission
}
}
`,
);
return result.data.repository && result.data.repository.viewerPermission === "ADMIN";
} catch (err) {
return false;
}
}

async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
const { owner, repoName: repo } = await this.githubContextParser.parseURL(user, cloneUrl);
const webhooks = (await this.githubApi.run(user, (gh) => gh.repos.listWebhooks({ owner, repo }))).data;
Expand Down
29 changes: 8 additions & 21 deletions components/server/src/prebuilds/gitlab-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { RepositoryService } from "../repohost/repo-service";
import { User } from "@gitpod/gitpod-protocol";
import { inject, injectable } from "inversify";
import { GitLabApi, GitLab } from "../gitlab/api";
import { AuthProviderParams } from "../auth/auth-provider";
import { GitLabApp } from "./gitlab-app";
import { Config } from "../config";
import { TokenService } from "../user/token-service";
Expand All @@ -19,25 +18,13 @@ import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
export class GitlabService extends RepositoryService {
static PREBUILD_TOKEN_SCOPE = "prebuilds";

@inject(GitLabApi) protected api: GitLabApi;
@inject(Config) protected readonly config: Config;
@inject(AuthProviderParams) protected authProviderConfig: AuthProviderParams;
@inject(TokenService) protected tokenService: TokenService;
@inject(GitlabContextParser) protected gitlabContextParser: GitlabContextParser;

async canInstallAutomatedPrebuilds(user: User, cloneUrl: string): Promise<boolean> {
const { host, owner, repoName } = await this.gitlabContextParser.parseURL(user, cloneUrl);
if (host !== this.authProviderConfig.host) {
return false;
}
const api = await this.api.create(user);
const response = (await api.Projects.show(`${owner}/${repoName}`)) as unknown as GitLab.Project;
if (GitLab.ApiError.is(response)) {
throw response;
}
// one need to have at least the access level of a maintainer (40) in order to install webhooks on a project
// cf. https://docs.gitlab.com/ee/api/members.html#valid-access-levels
return GitLab.Permissions.hasMaintainerAccess(response);
constructor(
@inject(GitLabApi) protected api: GitLabApi,
@inject(Config) private readonly config: Config,
@inject(TokenService) private readonly tokenService: TokenService,
@inject(GitlabContextParser) private readonly gitlabContextParser: GitlabContextParser,
) {
super();
}

async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
Expand Down Expand Up @@ -69,7 +56,7 @@ export class GitlabService extends RepositoryService {
log.info("Installed Webhook for " + cloneUrl, { cloneUrl, userId: user.id });
}

protected getHookUrl() {
private getHookUrl() {
return this.config.hostUrl
.asPublicServices()
.with({
Expand Down
4 changes: 0 additions & 4 deletions components/server/src/repohost/repo-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ export class RepositoryService {
return [];
}

async canInstallAutomatedPrebuilds(user: User, cloneUrl: string): Promise<boolean> {
return false;
}

async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
throw new Error("unsupported");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,6 @@ const mockApplyingContainerModule = new ContainerModule((bind, unbound, isbound,
installAutomatedPrebuilds: async (user: any, cloneUrl: string) => {
webhooks.add(cloneUrl);
},
canInstallAutomatedPrebuilds: async () => {
throw "not expected to be called";
},
},
repositoryProvider: {
hasReadAccess: async (user: any, owner: string, repo: string) => {
Expand Down
26 changes: 0 additions & 26 deletions components/server/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
PrebuiltWorkspace,
PrebuiltWorkspaceContext,
SetWorkspaceTimeoutResult,
StartPrebuildContext,
StartWorkspaceResult,
Token,
User,
Expand Down Expand Up @@ -96,7 +95,6 @@ import { SupportedWorkspaceClass } from "@gitpod/gitpod-protocol/lib/workspace-c
import { WorkspaceManagerClientProvider } from "@gitpod/ws-manager/lib/client-provider";
import { StopWorkspacePolicy, TakeSnapshotRequest } from "@gitpod/ws-manager/lib/core_pb";
import { inject, injectable } from "inversify";
import { URL } from "url";
import { v4 as uuidv4, validate as uuidValidate } from "uuid";
import { Disposable, CancellationToken } from "vscode-jsonrpc";
import { IAnalyticsWriter } from "@gitpod/gitpod-protocol/lib/analytics";
Expand Down Expand Up @@ -1122,30 +1120,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
context = WithDefaultConfig.mark(context);
}

// if this is an explicit prebuild, check if the user wants to install an app.
if (
StartPrebuildContext.is(context) &&
CommitContext.is(context.actual) &&
context.actual.repository.cloneUrl
) {
const cloneUrl = context.actual.repository.cloneUrl;
const host = new URL(cloneUrl).hostname;
const hostContext = this.hostContextProvider.get(host);
const services = hostContext && hostContext.services;
if (!hostContext || !services) {
console.error("Unknown host: " + host);
} else {
// on purpose to not await on that installation process, because it‘s not required of workspace start
// See https://github.com/gitpod-io/gitpod/pull/6420#issuecomment-953499632 for more detail
(async () => {
if (await services.repositoryService.canInstallAutomatedPrebuilds(user, cloneUrl)) {
console.log("Installing automated prebuilds for " + cloneUrl);
await services.repositoryService.installAutomatedPrebuilds(user, cloneUrl);
}
})().catch((e) => console.error("Install automated prebuilds failed", e));
}
}

if (!options.ignoreRunningWorkspaceOnSameCommit && !context.forceCreateNewWorkspace) {
const runningForContext = await runningForContextPromise;
if (runningForContext.length > 0) {
Expand Down

0 comments on commit 0fba169

Please sign in to comment.