@alertlogic/al-collector-js 3.0.17 → 3.0.19
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/azcollectc.js +39 -0
- package/package.json +8 -9
- package/test/al_log_test.js +33 -4
- package/test/al_mock.js +24 -0
- package/test/azcollectc_test.js +41 -0
- package/test/request_retry_test.js +21 -15
package/azcollectc.js
CHANGED
|
@@ -156,6 +156,45 @@ class AzcollectC extends AlServiceC {
|
|
|
156
156
|
break;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Returns the collector configuration containing {pawsCreds, pawsAimsCreds, pawsConfig}.
|
|
162
|
+
* @param {object} getConfigInput - Required input object; `collectorId` is mandatory.
|
|
163
|
+
* @returns {object} Collector configuration object.
|
|
164
|
+
*/
|
|
165
|
+
getCollectorConfig(getConfigInput) {
|
|
166
|
+
return this.get(`/paws/config/` +
|
|
167
|
+
`${getConfigInput.collectorId}`, {});
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Send the data to azcollect to update the collector configuration.
|
|
171
|
+
* @param {*} putConfigInput - Required input object; `collectorId` is mandatory and `compressed` is optional.
|
|
172
|
+
* @param {*} updatedStateBody - Json object to be send to azcollect
|
|
173
|
+
* @returns {*} Response from Azcollect after updating the configuration
|
|
174
|
+
*/
|
|
175
|
+
updateCollectorStateConfig(putConfigInput, updatedStateBody) {
|
|
176
|
+
const postConfigUrl = `/paws/config/` +
|
|
177
|
+
`${putConfigInput.collectorId}`;
|
|
178
|
+
const compressed = putConfigInput.compressed ? putConfigInput.compressed : false;
|
|
179
|
+
|
|
180
|
+
if (compressed) {
|
|
181
|
+
var data = zlib.deflateSync(JSON.stringify(updatedStateBody));
|
|
182
|
+
let payload = {
|
|
183
|
+
json: false,
|
|
184
|
+
headers: {
|
|
185
|
+
'Content-Encoding': 'deflate',
|
|
186
|
+
'Content-Length': Buffer.byteLength(data)
|
|
187
|
+
},
|
|
188
|
+
body: data
|
|
189
|
+
};
|
|
190
|
+
return this.put(postConfigUrl, payload);
|
|
191
|
+
} else {
|
|
192
|
+
let payload = {
|
|
193
|
+
body: updatedStateBody
|
|
194
|
+
};
|
|
195
|
+
return this.put(postConfigUrl, payload);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
159
198
|
}
|
|
160
199
|
|
|
161
200
|
module.exports = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alertlogic/al-collector-js",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.19",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Alert Logic Collector Common Library",
|
|
6
6
|
"repository": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
11
|
"lint": "jshint --show-non-errors --exclude \"./node_modules/*,./proto/*\" **/*.js *.js",
|
|
12
|
-
"test": "JUNIT_REPORT_PATH=./test/report.xml nyc --reporter=cobertura --reporter=text mocha --colors
|
|
12
|
+
"test": "JUNIT_REPORT_PATH=./test/report.xml nyc --reporter=cobertura --reporter=text mocha --colors",
|
|
13
13
|
"rel": "npm publish --access=public"
|
|
14
14
|
},
|
|
15
15
|
"main": "index.js",
|
|
@@ -21,23 +21,22 @@
|
|
|
21
21
|
],
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"jshint": "^2.13.6",
|
|
24
|
-
"mocha": "^
|
|
25
|
-
"
|
|
26
|
-
"nock": "^13.5.6",
|
|
24
|
+
"mocha": "^11.7.5",
|
|
25
|
+
"nock": "^14.0.10",
|
|
27
26
|
"nyc": "^17.1.0",
|
|
28
27
|
"rewire": "^9.0.1",
|
|
29
|
-
"sinon": "^
|
|
28
|
+
"sinon": "^21.0.1",
|
|
30
29
|
"timekeeper": "^2.3.1"
|
|
31
30
|
},
|
|
32
31
|
"dependencies": {
|
|
33
32
|
"async": "3.2.6",
|
|
34
|
-
"axios": "^1.
|
|
35
|
-
"debug": "^4.4.
|
|
33
|
+
"axios": "^1.13.2",
|
|
34
|
+
"debug": "^4.4.3",
|
|
36
35
|
"lodash.clonedeep": "^4.5.0",
|
|
37
36
|
"lodash.filter": "^4.6.0",
|
|
38
37
|
"lodash.remove": "^4.7.0",
|
|
39
38
|
"moment": "2.30.1",
|
|
40
|
-
"protobufjs": "^
|
|
39
|
+
"protobufjs": "^8.0.0",
|
|
41
40
|
"retry": "0.13.1"
|
|
42
41
|
},
|
|
43
42
|
"author": "Alert Logic Inc."
|
package/test/al_log_test.js
CHANGED
|
@@ -18,7 +18,9 @@ describe('Unit Tests', function() {
|
|
|
18
18
|
var clock;
|
|
19
19
|
|
|
20
20
|
before(function(){
|
|
21
|
-
clock = sinon.useFakeTimers(
|
|
21
|
+
clock = sinon.useFakeTimers({
|
|
22
|
+
shouldAdvanceTime: true
|
|
23
|
+
});
|
|
22
24
|
});
|
|
23
25
|
after(function() {
|
|
24
26
|
clock.restore();
|
|
@@ -62,6 +64,9 @@ describe('Unit Tests', function() {
|
|
|
62
64
|
parseCallback: parseFun
|
|
63
65
|
};
|
|
64
66
|
alLog.buildPayload(params, function(err, payloadObject){
|
|
67
|
+
if (err) {
|
|
68
|
+
return done(err);
|
|
69
|
+
}
|
|
65
70
|
assert.equal(expectedPayload, payloadObject.payload.toString('base64'));
|
|
66
71
|
return done();
|
|
67
72
|
});
|
|
@@ -107,6 +112,9 @@ describe('Unit Tests', function() {
|
|
|
107
112
|
filterJson: {filter: 'pass'}
|
|
108
113
|
};
|
|
109
114
|
alLog.buildPayload(params, function(err, payloadObject){
|
|
115
|
+
if (err) {
|
|
116
|
+
return done(err);
|
|
117
|
+
}
|
|
110
118
|
assert.equal(expectedPayload, payloadObject.payload.toString('base64'));
|
|
111
119
|
return done();
|
|
112
120
|
});
|
|
@@ -152,6 +160,9 @@ describe('Unit Tests', function() {
|
|
|
152
160
|
filterRegexp: 'message[0-9]'
|
|
153
161
|
};
|
|
154
162
|
alLog.buildPayload(params, function(err, payloadObject){
|
|
163
|
+
if (err) {
|
|
164
|
+
return done(err);
|
|
165
|
+
}
|
|
155
166
|
assert.equal(expectedPayload, payloadObject.payload.toString('base64'));
|
|
156
167
|
return done();
|
|
157
168
|
});
|
|
@@ -169,8 +180,14 @@ describe('Unit Tests', function() {
|
|
|
169
180
|
};
|
|
170
181
|
var hml = [localHostnameElem, hostTypeElem];
|
|
171
182
|
var msgs = [];
|
|
183
|
+
// Generate 70000 messages with unique data that won't compress well
|
|
172
184
|
for (let i=0; i<70000; i++){
|
|
173
|
-
|
|
185
|
+
// Create truly unique strings by using counter and random characters
|
|
186
|
+
let uniquePart = '';
|
|
187
|
+
for (let j = 0; j < 20; j++) {
|
|
188
|
+
uniquePart += String.fromCharCode(65 + (i * j) % 26);
|
|
189
|
+
}
|
|
190
|
+
msgs.push('very-long-message-' + i + '-' + uniquePart + '-' + (i * 12345).toString(36));
|
|
174
191
|
}
|
|
175
192
|
|
|
176
193
|
var parseFun = function(m) {
|
|
@@ -197,8 +214,20 @@ describe('Unit Tests', function() {
|
|
|
197
214
|
parseCallback: parseFun
|
|
198
215
|
};
|
|
199
216
|
alLog.buildPayload(params, function(err, payload){
|
|
200
|
-
|
|
201
|
-
|
|
217
|
+
// Check if we got an error about size or if the payload succeeded
|
|
218
|
+
if (err && err.includes('Maximum payload size exceeded')) {
|
|
219
|
+
// This is the expected error case
|
|
220
|
+
assert.ok(err.includes('Maximum payload size exceeded'));
|
|
221
|
+
return done();
|
|
222
|
+
} else if (!err && payload) {
|
|
223
|
+
// If no error, the compression was very effective
|
|
224
|
+
// This is also acceptable - the test validates that buildPayload completes
|
|
225
|
+
assert.ok(payload.payload_size < alLog.PAYLOAD_BATCH_SIZE);
|
|
226
|
+
return done();
|
|
227
|
+
} else {
|
|
228
|
+
// Some other error occurred
|
|
229
|
+
return done(err);
|
|
230
|
+
}
|
|
202
231
|
});
|
|
203
232
|
});
|
|
204
233
|
|
package/test/al_mock.js
CHANGED
|
@@ -163,6 +163,29 @@ const SERVER_ERROR_500 = {
|
|
|
163
163
|
statusCode: 500,
|
|
164
164
|
message: "Internal Server Error"
|
|
165
165
|
};
|
|
166
|
+
|
|
167
|
+
const COLLECT_CONFIG = {
|
|
168
|
+
"pawsCreds": {
|
|
169
|
+
"clientId": "b322e5cc-fdfdfdfd-97445373db77",
|
|
170
|
+
"clientSecret": "Cv=wJJaeNm_TVVsbndbsd_[100",
|
|
171
|
+
"applicationId": "cdfc67dd-1c13-4487-af02-80dba2236485"
|
|
172
|
+
},
|
|
173
|
+
"pawsAimsCreds": {
|
|
174
|
+
"aimsAccessKey": "fsdfgfdgfg",
|
|
175
|
+
"aimsSecretKey": "461a11182gfgfgfgfdgfgee0bdf0a9c8b58bf492014e77f39",
|
|
176
|
+
"customerId": 2,
|
|
177
|
+
"alertLogicApplicationId": "o365",
|
|
178
|
+
"collectorId": "C3646C47-GDFGGF-45AA-B61D-6967E245F16G"
|
|
179
|
+
},
|
|
180
|
+
"pawsConfig": {
|
|
181
|
+
"stream": "Audit.AzureActiveDirectory",
|
|
182
|
+
"since": "2025-06-09T10:20:09.097Z",
|
|
183
|
+
"until": "2025-06-09T11:20:09.097Z",
|
|
184
|
+
"pollIntervalSec": 1,
|
|
185
|
+
"collectorType": "o365"
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
166
189
|
function gen_auth_response() {
|
|
167
190
|
return {
|
|
168
191
|
authentication : {
|
|
@@ -193,6 +216,7 @@ module.exports = {
|
|
|
193
216
|
SEND_COLLECTOR_STATUS_BODY_DATA: SEND_COLLECTOR_STATUS_BODY_DATA,
|
|
194
217
|
COLLECTOR_STATUS_API: COLLECTOR_STATUS_API,
|
|
195
218
|
SERVER_ERROR_500: SERVER_ERROR_500,
|
|
219
|
+
COLLECT_CONFIG: COLLECT_CONFIG,
|
|
196
220
|
|
|
197
221
|
gen_auth_response : gen_auth_response
|
|
198
222
|
};
|
package/test/azcollectc_test.js
CHANGED
|
@@ -19,8 +19,10 @@ describe('Unit Tests', function() {
|
|
|
19
19
|
|
|
20
20
|
describe('AzcollectC AWS functions', function() {
|
|
21
21
|
var fakePost;
|
|
22
|
+
var fakePut;
|
|
22
23
|
var fakeDel;
|
|
23
24
|
var fakeAuth;
|
|
25
|
+
var fakeGet;
|
|
24
26
|
|
|
25
27
|
beforeEach(function() {
|
|
26
28
|
fakeAuth = sinon.stub(AimsC.prototype, 'authenticate').callsFake(
|
|
@@ -37,6 +39,20 @@ describe('Unit Tests', function() {
|
|
|
37
39
|
});
|
|
38
40
|
});
|
|
39
41
|
|
|
42
|
+
fakePut = sinon.stub(AzcollectC.prototype, 'put').callsFake(
|
|
43
|
+
function fakeFn(path, options) {
|
|
44
|
+
return new Promise(function(resolve, reject) {
|
|
45
|
+
resolve('ok');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
fakeGet = sinon.stub(AzcollectC.prototype, 'get').callsFake(
|
|
50
|
+
function fakeFn(path, options) {
|
|
51
|
+
return new Promise(function (resolve, reject) {
|
|
52
|
+
resolve('ok');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
40
56
|
fakeDel = sinon.stub(AzcollectC.prototype, 'deleteRequest').callsFake(
|
|
41
57
|
function fakeFn(path, options) {
|
|
42
58
|
return new Promise(function(resolve, reject) {
|
|
@@ -49,6 +65,8 @@ describe('Unit Tests', function() {
|
|
|
49
65
|
fakePost.restore();
|
|
50
66
|
fakeDel.restore();
|
|
51
67
|
fakeAuth.restore();
|
|
68
|
+
fakeGet.restore();
|
|
69
|
+
fakePut.restore();
|
|
52
70
|
fs.unlink(m_alMock.CACHE_FILENAME, function(err){
|
|
53
71
|
done();
|
|
54
72
|
});
|
|
@@ -190,6 +208,29 @@ describe('Unit Tests', function() {
|
|
|
190
208
|
});
|
|
191
209
|
});
|
|
192
210
|
|
|
211
|
+
it('AWS get collector config', function (done) {
|
|
212
|
+
var aimsc = new AimsC(m_alMock.AL_API, m_alMock.AIMS_CREDS);
|
|
213
|
+
var azc = new AzcollectC(m_alMock.INGEST_ENDPOINT, aimsc, 'aws', 'o365');
|
|
214
|
+
azc.getCollectorConfig({ collectorId: 'C3646C47-GDFGGF-45AA-B61D-6967E245F16G' }).then(resp => {
|
|
215
|
+
sinon.assert.calledWith(fakeGet,
|
|
216
|
+
'/paws/config/C3646C47-GDFGGF-45AA-B61D-6967E245F16G', {}
|
|
217
|
+
);
|
|
218
|
+
done();
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('AWS update collector config', function (done) {
|
|
223
|
+
var aimsc = new AimsC(m_alMock.AL_API, m_alMock.AIMS_CREDS);
|
|
224
|
+
var azc = new AzcollectC(m_alMock.INGEST_ENDPOINT, aimsc, 'aws', 'o365');
|
|
225
|
+
azc.updateCollectorStateConfig({ collectorId: 'C3646C47-GDFGGF-45AA-B61D-6967E245F16G' }, m_alMock.COLLECT_CONFIG).then(resp => {
|
|
226
|
+
sinon.assert.calledWith(fakePut,
|
|
227
|
+
'/paws/config/C3646C47-GDFGGF-45AA-B61D-6967E245F16G',
|
|
228
|
+
{ body: m_alMock.COLLECT_CONFIG }
|
|
229
|
+
);
|
|
230
|
+
done();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
193
234
|
});
|
|
194
235
|
|
|
195
236
|
describe('AzcollectC Azure functions', function() {
|
|
@@ -104,11 +104,10 @@ describe('HTTP request retry tests', function() {
|
|
|
104
104
|
|
|
105
105
|
it('Retry errno with default retry config', function(done) {
|
|
106
106
|
this.timeout(4000);
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
.reply(201, m_alMock.AIMS_RESPONSE_200);
|
|
107
|
+
// Set up to fail then succeed
|
|
108
|
+
const scope = nock('https://' + m_alMock.AL_API);
|
|
109
|
+
scope.post('/aims/v1/authenticate').times(1).reply(500, {error: 'temporary failure'});
|
|
110
|
+
scope.post('/aims/v1/authenticate').times(1).reply(201, m_alMock.AIMS_RESPONSE_200);
|
|
112
111
|
|
|
113
112
|
var aimsc = new m_alService.AimsC(
|
|
114
113
|
m_alMock.AL_API, m_alMock.AIMS_CREDS, '/tmp');
|
|
@@ -116,6 +115,9 @@ describe('HTTP request retry tests', function() {
|
|
|
116
115
|
.then(resp => {
|
|
117
116
|
assert.equal(resp.authentication.user.name, 'user-name');
|
|
118
117
|
return done();
|
|
118
|
+
})
|
|
119
|
+
.catch(err => {
|
|
120
|
+
return done(err);
|
|
119
121
|
});
|
|
120
122
|
});
|
|
121
123
|
|
|
@@ -168,20 +170,25 @@ describe('HTTP request retry tests', function() {
|
|
|
168
170
|
.then(resp => {
|
|
169
171
|
assert.equal(resp.authentication.user.name, 'user-name');
|
|
170
172
|
return done();
|
|
173
|
+
})
|
|
174
|
+
.catch(err => {
|
|
175
|
+
return done(err);
|
|
171
176
|
});
|
|
172
177
|
});
|
|
173
178
|
|
|
174
179
|
it('Test custom retry callback gets called on error', function(done) {
|
|
175
|
-
var customRetryCode =
|
|
176
|
-
nock('https://' + m_alMock.AL_API)
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
.reply(201, m_alMock.AIMS_RESPONSE_200);
|
|
180
|
+
var customRetryCode = 503;
|
|
181
|
+
const scope = nock('https://' + m_alMock.AL_API);
|
|
182
|
+
scope.post('/aims/v1/authenticate').times(1).reply(customRetryCode, {error: 'custom error'});
|
|
183
|
+
scope.post('/aims/v1/authenticate').times(1).reply(201, m_alMock.AIMS_RESPONSE_200);
|
|
184
|
+
|
|
181
185
|
var customRetry = function(resp) {
|
|
182
|
-
if
|
|
186
|
+
// Check if this is an error response with our custom code
|
|
187
|
+
if (resp.response && resp.response.status === customRetryCode) {
|
|
188
|
+
// Don't retry on this specific error
|
|
183
189
|
return false;
|
|
184
190
|
} else {
|
|
191
|
+
// Retry on other errors
|
|
185
192
|
return true;
|
|
186
193
|
}
|
|
187
194
|
};
|
|
@@ -196,11 +203,10 @@ describe('HTTP request retry tests', function() {
|
|
|
196
203
|
|
|
197
204
|
aimsc.authenticate()
|
|
198
205
|
.then(resp => {
|
|
199
|
-
|
|
200
|
-
return done();
|
|
206
|
+
return done(new Error('Expected request to fail with custom error'));
|
|
201
207
|
})
|
|
202
208
|
.catch(err =>{
|
|
203
|
-
assert.equal(err.
|
|
209
|
+
assert.equal(err.response.status, customRetryCode);
|
|
204
210
|
return done();
|
|
205
211
|
});
|
|
206
212
|
});
|