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

This commit is contained in:
2026-03-17 16:22:57 +03:30
commit 3d5eaf9445
15349 changed files with 2847338 additions and 0 deletions
@@ -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',
},
});
});
});