remove factory signature from gh creds provider

This change required the SingleInstanceGithubCredentialsProvider to be
changed to allow it to look up the credentials from the whole list of
integrations.

As such all places where it was used I have updated.

Signed-off-by: Brian Fletcher <brian@roadie.io>
This commit is contained in:
Brian Fletcher
2022-01-04 15:30:07 +00:00
parent 57261f7e86
commit 7af4986af8
26 changed files with 363 additions and 203 deletions
@@ -14,6 +14,8 @@
* limitations under the License.
*/
import { ScmIntegrations } from '../ScmIntegrations';
const octokit = {
paginate: async (fn: any) => (await fn()).data,
apps: {
@@ -34,22 +36,33 @@ jest.doMock('@octokit/rest', () => {
import { SingleInstanceGithubCredentialsProvider } from './SingleInstanceGithubCredentialsProvider';
import { RestEndpointMethodTypes } from '@octokit/rest';
import { DateTime } from 'luxon';
import { ConfigReader } from '@backstage/config';
const github = SingleInstanceGithubCredentialsProvider.create({
host: 'github.com',
apps: [
{
appId: 1,
privateKey: 'privateKey',
webhookSecret: '123',
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
let integrations = ScmIntegrations.fromConfig(
new ConfigReader({
integrations: {
github: [
{
host: 'github.com',
apps: [
{
appId: 1,
privateKey: 'privateKey',
webhookSecret: '123',
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
},
],
token: 'hardcoded_token',
},
],
},
],
token: 'hardcoded_token',
});
}),
);
describe('DefaultGithubCredentialsProvider tests', () => {
const github = SingleInstanceGithubCredentialsProvider.create(integrations);
describe('SingleInstanceGithubCredentialsProvider tests', () => {
beforeEach(() => {
jest.resetAllMocks();
});
@@ -204,11 +217,22 @@ describe('DefaultGithubCredentialsProvider tests', () => {
});
it('should return the default token if no app is configured', async () => {
const githubProvider = SingleInstanceGithubCredentialsProvider.create({
host: 'github.com',
apps: [],
token: 'fallback_token',
});
integrations = ScmIntegrations.fromConfig(
new ConfigReader({
integrations: {
github: [
{
host: 'github.com',
apps: [],
token: 'fallback_token',
},
],
},
}),
);
const githubProvider =
SingleInstanceGithubCredentialsProvider.create(integrations);
await expect(
githubProvider.getCredentials({
@@ -218,19 +242,29 @@ describe('DefaultGithubCredentialsProvider tests', () => {
});
it('should return the configured token if there are no installations', async () => {
const githubProvider = SingleInstanceGithubCredentialsProvider.create({
host: 'github.com',
apps: [
{
appId: 1,
privateKey: 'privateKey',
webhookSecret: '123',
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
integrations = ScmIntegrations.fromConfig(
new ConfigReader({
integrations: {
github: [
{
host: 'github.com',
apps: [
{
appId: 1,
privateKey: 'privateKey',
webhookSecret: '123',
clientId: 'CLIENT_ID',
clientSecret: 'CLIENT_SECRET',
},
],
token: 'hardcoded_token',
},
],
},
],
token: 'hardcoded_token',
});
}),
);
const githubProvider =
SingleInstanceGithubCredentialsProvider.create(integrations);
octokit.apps.listInstallations.mockResolvedValue({
data: [],
} as unknown as RestEndpointMethodTypes['apps']['listInstallations']['response']);
@@ -243,9 +277,19 @@ describe('DefaultGithubCredentialsProvider tests', () => {
});
it('should return undefined if no token or apps are configured', async () => {
const githubProvider = SingleInstanceGithubCredentialsProvider.create({
host: 'github.com',
});
integrations = ScmIntegrations.fromConfig(
new ConfigReader({
integrations: {
github: [
{
host: 'github.com',
},
],
},
}),
);
const githubProvider =
SingleInstanceGithubCredentialsProvider.create(integrations);
await expect(
githubProvider.getCredentials({
@@ -22,9 +22,9 @@ import { DateTime } from 'luxon';
import {
GithubCredentials,
GithubCredentialsProvider,
GithubCredentialsProviderFactory,
GithubCredentialType,
} from './types';
import { ScmIntegrations } from '../ScmIntegrations';
type InstallationData = {
installationId: number;
@@ -232,17 +232,11 @@ export class GithubAppCredentialsMux {
export class SingleInstanceGithubCredentialsProvider
implements GithubCredentialsProvider
{
static create: GithubCredentialsProviderFactory = config => {
return new SingleInstanceGithubCredentialsProvider(
new GithubAppCredentialsMux(config),
config.token,
);
};
static create(integrations: ScmIntegrations) {
return new SingleInstanceGithubCredentialsProvider(integrations);
}
private constructor(
private readonly githubAppCredentialsMux: GithubAppCredentialsMux,
private readonly token?: string,
) {}
private constructor(private readonly integrations: ScmIntegrations) {}
/**
* Returns {@link GithubCredentials} for a given URL.
@@ -266,15 +260,24 @@ export class SingleInstanceGithubCredentialsProvider
*/
async getCredentials(opts: { url: string }): Promise<GithubCredentials> {
const parsed = parseGitUrl(opts.url);
const gitHubConfig = this.integrations.github.byUrl(opts.url)?.config;
if (!gitHubConfig) {
throw new Error(
`There is no GitHub integration that matches ${opts.url}. Please add a configuration for an integration.`,
);
}
const githubAppCredentialsMux = new GithubAppCredentialsMux(gitHubConfig);
const defaultToken = gitHubConfig.token;
const owner = parsed.owner || parsed.name;
const repo = parsed.owner ? parsed.name : undefined;
let type: GithubCredentialType = 'app';
let token = await this.githubAppCredentialsMux.getAppToken(owner, repo);
let token = await githubAppCredentialsMux.getAppToken(owner, repo);
if (!token) {
type = 'token';
token = this.token;
token = defaultToken;
}
return {
-1
View File
@@ -27,7 +27,6 @@ export {
export type {
GithubCredentials,
GithubCredentialsProvider,
GithubCredentialsProviderFactory,
GithubCredentialType,
} from './types';
export { GitHubIntegration, replaceGitHubUrlType } from './GitHubIntegration';
-12
View File
@@ -14,8 +14,6 @@
* limitations under the License.
*/
import { GitHubIntegrationConfig } from './config';
/**
* The type of credentials produced by the credential provider.
*
@@ -43,13 +41,3 @@ export type GithubCredentials = {
export interface GithubCredentialsProvider {
getCredentials(opts: { url: string }): Promise<GithubCredentials>;
}
/**
* This allows implementations to be provided to create credentials providers.
*
* @public
*
*/
export type GithubCredentialsProviderFactory = (
config: GitHubIntegrationConfig,
) => GithubCredentialsProvider;