feat(backend-common): exposed onAuth callback
Exposed the `onAuth` callback from isomorphic git to allow callers to specify a callback to resolve credentials based on the URL of the remote instead of providing static credentials. For example, the [DefaultAzureDevOpsCredentialsProvider](https://github.com/backstage/backstage/blob/master/packages/integration/src/azure/DefaultAzureDevOpsCredentialsProvider.ts) can be used to resolve Azure DevOps credentials based on the request URL. Signed-off-by: Sander Aernouts <sander.aernouts@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/backend-common': patch
|
||||
---
|
||||
|
||||
Expose an `onAuth` handler for `git` actions to provide custom credentials
|
||||
@@ -7,6 +7,7 @@
|
||||
/// <reference types="webpack-env" />
|
||||
|
||||
import { AppConfig } from '@backstage/config';
|
||||
import { AuthCallback } from 'isomorphic-git';
|
||||
import { AwsCredentialsManager } from '@backstage/integration-aws-node';
|
||||
import { AwsS3Integration } from '@backstage/integration';
|
||||
import { AzureDevOpsCredentialsProvider } from '@backstage/integration';
|
||||
@@ -66,6 +67,12 @@ import { V1PodTemplateSpec } from '@kubernetes/client-node';
|
||||
import * as winston from 'winston';
|
||||
import { Writable } from 'stream';
|
||||
|
||||
// @public
|
||||
export type AuthCallbackOptions = {
|
||||
onAuth: AuthCallback;
|
||||
logger?: LoggerService;
|
||||
};
|
||||
|
||||
// @public
|
||||
export class AwsS3UrlReader implements UrlReader {
|
||||
constructor(
|
||||
@@ -379,12 +386,7 @@ export class Git {
|
||||
deleteRemote(options: { dir: string; remote: string }): Promise<void>;
|
||||
fetch(options: { dir: string; remote?: string }): Promise<void>;
|
||||
// (undocumented)
|
||||
static fromAuth: (options: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
logger?: LoggerService;
|
||||
}) => Git;
|
||||
static fromAuth: (options: StaticAuthOptions | AuthCallbackOptions) => Git;
|
||||
// (undocumented)
|
||||
init(options: { dir: string; defaultBranch?: string }): Promise<void>;
|
||||
log(options: { dir: string; ref?: string }): Promise<ReadCommitResult[]>;
|
||||
@@ -749,6 +751,14 @@ export function setRootLogger(newLogger: winston.Logger): void;
|
||||
// @public @deprecated
|
||||
export const SingleHostDiscovery: typeof HostDiscovery;
|
||||
|
||||
// @public
|
||||
export type StaticAuthOptions = {
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
logger?: LoggerService;
|
||||
};
|
||||
|
||||
// @public
|
||||
export type StatusCheck = () => Promise<any>;
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ describe('Git', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass a function that returns the authorization as the onAuth handler', async () => {
|
||||
it('should pass a function that returns the authorization as the onAuth handler when username and password are specified', async () => {
|
||||
const url = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
@@ -208,6 +208,25 @@ describe('Git', () => {
|
||||
expect(onAuth()).toEqual(auth);
|
||||
});
|
||||
|
||||
it('should pass the provided callback as the onAuth handler when on auth is specified', async () => {
|
||||
const url = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
const auth = {
|
||||
username: 'from',
|
||||
password: 'callback',
|
||||
};
|
||||
|
||||
const git = Git.fromAuth({ onAuth: () => auth });
|
||||
|
||||
await git.clone({ url, dir });
|
||||
|
||||
const { onAuth } = (
|
||||
isomorphic.clone as unknown as jest.Mock<(typeof isomorphic)['clone']>
|
||||
).mock.calls[0][0]!;
|
||||
|
||||
expect(onAuth()).toEqual(auth);
|
||||
});
|
||||
|
||||
it('should propagate the data from the error handler', async () => {
|
||||
const url = 'http://github.com/some/repo';
|
||||
const dir = '/some/mock/dir';
|
||||
|
||||
@@ -18,11 +18,40 @@ import git, {
|
||||
ProgressCallback,
|
||||
MergeResult,
|
||||
ReadCommitResult,
|
||||
AuthCallback,
|
||||
} from 'isomorphic-git';
|
||||
import http from 'isomorphic-git/http/node';
|
||||
import fs from 'fs-extra';
|
||||
import { LoggerService } from '@backstage/backend-plugin-api';
|
||||
|
||||
function isAuthCallbackOptions(
|
||||
options: StaticAuthOptions | AuthCallbackOptions,
|
||||
): options is AuthCallbackOptions {
|
||||
return 'onAuth' in options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure static credential for authentication
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type StaticAuthOptions = {
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
logger?: LoggerService;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure an authentication callback that can provide credentials on demand
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export type AuthCallbackOptions = {
|
||||
onAuth: AuthCallback;
|
||||
logger?: LoggerService;
|
||||
};
|
||||
|
||||
/*
|
||||
provider username password
|
||||
Azure 'notempty' token
|
||||
@@ -42,6 +71,7 @@ instead of Basic Auth (e.g., Bitbucket Server).
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
export class Git {
|
||||
private readonly headers: {
|
||||
[x: string]: string;
|
||||
@@ -49,12 +79,13 @@ export class Git {
|
||||
|
||||
private constructor(
|
||||
private readonly config: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
onAuth: AuthCallback;
|
||||
token?: string;
|
||||
logger?: LoggerService;
|
||||
},
|
||||
) {
|
||||
this.onAuth = config.onAuth;
|
||||
|
||||
this.headers = {
|
||||
'user-agent': 'git/@isomorphic-git',
|
||||
...(config.token ? { Authorization: `Bearer ${config.token}` } : {}),
|
||||
@@ -283,10 +314,7 @@ export class Git {
|
||||
});
|
||||
}
|
||||
|
||||
private onAuth = () => ({
|
||||
username: this.config.username,
|
||||
password: this.config.password,
|
||||
});
|
||||
private onAuth: AuthCallback;
|
||||
|
||||
private onProgressHandler = (): ProgressCallback => {
|
||||
let currentPhase = '';
|
||||
@@ -303,13 +331,13 @@ export class Git {
|
||||
};
|
||||
};
|
||||
|
||||
static fromAuth = (options: {
|
||||
username?: string;
|
||||
password?: string;
|
||||
token?: string;
|
||||
logger?: LoggerService;
|
||||
}) => {
|
||||
static fromAuth = (options: StaticAuthOptions | AuthCallbackOptions) => {
|
||||
if (isAuthCallbackOptions(options)) {
|
||||
const { onAuth, logger } = options;
|
||||
return new Git({ onAuth, logger });
|
||||
}
|
||||
|
||||
const { username, password, token, logger } = options;
|
||||
return new Git({ username, password, token, logger });
|
||||
return new Git({ onAuth: () => ({ username, password }), token, logger });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export { Git } from './git';
|
||||
export type { StaticAuthOptions, AuthCallbackOptions } from './git';
|
||||
|
||||
Reference in New Issue
Block a user