-
Notifications
You must be signed in to change notification settings - Fork 122
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
895 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"BROKER_CLIENT_CONFIGURATION": { | ||
"common": { | ||
"default": { | ||
"BROKER_SERVER_URL": "https://broker.pre-prod.snyk.io", | ||
"BROKER_HA_MODE_ENABLED": "false", | ||
"BROKER_DISPATCHER_BASE_URL": "https://api.pre-prod.snyk.io" | ||
}, | ||
"oauth": { | ||
"clientId": "${CLIENT_ID}", | ||
"clientSecret": "${CLIENT_SECRET}" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { | ||
HttpResponse, | ||
makeRequestToDownstream, | ||
} from '../../common/http/request'; | ||
import { PostFilterPreparedRequest } from '../../common/relay/prepareRequest'; | ||
import { log as logger } from '../../logs/logger'; | ||
|
||
export default abstract class BrokerPlugin { | ||
abstract pluginCode: string; | ||
abstract pluginName: string; | ||
abstract description: string; | ||
abstract version: string; | ||
abstract applicableBrokerTypes: Array<string>; | ||
logger; | ||
brokerClientConfiguration: Record<string, any>; | ||
makeRequestToDownstream: ( | ||
req: PostFilterPreparedRequest, | ||
retries?: any, | ||
) => Promise<HttpResponse>; | ||
request?: PostFilterPreparedRequest; | ||
|
||
constructor(brokerClientCfg: Record<string, any>) { | ||
this.logger = logger; | ||
this.brokerClientConfiguration = brokerClientCfg; | ||
this.makeRequestToDownstream = makeRequestToDownstream; | ||
} | ||
|
||
getApplicableTypes(): Array<string> { | ||
const applicableTypes: Array<string> = []; | ||
if ( | ||
this.applicableBrokerTypes.every((type) => | ||
this.brokerClientConfiguration.supportedBrokerTypes.includes(type), | ||
) | ||
) { | ||
applicableTypes.push(...this.applicableBrokerTypes); | ||
} | ||
return applicableTypes; | ||
} | ||
isDisabled(config): boolean { | ||
let isDisabled = false; | ||
if (config[`DISABLE_${this.pluginCode}_PLUGIN`]) { | ||
logger.info({ plugin: this.pluginName }, `Plugin disabled`); | ||
isDisabled = true; | ||
} | ||
return isDisabled; | ||
} | ||
abstract isPluginActive(): boolean; | ||
|
||
abstract startUp(connectionConfiguration: Record<string, any>): Promise<void>; | ||
|
||
async preRequest( | ||
connectionConfiguration: Record<string, any>, | ||
postFilterPreparedRequest: PostFilterPreparedRequest, | ||
): Promise<PostFilterPreparedRequest> { | ||
return postFilterPreparedRequest; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { readdir } from 'fs/promises'; | ||
import { log as logger } from '../../logs/logger'; | ||
import BrokerPlugin from './abstractBrokerPlugin'; | ||
import { existsSync } from 'fs'; | ||
import { PostFilterPreparedRequest } from '../../common/relay/prepareRequest'; | ||
|
||
export const loadPlugins = async (pluginsFolderPath: string, clientOpts) => { | ||
clientOpts.config['plugins'] = new Map<string, unknown>(); | ||
clientOpts.config.supportedBrokerTypes.forEach((type) => { | ||
clientOpts.config.plugins.set(type, []); | ||
}); | ||
try { | ||
if (existsSync(pluginsFolderPath)) { | ||
const pluginsFiles = await readdir(pluginsFolderPath); | ||
for (const pluginFile of pluginsFiles.filter((filename) => | ||
filename.endsWith('.js'), | ||
)) { | ||
const plugin = await import(`${pluginsFolderPath}/${pluginFile}`); | ||
// Passing the config object so we can mutate things like filters instead of READONLY | ||
const pluginInstance = new plugin.Plugin(clientOpts.config); | ||
const applicableBrokerTypes = pluginInstance.getApplicableTypes(); | ||
applicableBrokerTypes.forEach((applicableBrokerType) => { | ||
if ( | ||
!pluginInstance.isDisabled(clientOpts.config) && | ||
pluginInstance.isPluginActive() | ||
) { | ||
logger.debug({}, `Loading plugin ${pluginInstance.pluginName}`); | ||
const configPluginForCurrentType = | ||
clientOpts.config.plugins.get(applicableBrokerType); | ||
if ( | ||
configPluginForCurrentType.some( | ||
(x) => | ||
x.pluginCode === pluginInstance.pluginCode || | ||
x.pluginName === pluginInstance.pluginName, | ||
) | ||
) { | ||
const errMsg = `Some Plugins have identical name or code.`; | ||
logger.error({}, errMsg); | ||
throw new Error(errMsg); | ||
} | ||
configPluginForCurrentType.push(pluginInstance); | ||
} else { | ||
logger.debug( | ||
{}, | ||
`Skipping plugin ${pluginInstance.pluginName}, not active.`, | ||
); | ||
} | ||
}); | ||
} | ||
} | ||
return clientOpts.config['plugins']; | ||
} catch (err) { | ||
const errMsg = `Error loading plugins from ${pluginsFolderPath}`; | ||
logger.error({ err }, `Error loading plugins from ${pluginsFolderPath}`); | ||
throw new Error(errMsg); | ||
} | ||
}; | ||
|
||
export const runStartupPlugins = async (clientOpts) => { | ||
const loadedPlugins = clientOpts.config.plugins as Map< | ||
string, | ||
BrokerPlugin[] | ||
>; | ||
const connectionsKeys = Object.keys(clientOpts.config.connections); | ||
|
||
for (const connectionKey of connectionsKeys) { | ||
if ( | ||
loadedPlugins.has(`${clientOpts.config.connections[connectionKey].type}`) | ||
) { | ||
const pluginInstances = | ||
loadedPlugins.get( | ||
`${clientOpts.config.connections[connectionKey].type}`, | ||
) ?? []; | ||
for (let i = 0; i < pluginInstances.length; i++) { | ||
await pluginInstances[i].startUp( | ||
clientOpts.config.connections[connectionKey], | ||
); | ||
} | ||
} | ||
} | ||
}; | ||
|
||
export const runPreRequestPlugins = async ( | ||
clientOpts, | ||
connectionIdentifier, | ||
pristinePreRequest: PostFilterPreparedRequest, | ||
) => { | ||
let preRequest = pristinePreRequest; | ||
const loadedPlugins = clientOpts.config.plugins as Map< | ||
string, | ||
BrokerPlugin[] | ||
>; | ||
const connectionsKeys = Object.keys(clientOpts.config.connections); | ||
let connectionKey; | ||
for (let i = 0; i < connectionsKeys.length; i++) { | ||
if ( | ||
clientOpts.config.connections[connectionsKeys[i]].identifier == | ||
connectionIdentifier | ||
) { | ||
connectionKey = connectionsKeys[i]; | ||
break; | ||
} | ||
} | ||
if (!connectionsKeys.includes(connectionKey)) { | ||
const errMsg = `Plugin preRequest: connection ${connectionKey} not found`; | ||
logger.error({ connectionKey }, errMsg); | ||
throw new Error(errMsg); | ||
} | ||
|
||
if ( | ||
loadedPlugins.has(`${clientOpts.config.connections[connectionKey].type}`) | ||
) { | ||
const pluginInstances = | ||
loadedPlugins.get( | ||
`${clientOpts.config.connections[connectionKey].type}`, | ||
) ?? []; | ||
for (let i = 0; i < pluginInstances.length; i++) { | ||
preRequest = await pluginInstances[i].preRequest( | ||
clientOpts.config.connections[connectionKey], | ||
preRequest, | ||
); | ||
} | ||
} | ||
|
||
return preRequest; | ||
}; |
60 changes: 60 additions & 0 deletions
60
lib/client/brokerClientPlugins/plugins/githubServerAppAuth.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// import { PostFilterPreparedRequest } from '../../../common/relay/prepareRequest'; | ||
import BrokerPlugin from '../abstractBrokerPlugin'; | ||
|
||
export class Plugin extends BrokerPlugin { | ||
// Plugin Code and Name must be unique across all plugins. | ||
pluginCode = 'GITHUB_SERVER_APP'; | ||
pluginName = 'Github Server App Authentication Plugin'; | ||
description = ` | ||
Plugin to retrieve and manage credentials for Brokered Github Server App installs | ||
`; | ||
version = '0.1'; | ||
applicableBrokerTypes = ['github-server-app']; // Must match broker types | ||
|
||
// Provide a way to include specific conditional logic to execute | ||
isPluginActive(): boolean { | ||
// if (this.brokerClientConfiguration['XYZ']) { | ||
// this.logger.debug({ plugin: this.pluginName }, 'Disabling plugin'); | ||
// return false; | ||
// } | ||
return true; | ||
} | ||
|
||
// Function running upon broker client startup | ||
// Useful for credentials retrieval, initial setup, etc... | ||
async startUp(connectionConfig): Promise<void> { | ||
this.logger.info({ plugin: this.pluginName }, 'Running Startup'); | ||
this.logger.info( | ||
{ config: connectionConfig }, | ||
'Connection Config passed to the plugin', | ||
); | ||
// const data = { | ||
// install_id: connectionConfig.GITHUB_APP_INSTALL_ID, | ||
// client_id: connectionConfig.GITHUB_CLIENT_ID, | ||
// client_secret: connectionConfig.GITHUB_CLIENT_SECRET, | ||
// }; | ||
// const formData = new URLSearchParams(data); | ||
|
||
// this.request = { | ||
// url: `https://${connectionConfig.GITHUB_API}/oauth/path`, | ||
// headers: { | ||
// 'Content-Type': 'application/x-www-form-urlencoded', | ||
// }, | ||
// method: 'POST', | ||
// body: formData.toString(), | ||
// }; | ||
// const response = await this.makeRequestToDownstream(this.request); | ||
// if (response.statusCode && response.statusCode > 299) { | ||
// throw Error('Error making request'); | ||
// } | ||
} | ||
|
||
// Hook to run pre requests operations - Optional. Uncomment to enable | ||
// async preRequest( | ||
// connectionConfiguration: Record<string, any>, | ||
// postFilterPreparedRequest:PostFilterPreparedRequest, | ||
// ) { | ||
// this.logger.debug({ plugin: this.pluginName, connection: connectionConfiguration }, 'Running prerequest plugin'); | ||
// return postFilterPreparedRequest; | ||
// } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.