Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 58 additions & 53 deletions components/dashboard/src/user-settings/Integrations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
* See License.AGPL.txt in the project root for license information.
*/

import { getScopesForAuthProviderType } from "@gitpod/public-api-common/lib/auth-providers";
import { getRequiredScopes, getScopesForAuthProviderType } from "@gitpod/public-api-common/lib/auth-providers";
import { SelectAccountPayload } from "@gitpod/gitpod-protocol/lib/auth";
import { useQuery } from "@tanstack/react-query";
import React, { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import Alert from "../components/Alert";
import { CheckboxInputField, CheckboxListField } from "../components/forms/CheckboxInputField";
import ConfirmationModal from "../components/ConfirmationModal";
Expand Down Expand Up @@ -54,6 +54,46 @@ export default function Integrations() {
);
}

const getDescriptionForScope = (scope: string) => {
switch (scope) {
// GitHub
case "user:email":
return "Read-only access to your email addresses";
case "read:user":
return "Read-only access to your profile information";
case "public_repo":
return "Write access to code in public repositories and organizations";
case "repo":
return "Read/write access to code in private repositories and organizations";
case "read:org":
return "Read-only access to organizations (used to suggest organizations when forking a repository)";
case "workflow":
return "Allow updating GitHub Actions workflow files";
// GitLab
case "read_user":
return "Read-only access to your email addresses";
case "api":
return "Allow making API calls (used to set up a webhook when enabling prebuilds for a repository)";
case "read_repository":
return "Read/write access to your repositories";
// Bitbucket
case "account":
return "Read-only access to your account information";
case "repository":
return "Read-only access to your repositories (note: Bitbucket doesn't support revoking scopes)";
case "repository:write":
return "Read/write access to your repositories (note: Bitbucket doesn't support revoking scopes)";
case "pullrequest":
return "Read access to pull requests and ability to collaborate via comments, tasks, and approvals (note: Bitbucket doesn't support revoking scopes)";
case "pullrequest:write":
return "Allow creating, merging and declining pull requests (note: Bitbucket doesn't support revoking scopes)";
case "webhook":
return "Allow installing webhooks (used when enabling prebuilds for a repository, note: Bitbucket doesn't support revoking scopes)";
default:
return "";
}
};

function GitProviders() {
const { user, setUser } = useContext(UserContext);

Expand Down Expand Up @@ -250,45 +290,6 @@ function GitProviders() {
setEditModal({ ...editModal, nextScopes });
};

const getDescriptionForScope = (scope: string) => {
switch (scope) {
case "user:email":
return "Read-only access to your email addresses";
case "read:user":
return "Read-only access to your profile information";
case "public_repo":
return "Write access to code in public repositories and organizations";
case "repo":
return "Read/write access to code in private repositories and organizations";
case "read:org":
return "Read-only access to organizations (used to suggest organizations when forking a repository)";
case "workflow":
return "Allow updating GitHub Actions workflow files";
// GitLab
case "read_user":
return "Read-only access to your email addresses";
case "api":
return "Allow making API calls (used to set up a webhook when enabling prebuilds for a repository)";
case "read_repository":
return "Read/write access to your repositories";
// Bitbucket
case "account":
return "Read-only access to your account information";
case "repository":
return "Read-only access to your repositories (note: Bitbucket doesn't support revoking scopes)";
case "repository:write":
return "Read/write access to your repositories (note: Bitbucket doesn't support revoking scopes)";
case "pullrequest":
return "Read access to pull requests and ability to collaborate via comments, tasks, and approvals (note: Bitbucket doesn't support revoking scopes)";
case "pullrequest:write":
return "Allow creating, merging and declining pull requests (note: Bitbucket doesn't support revoking scopes)";
case "webhook":
return "Allow installing webhooks (used when enabling prebuilds for a repository, note: Bitbucket doesn't support revoking scopes)";
default:
return "";
}
};

return (
<div>
{selectAccountModal && (
Expand Down Expand Up @@ -325,18 +326,22 @@ function GitProviders() {
<ModalHeader>Edit Permissions</ModalHeader>
<ModalBody>
<CheckboxListField label="Configure provider permissions.">
{(getScopesForAuthProviderType(editModal.provider.type) || []).map((scope) => (
<CheckboxInputField
key={scope}
value={scope}
label={scope}
hint={getDescriptionForScope(scope)}
checked={editModal.nextScopes.has(scope)}
// disabled={editModal.provider.requirements?.default.includes(scope)} // what?!
topMargin={false}
onChange={(checked) => onChangeScopeHandler(checked, scope)}
/>
))}
{(getScopesForAuthProviderType(editModal.provider.type) || []).map((scope) => {
const isRequired = getRequiredScopes(editModal.provider.type)?.default.includes(scope);

return (
<CheckboxInputField
key={scope}
value={scope}
label={scope + (isRequired ? " (required)" : "")}
hint={getDescriptionForScope(scope)}
checked={editModal.nextScopes.has(scope)}
disabled={isRequired}
topMargin={false}
onChange={(checked) => onChangeScopeHandler(checked, scope)}
/>
);
})}
</CheckboxListField>
</ModalBody>
<ModalFooter>
Expand Down
2 changes: 1 addition & 1 deletion components/gitpod-db/src/typeorm/user-db-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ export class TypeORMUserDBImpl extends TransactionalDBImpl<UserDB> implements Us
accessTokenExpiresAt: expiry,
client,
user,
scopes: scopes,
scopes,
};
}
async issueRefreshToken(accessToken: OAuthToken): Promise<OAuthToken> {
Expand Down
84 changes: 50 additions & 34 deletions components/public-api/typescript-common/src/auth-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@

import { AuthProviderType } from "@gitpod/public-api/lib/gitpod/v1/authprovider_pb";

export namespace GitLabScope {
export namespace GitLabOAuthScopes {
export const READ_USER = "read_user";
export const API = "api";
export const READ_REPO = "read_repository";

export const ALL = [READ_USER, API, READ_REPO];
/**
* Minimal required permission.
* GitLab API usage requires the permission of a user.
*/
export const DEFAULT = [READ_USER, API];
export const REPO = [API, READ_REPO];

export const Requirements = {
/**
* Minimal required permission.
* GitLab API usage requires the permission of a user.
*/
DEFAULT: [READ_USER, API],

REPO: [API, READ_REPO],
};
}

export namespace GitHubScope {
export namespace GitHubOAuthScopes {
export const EMAIL = "user:email";
export const READ_USER = "read:user";
export const PUBLIC = "public_repo";
Expand All @@ -29,9 +33,17 @@ export namespace GitHubScope {
export const WORKFLOW = "workflow";

export const ALL = [EMAIL, READ_USER, PUBLIC, PRIVATE, ORGS, WORKFLOW];
export const DEFAULT = ALL;
export const PUBLIC_REPO = ALL;
export const PRIVATE_REPO = ALL;

export const Requirements = {
/**
* Minimal required permission.
* GitHub's API is not restricted any further.
*/
DEFAULT: [EMAIL],

PUBLIC_REPO: [PUBLIC],
PRIVATE_REPO: [PRIVATE],
};
}

export namespace BitbucketOAuthScopes {
Expand All @@ -48,15 +60,14 @@ export namespace BitbucketOAuthScopes {
/** Create, comment and merge pull requests */
export const PULL_REQUEST_WRITE = "pullrequest:write";

export const ALL = [
ACCOUNT_READ,
REPOSITORY_READ,
REPOSITORY_WRITE,
PULL_REQUEST_READ,
PULL_REQUEST_WRITE,
];
export const ALL = [ACCOUNT_READ, REPOSITORY_READ, REPOSITORY_WRITE, PULL_REQUEST_READ, PULL_REQUEST_WRITE];

export const DEFAULT = ALL;
export const Requirements = {
/**
* Minimal required permission.
*/
DEFAULT: ALL,
};
}

export namespace BitbucketServerOAuthScopes {
Expand All @@ -74,17 +85,22 @@ export namespace BitbucketServerOAuthScopes {

export const ALL = [PUBLIC_REPOS, REPO_READ, REPO_WRITE, REPO_ADMIN, PROJECT_ADMIN];

export const DEFAULT = ALL;
export const Requirements = {
/**
* Minimal required permission.
*/
DEFAULT: [PUBLIC_REPOS, REPO_READ, REPO_WRITE],
};
}

export function getScopesForAuthProviderType(type: AuthProviderType | string) {
switch (type) {
case AuthProviderType.GITHUB:
case "GitHub":
return GitHubScope.ALL;
return GitHubOAuthScopes.ALL;
case AuthProviderType.GITLAB:
case "GitLab":
return GitLabScope.ALL;
return GitLabOAuthScopes.ALL;
case AuthProviderType.BITBUCKET:
case "Bitbucket":
return BitbucketOAuthScopes.ALL;
Expand All @@ -99,30 +115,30 @@ export function getRequiredScopes(type: AuthProviderType | string) {
case AuthProviderType.GITHUB:
case "GitHub":
return {
default: GitHubScope.DEFAULT,
publicRepo: GitHubScope.PUBLIC_REPO,
privateRepo: GitHubScope.PRIVATE_REPO,
default: GitHubOAuthScopes.Requirements.DEFAULT,
publicRepo: GitHubOAuthScopes.Requirements.PUBLIC_REPO,
privateRepo: GitHubOAuthScopes.Requirements.PRIVATE_REPO,
};
case AuthProviderType.GITLAB:
case "GitLab":
return {
default: GitLabScope.DEFAULT,
publicRepo: GitLabScope.DEFAULT,
privateRepo: GitLabScope.REPO,
default: GitLabOAuthScopes.Requirements.DEFAULT,
publicRepo: GitLabOAuthScopes.Requirements.DEFAULT,
privateRepo: GitLabOAuthScopes.Requirements.REPO,
};
case AuthProviderType.BITBUCKET:
case "Bitbucket":
return {
default: BitbucketOAuthScopes.DEFAULT,
publicRepo: BitbucketOAuthScopes.DEFAULT,
privateRepo: BitbucketOAuthScopes.DEFAULT,
default: BitbucketOAuthScopes.Requirements.DEFAULT,
publicRepo: BitbucketOAuthScopes.Requirements.DEFAULT,
privateRepo: BitbucketOAuthScopes.Requirements.DEFAULT,
};
case AuthProviderType.BITBUCKET_SERVER:
case "BitbucketServer":
return {
default: BitbucketServerOAuthScopes.DEFAULT,
publicRepo: BitbucketServerOAuthScopes.DEFAULT,
privateRepo: BitbucketServerOAuthScopes.DEFAULT,
default: BitbucketServerOAuthScopes.Requirements.DEFAULT,
publicRepo: BitbucketServerOAuthScopes.Requirements.DEFAULT,
privateRepo: BitbucketServerOAuthScopes.Requirements.DEFAULT,
};
}
}
51 changes: 0 additions & 51 deletions components/server/src/auth/auth-provider-scopes.ts

This file was deleted.

6 changes: 3 additions & 3 deletions components/server/src/auth/auth-provider-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
import fetch from "node-fetch";
import { Authorizer } from "../authorization/authorizer";
import { ApplicationError, ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
import { getRequiredScopes, getScopesOfProvider } from "./auth-provider-scopes";
import { getRequiredScopes, getScopesForAuthProviderType } from "@gitpod/public-api-common/lib/auth-providers";

@injectable()
export class AuthProviderService {
Expand Down Expand Up @@ -106,8 +106,8 @@ export class AuthProviderService {
hiddenOnDashboard: ap.hiddenOnDashboard,
disallowLogin: ap.disallowLogin,
description: ap.description,
scopes: getScopesOfProvider(ap),
requirements: getRequiredScopes(ap),
scopes: getScopesForAuthProviderType(ap.type),
requirements: getRequiredScopes(ap.type),
};
}

Expand Down
4 changes: 2 additions & 2 deletions components/server/src/auth/resource-access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import { UnauthorizedError } from "../errors";
import { RepoURL } from "../repohost";
import { HostContextProvider } from "./host-context-provider";
import { reportGuardAccessCheck } from "../prometheus-metrics";
import { getRequiredScopes } from "./auth-provider-scopes";
import { FunctionAccessGuard } from "./function-access";
import { getRequiredScopes } from "@gitpod/public-api-common/lib/auth-providers";

declare let resourceInstance: GuardedResource;
export type GuardedResourceKind = typeof resourceInstance.kind;
Expand Down Expand Up @@ -585,7 +585,7 @@ export class RepositoryResourceGuard implements ResourceAccessGuard {
const identity = User.getIdentity(this.user, authProvider.authProviderId);
if (!identity) {
const providerType = authProvider.info.authProviderType;
const requiredScopes = getRequiredScopes({ type: providerType })?.default;
const requiredScopes = getRequiredScopes(providerType)?.default;
throw UnauthorizedError.create({
host: repoUrl.host,
repoName: repoUrl.repo,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import express from "express";
import { inject, injectable } from "inversify";
import { AuthUserSetup } from "../auth/auth-provider";
import { GenericAuthProvider } from "../auth/generic-auth-provider";
import { BitbucketServerOAuthScopes } from "./bitbucket-server-oauth-scopes";
import { BitbucketServerApi } from "./bitbucket-server-api";
import { BitbucketServerOAuthScopes } from "@gitpod/public-api-common/lib/auth-providers";

@injectable()
export class BitbucketServerAuthProvider extends GenericAuthProvider {
Expand Down
Loading
Loading