Skip to content

Commit 3a6c0c2

Browse files
[backend] Playbook : added filter to Promote Observable to Indicator Component (#14283)
1 parent e4fc703 commit 3a6c0c2

1 file changed

Lines changed: 98 additions & 0 deletions

File tree

opencti-platform/opencti-graphql/tests/03-integration/01-database/playbookComponents/create-observable-component-test.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,5 +253,103 @@ describe('PLAYBOOK_CREATE_OBSERVABLE_COMPONENT', () => {
253253
expect(result.bundle.objects.filter((o) => o.type === 'domain-name').length).toEqual(0);
254254
expect(result.bundle.objects.filter((o) => o.type === 'ipv4-addr').length).toEqual(0);
255255
});
256+
257+
it('should extract observables only from filtered indicators when applyToElements = "all-elements" and filter matches partial bundle', async () => {
258+
const THIRD_INDICATOR_ID = 'indicator--7a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d';
259+
const bundleObjects = [
260+
testBundleObject<StixIndicator>({
261+
id: MAIN_INDICATOR_ID,
262+
type: 'indicator',
263+
octiExtension: { type: 'Indicator' },
264+
pattern: "[domain-name:value = 'example.org']",
265+
}),
266+
testBundleObject<StixIndicator>({
267+
id: SECOND_INDICATOR_ID,
268+
type: 'indicator',
269+
octiExtension: { type: 'Indicator' },
270+
pattern: "[ipv4-addr:value = '8.8.8.8']",
271+
}),
272+
testBundleObject({
273+
id: THIRD_INDICATOR_ID,
274+
type: 'Malware',
275+
}),
276+
];
277+
278+
const filterIndicator = '{"mode":"and","filters":[{"key":["entity_type"],"operator":"eq","values":["Indicator"],"mode":"or"}],"filterGroups":[]}';
279+
280+
const result = await PLAYBOOK_CREATE_OBSERVABLE_COMPONENT.executor(testExecutor({
281+
mainId: MAIN_INDICATOR_ID,
282+
bundleObjects,
283+
configuration: {
284+
applyToElements: playbookBundleElementsToApply.allElements.value,
285+
applyWithFilters: filterIndicator,
286+
wrap_in_container: false,
287+
},
288+
}));
289+
290+
// Only the 2 indicators matched the filter, Malware is ignored
291+
// 2 observables + 2 relationships added = 3 original + 4 new = 7
292+
expect(result.output_port).toBe('out');
293+
expect(result.bundle.objects.length).toEqual(7);
294+
295+
const relationships = result.bundle.objects.filter((o) => o.type === 'relationship') as unknown as StixRelation[];
296+
expect(relationships.filter((r) => r.source_ref === MAIN_INDICATOR_ID).length).toEqual(1);
297+
expect(relationships.filter((r) => r.source_ref === SECOND_INDICATOR_ID).length).toEqual(1);
298+
299+
// Malware did not produce any observable
300+
expect(result.bundle.objects.filter((o) => o.type === 'domain-name').length).toEqual(1);
301+
expect(result.bundle.objects.filter((o) => o.type === 'ipv4-addr').length).toEqual(1);
302+
});
303+
304+
it('should extract observables only from filtered indicators except main when applyToElements = "all-except-main" and filter matches partial bundle', async () => {
305+
const THIRD_INDICATOR_ID = 'indicator--7a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d';
306+
const bundleObjects = [
307+
testBundleObject<StixIndicator>({
308+
id: MAIN_INDICATOR_ID,
309+
type: 'indicator',
310+
octiExtension: { type: 'Indicator' },
311+
pattern: "[domain-name:value = 'example.org']",
312+
}),
313+
testBundleObject<StixIndicator>({
314+
id: SECOND_INDICATOR_ID,
315+
type: 'indicator',
316+
octiExtension: { type: 'Indicator' },
317+
pattern: "[ipv4-addr:value = '8.8.8.8']",
318+
}),
319+
testBundleObject({
320+
id: THIRD_INDICATOR_ID,
321+
type: 'Malware',
322+
}),
323+
];
324+
325+
const filterIndicator = '{"mode":"and","filters":[{"key":["entity_type"],"operator":"eq","values":["Indicator"],"mode":"or"}],"filterGroups":[]}';
326+
327+
const result = await PLAYBOOK_CREATE_OBSERVABLE_COMPONENT.executor(testExecutor({
328+
mainId: MAIN_INDICATOR_ID,
329+
bundleObjects,
330+
configuration: {
331+
applyToElements: playbookBundleElementsToApply.allExceptMain.value,
332+
applyWithFilters: filterIndicator,
333+
wrap_in_container: false,
334+
},
335+
}));
336+
337+
// Filter matches both indicators but applyToElements excludes main:
338+
// only SECOND_INDICATOR processed, Malware ignored
339+
// 1 observable + 1 relationship added = 3 original + 2 new = 5
340+
expect(result.output_port).toBe('out');
341+
expect(result.bundle.objects.length).toEqual(5);
342+
343+
const relationships = result.bundle.objects.filter((o) => o.type === 'relationship') as unknown as StixRelation[];
344+
expect(relationships.filter((r) => r.source_ref === MAIN_INDICATOR_ID).length).toEqual(0);
345+
expect(relationships.filter((r) => r.source_ref === SECOND_INDICATOR_ID).length).toEqual(1);
346+
347+
// Main indicator did not produce any observable
348+
expect(result.bundle.objects.filter((o) => o.type === 'domain-name').length).toEqual(0);
349+
// Second indicator produced its observable
350+
expect(result.bundle.objects.filter((o) => o.type === 'ipv4-addr').length).toEqual(1);
351+
// Malware did not produce any observable
352+
expect(result.bundle.objects.filter((o) => o.type === 'Malware').length).toEqual(1);
353+
});
256354
});
257355
});

0 commit comments

Comments
 (0)