@newrelic/security-agent 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/README.md +1 -0
- package/THIRD_PARTY_NOTICES.md +1 -211
- package/lib/instrumentation-security/core/sec-utils.js +1 -0
- package/lib/instrumentation-security/hooks/@nestjs/nr-nestjs-core.js +1 -0
- package/lib/instrumentation-security/hooks/express/nr-express.js +2 -0
- package/lib/instrumentation-security/hooks/fastify/nr-fastify.js +1 -0
- package/lib/instrumentation-security/hooks/fs/nr-fs.js +56 -20
- package/lib/instrumentation-security/hooks/hapi/nr-hapi.js +2 -1
- package/lib/instrumentation-security/hooks/http/nr-http.js +96 -4
- package/lib/instrumentation-security/hooks/koa/@koa/nr-@koa-router.js +3 -1
- package/lib/instrumentation-security/hooks/ldap/nr-ldap.js +1 -0
- package/lib/instrumentation-security/hooks/mongodb/common.js +2 -0
- package/lib/instrumentation-security/hooks/mongodb/nr-mongodb.js +1 -1
- package/lib/instrumentation-security/hooks/mysql/nr-mysql.js +5 -2
- package/lib/instrumentation-security/hooks/native/nr-childProcess.js +3 -0
- package/lib/instrumentation-security/hooks/postgres/nr-postgres.js +1 -0
- package/lib/instrumentation-security/hooks/require/nr-require.js +3 -2
- package/lib/instrumentation-security/hooks/restify/nr-restify.js +3 -1
- package/lib/instrumentation-security/hooks/xpath/nr-xpath.js +4 -2
- package/lib/nr-security-agent/index.js +9 -4
- package/lib/nr-security-agent/lib/core/Auth-headers.js +7 -0
- package/lib/nr-security-agent/lib/core/LogMessage.js +40 -14
- package/lib/nr-security-agent/lib/core/commonUtils.js +35 -4
- package/lib/nr-security-agent/lib/core/connections/aws-lambda-client.js +6 -8
- package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js +21 -6
- package/lib/nr-security-agent/lib/core/connections/websocket/response/index.js +5 -2
- package/lib/nr-security-agent/lib/core/connections/websocket/websocket.js +20 -1
- package/lib/nr-security-agent/lib/core/sec-agent-constants.js +3 -0
- package/lib/nr-security-agent/lib/core/sec-util.js +14 -6
- package/lib/nr-security-agent/lib/core/statusUtils.js +4 -1
- package/lib/nr-security-agent/lib/core/websocket-client.js +19 -8
- package/package.json +4 -5
package/lib/nr-security-agent/lib/core/connections/websocket/response/fuzz-request-handler.js
CHANGED
|
@@ -9,14 +9,16 @@ const stringify = require('fast-safe-stringify');
|
|
|
9
9
|
const restClient = require('../../restclient');
|
|
10
10
|
const { Agent } = require('../../../agent');
|
|
11
11
|
const { FuzzFailEvent } = require('../../../FuzzFailEvent');
|
|
12
|
-
const { CSEC_HOME_TMP, COLON, NR_CSEC_FUZZ_REQUEST_ID, SLASH, CSEC_SEP } = require('../../../sec-agent-constants');
|
|
12
|
+
const { CSEC_HOME_TMP, COLON, NR_CSEC_FUZZ_REQUEST_ID, SLASH, CSEC_SEP, SEVERE } = require('../../../sec-agent-constants');
|
|
13
13
|
const LOCALHOST = 'localhost';
|
|
14
14
|
const COLON_SLASH_SLASH = '://';
|
|
15
15
|
const http = require('http');
|
|
16
16
|
const https = require('https');
|
|
17
17
|
const IASTUtil = require('./IASTUtils');
|
|
18
|
+
const LogMessage = require('../../../LogMessage');
|
|
18
19
|
|
|
19
20
|
require('dns').setDefaultResultOrder('ipv4first')
|
|
21
|
+
const PolicyManager = require('../../../Policy');
|
|
20
22
|
|
|
21
23
|
const {
|
|
22
24
|
IS_LAMBDA_ENV,
|
|
@@ -42,6 +44,16 @@ function startIASTSchedular() {
|
|
|
42
44
|
if (iastIntervalConst) {
|
|
43
45
|
clearInterval(iastIntervalConst);
|
|
44
46
|
}
|
|
47
|
+
let probingInterval = 5;
|
|
48
|
+
|
|
49
|
+
const policyInstance = PolicyManager.getInstance();
|
|
50
|
+
if (policyInstance.data) {
|
|
51
|
+
probingInterval = policyInstance.data.vulnerabilityScan.iastScan.probing.interval;
|
|
52
|
+
}
|
|
53
|
+
if (isNaN(probingInterval)) {
|
|
54
|
+
probingInterval = 5;
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
iastIntervalConst = setInterval(() => {
|
|
46
58
|
let data = IASTUtil.generateIASTDataRequest();
|
|
47
59
|
let currentTime = Date.now();
|
|
@@ -55,7 +67,7 @@ function startIASTSchedular() {
|
|
|
55
67
|
if (timeDiffInSeconds > 5 && additionalCoolDownTime == 0) {
|
|
56
68
|
Agent.getAgent().client.dispatcher(data);
|
|
57
69
|
}
|
|
58
|
-
},
|
|
70
|
+
}, probingInterval * 1000);
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
/**
|
|
@@ -65,7 +77,7 @@ function startIASTSchedular() {
|
|
|
65
77
|
function logScannedApiId(fuzzHeader, requestURL) {
|
|
66
78
|
try {
|
|
67
79
|
let apiId = fuzzHeader.split(CSEC_SEP)[0]
|
|
68
|
-
if (apiId && !fuzzedApiIDSet.has(apiId)
|
|
80
|
+
if (apiId && !fuzzedApiIDSet.has(apiId)) {
|
|
69
81
|
fuzzedApiIDSet.add(apiId);
|
|
70
82
|
logger.info("IAST Scan for API %s with ID : %s started.", requestURL, apiId);
|
|
71
83
|
}
|
|
@@ -87,6 +99,9 @@ function handler(json) {
|
|
|
87
99
|
IASTUtil.addPendingRequestId(json.id);
|
|
88
100
|
} catch (error) {
|
|
89
101
|
logger.error('Parsing exeception in fuzz request: ', error);
|
|
102
|
+
|
|
103
|
+
const logMessage = new LogMessage.logMessage(SEVERE, 'Parsing exeception in fuzz request', __filename, error);
|
|
104
|
+
require('../../../commonUtils').addLogEventtoBuffer(logMessage);
|
|
90
105
|
}
|
|
91
106
|
if (!fuzzRequest) {
|
|
92
107
|
return;
|
|
@@ -132,10 +147,10 @@ function handleFuzzRequest(fuzzDetails) {
|
|
|
132
147
|
|
|
133
148
|
IASTUtil.completedRequestsMapInit(fuzzRequest.id);
|
|
134
149
|
|
|
135
|
-
if(fuzzRequest.headers && fuzzRequest.headers[NR_CSEC_FUZZ_REQUEST_ID]){
|
|
150
|
+
if (fuzzRequest.headers && fuzzRequest.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
136
151
|
logScannedApiId(fuzzRequest.headers[NR_CSEC_FUZZ_REQUEST_ID], fuzzRequest.requestURI)
|
|
137
152
|
}
|
|
138
|
-
|
|
153
|
+
|
|
139
154
|
|
|
140
155
|
logger.info('Firing http request:: URL: ' + config.url);
|
|
141
156
|
|
|
@@ -181,7 +196,7 @@ function handleFuzzResponse(response, fuzzDetails) {
|
|
|
181
196
|
function parseAxiosHttpRequestToFuzz(requestObject) {
|
|
182
197
|
let serverName = requestObject.serverName ? requestObject.serverName : LOCALHOST;
|
|
183
198
|
let host = serverName + COLON + requestObject.serverPort;
|
|
184
|
-
if(requestObject.headers && requestObject.headers['content-length']){
|
|
199
|
+
if (requestObject.headers && requestObject.headers['content-length']) {
|
|
185
200
|
delete requestObject.headers['content-length'];
|
|
186
201
|
}
|
|
187
202
|
return {
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const _ = require('lodash');
|
|
7
7
|
|
|
8
|
-
const { SERVER_COMMAND } = require('../../../sec-agent-constants');
|
|
8
|
+
const { SERVER_COMMAND, SEVERE } = require('../../../sec-agent-constants');
|
|
9
9
|
const UnsupportedAgentHandler = require('./unsupported-agent-handler');
|
|
10
10
|
const StartupHandshakeHandler = require('./startup-handshake-handler');
|
|
11
11
|
const FuzzRequestHandler = require('./fuzz-request-handler');
|
|
@@ -17,6 +17,7 @@ const coolDown = require('./iast-cool-down');
|
|
|
17
17
|
const recordDeletion = require('./iast-record-deletion');
|
|
18
18
|
const logs = require('../../../logging');
|
|
19
19
|
let logger = logs.getLogger();
|
|
20
|
+
const LogMessage = require('../../../LogMessage');
|
|
20
21
|
|
|
21
22
|
const commandHandlerMap = {
|
|
22
23
|
[SERVER_COMMAND.STARTUP_WELCOME_MSG]: StartupHandshakeHandler,
|
|
@@ -38,7 +39,9 @@ const handle = function handle (json) {
|
|
|
38
39
|
NoOpHandler.handler.call(this, json);
|
|
39
40
|
}
|
|
40
41
|
} catch (error) {
|
|
41
|
-
logger.error("Error in handling Control
|
|
42
|
+
logger.error("Error in handling Control Command",error);
|
|
43
|
+
const logMessage = new LogMessage.logMessage(SEVERE, 'Error in handling Control Command', __filename, error);
|
|
44
|
+
require('../../../commonUtils').addLogEventtoBuffer(logMessage);
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
};
|
|
@@ -17,10 +17,11 @@ const hc = require('../../health-check');
|
|
|
17
17
|
const fs = require('fs');
|
|
18
18
|
const { promisify } = require('../../sec-util');
|
|
19
19
|
const ResponseHandler = require('./response');
|
|
20
|
-
const { EMPTY_APPLICATION_UUID, LOG_MESSAGES, CSEC_SEP, NR_CSEC_FUZZ_REQUEST_ID, EXITEVENT, JSON_NAME, RASP } = require('../../sec-agent-constants');
|
|
20
|
+
const { EMPTY_APPLICATION_UUID, LOG_MESSAGES, CSEC_SEP, NR_CSEC_FUZZ_REQUEST_ID, EXITEVENT, JSON_NAME, RASP, SEVERE } = require('../../sec-agent-constants');
|
|
21
21
|
const statusUtils = require('../../statusUtils');
|
|
22
22
|
const commonUtils = require('../../commonUtils');
|
|
23
23
|
const IASTUtil = require('../websocket/response/IASTUtils');
|
|
24
|
+
const LogMessage = require('../../LogMessage');
|
|
24
25
|
|
|
25
26
|
const BUSY = 'busy';
|
|
26
27
|
const IDLE = 'idle';
|
|
@@ -109,6 +110,9 @@ SecWebSocket.prototype.init = function init() {
|
|
|
109
110
|
cert = fs.readFileSync(certPath, 'utf8');
|
|
110
111
|
} catch (error) {
|
|
111
112
|
logger.error("Error in reading certificate:", error);
|
|
113
|
+
const logMessage = new LogMessage.logMessage(SEVERE, 'Error in reading certificate for websocket', __filename, error);
|
|
114
|
+
commonUtils.addLogEventtoBuffer(logMessage);
|
|
115
|
+
|
|
112
116
|
}
|
|
113
117
|
|
|
114
118
|
webSocket = new WebSocket(validatorService, { headers: authHeaders, cert: cert, handshakeTimeout: 10000 });
|
|
@@ -120,6 +124,17 @@ SecWebSocket.prototype.init = function init() {
|
|
|
120
124
|
lastPongtime = Date.now();
|
|
121
125
|
commonUtils.setWSHealthStatus('OK');
|
|
122
126
|
logger.debug("Pong received from Validator");
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
let logBuffer = commonUtils.getLogEvents();
|
|
130
|
+
while (logBuffer.size() > 0) {
|
|
131
|
+
let logEvent = logBuffer.deq();
|
|
132
|
+
this.dispatch(logEvent);
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
logger.error("Error while sending log events", error);
|
|
136
|
+
}
|
|
137
|
+
|
|
123
138
|
})
|
|
124
139
|
webSocket.on('close', () => {
|
|
125
140
|
logger.warn("WS connection closed");
|
|
@@ -172,6 +187,7 @@ SecWebSocket.prototype.obeyReconnect = function obeyReconnect() {
|
|
|
172
187
|
SecWebSocket.prototype.pingWS = async function pingWS() {
|
|
173
188
|
const self = this;
|
|
174
189
|
let currentTime = Date.now();
|
|
190
|
+
|
|
175
191
|
let timeDiffInPing = (currentTime - lastPongtime) / 1000;
|
|
176
192
|
if (timeDiffInPing > 40 && lastPongtime != 0) {
|
|
177
193
|
self.obeyReconnect();
|
|
@@ -193,6 +209,7 @@ SecWebSocket.prototype.pingWS = async function pingWS() {
|
|
|
193
209
|
commonUtils.setWSHealthStatus('Error');
|
|
194
210
|
return;
|
|
195
211
|
}
|
|
212
|
+
|
|
196
213
|
}
|
|
197
214
|
|
|
198
215
|
/**
|
|
@@ -412,6 +429,8 @@ const defaultOnErrCB = () => function onClose(error) {
|
|
|
412
429
|
statusUtils.addErrortoBuffer(error);
|
|
413
430
|
const self = this;
|
|
414
431
|
logger.error("Error while connecting to validator:", error.message)
|
|
432
|
+
const logMessage = new LogMessage.logMessage(SEVERE, 'Error while connecting to validator', __filename, error);
|
|
433
|
+
commonUtils.addLogEventtoBuffer(logMessage);
|
|
415
434
|
logger.warn("Security Agent INACTIVE!!!")
|
|
416
435
|
if (error && error.code && (error.code === 'ECONNREFUSED' || error.code === 'EPIPE' || error.code === 'ECONNRESET')) {
|
|
417
436
|
logger.debug("WS Client Error callback called:", error);
|
|
@@ -108,6 +108,9 @@ module.exports = {
|
|
|
108
108
|
CSEC_SEP: ':IAST:',
|
|
109
109
|
RASP: 'RASP',
|
|
110
110
|
IAST: 'IAST',
|
|
111
|
+
SEVERE: 'SEVERE',
|
|
112
|
+
HIGH: 'HIGH',
|
|
113
|
+
CRITICAL: 'CRITICAL',
|
|
111
114
|
|
|
112
115
|
LOG_MESSAGES: {
|
|
113
116
|
LOADED_CSEC_ENVS_MSG: '[STEP-1][COMPLETE][env] Environment Information Gathering Done.',
|
|
@@ -9,10 +9,12 @@ const { SecEvent } = require('./event');
|
|
|
9
9
|
const logs = require('./logging');
|
|
10
10
|
const { Agent } = require('./agent');
|
|
11
11
|
const shaUtil = require('./sha-size-util');
|
|
12
|
-
const { LOG_MESSAGES, NR_CSEC_FUZZ_REQUEST_ID, COLON, VULNERABLE, EXITEVENT, EMPTY_STR, RASP } = require('./sec-agent-constants');
|
|
12
|
+
const { LOG_MESSAGES, NR_CSEC_FUZZ_REQUEST_ID, COLON, VULNERABLE, EXITEVENT, EMPTY_STR, RASP, SEVERE } = require('./sec-agent-constants');
|
|
13
13
|
const API = require('../../../nr-security-api');
|
|
14
14
|
const NRAgent = API.getNRAgent();
|
|
15
15
|
const HC = require('./health-check');
|
|
16
|
+
const LogMessage = require('./LogMessage');
|
|
17
|
+
const commonUtils = require('./commonUtils');
|
|
16
18
|
|
|
17
19
|
const statusUtils = require('./statusUtils');
|
|
18
20
|
|
|
@@ -67,10 +69,10 @@ function generateSecEvent(securityMetadata) {
|
|
|
67
69
|
const traceObject = securityMetadata.traceObject;
|
|
68
70
|
const request = securityMetadata.request;
|
|
69
71
|
|
|
70
|
-
if(request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]){
|
|
72
|
+
if (request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
71
73
|
HC.getInstance().iastEventStats.processed++;
|
|
72
74
|
}
|
|
73
|
-
else{
|
|
75
|
+
else {
|
|
74
76
|
HC.getInstance().raspEventStats.processed++;
|
|
75
77
|
}
|
|
76
78
|
try {
|
|
@@ -102,11 +104,14 @@ function generateSecEvent(securityMetadata) {
|
|
|
102
104
|
} catch (e) {
|
|
103
105
|
statusUtils.addErrortoBuffer(e);
|
|
104
106
|
logger.error("Error in generating event:", e);
|
|
105
|
-
|
|
106
|
-
|
|
107
|
+
|
|
108
|
+
const logMessage = new LogMessage.logMessage(SEVERE, 'Error while generating event', __filename, e);
|
|
109
|
+
commonUtils.addLogEventtoBuffer(logMessage);
|
|
110
|
+
|
|
111
|
+
if (request && request.headers[NR_CSEC_FUZZ_REQUEST_ID]) {
|
|
107
112
|
HC.getInstance().iastEventStats.errorCount++;
|
|
108
113
|
}
|
|
109
|
-
else{
|
|
114
|
+
else {
|
|
110
115
|
HC.getInstance().raspEventStats.errorCount++;
|
|
111
116
|
}
|
|
112
117
|
}
|
|
@@ -141,6 +146,9 @@ function generateExitEvent(secEvent) {
|
|
|
141
146
|
}
|
|
142
147
|
} catch (error) {
|
|
143
148
|
logger.error('Error in generating exit event', error);
|
|
149
|
+
|
|
150
|
+
const logMessage = new LogMessage.logMessage(SEVERE, 'Error in generating exit event', __filename, error);
|
|
151
|
+
commonUtils.addLogEventtoBuffer(logMessage);
|
|
144
152
|
HC.getInstance().exitEventStats.errorCount++;
|
|
145
153
|
}
|
|
146
154
|
}
|
|
@@ -83,7 +83,7 @@ function getFormattedData() {
|
|
|
83
83
|
const appInfo = Agent.applicationInfo;
|
|
84
84
|
const deployedApplications = appInfo && appInfo.serverInfo && appInfo.serverInfo.deployedApplications;
|
|
85
85
|
const appLoc = deployedApplications[0].deployedPath;
|
|
86
|
-
const formattedSnapshot = util.format(statusTemplate, new Date().toString(), appLoc, appInfo.serverInfo.name, njsAgentConstants.FRAMEWORK,commonUtils.getWSHealthStatus(), appInfo.policyVersion, getKeyValPairs(lastHC.stats), getKeyValPairs(lastHC.serviceStatus), JSON.stringify(getBufferedErrors()), JSON.stringify(getBufferedHC()));
|
|
86
|
+
const formattedSnapshot = util.format(statusTemplate, new Date().toString(), appLoc, appInfo.serverInfo.name, njsAgentConstants.FRAMEWORK, commonUtils.getWSHealthStatus(), appInfo.policyVersion, getKeyValPairs(lastHC.stats), getKeyValPairs(lastHC.serviceStatus), JSON.stringify(getBufferedErrors()), JSON.stringify(getBufferedHC()));
|
|
87
87
|
return formattedSnapshot;
|
|
88
88
|
}
|
|
89
89
|
|
|
@@ -96,6 +96,9 @@ function writeSnapshot() {
|
|
|
96
96
|
fs.writeFile(statusFile, snapshot, { mode: 0o777 }, function (err) {
|
|
97
97
|
if (err) {
|
|
98
98
|
logger.debug(err.message);
|
|
99
|
+
const LogMessage = require('./LogMessage');
|
|
100
|
+
const logMessage = new LogMessage.logMessage("SEVERE", 'Error in creating snapshot file', __filename, err);
|
|
101
|
+
commonUtils.addLogEventtoBuffer(logMessage);
|
|
99
102
|
} else {
|
|
100
103
|
logger.info('Snapshot updated to file: %s', statusFile);
|
|
101
104
|
fs.chmod(statusFile, 0o777, (err) => {
|
|
@@ -15,6 +15,7 @@ const initLogger = require('./logging').getInitLogger();
|
|
|
15
15
|
const commonUtils = require('./commonUtils');
|
|
16
16
|
const API = require('../../../nr-security-api');
|
|
17
17
|
const NRAgent = API.getNRAgent();
|
|
18
|
+
const LogMessage = require('./LogMessage');
|
|
18
19
|
const {
|
|
19
20
|
SecWebSocket,
|
|
20
21
|
setWebSocketConn,
|
|
@@ -69,6 +70,15 @@ const initialize = function () {
|
|
|
69
70
|
setTimeout(() => {
|
|
70
71
|
setInterval(sendHC, HC_INTERVAL_MS);
|
|
71
72
|
sendHC();
|
|
73
|
+
try {
|
|
74
|
+
const framework = NRAgent.environment.get('Framework')[0];
|
|
75
|
+
const dispatcher = NRAgent.environment.get('Dispatcher')[0];
|
|
76
|
+
const logMessage = new LogMessage.logMessage("SEVERE", `Detected framework: ${framework} and dispatcher: ${dispatcher}`, __filename, null);
|
|
77
|
+
commonUtils.addLogEventtoBuffer(logMessage);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.debug("Error while extracting data from APM environment",error);
|
|
80
|
+
}
|
|
81
|
+
|
|
72
82
|
}, 30000);
|
|
73
83
|
|
|
74
84
|
setInterval(commonUtils.logRollOver, 30000);
|
|
@@ -140,17 +150,18 @@ const sendHC = async function () {
|
|
|
140
150
|
* @param {JSON} eventJson
|
|
141
151
|
*/
|
|
142
152
|
function getDispatcherAndSendEvent(eventJson) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
153
|
+
if (eventJson) {
|
|
154
|
+
const eventType = eventJson.jsonName;
|
|
155
|
+
if (eventType === JSON_NAME.EVENT || eventType === EXITEVENT) {
|
|
156
|
+
hc.getInstance().registerEventProcessed();
|
|
157
|
+
}
|
|
147
158
|
|
|
148
|
-
|
|
159
|
+
dispatcher(eventJson);
|
|
149
160
|
|
|
150
|
-
|
|
151
|
-
|
|
161
|
+
if (eventType === JSON_NAME.EVENT || eventType === EXITEVENT) {
|
|
162
|
+
hc.getInstance().registerEventSent();
|
|
163
|
+
}
|
|
152
164
|
}
|
|
153
|
-
|
|
154
165
|
}
|
|
155
166
|
|
|
156
167
|
/**
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/security-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "New Relic Security Agent for Node.js",
|
|
5
5
|
"main": "index.js",
|
|
6
|
-
"jsonVersion": "1.1.
|
|
6
|
+
"jsonVersion": "1.1.1",
|
|
7
7
|
"contributors": [
|
|
8
8
|
{
|
|
9
9
|
"name": "Sumit Suthar",
|
|
@@ -35,9 +35,8 @@
|
|
|
35
35
|
"url": "https://github.com/newrelic/csec-node-agent.git"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"check-disk-space": "3.4.0",
|
|
38
|
+
"axios": "^1.6.5",
|
|
39
|
+
"check-disk-space": "^3.4.0",
|
|
41
40
|
"content-type": "^1.0.5",
|
|
42
41
|
"fast-safe-stringify": "^2.1.1",
|
|
43
42
|
"find-package-json": "^1.2.0",
|