Skip to content

Commit d99c1af

Browse files
committed
fix webhook detection
1 parent 34dfbe2 commit d99c1af

File tree

7 files changed

+23
-63
lines changed

7 files changed

+23
-63
lines changed

components/server/src/api/configuration-service-api.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,10 +252,14 @@ export class ConfigurationServiceAPI implements ServiceImpl<typeof Configuration
252252
throw new ApplicationError(ErrorCodes.NOT_FOUND, "configuration not found");
253253
}
254254
const user = await this.userService.findUserById(ctxUserId(), ctxUserId());
255-
const event = await this.projectService.getRecentWebhookEvent({}, user, configuration, 7 * 24 * 60 * 60 * 1000);
255+
let event = await this.projectService.getRecentWebhookEvent({}, user, configuration, 7 * 24 * 60 * 60 * 1000);
256+
const isWebhookActive = event !== undefined;
257+
if (event?.id === "n/a") {
258+
event = undefined; // if we know webhooks are enabled but we never received an event,
259+
}
256260

257261
const resp = new GetConfigurationWebhookActivityStatusResponse({
258-
isWebhookActive: event !== undefined,
262+
isWebhookActive,
259263
latestWebhookEvent: {
260264
commit: event?.commit,
261265
creationTime: event?.creationTime ? Timestamp.fromDate(new Date(event.creationTime)) : undefined,

components/server/src/auth/host-context-provider-impl.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
1414
import { HostContainerMapping } from "./host-container-mapping";
1515
import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
1616
import { repeat } from "@gitpod/gitpod-protocol/lib/util/repeat";
17+
import { RepositoryService } from "../repohost/repo-service";
1718

1819
@injectable()
1920
export class HostContextProviderImpl implements HostContextProvider {
@@ -152,6 +153,7 @@ export class HostContextProviderImpl implements HostContextProvider {
152153
const container = parentContainer.createChild();
153154
container.bind(AuthProviderParams).toConstantValue(authProviderConfig);
154155
container.bind(HostContext).toSelf().inSingletonScope();
156+
container.bind(RepositoryService).toSelf().inSingletonScope();
155157

156158
const hostContainerMapping = parentContainer.get(HostContainerMapping);
157159
const containerModules = hostContainerMapping.get(authProviderConfig.type);

components/server/src/github/github-container-module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import { GithubRepositoryProvider } from "./github-repository-provider";
1616
import { GitHubTokenHelper } from "./github-token-helper";
1717
import { IGitTokenValidator } from "../workspace/git-token-validator";
1818
import { GitHubTokenValidator } from "./github-token-validator";
19+
import { RepositoryService } from "../repohost/repo-service";
20+
import { GitHubService } from "../prebuilds/github-service";
1921

2022
export const githubContainerModule = new ContainerModule((bind, _unbind, _isBound, rebind) => {
2123
bind(RepositoryHost).toSelf().inSingletonScope();
@@ -32,4 +34,5 @@ export const githubContainerModule = new ContainerModule((bind, _unbind, _isBoun
3234
bind(GitHubTokenHelper).toSelf().inSingletonScope();
3335
bind(GitHubTokenValidator).toSelf().inSingletonScope();
3436
bind(IGitTokenValidator).toService(GitHubTokenValidator);
37+
rebind(RepositoryService).to(GitHubService).inSingletonScope();
3538
});

components/server/src/prebuilds/github-service.ts

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -11,73 +11,20 @@ import { GitHubEnterpriseApp } from "./github-enterprise-app";
1111
import { GithubContextParser } from "../github/github-context-parser";
1212
import { User } from "@gitpod/gitpod-protocol";
1313
import { Config } from "../config";
14-
import { TokenService } from "../user/token-service";
1514
import { RepoURL } from "../repohost";
16-
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
1715
import { UnauthorizedError } from "../errors";
18-
import { containsScopes } from "./token-scopes-inclusion";
1916
import { GitHubOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers";
2017

2118
@injectable()
2219
export class GitHubService extends RepositoryService {
23-
static PREBUILD_TOKEN_SCOPE = "prebuilds";
24-
2520
constructor(
2621
@inject(GitHubRestApi) protected readonly githubApi: GitHubRestApi,
2722
@inject(Config) private readonly config: Config,
28-
@inject(TokenService) private readonly tokenService: TokenService,
2923
@inject(GithubContextParser) private readonly githubContextParser: GithubContextParser,
3024
) {
3125
super();
3226
}
3327

34-
async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
35-
const parsedRepoUrl = RepoURL.parseRepoUrl(cloneUrl);
36-
if (!parsedRepoUrl) {
37-
throw new ApplicationError(ErrorCodes.BAD_REQUEST, `Clone URL not parseable.`);
38-
}
39-
let tokenEntry;
40-
try {
41-
const { owner, repoName: repo } = await this.githubContextParser.parseURL(user, cloneUrl);
42-
const webhooks = (await this.githubApi.run(user, (gh) => gh.repos.listWebhooks({ owner, repo }))).data;
43-
for (const webhook of webhooks) {
44-
if (webhook.config.url === this.getHookUrl()) {
45-
await this.githubApi.run(user, (gh) =>
46-
gh.repos.deleteWebhook({ owner, repo, hook_id: webhook.id }),
47-
);
48-
}
49-
}
50-
tokenEntry = await this.tokenService.createGitpodToken(user, GitHubService.PREBUILD_TOKEN_SCOPE, cloneUrl);
51-
const config = {
52-
url: this.getHookUrl(),
53-
content_type: "json",
54-
secret: user.id + "|" + tokenEntry.token.value,
55-
};
56-
await this.githubApi.run(user, (gh) => gh.repos.createWebhook({ owner, repo, config }));
57-
} catch (error) {
58-
// Hint: here we catch all GH API errors to forward them as Unauthorized to FE,
59-
// eventually that should be done depending on the error code.
60-
// Also, if user is not connected at all, then the GH API wrapper is throwing
61-
// the same error type, but with `providerIsConnected: false`.
62-
63-
if (GitHubApiError.is(error)) {
64-
// TODO check for `error.code`
65-
throw UnauthorizedError.create({
66-
host: parsedRepoUrl.host,
67-
providerType: "GitHub",
68-
repoName: parsedRepoUrl.repo,
69-
requiredScopes: GitHubOAuthScopes.Requirements.DEFAULT,
70-
providerIsConnected: true,
71-
isMissingScopes: containsScopes(
72-
tokenEntry?.token.scopes,
73-
GitHubOAuthScopes.Requirements.PRIVATE_REPO,
74-
),
75-
});
76-
}
77-
throw error;
78-
}
79-
}
80-
8128
async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise<boolean> {
8229
try {
8330
const { owner, repoName: repo } = await this.githubContextParser.parseURL(user, cloneUrl);

components/server/src/projects/projects-service.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -556,10 +556,6 @@ export class ProjectsService {
556556
const context = (await this.contextParser.handle(ctx, user, project.cloneUrl)) as CommitContext;
557557

558558
const events = await this.webhookEventDb.findByCloneUrl(project.cloneUrl, 50);
559-
if (events.length === 0) {
560-
return undefined;
561-
}
562-
563559
const hostContext = this.hostContextProvider.get(context.repository.host);
564560
const repoService = hostContext?.services?.repositoryService;
565561
if (!repoService) {
@@ -568,7 +564,16 @@ export class ProjectsService {
568564

569565
try {
570566
const webhookEnabled = await repoService.isGitpodWebhookEnabled(user, project.cloneUrl);
571-
return webhookEnabled ? events[0] : undefined; // todo(ft): figure out what to return if webhook is enabled but we have no events
567+
return webhookEnabled
568+
? events[0] ?? {
569+
commit: "n/a",
570+
creationTime: "",
571+
id: "initial_data",
572+
type: "initial_data",
573+
rawEvent: "{}",
574+
status: "processed",
575+
}
576+
: undefined;
572577
} catch (error) {
573578
if (!UnauthorizedError.is(error) && error.message !== "unsupported") {
574579
throw error;

components/server/src/repohost/repo-service.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ import { injectable } from "inversify";
99

1010
@injectable()
1111
export class RepositoryService {
12-
async installAutomatedPrebuilds(user: User, cloneUrl: string): Promise<void> {
13-
throw new Error("unsupported");
14-
}
1512
async isGitpodWebhookEnabled(user: User, cloneUrl: string): Promise<boolean> {
1613
throw new Error("unsupported");
1714
}

components/server/src/repohost/repository-host.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import { inject, injectable } from "inversify";
88

99
import { FileProvider } from "./file-provider";
1010
import { RepositoryProvider } from "./repository-provider";
11+
import { RepositoryService } from "./repo-service";
1112

1213
@injectable()
1314
export class RepositoryHost {
1415
@inject(FileProvider) fileProvider: FileProvider;
1516
@inject(RepositoryProvider) repositoryProvider: RepositoryProvider;
17+
@inject(RepositoryService) repositoryService: RepositoryService;
1618
}

0 commit comments

Comments
 (0)