Skip to content

Commit d8c0252

Browse files
CDeltakaitegefaulkes
authored andcommitted
feat: added additional tests for NodesAuditEventsGet
fix: fixed rpc handler to decode input if id before passing it in
1 parent fee57c4 commit d8c0252

File tree

6 files changed

+225
-17
lines changed

6 files changed

+225
-17
lines changed

src/PolykeyAgent.ts

+1
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,7 @@ class PolykeyAgent {
804804
port: optionsDefaulted.agentServicePort,
805805
ipv6Only: optionsDefaulted.ipv6Only,
806806
agentService: agentServerManifest({
807+
audit: this.audit,
807808
acl: this.acl,
808809
db: this.db,
809810
keyRing: this.keyRing,

src/nodes/agent/handlers/NodesAuditEventsGet.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,14 @@ class NodesAuditEventsGet extends ServerHandler<
2929
_meta: Record<string, JSONValue> | undefined,
3030
ctx: ContextTimed,
3131
): AsyncGenerator<AgentRPCResponseResult<AgentAuditMessage<AuditEvent>>> {
32-
const { seek, seekEnd, limit } = input;
32+
let { seek, seekEnd, limit } = input;
33+
if (typeof seek !== 'number') {
34+
seek = auditUtils.decodeAuditEventId(seek);
35+
}
36+
if (typeof seekEnd !== 'number') {
37+
seekEnd = auditUtils.decodeAuditEventId(seekEnd);
38+
}
39+
3340
const { audit, db }: { audit: Audit; db: DB } = this.container;
3441

3542
yield* db.withTransactionG(async function* (tran): AsyncGenerator<
@@ -45,6 +52,13 @@ class NodesAuditEventsGet extends ServerHandler<
4552
tran,
4653
)) {
4754
ctx.signal.throwIfAborted();
55+
// Skip the seek event to ensure exclusivity if given an AuditEventId
56+
// This assumes that ids are unique
57+
if (seek !== undefined) {
58+
if (typeof seek !== 'number' && auditEvent.id.equals(seek)) {
59+
continue;
60+
}
61+
}
4862
yield {
4963
id: auditUtils.encodeAuditEventId(auditEvent.id),
5064
path: auditEvent.path,

src/nodes/agent/handlers/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { DB } from '@matrixai/db';
22
import type Logger from '@matrixai/logger';
33
import type KeyRing from '../../../keys/KeyRing';
4+
import type Audit from '../../../audit/Audit';
45
import type Sigchain from '../../../sigchain/Sigchain';
56
import type ACL from '../../../acl/ACL';
67
import type NodeGraph from '../../../nodes/NodeGraph';
@@ -26,6 +27,7 @@ import VaultsScan from './VaultsScan';
2627
* Server manifest factory.
2728
*/
2829
const manifestServer = (container: {
30+
audit: Audit;
2931
db: DB;
3032
sigchain: Sigchain;
3133
nodeGraph: NodeGraph;

src/nodes/agent/types.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ type AgentRPCResponseResult<T extends JSONObject = JSONObject> =
2424
JSONRPCResponseResult<T>;
2525

2626
type AuditIdMessage = {
27-
seek?: AuditEventId | number;
28-
seekEnd?: AuditEventId | number;
27+
seek?: AuditEventIdEncoded | number;
28+
seekEnd?: AuditEventIdEncoded | number;
2929
order?: 'asc' | 'desc';
3030
limit?: number;
3131
};

tests/nodes/agent/handlers/nodesAuditsGet.test.ts

+203-14
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
99
import { QUICClient, QUICServer, events as quicEvents } from '@matrixai/quic';
1010
import { DB } from '@matrixai/db';
1111
import { RPCClient, RPCServer } from '@matrixai/rpc';
12-
import { IdInternal } from '@matrixai/id';
1312
import NodesAuditEventsGet from '@/nodes/agent/handlers/NodesAuditEventsGet';
1413
import { nodesAuditEventsGet } from '@/nodes/agent/callers';
1514
import * as nodesUtils from '@/nodes/utils';
@@ -18,7 +17,6 @@ import Audit from '@/audit/Audit';
1817
import * as keysUtils from '@/keys/utils';
1918
import * as networkUtils from '@/network/utils';
2019
import * as auditUtils from '@/audit/utils';
21-
import { TopicPath } from '@/audit/types';
2220
import * as tlsTestsUtils from '../../../utils/tls';
2321
import * as testNodesUtils from '../../../nodes/utils';
2422

@@ -209,7 +207,7 @@ function generateMockAuditEvents(
209207

210208
test('should get audit events', async () => {
211209
// Generate valid AuditEventIds
212-
const mockAuditEvents = generateMockAuditEvents(200, callProtectedGenerateAuditEventId);
210+
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);
213211

214212
// Add events with correct topicPath and full path in event data
215213
for (const event of mockAuditEvents) {
@@ -230,14 +228,11 @@ function generateMockAuditEvents(
230228
//Parameters
231229
let seekValue = 0;
232230
let seekEndVal = Date.now();
233-
let limitVal = 50;
234231

235232
try {
236-
console.log('attempt rpc call');
237233
const response = await rpcClient.methods.nodesAuditEventsGet({
238234
seek: seekValue,
239235
seekEnd: seekEndVal,
240-
//limit: limitVal,
241236
});
242237

243238
// Collect results
@@ -246,23 +241,217 @@ function generateMockAuditEvents(
246241
auditIds.push(result.id);
247242
}
248243

249-
console.log(auditIds);
250-
251244
const mappedMockedAuditEvents = mockAuditEvents.map((event) => auditUtils.encodeAuditEventId(event.id))
252-
console.log(mappedMockedAuditEvents);
253-
254-
// Verify all events were returned with correct encoded IDs
255-
//expect(auditIds).toHaveLength(limitVal);
256245

257246
//Check if the audits grabbed from the rpc handler is the same as the generated audits from mockAuditEvents
258247
expect(auditIds).toEqual(
259248
mappedMockedAuditEvents
260249
);
261250
} catch (error) {
262-
// console.log('error');
263-
// console.error(error);
264251

265252
throw error;
266253
}
267254
});
255+
256+
test('should get audit events with limit', async () => {
257+
// Generate valid AuditEventIds
258+
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);
259+
260+
// Add events with correct topicPath and full path in event data
261+
for (const event of mockAuditEvents) {
262+
// @ts-ignore: accessing a protected method
263+
await audit.setAuditEvent(['node', 'connection', 'forward'], {
264+
// @ts-ignore: protected
265+
id: event.id,
266+
data: {
267+
remoteNodeId: 'asdasd',
268+
remoteHost: '127.0.0.1',
269+
remotePort: 54321,
270+
type: 'forward',
271+
},
272+
path: ['node', 'connection', 'forward'],
273+
});
274+
}
275+
//Parameters
276+
let seekValue = 0;
277+
let seekEndVal = Date.now();
278+
let limitVal = 50;
279+
280+
try {
281+
const response = await rpcClient.methods.nodesAuditEventsGet({
282+
seek: seekValue,
283+
seekEnd: seekEndVal,
284+
limit: limitVal,
285+
});
286+
287+
// Collect results
288+
const auditIds: Array<string> = [];
289+
for await (const result of response) {
290+
auditIds.push(result.id);
291+
}
292+
293+
// Verify that the number of events returned is equal to the limit
294+
expect(auditIds).toHaveLength(limitVal);
295+
296+
} catch (error) {
297+
298+
throw error;
299+
}
300+
});
301+
302+
303+
test('should get audit events with specific seek = 50', async () => {
304+
// Generate valid AuditEventIds
305+
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);
306+
307+
// Add events with correct topicPath and full path in event data
308+
for (const event of mockAuditEvents) {
309+
// @ts-ignore: accessing a protected method
310+
await audit.setAuditEvent(['node', 'connection', 'forward'], {
311+
// @ts-ignore: protected
312+
id: event.id,
313+
data: {
314+
remoteNodeId: 'asdasd',
315+
remoteHost: '127.0.0.1',
316+
remotePort: 54321,
317+
type: 'forward',
318+
},
319+
path: ['node', 'connection', 'forward'],
320+
});
321+
}
322+
323+
//Pick some value to seek from the mockAuditEvents selected from the mockAuditEvents
324+
let seekIndex = 50;
325+
let seekValueEncoded = auditUtils.encodeAuditEventId(mockAuditEvents[seekIndex].id);
326+
327+
328+
try {
329+
const response = await rpcClient.methods.nodesAuditEventsGet({
330+
seek: seekValueEncoded,
331+
});
332+
333+
// Collect results
334+
const auditIds: Array<string> = [];
335+
for await (const result of response) {
336+
auditIds.push(result.id);
337+
}
338+
339+
//Verify that the results are the same as the mockAuditEvents from the seek value onwards
340+
expect(auditIds).toEqual(
341+
mockAuditEvents.slice(seekIndex + 1).map((event) => auditUtils.encodeAuditEventId(event.id))
342+
);
343+
344+
//Additionally, verify the seek value is exclusive and should be excluded from the results.
345+
expect(auditIds).not.toContain(seekValueEncoded);
346+
347+
348+
} catch (error) {
349+
console.error(error);
350+
throw error;
351+
}
352+
353+
});
354+
355+
test('should get audit events with specific seek at index 0 (exclude the first event)', async () => {
356+
// Generate valid AuditEventIds
357+
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);
358+
359+
// Insert them all
360+
for (const event of mockAuditEvents) {
361+
// @ts-ignore: protected
362+
await audit.setAuditEvent(['node', 'connection', 'forward'], {
363+
// @ts-ignore: protected
364+
id: event.id,
365+
data: {
366+
remoteNodeId: 'asdasd',
367+
remoteHost: '127.0.0.1',
368+
remotePort: 54321,
369+
type: 'forward',
370+
},
371+
path: ['node', 'connection', 'forward'],
372+
});
373+
}
374+
375+
// Seek the event at index 0
376+
const seekIndex = 0;
377+
const seekId = mockAuditEvents[seekIndex].id;
378+
const seekIdEncoded = auditUtils.encodeAuditEventId(seekId);
379+
380+
try {
381+
// Make the RPC call
382+
const response = await rpcClient.methods.nodesAuditEventsGet({
383+
seek: seekIdEncoded,
384+
});
385+
386+
// Collect results
387+
const auditIds: Array<string> = [];
388+
for await (const result of response) {
389+
auditIds.push(result.id);
390+
}
391+
392+
// Expect everything from index 1 onward
393+
// (index 0 is excluded because we said exclusive).
394+
const expectedIds = mockAuditEvents
395+
.slice(seekIndex + 1)
396+
.map((event) => auditUtils.encodeAuditEventId(event.id));
397+
398+
expect(auditIds).toEqual(expectedIds);
399+
// And confirm index 0 is NOT in the list
400+
expect(auditIds).not.toContain(seekIdEncoded);
401+
} catch (error) {
402+
console.error(error);
403+
throw error;
404+
}
405+
});
406+
407+
test('should get audit events with specific seek at index 99 (exclude the last event)', async () => {
408+
// Generate valid AuditEventIds
409+
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);
410+
411+
// Insert them all
412+
for (const event of mockAuditEvents) {
413+
// @ts-ignore: protected
414+
await audit.setAuditEvent(['node', 'connection', 'forward'], {
415+
// @ts-ignore: protected
416+
id: event.id,
417+
data: {
418+
remoteNodeId: 'asdasd',
419+
remoteHost: '127.0.0.1',
420+
remotePort: 54321,
421+
type: 'forward',
422+
},
423+
path: ['node', 'connection', 'forward'],
424+
});
425+
}
426+
427+
// Seek the event at index 99
428+
const seekIndex = 99;
429+
const seekId = mockAuditEvents[seekIndex].id;
430+
const seekIdEncoded = auditUtils.encodeAuditEventId(seekId);
431+
432+
try {
433+
// Make the RPC call
434+
const response = await rpcClient.methods.nodesAuditEventsGet({
435+
seek: seekIdEncoded,
436+
});
437+
438+
// Collect results
439+
const auditIds: Array<string> = [];
440+
for await (const result of response) {
441+
auditIds.push(result.id);
442+
}
443+
444+
// We expect an EMPTY result, because there's nothing after index 99
445+
// (the last event is excluded).
446+
expect(auditIds).toHaveLength(0);
447+
// Confirm that the last event’s ID is not present
448+
expect(auditIds).not.toContain(seekIdEncoded);
449+
} catch (error) {
450+
console.error(error);
451+
throw error;
452+
}
453+
});
454+
455+
456+
268457
});

tests/nodes/agent/handlers/nodesClaimsGet.test.ts

+2
Original file line numberDiff line numberDiff line change
@@ -196,4 +196,6 @@ describe('nodesClaimsGet', () => {
196196
}
197197
expect(chainIds).toHaveLength(10);
198198
});
199+
200+
199201
});

0 commit comments

Comments
 (0)