Skip to content

Commit

Permalink
feat: added additional tests for NodesAuditEventsGet
Browse files Browse the repository at this point in the history
fix: fixed rpc handler to decode input if id before passing it in
  • Loading branch information
CDeltakai committed Feb 21, 2025
1 parent 14f63d7 commit ef13883
Show file tree
Hide file tree
Showing 6 changed files with 225 additions and 17 deletions.
1 change: 1 addition & 0 deletions src/PolykeyAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,7 @@ class PolykeyAgent {
port: optionsDefaulted.agentServicePort,
ipv6Only: optionsDefaulted.ipv6Only,
agentService: agentServerManifest({
audit: this.audit,
acl: this.acl,
db: this.db,
keyRing: this.keyRing,
Expand Down
16 changes: 15 additions & 1 deletion src/nodes/agent/handlers/NodesAuditEventsGet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ class NodesAuditEventsGet extends ServerHandler<
_meta: Record<string, JSONValue> | undefined,
ctx: ContextTimed,
): AsyncGenerator<AgentRPCResponseResult<AgentAuditMessage<AuditEvent>>> {
const { seek, seekEnd, limit } = input;
let { seek, seekEnd, limit } = input;
if (typeof seek !== 'number') {
seek = auditUtils.decodeAuditEventId(seek);
}
if (typeof seekEnd !== 'number') {
seekEnd = auditUtils.decodeAuditEventId(seekEnd);
}

const { audit, db }: { audit: Audit; db: DB } = this.container;

yield* db.withTransactionG(async function* (tran): AsyncGenerator<
Expand All @@ -45,6 +52,13 @@ class NodesAuditEventsGet extends ServerHandler<
tran,
)) {
ctx.signal.throwIfAborted();
// Skip the seek event to ensure exclusivity if given an AuditEventId
// This assumes that ids are unique
if (seek !== undefined) {
if (typeof seek !== 'number' && auditEvent.id.equals(seek)) {
continue;
}
}
yield {
id: auditUtils.encodeAuditEventId(auditEvent.id),
path: auditEvent.path,
Expand Down
2 changes: 2 additions & 0 deletions src/nodes/agent/handlers/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DB } from '@matrixai/db';
import type Logger from '@matrixai/logger';
import type KeyRing from '../../../keys/KeyRing';
import type Audit from '../../../audit/Audit';
import type Sigchain from '../../../sigchain/Sigchain';
import type ACL from '../../../acl/ACL';
import type NodeGraph from '../../../nodes/NodeGraph';
Expand All @@ -25,6 +26,7 @@ import VaultsScan from './VaultsScan';
* Server manifest factory.
*/
const manifestServer = (container: {
audit: Audit;
db: DB;
sigchain: Sigchain;
nodeGraph: NodeGraph;
Expand Down
4 changes: 2 additions & 2 deletions src/nodes/agent/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ type AgentRPCResponseResult<T extends JSONObject = JSONObject> =
JSONRPCResponseResult<T>;

type AuditIdMessage = {
seek?: AuditEventId | number;
seekEnd?: AuditEventId | number;
seek?: AuditEventIdEncoded | number;
seekEnd?: AuditEventIdEncoded | number;
order?: 'asc' | 'desc';
limit?: number;
};
Expand Down
217 changes: 203 additions & 14 deletions tests/nodes/agent/handlers/nodesAuditsGet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import Logger, { LogLevel, StreamHandler } from '@matrixai/logger';
import { QUICClient, QUICServer, events as quicEvents } from '@matrixai/quic';
import { DB } from '@matrixai/db';
import { RPCClient, RPCServer } from '@matrixai/rpc';
import { IdInternal } from '@matrixai/id';
import NodesAuditEventsGet from '@/nodes/agent/handlers/NodesAuditEventsGet';
import { nodesAuditEventsGet } from '@/nodes/agent/callers';
import * as nodesUtils from '@/nodes/utils';
Expand All @@ -18,7 +17,6 @@ import Audit from '@/audit/Audit';
import * as keysUtils from '@/keys/utils';
import * as networkUtils from '@/network/utils';
import * as auditUtils from '@/audit/utils';
import { TopicPath } from '@/audit/types';
import * as tlsTestsUtils from '../../../utils/tls';
import * as testNodesUtils from '../../../nodes/utils';

Expand Down Expand Up @@ -209,7 +207,7 @@ function generateMockAuditEvents(

test('should get audit events', async () => {
// Generate valid AuditEventIds
const mockAuditEvents = generateMockAuditEvents(200, callProtectedGenerateAuditEventId);
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);

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

try {
console.log('attempt rpc call');
const response = await rpcClient.methods.nodesAuditEventsGet({
seek: seekValue,
seekEnd: seekEndVal,
//limit: limitVal,
});

// Collect results
Expand All @@ -246,23 +241,217 @@ function generateMockAuditEvents(
auditIds.push(result.id);
}

console.log(auditIds);

const mappedMockedAuditEvents = mockAuditEvents.map((event) => auditUtils.encodeAuditEventId(event.id))
console.log(mappedMockedAuditEvents);

// Verify all events were returned with correct encoded IDs
//expect(auditIds).toHaveLength(limitVal);

//Check if the audits grabbed from the rpc handler is the same as the generated audits from mockAuditEvents
expect(auditIds).toEqual(
mappedMockedAuditEvents
);
} catch (error) {
// console.log('error');
// console.error(error);

throw error;
}
});

test('should get audit events with limit', async () => {
// Generate valid AuditEventIds
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);

// Add events with correct topicPath and full path in event data
for (const event of mockAuditEvents) {
// @ts-ignore: accessing a protected method
await audit.setAuditEvent(['node', 'connection', 'forward'], {
// @ts-ignore: protected
id: event.id,
data: {
remoteNodeId: 'asdasd',
remoteHost: '127.0.0.1',
remotePort: 54321,
type: 'forward',
},
path: ['node', 'connection', 'forward'],
});
}
//Parameters
let seekValue = 0;
let seekEndVal = Date.now();
let limitVal = 50;

try {
const response = await rpcClient.methods.nodesAuditEventsGet({
seek: seekValue,
seekEnd: seekEndVal,
limit: limitVal,
});

// Collect results
const auditIds: Array<string> = [];
for await (const result of response) {
auditIds.push(result.id);
}

// Verify that the number of events returned is equal to the limit
expect(auditIds).toHaveLength(limitVal);

} catch (error) {

throw error;
}
});


test('should get audit events with specific seek = 50', async () => {
// Generate valid AuditEventIds
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);

// Add events with correct topicPath and full path in event data
for (const event of mockAuditEvents) {
// @ts-ignore: accessing a protected method
await audit.setAuditEvent(['node', 'connection', 'forward'], {
// @ts-ignore: protected
id: event.id,
data: {
remoteNodeId: 'asdasd',
remoteHost: '127.0.0.1',
remotePort: 54321,
type: 'forward',
},
path: ['node', 'connection', 'forward'],
});
}

//Pick some value to seek from the mockAuditEvents selected from the mockAuditEvents
let seekIndex = 50;
let seekValueEncoded = auditUtils.encodeAuditEventId(mockAuditEvents[seekIndex].id);


try {
const response = await rpcClient.methods.nodesAuditEventsGet({
seek: seekValueEncoded,
});

// Collect results
const auditIds: Array<string> = [];
for await (const result of response) {
auditIds.push(result.id);
}

//Verify that the results are the same as the mockAuditEvents from the seek value onwards
expect(auditIds).toEqual(
mockAuditEvents.slice(seekIndex + 1).map((event) => auditUtils.encodeAuditEventId(event.id))
);

//Additionally, verify the seek value is exclusive and should be excluded from the results.
expect(auditIds).not.toContain(seekValueEncoded);


} catch (error) {
console.error(error);
throw error;
}

});

test('should get audit events with specific seek at index 0 (exclude the first event)', async () => {
// Generate valid AuditEventIds
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);

// Insert them all
for (const event of mockAuditEvents) {
// @ts-ignore: protected
await audit.setAuditEvent(['node', 'connection', 'forward'], {
// @ts-ignore: protected
id: event.id,
data: {
remoteNodeId: 'asdasd',
remoteHost: '127.0.0.1',
remotePort: 54321,
type: 'forward',
},
path: ['node', 'connection', 'forward'],
});
}

// Seek the event at index 0
const seekIndex = 0;
const seekId = mockAuditEvents[seekIndex].id;
const seekIdEncoded = auditUtils.encodeAuditEventId(seekId);

try {
// Make the RPC call
const response = await rpcClient.methods.nodesAuditEventsGet({
seek: seekIdEncoded,
});

// Collect results
const auditIds: Array<string> = [];
for await (const result of response) {
auditIds.push(result.id);
}

// Expect everything from index 1 onward
// (index 0 is excluded because we said exclusive).
const expectedIds = mockAuditEvents
.slice(seekIndex + 1)
.map((event) => auditUtils.encodeAuditEventId(event.id));

expect(auditIds).toEqual(expectedIds);
// And confirm index 0 is NOT in the list
expect(auditIds).not.toContain(seekIdEncoded);
} catch (error) {
console.error(error);
throw error;
}
});

test('should get audit events with specific seek at index 99 (exclude the last event)', async () => {
// Generate valid AuditEventIds
const mockAuditEvents = generateMockAuditEvents(100, callProtectedGenerateAuditEventId);

// Insert them all
for (const event of mockAuditEvents) {
// @ts-ignore: protected
await audit.setAuditEvent(['node', 'connection', 'forward'], {
// @ts-ignore: protected
id: event.id,
data: {
remoteNodeId: 'asdasd',
remoteHost: '127.0.0.1',
remotePort: 54321,
type: 'forward',
},
path: ['node', 'connection', 'forward'],
});
}

// Seek the event at index 99
const seekIndex = 99;
const seekId = mockAuditEvents[seekIndex].id;
const seekIdEncoded = auditUtils.encodeAuditEventId(seekId);

try {
// Make the RPC call
const response = await rpcClient.methods.nodesAuditEventsGet({
seek: seekIdEncoded,
});

// Collect results
const auditIds: Array<string> = [];
for await (const result of response) {
auditIds.push(result.id);
}

// We expect an EMPTY result, because there's nothing after index 99
// (the last event is excluded).
expect(auditIds).toHaveLength(0);
// Confirm that the last event’s ID is not present
expect(auditIds).not.toContain(seekIdEncoded);
} catch (error) {
console.error(error);
throw error;
}
});



});
2 changes: 2 additions & 0 deletions tests/nodes/agent/handlers/nodesClaimsGet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,4 +196,6 @@ describe('nodesClaimsGet', () => {
}
expect(chainIds).toHaveLength(10);
});


});

0 comments on commit ef13883

Please sign in to comment.