synapse 2.192.0__py311-none-any.whl → 2.194.0__py311-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse might be problematic. Click here for more details.
- synapse/common.py +15 -0
- synapse/cortex.py +19 -25
- synapse/datamodel.py +6 -3
- synapse/exc.py +6 -1
- synapse/lib/agenda.py +17 -6
- synapse/lib/ast.py +242 -97
- synapse/lib/auth.py +1 -0
- synapse/lib/cell.py +31 -85
- synapse/lib/cli.py +20 -11
- synapse/lib/parser.py +5 -1
- synapse/lib/snap.py +44 -15
- synapse/lib/storm.lark +16 -1
- synapse/lib/storm.py +40 -21
- synapse/lib/storm_format.py +1 -0
- synapse/lib/stormctrl.py +88 -6
- synapse/lib/stormlib/cache.py +6 -2
- synapse/lib/stormlib/json.py +5 -2
- synapse/lib/stormlib/scrape.py +1 -1
- synapse/lib/stormlib/stix.py +8 -8
- synapse/lib/stormtypes.py +32 -5
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +20 -3
- synapse/models/geopol.py +1 -0
- synapse/models/geospace.py +1 -0
- synapse/models/inet.py +20 -1
- synapse/models/infotech.py +24 -6
- synapse/models/orgs.py +7 -2
- synapse/models/person.py +15 -4
- synapse/models/risk.py +19 -2
- synapse/models/telco.py +10 -3
- synapse/tests/test_axon.py +6 -6
- synapse/tests/test_cortex.py +133 -14
- synapse/tests/test_exc.py +4 -0
- synapse/tests/test_lib_agenda.py +282 -2
- synapse/tests/test_lib_aha.py +13 -6
- synapse/tests/test_lib_ast.py +301 -10
- synapse/tests/test_lib_auth.py +6 -7
- synapse/tests/test_lib_cell.py +71 -1
- synapse/tests/test_lib_grammar.py +14 -0
- synapse/tests/test_lib_layer.py +1 -1
- synapse/tests/test_lib_lmdbslab.py +3 -3
- synapse/tests/test_lib_storm.py +273 -55
- synapse/tests/test_lib_stormctrl.py +65 -0
- synapse/tests/test_lib_stormhttp.py +5 -5
- synapse/tests/test_lib_stormlib_auth.py +5 -5
- synapse/tests/test_lib_stormlib_cache.py +38 -6
- synapse/tests/test_lib_stormlib_json.py +20 -0
- synapse/tests/test_lib_stormlib_modelext.py +3 -3
- synapse/tests/test_lib_stormlib_scrape.py +6 -6
- synapse/tests/test_lib_stormlib_spooled.py +1 -1
- synapse/tests/test_lib_stormlib_xml.py +5 -5
- synapse/tests/test_lib_stormtypes.py +54 -57
- synapse/tests/test_lib_view.py +1 -1
- synapse/tests/test_model_base.py +1 -2
- synapse/tests/test_model_geopol.py +4 -0
- synapse/tests/test_model_geospace.py +6 -0
- synapse/tests/test_model_inet.py +43 -5
- synapse/tests/test_model_infotech.py +10 -1
- synapse/tests/test_model_orgs.py +17 -2
- synapse/tests/test_model_person.py +23 -1
- synapse/tests/test_model_risk.py +13 -0
- synapse/tests/test_tools_healthcheck.py +4 -4
- synapse/tests/test_tools_storm.py +95 -0
- synapse/tests/test_utils.py +17 -18
- synapse/tests/test_utils_getrefs.py +1 -1
- synapse/tests/utils.py +0 -35
- synapse/tools/changelog.py +6 -4
- synapse/tools/storm.py +1 -1
- synapse/utils/getrefs.py +14 -3
- synapse/vendor/cpython/lib/http/__init__.py +0 -0
- synapse/vendor/cpython/lib/http/cookies.py +59 -0
- synapse/vendor/cpython/lib/test/test_http_cookies.py +49 -0
- {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/METADATA +6 -6
- {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/RECORD +77 -73
- {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/WHEEL +1 -1
- {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/LICENSE +0 -0
- {synapse-2.192.0.dist-info → synapse-2.194.0.dist-info}/top_level.txt +0 -0
synapse/tests/test_lib_storm.py
CHANGED
|
@@ -4,6 +4,7 @@ import asyncio
|
|
|
4
4
|
import datetime
|
|
5
5
|
import itertools
|
|
6
6
|
import urllib.parse as u_parse
|
|
7
|
+
import unittest.mock as mock
|
|
7
8
|
|
|
8
9
|
import synapse.exc as s_exc
|
|
9
10
|
import synapse.common as s_common
|
|
@@ -52,10 +53,6 @@ class StormTest(s_t_utils.SynTest):
|
|
|
52
53
|
with self.raises(s_exc.BadTypeValu):
|
|
53
54
|
await core.nodes('[ ou:org=({"hq": "woot"}) ]')
|
|
54
55
|
|
|
55
|
-
msgs = await core.stormlist('[ ou:org=({"hq": "woot", "$try": true}) ]')
|
|
56
|
-
self.len(0, [m for m in msgs if m[0] == 'node'])
|
|
57
|
-
self.stormIsInWarn('Bad value for prop hq: valu is not a guid', msgs)
|
|
58
|
-
|
|
59
56
|
nodes05 = await core.nodes('[ ou:org=({"name": "vertex", "$props": {"motto": "for the people"}}) ]')
|
|
60
57
|
self.len(1, nodes05)
|
|
61
58
|
self.eq('vertex', nodes05[0].get('name'))
|
|
@@ -95,6 +92,57 @@ class StormTest(s_t_utils.SynTest):
|
|
|
95
92
|
self.len(1, nodes12)
|
|
96
93
|
self.ne(nodes11[0].ndef, nodes12[0].ndef)
|
|
97
94
|
|
|
95
|
+
# GUID ctor has a short-circuit where it tries to find an existing ndef before it does,
|
|
96
|
+
# some property deconfliction, and `<form>=({})` when pushed through guid generation gives
|
|
97
|
+
# back the same guid as `<form>=()`, which if we're not careful could lead to an
|
|
98
|
+
# inconsistent case where you fail to make a node because you don't provide any props,
|
|
99
|
+
# make a node with that matching ndef, and then run that invalid GUID ctor query again,
|
|
100
|
+
# and have it return back a node due to the short circuit. So test that we're consistent here.
|
|
101
|
+
with self.raises(s_exc.BadTypeValu):
|
|
102
|
+
await core.nodes('[ ou:org=({}) ]')
|
|
103
|
+
|
|
104
|
+
self.len(1, await core.nodes('[ ou:org=() ]'))
|
|
105
|
+
|
|
106
|
+
with self.raises(s_exc.BadTypeValu):
|
|
107
|
+
await core.nodes('[ ou:org=({}) ]')
|
|
108
|
+
|
|
109
|
+
msgs = await core.stormlist('[ ou:org=({"$props": {"desc": "lol"}})]')
|
|
110
|
+
self.len(0, [m for m in msgs if m[0] == 'node'])
|
|
111
|
+
self.stormIsInErr('No values provided for form ou:org', msgs)
|
|
112
|
+
|
|
113
|
+
msgs = await core.stormlist('[ou:org=({"name": "burrito corp", "$props": {"phone": "lolnope"}})]')
|
|
114
|
+
self.len(0, [m for m in msgs if m[0] == 'node'])
|
|
115
|
+
self.stormIsInErr('Bad value for prop ou:org:phone: requires a digit string', msgs)
|
|
116
|
+
|
|
117
|
+
with self.raises(s_exc.BadTypeValu):
|
|
118
|
+
await core.nodes('[ ou:org=({"$try": true}) ]')
|
|
119
|
+
|
|
120
|
+
# $try only affects $props
|
|
121
|
+
msgs = await core.stormlist('[ ou:org=({"founded": "lolnope", "$try": true}) ]')
|
|
122
|
+
self.len(0, [m for m in msgs if m[0] == 'node'])
|
|
123
|
+
self.stormIsInErr('Bad value for prop ou:org:founded: Unknown time format for lolnope', msgs)
|
|
124
|
+
|
|
125
|
+
msgs = await core.stormlist('[ou:org=({"name": "burrito corp", "$try": true, "$props": {"phone": "lolnope", "desc": "burritos man"}})]')
|
|
126
|
+
nodes = [m for m in msgs if m[0] == 'node']
|
|
127
|
+
self.len(1, nodes)
|
|
128
|
+
node = nodes[0][1]
|
|
129
|
+
props = node[1]['props']
|
|
130
|
+
self.none(props.get('phone'))
|
|
131
|
+
self.eq(props.get('name'), 'burrito corp')
|
|
132
|
+
self.eq(props.get('desc'), 'burritos man')
|
|
133
|
+
self.stormIsInWarn('Skipping bad value for prop ou:org:phone: requires a digit string', msgs)
|
|
134
|
+
|
|
135
|
+
await self.asyncraises(s_exc.BadTypeValu, core.addNode(core.auth.rootuser, 'ou:org', {'name': 'org name 77', 'phone': 'lolnope'}, props={'desc': 'an org desc'}))
|
|
136
|
+
|
|
137
|
+
await self.asyncraises(s_exc.BadTypeValu, core.addNode(core.auth.rootuser, 'ou:org', {'name': 'org name 77'}, props={'desc': 'an org desc', 'phone': 'lolnope'}))
|
|
138
|
+
|
|
139
|
+
node = await core.addNode(core.auth.rootuser, 'ou:org', {'$try': True, '$props': {'phone': 'invalid'}, 'name': 'org name 77'}, props={'desc': 'an org desc'})
|
|
140
|
+
self.nn(node)
|
|
141
|
+
props = node[1]['props']
|
|
142
|
+
self.none(props.get('phone'))
|
|
143
|
+
self.eq(props.get('name'), 'org name 77')
|
|
144
|
+
self.eq(props.get('desc'), 'an org desc')
|
|
145
|
+
|
|
98
146
|
async def test_lib_storm_jsonexpr(self):
|
|
99
147
|
async with self.getTestCore() as core:
|
|
100
148
|
|
|
@@ -253,7 +301,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
253
301
|
emit bar
|
|
254
302
|
}
|
|
255
303
|
function makelist() {
|
|
256
|
-
$retn =
|
|
304
|
+
$retn = ()
|
|
257
305
|
for $item in $generate() { $retn.append($item) }
|
|
258
306
|
return($retn)
|
|
259
307
|
}
|
|
@@ -266,7 +314,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
266
314
|
emit $node.repr()
|
|
267
315
|
}
|
|
268
316
|
function makelist() {
|
|
269
|
-
$retn =
|
|
317
|
+
$retn = ()
|
|
270
318
|
for $item in $generate() { $retn.append($item) }
|
|
271
319
|
return($retn)
|
|
272
320
|
}
|
|
@@ -338,9 +386,135 @@ class StormTest(s_t_utils.SynTest):
|
|
|
338
386
|
prnt = [m[1]['mesg'] for m in msgs if m[0] == 'print']
|
|
339
387
|
self.eq(prnt, ['inner 0', 'outer 0'])
|
|
340
388
|
|
|
341
|
-
|
|
389
|
+
# Emit outside an emitter function raises a runtime error with posinfo
|
|
390
|
+
with self.raises(s_exc.StormRuntimeError) as cm:
|
|
391
|
+
await core.nodes('emit foo')
|
|
392
|
+
self.nn(cm.exception.get('highlight'))
|
|
342
393
|
|
|
343
|
-
|
|
394
|
+
with self.raises(s_exc.StormRuntimeError) as cm:
|
|
395
|
+
await core.nodes('[test:str=emit] emit foo')
|
|
396
|
+
self.nn(cm.exception.get('highlight'))
|
|
397
|
+
|
|
398
|
+
# stop cannot cross function boundaries
|
|
399
|
+
q = '''
|
|
400
|
+
function inner(v) {
|
|
401
|
+
if ( $v = 2 ) {
|
|
402
|
+
stop
|
|
403
|
+
}
|
|
404
|
+
return ( $v )
|
|
405
|
+
}
|
|
406
|
+
function outer(n) {
|
|
407
|
+
for $i in $lib.range($n) {
|
|
408
|
+
emit $inner($i)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
$N = (5)
|
|
412
|
+
for $valu in $outer($N) {
|
|
413
|
+
$lib.print(`{$valu}/{$N}`)
|
|
414
|
+
}
|
|
415
|
+
'''
|
|
416
|
+
msgs = await core.stormlist(q)
|
|
417
|
+
self.stormIsInPrint('1/5', msgs)
|
|
418
|
+
self.stormNotInPrint('2/5', msgs)
|
|
419
|
+
self.stormIsInErr('function inner - Generator control statement "stop" used outside of a generator '
|
|
420
|
+
'function.',
|
|
421
|
+
msgs)
|
|
422
|
+
|
|
423
|
+
# The function exception raised can be caught.
|
|
424
|
+
q = '''
|
|
425
|
+
function inner(v) {
|
|
426
|
+
if ( $v = 2 ) {
|
|
427
|
+
stop
|
|
428
|
+
}
|
|
429
|
+
return ( $v )
|
|
430
|
+
}
|
|
431
|
+
function outer(n) {
|
|
432
|
+
for $i in $lib.range($n) {
|
|
433
|
+
emit $inner($i)
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
$N = (5)
|
|
437
|
+
try {
|
|
438
|
+
for $valu in $outer($N) {
|
|
439
|
+
$lib.print(`{$valu}/{$N}`)
|
|
440
|
+
}
|
|
441
|
+
} catch StormRuntimeError as err {
|
|
442
|
+
$lib.print(`caught: {$err.mesg}`)
|
|
443
|
+
}
|
|
444
|
+
'''
|
|
445
|
+
msgs = await core.stormlist(q)
|
|
446
|
+
self.stormIsInPrint('1/5', msgs)
|
|
447
|
+
self.stormNotInPrint('2/5', msgs)
|
|
448
|
+
self.stormIsInPrint('caught: function inner - Generator control statement "stop" used outside of a'
|
|
449
|
+
' generator function.',
|
|
450
|
+
msgs)
|
|
451
|
+
|
|
452
|
+
# Outside a function, StopStorm is caught and converted into a StormRuntimeError for the message stream.
|
|
453
|
+
# Since this is tearing down the runtime, it cannot be caught.
|
|
454
|
+
q = '''
|
|
455
|
+
$N = (5)
|
|
456
|
+
for $j in $lib.range($N) {
|
|
457
|
+
if ($j = 2) {
|
|
458
|
+
stop
|
|
459
|
+
}
|
|
460
|
+
$lib.print(`{$j}/{$N}`)
|
|
461
|
+
}
|
|
462
|
+
'''
|
|
463
|
+
msgs = await core.stormlist(q)
|
|
464
|
+
self.stormIsInPrint('1/5', msgs)
|
|
465
|
+
self.stormNotInPrint('2/5', msgs)
|
|
466
|
+
self.stormIsInErr('Generator control statement "stop" used outside of a generator function.',
|
|
467
|
+
msgs)
|
|
468
|
+
errname = [m[1][0] for m in msgs if m[0] == 'err'][0]
|
|
469
|
+
self.eq(errname, 'StormRuntimeError')
|
|
470
|
+
|
|
471
|
+
q = '''
|
|
472
|
+
$N = (5)
|
|
473
|
+
try {
|
|
474
|
+
for $j in $lib.range($N) {
|
|
475
|
+
if ($j = 2) {
|
|
476
|
+
stop
|
|
477
|
+
}
|
|
478
|
+
$lib.print(`{$j}/{$N}`)
|
|
479
|
+
}
|
|
480
|
+
} catch StormRuntimeError as err {
|
|
481
|
+
$lib.print(`caught: {$err.mesg}`)
|
|
482
|
+
}
|
|
483
|
+
'''
|
|
484
|
+
msgs = await core.stormlist(q)
|
|
485
|
+
self.stormIsInPrint('1/5', msgs)
|
|
486
|
+
self.stormNotInPrint('2/5', msgs)
|
|
487
|
+
self.stormNotInPrint('caught:', msgs)
|
|
488
|
+
self.stormIsInErr('Generator control statement "stop" used outside of a generator function.',
|
|
489
|
+
msgs)
|
|
490
|
+
|
|
491
|
+
# Mixing a Loop control flow statement in an emitter to stop its processing
|
|
492
|
+
# will be converted into a catchable StormRuntimeError
|
|
493
|
+
q = '''
|
|
494
|
+
function inner(n) {
|
|
495
|
+
emit $n
|
|
496
|
+
$n = ( $n + 1 )
|
|
497
|
+
emit $n
|
|
498
|
+
$n = ( $n + 1 )
|
|
499
|
+
if ( $n >= 2 ) {
|
|
500
|
+
break
|
|
501
|
+
}
|
|
502
|
+
emit $n
|
|
503
|
+
}
|
|
504
|
+
$N = (0)
|
|
505
|
+
try {
|
|
506
|
+
for $valu in $inner($N) {
|
|
507
|
+
$lib.print(`got {$valu}`)
|
|
508
|
+
}
|
|
509
|
+
} catch StormRuntimeError as err {
|
|
510
|
+
$lib.print(`caught: {$err.mesg}`)
|
|
511
|
+
}
|
|
512
|
+
'''
|
|
513
|
+
msgs = await core.stormlist(q)
|
|
514
|
+
self.stormIsInPrint('got 1', msgs)
|
|
515
|
+
self.stormNotInPrint('got 2', msgs)
|
|
516
|
+
self.stormIsInPrint('caught: function inner - Loop control statement "break" used outside of a loop.',
|
|
517
|
+
msgs)
|
|
344
518
|
|
|
345
519
|
async def test_lib_storm_intersect(self):
|
|
346
520
|
async with self.getTestCore() as core:
|
|
@@ -579,7 +753,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
579
753
|
return((0))
|
|
580
754
|
}
|
|
581
755
|
|
|
582
|
-
$alerts =
|
|
756
|
+
$alerts = ()
|
|
583
757
|
{ $alerts.append($node.repr()) }
|
|
584
758
|
|
|
585
759
|
$bool = $stuff($alerts)
|
|
@@ -646,32 +820,6 @@ class StormTest(s_t_utils.SynTest):
|
|
|
646
820
|
self.none(task['info'].get('opts'))
|
|
647
821
|
self.eq(core.view.iden, task['info'].get('view'))
|
|
648
822
|
|
|
649
|
-
# test the parallel command
|
|
650
|
-
nodes = await core.nodes('parallel --size 4 { [ ou:org=* ] }')
|
|
651
|
-
self.len(4, nodes)
|
|
652
|
-
|
|
653
|
-
# check that subquery validation happens
|
|
654
|
-
with self.raises(s_exc.NoSuchVar):
|
|
655
|
-
await core.nodes('parallel --size 4 { [ ou:org=$foo ] }')
|
|
656
|
-
|
|
657
|
-
# check that an exception on inbound percolates correctly
|
|
658
|
-
with self.raises(s_exc.BadTypeValu):
|
|
659
|
-
await core.nodes('[ ou:org=* ou:org=foo ] | parallel { [:name=bar] }')
|
|
660
|
-
|
|
661
|
-
# check that an exception in the parallel pipeline percolates correctly
|
|
662
|
-
with self.raises(s_exc.BadTypeValu):
|
|
663
|
-
await core.nodes('parallel { [ou:org=foo] }')
|
|
664
|
-
|
|
665
|
-
nodes = await core.nodes('ou:org | parallel {[ :name=foo ]}')
|
|
666
|
-
self.true(all([n.get('name') == 'foo' for n in nodes]))
|
|
667
|
-
|
|
668
|
-
# Runtsafety test
|
|
669
|
-
q = '[ inet:fqdn=www.vertex.link ] $q=:domain | parallel $q'
|
|
670
|
-
await self.asyncraises(s_exc.StormRuntimeError, core.nodes(q))
|
|
671
|
-
|
|
672
|
-
nodes = await core.nodes('ou:org | parallel ${ $foo=bar [ :name=$foo ]}')
|
|
673
|
-
self.true(all([n.get('name') == 'bar' for n in nodes]))
|
|
674
|
-
|
|
675
823
|
# test $lib.exit() and the StormExit handlers
|
|
676
824
|
msgs = [m async for m in core.view.storm('$lib.exit()')]
|
|
677
825
|
self.eq(msgs[-1][0], 'fini')
|
|
@@ -789,10 +937,10 @@ class StormTest(s_t_utils.SynTest):
|
|
|
789
937
|
},
|
|
790
938
|
)
|
|
791
939
|
}
|
|
792
|
-
|
|
940
|
+
core.loadStormPkg(emptypkg)
|
|
793
941
|
await core.addStormPkg(strverpkg)
|
|
794
942
|
|
|
795
|
-
|
|
943
|
+
core.loadStormPkg(pkg0)
|
|
796
944
|
|
|
797
945
|
await core.nodes('$lib.import(foo.baz)', opts=opts)
|
|
798
946
|
await core.nodes('$lib.import(foo.baz, reqvers="==0.0.1")', opts=opts)
|
|
@@ -934,7 +1082,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
934
1082
|
|
|
935
1083
|
opts = {'view': view}
|
|
936
1084
|
self.len(0, await core.callStorm('''
|
|
937
|
-
$list =
|
|
1085
|
+
$list = ()
|
|
938
1086
|
$layr = $lib.view.get().layers.0
|
|
939
1087
|
for $item in $layr.getStorNodes() {
|
|
940
1088
|
$list.append($item)
|
|
@@ -947,7 +1095,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
947
1095
|
await core.callStorm('inet:ipv4=11.22.33.44 [ +(blahverb)> { inet:asn=99 } ]', opts=opts)
|
|
948
1096
|
|
|
949
1097
|
sodes = await core.callStorm('''
|
|
950
|
-
$list =
|
|
1098
|
+
$list = ()
|
|
951
1099
|
$layr = $lib.view.get().layers.0
|
|
952
1100
|
for $item in $layr.getStorNodes() {
|
|
953
1101
|
$list.append($item)
|
|
@@ -956,7 +1104,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
956
1104
|
self.len(2, sodes)
|
|
957
1105
|
|
|
958
1106
|
ipv4 = await core.callStorm('''
|
|
959
|
-
$list =
|
|
1107
|
+
$list = ()
|
|
960
1108
|
$layr = $lib.view.get().layers.0
|
|
961
1109
|
for ($buid, $sode) in $layr.getStorNodes() {
|
|
962
1110
|
yield $buid
|
|
@@ -1098,7 +1246,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
1098
1246
|
self.len(0, await core.nodes('diff', opts=opts))
|
|
1099
1247
|
|
|
1100
1248
|
self.len(0, await core.callStorm('''
|
|
1101
|
-
$list =
|
|
1249
|
+
$list = ()
|
|
1102
1250
|
for ($buid, $sode) in $lib.view.get().layers.0.getStorNodes() {
|
|
1103
1251
|
$list.append($buid)
|
|
1104
1252
|
}
|
|
@@ -1379,9 +1527,9 @@ class StormTest(s_t_utils.SynTest):
|
|
|
1379
1527
|
'''))
|
|
1380
1528
|
|
|
1381
1529
|
self.eq(('foo', 'bar', 'baz'), await core.callStorm('''
|
|
1382
|
-
return(
|
|
1383
|
-
/* hehe */ foo /* hehe */ , /* hehe */ bar /* hehe */ , /* hehe */ baz /* hehe */
|
|
1384
|
-
))
|
|
1530
|
+
return(([ // do foo thing
|
|
1531
|
+
/* hehe */ "foo" /* hehe */ , /* hehe */ "bar" /* hehe */ , /* hehe */ "baz" /* hehe */
|
|
1532
|
+
]))
|
|
1385
1533
|
'''))
|
|
1386
1534
|
|
|
1387
1535
|
# surrogate escapes are allowed
|
|
@@ -2594,6 +2742,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
2594
2742
|
class PkgHandler(s_httpapi.Handler):
|
|
2595
2743
|
|
|
2596
2744
|
async def get(self, name):
|
|
2745
|
+
assert self.request.headers.get('X-Synapse-Version') == s_version.verstring
|
|
2597
2746
|
|
|
2598
2747
|
if name == 'notok':
|
|
2599
2748
|
self.sendRestErr('FooBar', 'baz faz')
|
|
@@ -2603,6 +2752,8 @@ class StormTest(s_t_utils.SynTest):
|
|
|
2603
2752
|
|
|
2604
2753
|
class PkgHandlerRaw(s_httpapi.Handler):
|
|
2605
2754
|
async def get(self, name):
|
|
2755
|
+
assert self.request.headers.get('X-Synapse-Version') == s_version.verstring
|
|
2756
|
+
|
|
2606
2757
|
self.set_header('Content-Type', 'application/json')
|
|
2607
2758
|
return self.write(pkg)
|
|
2608
2759
|
|
|
@@ -3279,7 +3430,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3279
3430
|
self.eq(nodes[4].ndef, ('inet:ipv4', 0x01020304))
|
|
3280
3431
|
|
|
3281
3432
|
# Queries can be a heavy list
|
|
3282
|
-
q = '$list =
|
|
3433
|
+
q = '$list = ([${ -> * }, ${ <- * }, ${ -> edge:refs:n2 :n1 -> * }]) inet:ipv4=1.2.3.4 | tee --join $list'
|
|
3283
3434
|
nodes = await core.nodes(q)
|
|
3284
3435
|
self.len(5, nodes)
|
|
3285
3436
|
self.eq(nodes[0].ndef, ('inet:asn', 0))
|
|
@@ -3289,22 +3440,22 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3289
3440
|
self.eq(nodes[4].ndef, ('inet:ipv4', 0x01020304))
|
|
3290
3441
|
|
|
3291
3442
|
# A empty list of queries still works as an nop
|
|
3292
|
-
q = '$list =
|
|
3443
|
+
q = '$list = () | tee $list'
|
|
3293
3444
|
msgs = await core.stormlist(q)
|
|
3294
3445
|
self.len(2, msgs)
|
|
3295
3446
|
self.eq(('init', 'fini'), [m[0] for m in msgs])
|
|
3296
3447
|
|
|
3297
|
-
q = 'inet:ipv4=1.2.3.4 $list =
|
|
3448
|
+
q = 'inet:ipv4=1.2.3.4 $list = () | tee --join $list'
|
|
3298
3449
|
msgs = await core.stormlist(q)
|
|
3299
3450
|
self.len(3, msgs)
|
|
3300
3451
|
self.eq(('init', 'node', 'fini'), [m[0] for m in msgs])
|
|
3301
3452
|
|
|
3302
|
-
q = '$list =
|
|
3453
|
+
q = '$list = () | tee --parallel $list'
|
|
3303
3454
|
msgs = await core.stormlist(q)
|
|
3304
3455
|
self.len(2, msgs)
|
|
3305
3456
|
self.eq(('init', 'fini'), [m[0] for m in msgs])
|
|
3306
3457
|
|
|
3307
|
-
q = 'inet:ipv4=1.2.3.4 $list =
|
|
3458
|
+
q = 'inet:ipv4=1.2.3.4 $list = () | tee --parallel --join $list'
|
|
3308
3459
|
msgs = await core.stormlist(q)
|
|
3309
3460
|
self.len(3, msgs)
|
|
3310
3461
|
self.eq(('init', 'node', 'fini'), [m[0] for m in msgs])
|
|
@@ -3437,6 +3588,73 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3437
3588
|
q = '[ inet:fqdn=www.vertex.link ] $q=:domain | tee $q'
|
|
3438
3589
|
await self.asyncraises(s_exc.StormRuntimeError, core.nodes(q))
|
|
3439
3590
|
|
|
3591
|
+
async def test_storm_parallel(self):
|
|
3592
|
+
|
|
3593
|
+
async with self.getTestCore() as core:
|
|
3594
|
+
|
|
3595
|
+
nodes = await core.nodes('parallel --size 4 { [ ou:org=* ] }')
|
|
3596
|
+
self.len(4, nodes)
|
|
3597
|
+
|
|
3598
|
+
# check that subquery validation happens
|
|
3599
|
+
with self.raises(s_exc.NoSuchVar):
|
|
3600
|
+
await core.nodes('parallel --size 4 { [ ou:org=$foo ] }')
|
|
3601
|
+
|
|
3602
|
+
# check that an exception on inbound percolates correctly
|
|
3603
|
+
with self.raises(s_exc.BadTypeValu):
|
|
3604
|
+
await core.nodes('[ ou:org=(foo,) ou:org=foo ] | parallel { [:name=bar] }')
|
|
3605
|
+
|
|
3606
|
+
with self.raises(s_exc.BadTypeValu):
|
|
3607
|
+
await core.nodes('[ ou:org=(foo,) ou:org=foo ] | parallel --size 1 { [:name=bar] }')
|
|
3608
|
+
|
|
3609
|
+
# check that an exception in the parallel pipeline percolates correctly
|
|
3610
|
+
with self.raises(s_exc.BadTypeValu):
|
|
3611
|
+
await core.nodes('parallel { [ou:org=foo] }')
|
|
3612
|
+
|
|
3613
|
+
nodes = await core.nodes('ou:org | parallel {[ :name=foo ]}')
|
|
3614
|
+
self.true(all([n.get('name') == 'foo' for n in nodes]))
|
|
3615
|
+
|
|
3616
|
+
# Runtsafety test
|
|
3617
|
+
q = '[ inet:fqdn=www.vertex.link ] $q=:domain | parallel $q'
|
|
3618
|
+
await self.asyncraises(s_exc.StormRuntimeError, core.nodes(q))
|
|
3619
|
+
|
|
3620
|
+
nodes = await core.nodes('ou:org | parallel ${ $foo=bar [ :name=$foo ]}')
|
|
3621
|
+
self.true(all([n.get('name') == 'bar' for n in nodes]))
|
|
3622
|
+
|
|
3623
|
+
orig = s_storm.ParallelCmd.pipeline
|
|
3624
|
+
tsks = {'cnt': 0}
|
|
3625
|
+
|
|
3626
|
+
async def pipecnt(self, runt, query, inq, outq):
|
|
3627
|
+
tsks['cnt'] += 1
|
|
3628
|
+
await orig(self, runt, query, inq, outq)
|
|
3629
|
+
|
|
3630
|
+
with mock.patch('synapse.lib.storm.ParallelCmd.pipeline', pipecnt):
|
|
3631
|
+
|
|
3632
|
+
nodes = await core.nodes('ou:org parallel --size 4 {[ :name=bar ]}')
|
|
3633
|
+
self.len(5, nodes)
|
|
3634
|
+
self.true(all([n.get('name') == 'bar' for n in nodes]))
|
|
3635
|
+
self.eq(4, tsks['cnt'])
|
|
3636
|
+
|
|
3637
|
+
tsks['cnt'] = 0
|
|
3638
|
+
|
|
3639
|
+
nodes = await core.nodes('ou:org parallel --size 5 {[ :name=bar ]}')
|
|
3640
|
+
self.len(5, nodes)
|
|
3641
|
+
self.true(all([n.get('name') == 'bar' for n in nodes]))
|
|
3642
|
+
self.eq(5, tsks['cnt'])
|
|
3643
|
+
|
|
3644
|
+
tsks['cnt'] = 0
|
|
3645
|
+
|
|
3646
|
+
# --size greater than number of nodes only creates a pipeline for each node
|
|
3647
|
+
nodes = await core.nodes('ou:org parallel --size 10 {[ :name=foo ]}')
|
|
3648
|
+
self.len(5, nodes)
|
|
3649
|
+
self.true(all([n.get('name') == 'foo' for n in nodes]))
|
|
3650
|
+
self.eq(5, tsks['cnt'])
|
|
3651
|
+
|
|
3652
|
+
tsks['cnt'] = 0
|
|
3653
|
+
|
|
3654
|
+
nodes = await core.nodes('parallel --size 4 {[ ou:org=* ]}')
|
|
3655
|
+
self.len(4, nodes)
|
|
3656
|
+
self.eq(4, tsks['cnt'])
|
|
3657
|
+
|
|
3440
3658
|
async def test_storm_yieldvalu(self):
|
|
3441
3659
|
|
|
3442
3660
|
async with self.getTestCore() as core:
|
|
@@ -3491,7 +3709,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3491
3709
|
fork = await core.callStorm('return( $lib.view.get().fork().iden )')
|
|
3492
3710
|
|
|
3493
3711
|
q = '''
|
|
3494
|
-
$nodes =
|
|
3712
|
+
$nodes = ()
|
|
3495
3713
|
view.exec $view { inet:ipv4=1.2.3.4 $nodes.append($node) } |
|
|
3496
3714
|
for $n in $nodes {
|
|
3497
3715
|
yield $n
|
|
@@ -3501,7 +3719,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3501
3719
|
self.stormIsInErr('Node is not from the current view.', msgs)
|
|
3502
3720
|
|
|
3503
3721
|
q = '''
|
|
3504
|
-
$nodes =
|
|
3722
|
+
$nodes = ()
|
|
3505
3723
|
view.exec $view { for $x in ${ inet:ipv4=1.2.3.4 } { $nodes.append($x) } } |
|
|
3506
3724
|
for $n in $nodes {
|
|
3507
3725
|
yield $n
|
|
@@ -3516,7 +3734,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3516
3734
|
|
|
3517
3735
|
# Nodes lifted from another view and referred to by iden() works
|
|
3518
3736
|
q = '''
|
|
3519
|
-
$nodes =
|
|
3737
|
+
$nodes = ()
|
|
3520
3738
|
view.exec $view { inet:ipv4=1.2.3.4 $nodes.append($node) } |
|
|
3521
3739
|
for $n in $nodes {
|
|
3522
3740
|
yield $n.iden()
|
|
@@ -3526,7 +3744,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3526
3744
|
self.len(1, nodes)
|
|
3527
3745
|
|
|
3528
3746
|
q = '''
|
|
3529
|
-
$nodes =
|
|
3747
|
+
$nodes = ()
|
|
3530
3748
|
view.exec $view { for $x in ${ inet:ipv4=1.2.3.4 } { $nodes.append($x) } } |
|
|
3531
3749
|
for $n in $nodes {
|
|
3532
3750
|
yield $n.iden()
|
|
@@ -3882,7 +4100,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3882
4100
|
)},
|
|
3883
4101
|
),
|
|
3884
4102
|
}
|
|
3885
|
-
|
|
4103
|
+
core.loadStormPkg(pdef)
|
|
3886
4104
|
msgs = await core.stormlist('woot --help')
|
|
3887
4105
|
helptext = '\n'.join([m[1].get('mesg') for m in msgs if m[0] == 'print'])
|
|
3888
4106
|
self.isin('Inputs:\n\n hehe:haha\n hoho:lol - We know whats up', helptext)
|
|
@@ -4656,7 +4874,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
4656
4874
|
async def test_storm_cmdscope(self):
|
|
4657
4875
|
|
|
4658
4876
|
async with self.getTestCore() as core:
|
|
4659
|
-
|
|
4877
|
+
core.loadStormPkg({
|
|
4660
4878
|
'name': 'testpkg',
|
|
4661
4879
|
'version': '0.0.1',
|
|
4662
4880
|
'commands': (
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import pickle
|
|
2
|
+
|
|
3
|
+
import synapse.lib.stormctrl as s_stormctrl
|
|
4
|
+
|
|
5
|
+
import synapse.tests.utils as s_t_utils
|
|
6
|
+
|
|
7
|
+
class StormctrlTest(s_t_utils.SynTest):
|
|
8
|
+
def test_basic(self):
|
|
9
|
+
|
|
10
|
+
# Classes inherit as expected
|
|
11
|
+
self.isinstance(s_stormctrl.StormReturn(), s_stormctrl.StormCtrlFlow)
|
|
12
|
+
self.isinstance(s_stormctrl.StormExit(), s_stormctrl.StormCtrlFlow)
|
|
13
|
+
self.isinstance(s_stormctrl.StormBreak(), s_stormctrl.StormCtrlFlow)
|
|
14
|
+
self.isinstance(s_stormctrl.StormContinue(), s_stormctrl.StormCtrlFlow)
|
|
15
|
+
self.isinstance(s_stormctrl.StormStop(), s_stormctrl.StormCtrlFlow)
|
|
16
|
+
|
|
17
|
+
# Subtypes are noted as well
|
|
18
|
+
self.isinstance(s_stormctrl.StormBreak(), s_stormctrl.StormLoopCtrl)
|
|
19
|
+
self.isinstance(s_stormctrl.StormContinue(), s_stormctrl.StormLoopCtrl)
|
|
20
|
+
self.isinstance(s_stormctrl.StormStop(), s_stormctrl.StormGenrCtrl)
|
|
21
|
+
|
|
22
|
+
# control flow and exist constructs inherit from the SynErrMixin
|
|
23
|
+
# return does not to keep it thin. it is used often.
|
|
24
|
+
self.isinstance(s_stormctrl.StormExit(), s_stormctrl._SynErrMixin)
|
|
25
|
+
self.isinstance(s_stormctrl.StormBreak(), s_stormctrl._SynErrMixin)
|
|
26
|
+
self.isinstance(s_stormctrl.StormContinue(), s_stormctrl._SynErrMixin)
|
|
27
|
+
self.isinstance(s_stormctrl.StormStop(), s_stormctrl._SynErrMixin)
|
|
28
|
+
self.false(isinstance(s_stormctrl.StormReturn(), s_stormctrl._SynErrMixin))
|
|
29
|
+
|
|
30
|
+
# The base class cannot be used on its own.
|
|
31
|
+
with self.raises(NotImplementedError):
|
|
32
|
+
s_stormctrl.StormCtrlFlow()
|
|
33
|
+
|
|
34
|
+
# The _SynErrMixin classes have several methods that let us treat
|
|
35
|
+
# instance of them like SynErr exceptions.
|
|
36
|
+
e = s_stormctrl.StormExit(mesg='words', foo='bar')
|
|
37
|
+
self.eq(e.get('foo'), 'bar')
|
|
38
|
+
self.eq(e.items(), {'mesg': 'words', 'foo': 'bar'})
|
|
39
|
+
self.eq("StormExit: foo='bar' mesg='words'", str(e))
|
|
40
|
+
e.set('hehe', 1234)
|
|
41
|
+
e.set('foo', 'words')
|
|
42
|
+
self.eq("StormExit: foo='words' hehe=1234 mesg='words'", str(e))
|
|
43
|
+
|
|
44
|
+
e.setdefault('defv', 1)
|
|
45
|
+
self.eq("StormExit: defv=1 foo='words' hehe=1234 mesg='words'", str(e))
|
|
46
|
+
|
|
47
|
+
e.setdefault('defv', 2)
|
|
48
|
+
self.eq("StormExit: defv=1 foo='words' hehe=1234 mesg='words'", str(e))
|
|
49
|
+
|
|
50
|
+
e.update({'foo': 'newwords', 'bar': 'baz'})
|
|
51
|
+
self.eq("StormExit: bar='baz' defv=1 foo='newwords' hehe=1234 mesg='words'", str(e))
|
|
52
|
+
|
|
53
|
+
# But it does not have an errname property
|
|
54
|
+
self.false(hasattr(e, 'errname'))
|
|
55
|
+
|
|
56
|
+
# StormReturn is used to move objects around.
|
|
57
|
+
e = s_stormctrl.StormReturn('weee')
|
|
58
|
+
self.eq(e.item, 'weee')
|
|
59
|
+
|
|
60
|
+
async def test_pickled_stormctrlflow(self):
|
|
61
|
+
e = s_stormctrl.StormExit(mesg='words', foo='bar')
|
|
62
|
+
buf = pickle.dumps(e)
|
|
63
|
+
new_e = pickle.loads(buf)
|
|
64
|
+
self.eq(new_e.get('foo'), 'bar')
|
|
65
|
+
self.eq("StormExit: foo='bar' mesg='words'", str(new_e))
|
|
@@ -518,11 +518,11 @@ class StormHttpTest(s_test.SynTest):
|
|
|
518
518
|
self.eq(data.get('body'), 'MTIzNA==')
|
|
519
519
|
|
|
520
520
|
q = '''
|
|
521
|
-
$fields
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
)
|
|
521
|
+
$fields=([
|
|
522
|
+
{"name": "foo", "value": "bar"},
|
|
523
|
+
{"name": "foo", "value": "bar2"},
|
|
524
|
+
{"name": "baz", "value": "cool"}
|
|
525
|
+
])
|
|
526
526
|
$resp = $lib.inet.http.post($url, fields=$fields, ssl_verify=$lib.false)
|
|
527
527
|
return ( $resp.json() )
|
|
528
528
|
'''
|
|
@@ -427,7 +427,7 @@ class StormLibAuthTest(s_test.SynTest):
|
|
|
427
427
|
|
|
428
428
|
await core.callStorm('$lib.user.json.set(hi, hehe, prop=foo)')
|
|
429
429
|
items = await core.callStorm('''
|
|
430
|
-
$list =
|
|
430
|
+
$list = ()
|
|
431
431
|
for $item in $lib.user.json.iter() { $list.append($item) }
|
|
432
432
|
return($list)
|
|
433
433
|
''')
|
|
@@ -437,7 +437,7 @@ class StormLibAuthTest(s_test.SynTest):
|
|
|
437
437
|
))
|
|
438
438
|
|
|
439
439
|
items = await core.callStorm('''
|
|
440
|
-
$list =
|
|
440
|
+
$list = ()
|
|
441
441
|
for $item in $lib.user.json.iter(path=bye) { $list.append($item) }
|
|
442
442
|
return($list)
|
|
443
443
|
''')
|
|
@@ -731,7 +731,7 @@ class StormLibAuthTest(s_test.SynTest):
|
|
|
731
731
|
'''))
|
|
732
732
|
|
|
733
733
|
# user roles can be set in bulk
|
|
734
|
-
roles = await core.callStorm('''$roles
|
|
734
|
+
roles = await core.callStorm('''$roles=()
|
|
735
735
|
$role=$lib.auth.roles.byname(admins) $roles.append($role.iden)
|
|
736
736
|
$role=$lib.auth.roles.byname(all) $roles.append($role.iden)
|
|
737
737
|
$lib.auth.users.byname(visi).setRoles($roles)
|
|
@@ -791,7 +791,7 @@ class StormLibAuthTest(s_test.SynTest):
|
|
|
791
791
|
visi = await core.callStorm('''
|
|
792
792
|
$rule = $lib.auth.ruleFromText(hehe.haha)
|
|
793
793
|
$visi = $lib.auth.users.byname(visi)
|
|
794
|
-
$visi.setRules(
|
|
794
|
+
$visi.setRules(([$rule]))
|
|
795
795
|
return($visi)
|
|
796
796
|
''')
|
|
797
797
|
self.eq(((True, ('hehe', 'haha')),), visi['rules'])
|
|
@@ -834,7 +834,7 @@ class StormLibAuthTest(s_test.SynTest):
|
|
|
834
834
|
ninjas = await core.callStorm('''
|
|
835
835
|
$rule = $lib.auth.ruleFromText(hehe.haha)
|
|
836
836
|
$ninjas = $lib.auth.roles.byname(ninjas)
|
|
837
|
-
$ninjas.setRules(
|
|
837
|
+
$ninjas.setRules(([$rule]))
|
|
838
838
|
return($ninjas)
|
|
839
839
|
''')
|
|
840
840
|
self.eq(((True, ('hehe', 'haha')),), ninjas['rules'])
|