Skip to content

Commit

Permalink
Add isOauth boolean field to the personalAccessToken type
Browse files Browse the repository at this point in the history
  • Loading branch information
vinokurig committed Nov 29, 2024
1 parent 930cd8a commit b2a07d9
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 72 deletions.
1 change: 1 addition & 0 deletions packages/common/src/dto/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export type PersonalAccessToken = {
tokenName: string;
tokenData: string; // base64 encoded
gitProviderEndpoint: string;
isOauth: boolean;
} & (
| {
gitProvider: Exclude<GitProvider, 'azure-devops'>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ describe('Helpers for Personal Access Token API', () => {
gitProviderEndpoint: 'https://github.com',
gitProviderOrganization: undefined,
tokenData: DUMMY_TOKEN_DATA,
isOauth: false,
});
});

Expand All @@ -128,6 +129,7 @@ describe('Helpers for Personal Access Token API', () => {
gitProvider: 'github',
gitProviderEndpoint: 'https://github.com',
tokenData: 'base64-encoded-token-data',
isOauth: false,
};

const secret = toSecret(namespace, token);
Expand Down Expand Up @@ -163,6 +165,7 @@ describe('Helpers for Personal Access Token API', () => {
gitProviderEndpoint: 'https://dev.azure.com',
gitProviderOrganization: 'azure-org',
tokenData: 'base64-encoded-token-data',
isOauth: false,
};

const secret = toSecret(namespace, token);
Expand Down Expand Up @@ -198,6 +201,7 @@ describe('Helpers for Personal Access Token API', () => {
gitProvider: 'github',
gitProviderEndpoint: 'https://github.com',
tokenData: DUMMY_TOKEN_DATA,
isOauth: false,
};

expect(() => toSecret(namespace, token)).toThrowError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ export function toToken(secret: k8s.V1Secret): api.PersonalAccessToken {
gitProvider: secret.metadata.annotations['che.eclipse.org/scm-provider-name'],
gitProviderEndpoint: secret.metadata.annotations['che.eclipse.org/scm-url'],
gitProviderOrganization: secret.metadata.annotations['che.eclipse.org/scm-organization'],
isOauth:
secret.metadata.annotations['che.eclipse.org/scm-personal-access-token-name'].startsWith(
'oauth2-',
),
tokenData: DUMMY_TOKEN_DATA,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ describe('AddEditModalForm', () => {
tokenData,
gitProvider,
gitProviderEndpoint,
isOauth: false,
};
patWithOrganization = {
...pat,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export class AddEditModalForm extends React.PureComponent<Props, State> {
gitProviderOrganization,
tokenName,
tokenData,
isOauth: false,
};
const isValid =
gitProviderEndpointIsValid &&
Expand All @@ -106,6 +107,7 @@ export class AddEditModalForm extends React.PureComponent<Props, State> {
gitProvider,
tokenName,
tokenData,
isOauth: false,
};
const isValid = gitProviderEndpointIsValid && tokenNameIsValid && tokenDataIsValid;
this.props.onChange(token, isValid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const token1: api.PersonalAccessToken = {
gitProviderEndpoint: 'https://github.com',
tokenData: 'token-data-1',
tokenName: 'token-name-1',
isOauth: false,
};

export const token2: api.PersonalAccessToken = {
Expand All @@ -26,4 +27,5 @@ export const token2: api.PersonalAccessToken = {
gitProviderEndpoint: 'https://github.com',
tokenData: 'token-data-2',
tokenName: 'token-name-2',
isOauth: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { PersonalAccessTokenListToolbar } from '@/pages/UserPreferences/Personal

const COLUMN_NAMES: Omit<
Record<keyof api.PersonalAccessToken, string>,
'cheUserId' | 'tokenData'
'cheUserId' | 'tokenData' | 'isOauth'
> = {
tokenName: 'Name',
gitProvider: 'Provider',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const token1: api.PersonalAccessToken = {
gitProviderEndpoint: 'https://github.com',
tokenData: 'token-data-1',
tokenName: 'token-name-1',
isOauth: false,
};

export const token2: api.PersonalAccessToken = {
Expand All @@ -26,4 +27,5 @@ export const token2: api.PersonalAccessToken = {
gitProviderEndpoint: 'https://github.com',
tokenData: 'token-data-2',
tokenName: 'token-name-2',
isOauth: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,11 @@ import {
import { createMockStore } from '@/store/__mocks__/mockActionsTestStore';
import {
actionCreators,
findUserToken,
findOauthToken,
gitOauthDeleteAction,
gitOauthErrorAction,
gitOauthReceiveAction,
gitOauthRequestAction,
isTokenGitProvider,
skipOauthReceiveAction,
} from '@/store/GitOauthConfig/actions';
import { IGitOauth } from '@/store/GitOauthConfig/reducer';
Expand Down Expand Up @@ -111,6 +110,7 @@ describe('GitOauthConfig', () => {
gitProviderEndpoint: 'https://github.com',
tokenData: 'test-token-data',
tokenName: 'test-token',
isOauth: true,
},
] as api.PersonalAccessToken[];
const mockOauthProviders = ['github'] as api.GitOauthProvider[];
Expand Down Expand Up @@ -294,32 +294,6 @@ describe('GitOauthConfig', () => {
});
});

describe('isTokenGitProvider', () => {
it('should return true for oauth2 git provider', () => {
const gitProvider = 'oauth2-provider';
const result = isTokenGitProvider(gitProvider);
expect(result).toBe(true);
});

it('should return true for bitbucket-server token format', () => {
const gitProvider = `che-token-<user-id>-<${window.location.hostname}>`;
const result = isTokenGitProvider(gitProvider);
expect(result).toBe(true);
});

it('should return false for non-oauth2 and non-bitbucket-server token format', () => {
const gitProvider = 'github';
const result = isTokenGitProvider(gitProvider);
expect(result).toBe(false);
});

it('should return false for invalid bitbucket-server token format', () => {
const gitProvider = `che-token-<user-id>-<invalid-hostname>`;
const result = isTokenGitProvider(gitProvider);
expect(result).toBe(false);
});
});

describe('findUserToken', () => {
const mockGitOauth = {
name: 'github',
Expand All @@ -330,20 +304,26 @@ describe('GitOauthConfig', () => {
const mockTokens = [
{
gitProviderEndpoint: 'https://github.com/',
gitProvider: 'oauth2-provider',
gitProvider: 'github',
tokenName: 'oauth2-provider',
isOauth: true,
},
{
gitProviderEndpoint: 'https://bitbucket.org/',
gitProvider: 'oauth2-provider',
gitProvider: 'bitbucket',
tokenName: 'oauth2-provider',
isOauth: true,
},
{
gitProviderEndpoint: 'https://github.com/',
gitProvider: `che-token-<user-id>-<${window.location.hostname}>`,
gitProviderEndpoint: 'https://bitbucket-server.com/',
gitProvider: 'bitbucket-server',
tokenName: `che-token-<user-id>-<${window.location.hostname}>`,
isOauth: true,
},
] as unknown as api.PersonalAccessToken[];

it('should return providers with token when matching token is found', () => {
const result = findUserToken(mockGitOauth, mockTokens);
const result = findOauthToken(mockGitOauth, mockTokens);
expect(result).toEqual(['github']);
});

Expand All @@ -353,7 +333,20 @@ describe('GitOauthConfig', () => {
endpointUrl: 'https://gitlab.com/',
} as IGitOauth;

const result = findUserToken(mockGitOauthNoMatch, mockTokens);
const result = findOauthToken(mockGitOauthNoMatch, mockTokens);
expect(result).toEqual([]);
});

it('should return an empty array with PAT', () => {
const mockTokens = [
{
gitProviderEndpoint: 'https://github.com/',
gitProvider: 'github',
tokenName: 'token-name',
},
] as unknown as api.PersonalAccessToken[];

const result = findOauthToken(mockGitOauth, mockTokens);
expect(result).toEqual([]);
});

Expand All @@ -369,28 +362,31 @@ describe('GitOauthConfig', () => {
gitProvider: 'oauth2-provider',
cheUserId: 'test-user',
tokenData: 'test-token-data',
tokenName: 'test-token',
tokenName: 'oauth2-token-name',
isOauth: true,
} as unknown as api.PersonalAccessToken,
];

const result = findUserToken(mockGitOauthWithTrailingSlash, mockTokensWithTrailingSlash);
const result = findOauthToken(mockGitOauthWithTrailingSlash, mockTokensWithTrailingSlash);
expect(result).toEqual(['github']);
});

it('should handle bitbucket-server token format', () => {
const mockGitOauthBitbucket = {
name: 'bitbucket',
endpointUrl: 'https://bitbucket.org/',
endpointUrl: 'https://bitbucket-server.org/',
} as IGitOauth;

const mockTokensBitbucket = [
{
gitProviderEndpoint: 'https://bitbucket.org/',
gitProvider: `che-token-<user-id>-<${window.location.hostname}>`,
gitProviderEndpoint: 'https://bitbucket-server.org/',
gitProvider: 'bitbucket-server',
tokenName: `che-token-<user-id>-<${window.location.hostname}>`,
isOauth: true,
} as unknown as api.PersonalAccessToken,
];

const result = findUserToken(mockGitOauthBitbucket, mockTokensBitbucket);
const result = findOauthToken(mockGitOauthBitbucket, mockTokensBitbucket);
expect(result).toEqual(['bitbucket']);
});
});
Expand Down
36 changes: 5 additions & 31 deletions packages/dashboard-frontend/src/store/GitOauthConfig/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,11 @@ export const actionCreators = {
const defaultKubernetesNamespace = selectDefaultNamespace(getState());
const tokens = await fetchTokens(defaultKubernetesNamespace.name);

const promises: Promise<void>[] = [];
for (const gitOauth of supportedGitOauth) {
promises.push(
getOAuthToken(gitOauth.name)
.then(() => {
providersWithToken.push(gitOauth.name);
})
.catch(() => {
// if `api/oauth/token` doesn't return a user's token,
// then check if there is the user's token in a Kubernetes Secret
providersWithToken.push(...findUserToken(gitOauth, tokens));
}),
);
// check if there is an oAuth token in a Kubernetes Secret
providersWithToken.push(...findOauthToken(gitOauth, tokens));
}
promises.push(dispatch(actionCreators.requestSkipAuthorizationProviders()));
await Promise.allSettled(promises);
await dispatch(actionCreators.requestSkipAuthorizationProviders());

dispatch(
gitOauthReceiveAction({
Expand Down Expand Up @@ -162,7 +151,7 @@ export const actionCreators = {
/**
* Check the user's token in a Kubernetes Secret
*/
export function findUserToken(gitOauth: IGitOauth, tokens: api.PersonalAccessToken[]) {
export function findOauthToken(gitOauth: IGitOauth, tokens: api.PersonalAccessToken[]) {
const providersWithToken: api.GitOauthProvider[] = [];

const normalizedGitOauthEndpoint = gitOauth.endpointUrl.endsWith('/')
Expand All @@ -175,25 +164,10 @@ export function findUserToken(gitOauth: IGitOauth, tokens: api.PersonalAccessTok
: token.gitProviderEndpoint;

// compare Git OAuth Endpoint url ONLY with OAuth tokens
const gitProvider = token.gitProvider;
if (
isTokenGitProvider(gitProvider) &&
normalizedGitOauthEndpoint === normalizedTokenGitProviderEndpoint
) {
if (token.isOauth && normalizedGitOauthEndpoint === normalizedTokenGitProviderEndpoint) {
providersWithToken.push(gitOauth.name);
break;
}
}
return providersWithToken;
}

/**
* For compatibility with the old format of the git provider value
*/
export function isTokenGitProvider(gitProvider: string): boolean {
return (
gitProvider.startsWith('oauth2') ||
// The git provider value format of a bitbucket-server token is 'che-token-<user id>-<che hostname>'
new RegExp(`^che-token-<.*>-<${window.location.hostname}>$`).test(gitProvider)
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const token1: api.PersonalAccessToken = {
gitProviderEndpoint: 'https://github.com',
tokenData: 'token-data-1',
tokenName: 'token-name-1',
isOauth: false,
};

export const token2: api.PersonalAccessToken = {
Expand All @@ -26,4 +27,5 @@ export const token2: api.PersonalAccessToken = {
gitProviderEndpoint: 'https://github.com',
tokenData: 'token-data-2',
tokenName: 'token-name-2',
isOauth: false,
};

0 comments on commit b2a07d9

Please sign in to comment.