first commit
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
Security: Sync from Public / sync-from-public (push) Has been cancelled
Test: Benchmark Nightly / build (push) Has been cancelled
Test: Benchmark Nightly / Notify Cats on failure (push) Has been cancelled
CI: Python / Checks (push) Has been cancelled
Test: Evals Python / Workflow Comparison Python (push) Has been cancelled
Util: Check Docs URLs / check-docs-urls (push) Has been cancelled
Test: Visual Storybook / Cloudflare Pages (push) Has been cancelled
Test: E2E Performance / build-and-test-performance (push) Has been cancelled
Test: Workflows Nightly / Run Workflow Tests (push) Has been cancelled
Util: Cleanup CI Docker Images / Delete stale CI images (push) Has been cancelled
Test: Benchmark Destroy Env / build (push) Has been cancelled
Util: Update Node Popularity / update-popularity (push) Has been cancelled
Test: E2E Coverage Weekly / Coverage Tests (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
import { NodeTestHarness } from '@nodes-testing/node-test-harness';
|
||||
import nock from 'nock';
|
||||
|
||||
describe('TheHiveProject', () => {
|
||||
const credentials = {
|
||||
theHiveProjectApi: {
|
||||
url: 'https://thehive.example.com',
|
||||
apiKey: 'test-api-key',
|
||||
},
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
nock.cleanAll();
|
||||
});
|
||||
|
||||
describe('Alert Operations', () => {
|
||||
describe('Create Alert', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock create alert API call
|
||||
mock.post('/api/v1/alert').reply(201, {
|
||||
_id: '~alert123',
|
||||
_type: 'Alert',
|
||||
title: 'Test Alert',
|
||||
description: 'Test alert description',
|
||||
type: 'incident',
|
||||
severity: 2,
|
||||
status: 'New',
|
||||
tags: ['test', 'n8n'],
|
||||
source: 'n8n-test',
|
||||
sourceRef: 'test-ref-001',
|
||||
follow: true,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock load options queries that might be needed
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['alert-create.workflow.json'],
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get Alert', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock get alert API call
|
||||
mock.get('/api/v1/alert/~123456').reply(200, {
|
||||
_id: '~123456',
|
||||
_type: 'Alert',
|
||||
title: 'Test Alert',
|
||||
description: 'Test alert description',
|
||||
type: 'incident',
|
||||
severity: 2,
|
||||
status: 'New',
|
||||
tags: ['test', 'n8n'],
|
||||
source: 'n8n-test',
|
||||
sourceRef: 'test-ref-001',
|
||||
follow: true,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock similar alerts query
|
||||
mock.post('/api/v1/query').reply(200, [
|
||||
{
|
||||
_id: '~alert456',
|
||||
title: 'Similar Alert',
|
||||
},
|
||||
]);
|
||||
|
||||
// Mock alertSearch method for resource locator
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['alert-get.workflow.json'],
|
||||
});
|
||||
});
|
||||
|
||||
describe('Search Alerts', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock search alerts API call with expected query structure
|
||||
mock
|
||||
.post('/api/v1/query', (body) => {
|
||||
return body.query && Array.isArray(body.query);
|
||||
})
|
||||
.reply(200, [
|
||||
{
|
||||
_id: '~alert123',
|
||||
_type: 'Alert',
|
||||
title: 'Test Alert 1',
|
||||
status: 'New',
|
||||
severity: 2,
|
||||
createdAt: 1698753600000,
|
||||
},
|
||||
{
|
||||
_id: '~alert456',
|
||||
_type: 'Alert',
|
||||
title: 'Test Alert 2',
|
||||
status: 'New',
|
||||
severity: 1,
|
||||
createdAt: 1698753660000,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['alert-search.workflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Case Operations', () => {
|
||||
describe('Create Case', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock create case API call
|
||||
mock.post('/api/v1/case').reply(201, {
|
||||
_id: '~123789',
|
||||
_type: 'Case',
|
||||
title: 'Test Case',
|
||||
description: 'Test case description',
|
||||
severity: 2,
|
||||
status: 'Open',
|
||||
tags: ['test', 'n8n'],
|
||||
tlp: 2,
|
||||
pap: 2,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock load options queries
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['case-create.workflow.json'],
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get Case', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock get case API call (via query endpoint)
|
||||
mock
|
||||
.post('/api/v1/query', (body) => {
|
||||
return body.query && body.query[0] && body.query[0]._name === 'getCase';
|
||||
})
|
||||
.query(true)
|
||||
.reply(200, {
|
||||
_id: '~123789',
|
||||
_type: 'Case',
|
||||
title: 'Test Case',
|
||||
description: 'Test case description',
|
||||
severity: 2,
|
||||
status: 'Open',
|
||||
tags: ['test', 'n8n'],
|
||||
tlp: 2,
|
||||
pap: 2,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock caseSearch method for resource locator
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['case-get.workflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Observable Operations', () => {
|
||||
describe('Create Observable', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock create observable API call
|
||||
mock.post('/api/v1/case/~123789/observable').reply(201, {
|
||||
_id: '~456789',
|
||||
_type: 'Observable',
|
||||
data: 'malicious.example.com',
|
||||
dataType: 'domain',
|
||||
message: 'Suspicious domain detected in analysis',
|
||||
tags: ['malware', 'suspicious'],
|
||||
tlp: 2,
|
||||
pap: 2,
|
||||
ioc: true,
|
||||
sighted: false,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock load options for observable types and other queries
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['observable-create.workflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Task Operations', () => {
|
||||
describe('Create Task', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock create task API call
|
||||
mock.post('/api/v1/case/~123789/task').reply(201, {
|
||||
_id: '~654321',
|
||||
_type: 'Task',
|
||||
title: 'Test Task',
|
||||
description: 'Test task description',
|
||||
group: 'Investigation',
|
||||
status: 'Waiting',
|
||||
flag: false,
|
||||
mandatory: true,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock load options queries
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['task-create.workflow.json'],
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get Task', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock get task API call (via query endpoint)
|
||||
mock
|
||||
.post('/api/v1/query', (body) => {
|
||||
return body.query && body.query[0] && body.query[0]._name === 'getTask';
|
||||
})
|
||||
.query(true)
|
||||
.reply(200, {
|
||||
_id: '~654321',
|
||||
_type: 'Task',
|
||||
title: 'Test Task',
|
||||
description: 'Test task description',
|
||||
group: 'Investigation',
|
||||
status: 'Waiting',
|
||||
flag: false,
|
||||
mandatory: true,
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock taskSearch method for resource locator
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['task-get.workflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Comment Operations', () => {
|
||||
describe('Add Comment', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock add comment API call
|
||||
mock.post('/api/v1/case/~123789/comment').reply(201, {
|
||||
_id: '~789123',
|
||||
_type: 'Comment',
|
||||
message: 'This is a test comment for the case',
|
||||
createdAt: 1698753600000,
|
||||
updatedAt: 1698753600000,
|
||||
});
|
||||
|
||||
// Mock load options queries
|
||||
mock.post('/api/v1/query').query(true).reply(200, []);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['comment-add.workflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Query Operations', () => {
|
||||
describe('Execute Query', () => {
|
||||
beforeAll(() => {
|
||||
const mock = nock(credentials.theHiveProjectApi.url);
|
||||
|
||||
// Mock query execution API call
|
||||
mock
|
||||
.post('/api/v1/query', (body) => {
|
||||
return (
|
||||
body.query &&
|
||||
Array.isArray(body.query) &&
|
||||
body.query[0] &&
|
||||
body.query[0]._name === 'listOrganisation'
|
||||
);
|
||||
})
|
||||
.reply(200, [
|
||||
{
|
||||
_id: '~org123',
|
||||
_type: 'Organisation',
|
||||
name: 'Test Organization',
|
||||
description: 'Test organization description',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
new NodeTestHarness().setupTests({
|
||||
credentials,
|
||||
workflowFiles: ['query-execute.workflow.json'],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,554 @@
|
||||
import { testWebhookTriggerNode } from '@test/nodes/TriggerHelpers';
|
||||
import { TheHiveProjectTrigger } from '../TheHiveProjectTrigger.node';
|
||||
|
||||
describe('TheHiveProjectTrigger', () => {
|
||||
describe('Alert Created Event', () => {
|
||||
it('should process alert_create event correctly', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
_id: '~12345',
|
||||
_type: 'Alert',
|
||||
title: 'Test Alert',
|
||||
description: 'Test alert description',
|
||||
severity: '2',
|
||||
date: 1698753600000,
|
||||
tags: ['malware', 'test'],
|
||||
tlp: 2,
|
||||
pap: 2,
|
||||
source: 'n8n-test',
|
||||
sourceRef: 'test-ref-001',
|
||||
follow: true,
|
||||
customFields: {},
|
||||
},
|
||||
organisationId: '~456',
|
||||
organisation: 'TestOrg',
|
||||
requestId: 'test-request-123',
|
||||
};
|
||||
|
||||
const headerData = {
|
||||
'content-type': 'application/json',
|
||||
'user-agent': 'TheHive/5.0',
|
||||
'x-request-id': 'test-request-123',
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
headerData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json).toEqual({
|
||||
event: 'alert_create',
|
||||
body: bodyData,
|
||||
headers: headerData,
|
||||
query: {},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Wildcard Event', () => {
|
||||
it('should process any event with * wildcard', async () => {
|
||||
const bodyData = {
|
||||
action: 'Update',
|
||||
objectType: 'Case',
|
||||
object: {
|
||||
_id: '~67890',
|
||||
_type: 'Case',
|
||||
title: 'Test Case',
|
||||
description: 'Test case description',
|
||||
severity: '1',
|
||||
status: 'Open',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['*'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('case_update');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Filtering', () => {
|
||||
it('should apply equal filter correctly', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
severity: '2',
|
||||
title: 'High Priority Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
filters: {
|
||||
values: [
|
||||
{
|
||||
field: 'object.severity',
|
||||
operator: 'equal',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
});
|
||||
|
||||
it('should filter out events that do not match equal filter', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
severity: '1',
|
||||
title: 'Low Priority Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
filters: {
|
||||
values: [
|
||||
{
|
||||
field: 'object.severity',
|
||||
operator: 'equal',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toEqual({});
|
||||
});
|
||||
|
||||
it('should apply notEqual filter correctly', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
severity: '1',
|
||||
title: 'Low Priority Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
filters: {
|
||||
values: [
|
||||
{
|
||||
field: 'object.severity',
|
||||
operator: 'notEqual',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
});
|
||||
|
||||
it('should apply includes filter correctly', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
title: 'Malware Detection Alert',
|
||||
tags: ['malware', 'detection'],
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
filters: {
|
||||
values: [
|
||||
{
|
||||
field: 'object.title',
|
||||
operator: 'includes',
|
||||
value: 'Malware',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
});
|
||||
|
||||
it('should filter out events that do not match includes filter', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
title: 'Network Alert',
|
||||
tags: ['network', 'monitoring'],
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
filters: {
|
||||
values: [
|
||||
{
|
||||
field: 'object.title',
|
||||
operator: 'includes',
|
||||
value: 'Malware',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Output Options', () => {
|
||||
it('should output only data when outputOnlyData is true', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
_id: '~12345',
|
||||
title: 'Test Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
options: {
|
||||
outputOnlyData: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json).toEqual(bodyData);
|
||||
});
|
||||
|
||||
it('should output full data structure when outputOnlyData is false', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
_id: '~12345',
|
||||
title: 'Test Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
options: {
|
||||
outputOnlyData: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json).toHaveProperty('event', 'alert_create');
|
||||
expect(responseData?.workflowData![0][0].json).toHaveProperty('body', bodyData);
|
||||
expect(responseData?.workflowData![0][0].json).toHaveProperty('headers');
|
||||
expect(responseData?.workflowData![0][0].json).toHaveProperty('query');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Invalid Data Handling', () => {
|
||||
it('should return empty response when action is missing', async () => {
|
||||
const bodyData = {
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
_id: '~12345',
|
||||
title: 'Test Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toEqual({});
|
||||
});
|
||||
|
||||
it('should return empty response when objectType is missing', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
object: {
|
||||
_id: '~12345',
|
||||
title: 'Test Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toEqual({});
|
||||
});
|
||||
|
||||
it('should return empty response when event is not in configured events list', async () => {
|
||||
const bodyData = {
|
||||
action: 'Delete',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
_id: '~12345',
|
||||
title: 'Test Alert',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create', 'alert_update'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple Event Types', () => {
|
||||
it('should process case_create event', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Case',
|
||||
object: {
|
||||
_id: '~case123',
|
||||
_type: 'Case',
|
||||
title: 'Test Case',
|
||||
description: 'Test case description',
|
||||
severity: '1',
|
||||
status: 'Open',
|
||||
tags: ['investigation'],
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['case_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('case_create');
|
||||
});
|
||||
|
||||
it('should process task_create event', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Task',
|
||||
object: {
|
||||
_id: '~task456',
|
||||
_type: 'Task',
|
||||
title: 'Investigate Alert',
|
||||
description: 'Investigate the suspicious activity',
|
||||
status: 'InProgress',
|
||||
assignee: 'analyst@company.com',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['task_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('task_create');
|
||||
});
|
||||
|
||||
it('should process observable_create event', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Observable',
|
||||
object: {
|
||||
_id: '~observable789',
|
||||
_type: 'Observable',
|
||||
dataType: 'ip',
|
||||
data: '192.168.1.100',
|
||||
message: 'Suspicious IP address',
|
||||
tlp: 2,
|
||||
ioc: true,
|
||||
tags: ['malicious', 'c2'],
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['observable_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('observable_create');
|
||||
});
|
||||
|
||||
it('should process comment_create event', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Comment',
|
||||
object: {
|
||||
_id: '~comment101',
|
||||
_type: 'Comment',
|
||||
message: 'This requires immediate attention',
|
||||
createdBy: 'analyst@company.com',
|
||||
createdAt: 1698753600000,
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['comment_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('comment_create');
|
||||
});
|
||||
|
||||
it('should process log_create event', async () => {
|
||||
const bodyData = {
|
||||
action: 'Create',
|
||||
objectType: 'Log',
|
||||
object: {
|
||||
_id: '~log202',
|
||||
_type: 'Log',
|
||||
message: 'Investigation completed',
|
||||
status: 'Success',
|
||||
attachment: {
|
||||
name: 'report.pdf',
|
||||
id: 'attachment123',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['log_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('log_create');
|
||||
});
|
||||
|
||||
it('should process multiple configured events', async () => {
|
||||
const bodyData = {
|
||||
action: 'Update',
|
||||
objectType: 'Alert',
|
||||
object: {
|
||||
_id: '~alert303',
|
||||
title: 'Updated Alert',
|
||||
status: 'Imported',
|
||||
},
|
||||
};
|
||||
|
||||
const { responseData } = await testWebhookTriggerNode(TheHiveProjectTrigger, {
|
||||
node: {
|
||||
parameters: {
|
||||
events: ['alert_create', 'alert_update', 'case_create'],
|
||||
},
|
||||
},
|
||||
request: { method: 'POST' },
|
||||
bodyData,
|
||||
});
|
||||
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData?.workflowData![0][0].json.event).toBe('alert_update');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "TheHive Alert Create Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "alert",
|
||||
"operation": "create",
|
||||
"alertFields": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"title": "Test Alert",
|
||||
"description": "Test alert description",
|
||||
"type": "incident",
|
||||
"source": "n8n-test",
|
||||
"sourceRef": "test-ref-001",
|
||||
"severity": 2,
|
||||
"tags": "test,n8n",
|
||||
"follow": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Alert Create",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Alert Create": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~alert123",
|
||||
"_type": "Alert",
|
||||
"title": "Test Alert",
|
||||
"description": "Test alert description",
|
||||
"type": "incident",
|
||||
"severity": 2,
|
||||
"status": "New",
|
||||
"tags": ["test", "n8n"],
|
||||
"source": "n8n-test",
|
||||
"sourceRef": "test-ref-001",
|
||||
"follow": true,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Alert Create",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "TheHive Alert Get Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "alert",
|
||||
"operation": "get",
|
||||
"alertId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "~123456"
|
||||
},
|
||||
"options": {
|
||||
"includeSimilarAlerts": true
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Alert Get",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Alert Get": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~123456",
|
||||
"_type": "Alert",
|
||||
"title": "Test Alert",
|
||||
"description": "Test alert description",
|
||||
"type": "incident",
|
||||
"severity": 2,
|
||||
"status": "New",
|
||||
"tags": ["test", "n8n"],
|
||||
"source": "n8n-test",
|
||||
"sourceRef": "test-ref-001",
|
||||
"follow": true,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000,
|
||||
"similarAlerts": [
|
||||
{
|
||||
"_id": "~alert456",
|
||||
"title": "Similar Alert"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Alert Get",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "TheHive Alert Search Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "alert",
|
||||
"operation": "search",
|
||||
"returnAll": false,
|
||||
"limit": 10,
|
||||
"filters": {
|
||||
"values": [
|
||||
{
|
||||
"field": "status",
|
||||
"operator": "_eq",
|
||||
"value": "New"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Alert Search",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Alert Search": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~alert123",
|
||||
"_type": "Alert",
|
||||
"title": "Test Alert 1",
|
||||
"status": "New",
|
||||
"severity": 2,
|
||||
"createdAt": 1698753600000
|
||||
}
|
||||
},
|
||||
{
|
||||
"json": {
|
||||
"_id": "~alert456",
|
||||
"_type": "Alert",
|
||||
"title": "Test Alert 2",
|
||||
"status": "New",
|
||||
"severity": 1,
|
||||
"createdAt": 1698753660000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Alert Search",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "TheHive Case Create Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "case",
|
||||
"operation": "create",
|
||||
"caseFields": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"title": "Test Case",
|
||||
"description": "Test case description",
|
||||
"severity": 2,
|
||||
"tags": "test,n8n",
|
||||
"tlp": 2,
|
||||
"pap": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Case Create",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Case Create": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~123789",
|
||||
"_type": "Case",
|
||||
"title": "Test Case",
|
||||
"description": "Test case description",
|
||||
"severity": 2,
|
||||
"status": "Open",
|
||||
"tags": ["test", "n8n"],
|
||||
"tlp": 2,
|
||||
"pap": 2,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Case Create",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
{
|
||||
"name": "TheHive Case Get Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "case",
|
||||
"operation": "get",
|
||||
"caseId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "~123789"
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Case Get",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Case Get": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~123789",
|
||||
"_type": "Case",
|
||||
"title": "Test Case",
|
||||
"description": "Test case description",
|
||||
"severity": 2,
|
||||
"status": "Open",
|
||||
"tags": ["test", "n8n"],
|
||||
"tlp": 2,
|
||||
"pap": 2,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Case Get",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "TheHive Comment Add Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "comment",
|
||||
"operation": "add",
|
||||
"addTo": "case",
|
||||
"id": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "~123789"
|
||||
},
|
||||
"message": "This is a test comment for the case"
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Comment Add",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Comment Add": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~789123",
|
||||
"_type": "Comment",
|
||||
"message": "This is a test comment for the case",
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Comment Add",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"name": "TheHive Observable Create Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "observable",
|
||||
"operation": "create",
|
||||
"createIn": "case",
|
||||
"id": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "~123789"
|
||||
},
|
||||
"dataType": "domain",
|
||||
"data": "malicious.example.com",
|
||||
"observableFields": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"message": "Suspicious domain detected in analysis",
|
||||
"tags": "malware,suspicious",
|
||||
"tlp": 2,
|
||||
"pap": 2,
|
||||
"ioc": true,
|
||||
"sighted": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Observable Create",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Observable Create": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~456789",
|
||||
"_type": "Observable",
|
||||
"data": "malicious.example.com",
|
||||
"dataType": "domain",
|
||||
"message": "Suspicious domain detected in analysis",
|
||||
"tags": ["malware", "suspicious"],
|
||||
"tlp": 2,
|
||||
"pap": 2,
|
||||
"ioc": true,
|
||||
"sighted": false,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Observable Create",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "TheHive Query Execute Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "query",
|
||||
"operation": "executeQuery",
|
||||
"queryJson": "[\n {\n \"_name\": \"listOrganisation\"\n }\n]"
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Query Execute",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Query Execute": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~org123",
|
||||
"_type": "Organisation",
|
||||
"name": "Test Organization",
|
||||
"description": "Test organization description"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Query Execute",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
{
|
||||
"name": "TheHive Task Create Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "task",
|
||||
"operation": "create",
|
||||
"caseId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "~123789"
|
||||
},
|
||||
"taskFields": {
|
||||
"mappingMode": "defineBelow",
|
||||
"value": {
|
||||
"title": "Test Task",
|
||||
"description": "Test task description",
|
||||
"group": "Investigation",
|
||||
"flag": false,
|
||||
"mandatory": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Task Create",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Task Create": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~654321",
|
||||
"_type": "Task",
|
||||
"title": "Test Task",
|
||||
"description": "Test task description",
|
||||
"group": "Investigation",
|
||||
"status": "Waiting",
|
||||
"flag": false,
|
||||
"mandatory": true,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Task Create",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "TheHive Task Get Test Workflow",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {},
|
||||
"type": "n8n-nodes-base.manualTrigger",
|
||||
"typeVersion": 1,
|
||||
"position": [0, 0],
|
||||
"id": "manual-trigger",
|
||||
"name": "When clicking 'Execute Workflow'"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"resource": "task",
|
||||
"operation": "get",
|
||||
"taskId": {
|
||||
"__rl": true,
|
||||
"mode": "id",
|
||||
"value": "~654321"
|
||||
}
|
||||
},
|
||||
"type": "n8n-nodes-base.theHiveProject",
|
||||
"typeVersion": 1,
|
||||
"position": [200, 0],
|
||||
"id": "thehive-node",
|
||||
"name": "TheHive Task Get",
|
||||
"credentials": {
|
||||
"theHiveProjectApi": {
|
||||
"id": "thehive-creds",
|
||||
"name": "TheHive API Credentials"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"TheHive Task Get": [
|
||||
{
|
||||
"json": {
|
||||
"_id": "~654321",
|
||||
"_type": "Task",
|
||||
"title": "Test Task",
|
||||
"description": "Test task description",
|
||||
"group": "Investigation",
|
||||
"status": "Waiting",
|
||||
"flag": false,
|
||||
"mandatory": true,
|
||||
"createdAt": 1698753600000,
|
||||
"updatedAt": 1698753600000
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"When clicking 'Execute Workflow'": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "TheHive Task Get",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": false,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
import type { IExecuteFunctions } from 'n8n-workflow';
|
||||
|
||||
import { theHiveApiQuery } from '../transport/queryHelper';
|
||||
import * as transport from '../transport/requestApi';
|
||||
|
||||
jest.mock('../transport/requestApi', () => {
|
||||
const originalModule = jest.requireActual('../transport/requestApi');
|
||||
return {
|
||||
...originalModule,
|
||||
theHiveApiRequest: jest.fn(async function () {
|
||||
return {};
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const fakeExecuteFunction = {} as unknown as IExecuteFunctions;
|
||||
|
||||
describe('Test TheHiveProject, theHiveApiQuery', () => {
|
||||
it('should make list query request', async () => {
|
||||
const scope = {
|
||||
query: 'listOrganisationPage',
|
||||
};
|
||||
const filtersValues = [
|
||||
{
|
||||
field: 'title',
|
||||
operator: '_like',
|
||||
value: 'Test',
|
||||
},
|
||||
];
|
||||
const sortFields = [
|
||||
{
|
||||
field: 'title',
|
||||
direction: 'asc',
|
||||
},
|
||||
];
|
||||
const limit = undefined;
|
||||
const returnCount = false;
|
||||
|
||||
await theHiveApiQuery.call(
|
||||
fakeExecuteFunction,
|
||||
scope,
|
||||
filtersValues,
|
||||
sortFields,
|
||||
limit,
|
||||
returnCount,
|
||||
);
|
||||
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledTimes(1);
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledWith('POST', '/v1/query', {
|
||||
query: [
|
||||
{ _name: 'listOrganisationPage' },
|
||||
{ _and: [{ _like: { _field: 'title', _value: 'Test' } }], _name: 'filter' },
|
||||
{ _fields: [{ title: 'asc' }], _name: 'sort' },
|
||||
{ _name: 'page', extraData: undefined, from: 0, to: 500 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should make get query request', async () => {
|
||||
const scope = {
|
||||
query: 'getTask',
|
||||
id: '~368644136',
|
||||
restrictTo: 'logs',
|
||||
};
|
||||
const filtersValues = [
|
||||
{
|
||||
field: 'message',
|
||||
operator: '_like',
|
||||
value: 'Test',
|
||||
},
|
||||
{
|
||||
field: 'date',
|
||||
operator: '_gt',
|
||||
value: 1687263671915,
|
||||
},
|
||||
];
|
||||
const sortFields = [
|
||||
{
|
||||
field: 'message',
|
||||
direction: 'desc',
|
||||
},
|
||||
];
|
||||
const limit = undefined;
|
||||
const returnCount = false;
|
||||
const extraData = ['taskId', 'case'];
|
||||
|
||||
await theHiveApiQuery.call(
|
||||
fakeExecuteFunction,
|
||||
scope,
|
||||
filtersValues,
|
||||
sortFields,
|
||||
limit,
|
||||
returnCount,
|
||||
extraData,
|
||||
);
|
||||
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledTimes(2);
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledWith('POST', '/v1/query', {
|
||||
query: [
|
||||
{ _name: 'getTask', idOrName: '~368644136' },
|
||||
{ _name: 'logs' },
|
||||
{
|
||||
_and: [
|
||||
{ _like: { _field: 'message', _value: 'Test' } },
|
||||
{ _gt: { _field: 'date', _value: 1687263671915 } },
|
||||
],
|
||||
_name: 'filter',
|
||||
},
|
||||
{ _fields: [{ message: 'desc' }], _name: 'sort' },
|
||||
{ _name: 'page', extraData: ['taskId', 'case'], from: 0, to: 500 },
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('should make return count query request', async () => {
|
||||
const scope = {
|
||||
query: 'listOrganisationPage',
|
||||
};
|
||||
const returnCount = true;
|
||||
|
||||
await theHiveApiQuery.call(
|
||||
fakeExecuteFunction,
|
||||
scope,
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
returnCount,
|
||||
);
|
||||
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledTimes(3);
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledWith('POST', '/v1/query', {
|
||||
query: [{ _name: 'listOrganisationPage' }, { _name: 'count' }],
|
||||
});
|
||||
});
|
||||
|
||||
it('should set limit to query request', async () => {
|
||||
const scope = {
|
||||
query: 'listOrganisationPage',
|
||||
};
|
||||
|
||||
const limit = 15;
|
||||
|
||||
await theHiveApiQuery.call(fakeExecuteFunction, scope, undefined, undefined, limit);
|
||||
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledTimes(4);
|
||||
expect(transport.theHiveApiRequest).toHaveBeenCalledWith('POST', '/v1/query', {
|
||||
query: [
|
||||
{ _name: 'listOrganisationPage' },
|
||||
{ _name: 'page', extraData: undefined, from: 0, to: 15 },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,179 @@
|
||||
import { splitAndTrim, fixFieldType, prepareInputItem, constructFilter } from '../helpers/utils';
|
||||
|
||||
describe('Test TheHiveProject, splitAndTrim', () => {
|
||||
it('should split and trim string, removing empty entries', () => {
|
||||
const data = 'a, b,, c, d, e, f,,';
|
||||
|
||||
const result = splitAndTrim(data);
|
||||
|
||||
expect(result).toEqual(['a', 'b', 'c', 'd', 'e', 'f']);
|
||||
});
|
||||
|
||||
it('should return unchanged array', () => {
|
||||
const data = ['a', 'b', 'c', 'd', 'e', 'f'];
|
||||
|
||||
const result = splitAndTrim(data);
|
||||
|
||||
expect(result).toEqual(data);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test TheHiveProject, fixFieldType', () => {
|
||||
it('should split and trim tags', () => {
|
||||
const data = {
|
||||
tags: 'a, b,, c, d, e, f,,',
|
||||
addTags: 'a, b,, c, d, e, f,,',
|
||||
removeTags: 'a, b,, c, d, e, f,,',
|
||||
notChanged: 'a, b,, c, d, e, f,,',
|
||||
};
|
||||
|
||||
const result = fixFieldType(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
tags: ['a', 'b', 'c', 'd', 'e', 'f'],
|
||||
addTags: ['a', 'b', 'c', 'd', 'e', 'f'],
|
||||
removeTags: ['a', 'b', 'c', 'd', 'e', 'f'],
|
||||
notChanged: 'a, b,, c, d, e, f,,',
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert date strings to milis', () => {
|
||||
const data = {
|
||||
date: '2020-01-01T00:00:00.000Z',
|
||||
lastSyncDate: '2020-01-01T00:00:00.000Z',
|
||||
startDate: '2020-01-01T00:00:00.000Z',
|
||||
endDate: '2020-01-01T00:00:00.000Z',
|
||||
dueDate: '2020-01-01T00:00:00.000Z',
|
||||
includeInTimeline: '2020-01-01T00:00:00.000Z',
|
||||
sightedAt: '2020-01-01T00:00:00.000Z',
|
||||
notChanged: '2020-01-01T00:00:00.000Z',
|
||||
};
|
||||
|
||||
const result = fixFieldType(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
date: 1577836800000,
|
||||
lastSyncDate: 1577836800000,
|
||||
startDate: 1577836800000,
|
||||
endDate: 1577836800000,
|
||||
dueDate: 1577836800000,
|
||||
includeInTimeline: 1577836800000,
|
||||
sightedAt: 1577836800000,
|
||||
notChanged: '2020-01-01T00:00:00.000Z',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test TheHiveProject, prepareInputItem', () => {
|
||||
it('should return object with fields present in schema', () => {
|
||||
const data = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
f: 5,
|
||||
g: 6,
|
||||
};
|
||||
|
||||
const schema = [
|
||||
{
|
||||
id: 'a',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'c',
|
||||
},
|
||||
{
|
||||
id: 'd',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'e',
|
||||
},
|
||||
];
|
||||
|
||||
const result = prepareInputItem(data, schema, 0);
|
||||
|
||||
expect(result).toEqual({
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test TheHiveProject, constructFilter', () => {
|
||||
it('should add default operator _eq', () => {
|
||||
const data = {
|
||||
field: 'myField',
|
||||
value: 'myValue',
|
||||
};
|
||||
|
||||
const result = constructFilter(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
_eq: {
|
||||
_field: 'myField',
|
||||
_value: 'myValue',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return filter _gte', () => {
|
||||
const data = {
|
||||
field: 'myField',
|
||||
value: 'myValue',
|
||||
operator: '_gte',
|
||||
};
|
||||
|
||||
const result = constructFilter(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
_gte: {
|
||||
_field: 'myField',
|
||||
_value: 'myValue',
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return filter _in', () => {
|
||||
const data = {
|
||||
field: 'myField',
|
||||
values: 'a, b,, c, d',
|
||||
operator: '_in',
|
||||
};
|
||||
|
||||
const result = constructFilter(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
_in: {
|
||||
_field: 'myField',
|
||||
_values: ['a', 'b', 'c', 'd'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('should return filter _between', () => {
|
||||
const data = {
|
||||
field: 'myField',
|
||||
from: 'a',
|
||||
to: 'b',
|
||||
operator: '_between',
|
||||
};
|
||||
|
||||
const result = constructFilter(data);
|
||||
|
||||
expect(result).toEqual({
|
||||
_between: {
|
||||
_field: 'myField',
|
||||
_from: 'a',
|
||||
_to: 'b',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user