@@ -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