Skip to content

Commit

Permalink
Merge pull request #12 from snyk-tech-services/feat/Add-snyk-token-ov…
Browse files Browse the repository at this point in the history
…erride-per-manager

feat: Allow snyk-token override in constructor
  • Loading branch information
aarlaud authored Jun 4, 2020
2 parents e36acce + 465019b commit 4c565af
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 102 deletions.
30 changes: 27 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ Following the same setup as snyk CLI, it uses the token stored in your system af
\
Same thing if you need to designate a different API base url to your onprem instance via `snyk config set endpoint` or `SNYK_API` to `https://yourhostname/api`

>Make sure to omit the base endpoint url when you define url to hit.
### 1 - Construct your manager

const requestManager = new requestsManager(20, period = 100, maxRetryCount = 10)

const requestManager = new requestsManager()

Default values if using `new requestsManager()`\
`requestsManager(burstSize = 10, period = 500, maxRetryCount = 5)`
`snykToken = '', burstSize = 10, period = 500, maxRetryCount = 5`



### 2 - Single shot request
Fire off your request and await it's result.
Expand Down Expand Up @@ -136,4 +141,23 @@ If not defining custom channel name, default channel name is used in the backend
}


Above will only show result of call to `/` as listener is only for 'test-channel'
Above will only show result of call to `/` as listener is only for 'test-channel'


### Customize token and or snyk token
While instantiating your manager

#### Customize queue size and intervals
```
const requestManager = new requestsManager({burstSize: 20, period: 100, maxRetryCount: 10})
```

#### Customize snyk token
```
const requestManager = new requestsManager({snykToken:'21346-1234-1234-1234')
```

#### Customize snyk token and queue|intervals|retries
```
const requestManager = new requestsManager({snykToken:'21346-1234-1234-1234', burstSize: 20, period: 100, maxRetryCount: 10})
```
9 changes: 5 additions & 4 deletions src/lib/request/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@ interface snykRequest {
requestId?: string
}

const makeSnykRequest = async (request: snykRequest) => {
const makeSnykRequest = async (request: snykRequest, snykToken: string = '') => {
const userConfig = getConfig()
const token = snykToken == '' ? userConfig.token : snykToken

const requestHeaders: Object = {
'Content-Type': 'application/json',
'Authorization': 'token '+userConfig.token,
'Authorization': 'token '+ token,
'User-Agent': 'tech-services/snyk-prevent/1.0'
}

}
const apiClient = axios.create({
baseURL: userConfig.endpoint,
responseType: 'json',
Expand Down
17 changes: 13 additions & 4 deletions src/lib/request/requestManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,29 @@ interface responseEvent {
data: any
}

interface requestsManagerParams {
snykToken?: string,
burstSize?: number,
period?: number,
maxRetryCount?: number
}

class requestsManager {
_requestsQueue: LeakyBucketQueue<queuedRequest>
// TODO: Type _events rather than plain obscure object structure
_events: any
_retryCounter: Map<string,number>
_MAX_RETRY_COUNT: number
_snykToken: string

constructor(burstSize = 10, period = 500, maxRetryCount = 5) {
this._requestsQueue = new LeakyBucketQueue<queuedRequest>({ burstSize: burstSize, period: period });
//snykToken = '', burstSize = 10, period = 500, maxRetryCount = 5
constructor(params: requestsManagerParams = {}) {
this._requestsQueue = new LeakyBucketQueue<queuedRequest>({ burstSize: params?.burstSize || 10, period: params?.period || 500 });
this._setupQueueExecutors(this._requestsQueue)
this._events = {}
this._retryCounter = new Map()
this._MAX_RETRY_COUNT = maxRetryCount
this._MAX_RETRY_COUNT = params?.maxRetryCount || 5
this._snykToken = params?.snykToken || ''
}

_setupQueueExecutors = (queue: LeakyBucketQueue<queuedRequest>) => {
Expand All @@ -52,7 +61,7 @@ class requestsManager {
_makeRequest = async (request: queuedRequest) => {
let requestId = request.id
try {
let response = await makeSnykRequest(request.snykRequest)
let response = await makeSnykRequest(request.snykRequest, this._snykToken)
this._emit({eventType: eventType.data, channel: request.channel, requestId: requestId, data: response })
} catch (err) {
let overloadedError = requestsManagerError.requestsManagerErrorOverload(err, request.channel, requestId)
Expand Down
25 changes: 25 additions & 0 deletions test/lib/request/request.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,13 @@ import {
const fixturesFolderPath = path.resolve(__dirname, '../..') + '/fixtures/';
beforeEach(() => {
return nock('https://snyk.io')
.persist()
.get(/\/xyz/)
.reply(404, '404')
.get(/\/customtoken/)
.reply(200, function() {
return this.req.headers.authorization;
})
.post(/\/xyz/)
.reply(404, '404')
.get(/\/apierror/)
Expand Down Expand Up @@ -192,3 +197,23 @@ describe('Test getConfig function', () => {
expect(getConfig().endpoint).toEqual('API');
});
});

describe('Test snykToken override', () => {
it('Test GET command on / with token override', async () => {
process.env.SNYK_TOKEN = '123';
const response = await makeSnykRequest(
{ verb: 'GET', url: '/customtoken' },
'0987654321',
);
expect(_.isEqual(response.data, 'token 0987654321')).toBeTruthy();
});

it('Test GET command on / without token override', async () => {
process.env.SNYK_TOKEN = '123';
const response = await makeSnykRequest({
verb: 'GET',
url: '/customtoken',
});
expect(_.isEqual(response.data, 'token 123')).toBeTruthy();
});
});
117 changes: 43 additions & 74 deletions test/lib/requestManager/normal-flows.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const fixturesFolderPath = path.resolve(__dirname, '../..') + '/fixtures/';
beforeAll(() => {
return nock('https://snyk.io')
.persist()
.get(/\/customtoken/)
.reply(200, function() {
return this.req.headers.authorization;
})
.get(/\/xyz/)
.reply(404, '404')
.post(/\/xyz/)
Expand Down Expand Up @@ -54,9 +58,19 @@ beforeAll(() => {
});
});

const requestManager = new requestsManager();
const OLD_ENV = process.env;
beforeEach(() => {
jest.resetModules(); // this is important - it clears the cache
process.env = { ...OLD_ENV };
delete process.env.SNYK_TOKEN;
});

afterEach(() => {
process.env = OLD_ENV;
});

describe('Testing Request Flows', () => {
const requestManager = new requestsManager();
it('Single Sync request', async () => {
try {
const responseSync = await requestManager.request({
Expand Down Expand Up @@ -111,7 +125,7 @@ describe('Testing Request Flows', () => {
try {
// dummypath is slowed down 1sec to verify that the response array respect the order of request
// waits for all request to be done and return an array of response in the same order.
const results: any = await requestManager.requestBulk([
const results: Array<any> = await requestManager.requestBulk([
{ verb: 'GET', url: '/dummypath' },
{
verb: 'POST',
Expand Down Expand Up @@ -244,78 +258,33 @@ describe('Testing Request Flows', () => {
console.log(err);
}
});
});

// const run = async () => {
// const manager = new requestsManager()
// manager.on('data', {
// callback:(requestId, data) => {
// console.log("response for request ", requestId)
// console.log(data)
// }
// })

// manager.on('error', {
// callback:(requestId, data) => {
// console.log("response for request ", requestId)
// console.log(data)
// }
// })

// try{
// let requestSync = await manager.request({verb: "GET", url: '/', body: ''})
// console.log(requestSync)
// console.log('done with synced request')
// } catch (err) {
// console.log('error')
// console.log(err)
// }

// manager.on('data', {
// callback:(requestId, data) => {
// console.log("response for request on test-channel ", requestId)
// console.log(data)
// },
// channel: 'test-channel'
// })

// try {
// console.log('1',manager.requestStream({verb: "GET", url: '/', body: ''}))
// console.log('1-channel',manager.requestStream({verb: "GET", url: '/', body: ''}, 'test-channel'))
// console.log('2',manager.requestStream({verb: "GET", url: '/', body: ''}))
// console.log('2-channel',manager.requestStream({verb: "GET", url: '/', body: ''}, 'test-channel'))
// console.log('3',manager.requestStream({verb: "GET", url: '/', body: ''}))
// console.log('3-channel',manager.requestStream({verb: "GET", url: '/', body: ''}, 'test-channel'))
// } catch (err) {
// console.log(err)
// }
it('Single Sync request with no token override', async () => {
process.env.SNYK_TOKEN = '123';
try {
const responseSync = await requestManager.request({
verb: 'GET',
url: '/customtoken',
});
expect(responseSync.data).toEqual('token 123');
} catch (err) {
throw new Error(err);
}
});
});

// const filters = `{
// "filters": {
// "severities": [
// "high",
// "medium",
// "low"
// ],
// "exploitMaturity": [
// "mature",
// "proof-of-concept",
// "no-known-exploit",
// "no-data"
// ],
// "types": [
// "vuln",
// "license"
// ],
// "ignored": false
// }
// }
// `
// try {
// const results = await manager.requestBulk([{verb: "GET", url: '/', body: ''}, {verb: "POST", url: '/org/334e0c45-5d3d-40f6-b882-ae82a164b317/project/0bbbfee1-2138-4322-80d4-4166d1259ae5/issues', body: filters}, {verb: "GET", url: '/', body: ''}])
// console.log(results)
// } catch(resultsWithError) {
// console.log(resultsWithError)
// }
describe('Testing Request Flows', () => {
const requestManager = new requestsManager({ snykToken: '0987654321' });
it('Single Sync request with token override', async () => {
try {
const responseSync = await requestManager.request({
verb: 'GET',
url: '/customtoken',
});

// }
expect(responseSync.data).toEqual('token 0987654321');
} catch (err) {
throw new Error(err);
}
});
});
Loading

0 comments on commit 4c565af

Please sign in to comment.