Skip to content

Commit

Permalink
Replace 'request' with 'axios' (#322)
Browse files Browse the repository at this point in the history
* Replace 'request' with 'axios'

* linting

* Watchman tests

* kubeClass tests

* linting

* package updates

* package auditing

* fix patch methods

* address Watchman API usage details

* enforce request options and response details

* typo

* typfoix

* allow and ignore json option

* cleanup, common RequestLib

* unit tests

* cleanup

* cleanup

* stream handling updates

* use razee/request-util

* add expiry to audit allowlist

* fix package prefix
  • Loading branch information
carrolp authored Apr 10, 2023
1 parent 56c9e2c commit 0927f3f
Show file tree
Hide file tree
Showing 9 changed files with 3,851 additions and 3,940 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ before_install:
- echo "$DOCKERHUB_TOKEN" | docker login -u "icdevops" --password-stdin

script:
- if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then npm audit; else npm audit || true; fi
- if [ "${TRAVIS_PULL_REQUEST}" != "false" ]; then npx audit-ci --config audit-ci.json; else npx audit-ci --config audit-ci.json || true; fi
- npm run lint
- npm test
- if [[ "${TRAVIS_TAG}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]]; then npm version --no-git-tag-version "${TRAVIS_TAG}"; fi
Expand Down
17 changes: 17 additions & 0 deletions audit-ci.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"low": true,
"_allowlistInfo": [
{
"advisory": "GHSA-p8p7-x288-28g6",
"details": "The Request package through 2.88.2 for Node.js allows a bypass of SSRF mitigations via an attacker-controller server that does a cross-protocol redirect (HTTP to HTTPS, or HTTPS to HTTP)",
"justification1": "Request package is deprecated and unlikely to receive updates.",
"justification2": "Application unaffected as it only talks to kubernetes, which can be asserted as not an attacker-controlled server.",
"expiry": "28 April 2023 00:00"
}
],
"allowlist": [
"GHSA-p8p7-x288-28g6"
],
"skip-dev": true
}

27 changes: 13 additions & 14 deletions lib/KubeResourceMeta.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
* Copyright 2019, 2023 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,7 +14,7 @@
* limitations under the License.
*/
const objectPath = require('object-path');
const request = require('request-promise-native');
const RequestLib = require('@razee/request-util');
const merge = require('deepmerge');

const KubeApiConfig = require('./KubeApiConfig');
Expand Down Expand Up @@ -95,33 +95,33 @@ module.exports = class KubeResourceMeta {

async request(reqOpt) {
this._logger.debug(`Request ${reqOpt.method || 'GET'} ${reqOpt.uri || reqOpt.url}`);
return request(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt]));
return RequestLib.doRequest(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt]), this._logger);
}

async get(name, ns, reqOpt = {}) {
const uri = this.uri({ name: name, namespace: ns });
this._logger.debug(`Get ${uri}`);
return request.get(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt, { uri: uri, json: true }]));
return this.request(merge.all([reqOpt, { uri: uri, json: true, method: 'get' }]));
}

async put(file, reqOpt = {}) {
const uri = this.uri({ name: objectPath.get(file, 'metadata.name'), namespace: objectPath.get(file, 'metadata.namespace') });
this._logger.debug(`Put ${uri}`);
return request.put(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt, { uri: uri, json: file }]));
return this.request(merge.all([reqOpt, { uri: uri, json: file, method: 'put' }]));
}

async post(file, reqOpt = {}) {
const uri = this.uri({ namespace: objectPath.get(file, 'metadata.namespace') });
this._logger.debug(`Post ${uri}`);
return request.post(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt, { uri: uri, json: file }]));
return this.request(merge.all([reqOpt, { uri: uri, json: file, method: 'post' }]));
}

async patch(name, ns, jPatch, reqOpt = {}) {
const uri = this.uri({ name: name, namespace: ns, status: reqOpt.status });
this._logger.debug(`Json Patch ${uri}`);
reqOpt = merge(reqOpt, { uri: uri, json: jPatch });
reqOpt = merge(reqOpt, { uri: uri, json: jPatch, method: 'patch' });
objectPath.set(reqOpt, ['headers', 'content-type'], objectPath.get(reqOpt, ['headers', 'content-type']) || 'application/json-patch+json');
return request.patch(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt]));
return this.request(reqOpt);
}

async jsonPatch(name, ns, jPatch, reqOpt = {}) {
Expand All @@ -131,23 +131,22 @@ module.exports = class KubeResourceMeta {
async mergePatch(name, ns, mPatch, reqOpt = {}) {
const uri = this.uri({ name: name, namespace: ns, status: reqOpt.status });
this._logger.debug(`MergePatch ${uri}`);
reqOpt = merge(reqOpt, { uri: uri, json: mPatch });
reqOpt = merge(reqOpt, { uri: uri, json: mPatch, method: 'patch' });
objectPath.set(reqOpt, ['headers', 'content-type'], objectPath.get(reqOpt, ['headers', 'content-type']) || 'application/merge-patch+json');
return request.patch(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt]));
return this.request(reqOpt);
}

async strategicMergePatch(name, ns, smPatch, reqOpt = {}) {
const uri = this.uri({ name: name, namespace: ns, status: reqOpt.status });
this._logger.debug(`StrategicMergePatch ${uri}`);
reqOpt = merge(reqOpt, { uri: uri, json: smPatch });
reqOpt = merge(reqOpt, { uri: uri, json: smPatch, method: 'patch' });
objectPath.set(reqOpt, ['headers', 'content-type'], objectPath.get(reqOpt, ['headers', 'content-type']) || 'application/strategic-merge-patch+json');
return request.patch(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt]));
return this.request(merge.all(reqOpt));
}

async delete(name, ns, reqOpt = {}) {
const uri = this.uri({ name: name, namespace: ns });
this._logger.debug(`Delete ${uri}`);
return request.delete(merge.all([this.kubeApiConfig(), this._extraHeaders, reqOpt, { uri: uri, json: true }]));
return this.request(merge.all([reqOpt, { uri: uri, json: true, method: 'delete' }]));
}

};
10 changes: 5 additions & 5 deletions lib/Watchman.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
* Copyright 2019, 2023 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const request = require('request');
const RequestLib = require('@razee/request-util');
const validUrl = require('valid-url');
const JSONStream = require('JSONStream');
const delay = require('delay');
Expand Down Expand Up @@ -93,7 +93,7 @@ module.exports = class Watchman {
this.end(this._rewatchOnTimeout);
this._logger.debug('Watchman: attempting new watch ');
// this._requestOptions must not contain a prior KubeApiConfig(), otherwise the old values will overrite the newly fetched ones
this._requestStream = request(merge(KubeApiConfig(), this._requestOptions))
this._requestStream = RequestLib.getStream(merge(KubeApiConfig(), this._requestOptions), this._logger)
.on('response', (response) => {
if (response.statusCode !== 200) {
if (this._logger) {
Expand Down Expand Up @@ -131,7 +131,7 @@ module.exports = class Watchman {
if (this._logger) {
this._logger.error(`GET ${this._requestOptions.uri} errored at data.type === ERROR, aborting`, JSON.stringify(data.object));
}
this._requestStream.abort();
if( this._requestStream && this._requestStream.abort ) this._requestStream.abort(); // During automated test, the call to logger.error will call end() on the Watchman instance, destroying _requestStream
} else {
this.objectHandler(data);
}
Expand All @@ -155,4 +155,4 @@ module.exports = class Watchman {
this._requestStream = undefined;
this._jsonStream = undefined;
}
};
};
18 changes: 9 additions & 9 deletions lib/kubeClass.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2019 IBM Corp. All Rights Reserved.
* Copyright 2019, 2023 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const request = require('request-promise-native');
const RequestLib = require('@razee/request-util');
const merge = require('deepmerge');
const clone = require('clone');
const objectPath = require('object-path');
Expand Down Expand Up @@ -42,7 +42,7 @@ module.exports = class KubeClass {
}

async getCoreApis() {
let coreApiList = await request.get('/api/v1', this._baseOptions);
let coreApiList = await RequestLib.doRequest(merge(this._baseOptions, {uri: '/api/v1', method: 'get'}), this._log);
if (coreApiList.statusCode !== 200) {
return Promise.reject({ statusCode: coreApiList.statusCode, body: coreApiList.body, message: 'Error getting /api/v1' });
}
Expand All @@ -54,7 +54,7 @@ module.exports = class KubeClass {


async getApis(getAll = false) {
let apiQuery = await request.get('/apis', this._baseOptions);
let apiQuery = await RequestLib.doRequest(merge(this._baseOptions, {uri: '/apis', method: 'get'}), this._log);
if (apiQuery.statusCode !== 200) {
return Promise.reject({ statusCode: apiQuery.statusCode, body: apiQuery.body, message: 'Error getting /apis' });
}
Expand Down Expand Up @@ -110,7 +110,7 @@ module.exports = class KubeClass {
}

async getApisSingle(groupVersion, krmHandler) {
let response = await request.get('/apis/' + groupVersion, this._baseOptions);
let response = await RequestLib.doRequest(merge(this._baseOptions, {uri: '/apis/' + groupVersion, method: 'get'}), this._log);
if (response.statusCode == 200 && objectPath.get(response, 'body.kind') === 'APIResourceList') {
let resources = objectPath.get(response, 'body.resources');
resources.map((r) => {
Expand Down Expand Up @@ -142,14 +142,14 @@ module.exports = class KubeClass {
'resource-metadata': resourceMeta
};
let options = merge({ qs: queryParams }, this._baseOptions);
let response = await request.get(resourceMeta.uri(), options);
let response = await RequestLib.doRequest(merge(options, {uri: resourceMeta.uri(), method: 'get'}), this._log);
result.statusCode = response.statusCode;
switch (response.statusCode) {
case 200:
result.object = this.injectSelfLink(response.body, resourceMeta);
break;
default:
// this.logger.error(`this.getResource ${uri} ${response.statusCode} ${status[response.statusCode]}.`, response.body);
// this._log.error(`kubeClass.getResource ${uri} ${response.statusCode} ${status[response.statusCode]}.`, response.body);
result.error = response.body;
}
return result;
Expand Down Expand Up @@ -196,7 +196,7 @@ module.exports = class KubeClass {
let crds = [];
try {
const crdsHash = {};
let response = await request.get('/apis/apiextensions.k8s.io/v1/customresourcedefinitions', this._baseOptions);
let response = await RequestLib.doRequest(merge(this._baseOptions, {uri: '/apis/apiextensions.k8s.io/v1/customresourcedefinitions', method: 'get'}), this._log);
if (response.statusCode == 200 && objectPath.get(response, 'body.kind') === 'CustomResourceDefinitionList') {
objectPath.get(response, 'body.items', []).map(crd => {
crdsHash[`/apis/${objectPath.get(crd, 'spec.group')}`] = true;
Expand Down Expand Up @@ -254,4 +254,4 @@ module.exports = class KubeClass {
return krm !== undefined ? krm.clone() : krm;
}

};
};
Loading

0 comments on commit 0927f3f

Please sign in to comment.