synapse 2.183.0__py311-none-any.whl → 2.185.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/cortex.py +1 -1
- synapse/datamodel.py +82 -9
- synapse/lib/ast.py +85 -23
- synapse/lib/auth.py +13 -0
- synapse/lib/autodoc.py +9 -2
- synapse/lib/cell.py +14 -1
- synapse/lib/modules.py +1 -0
- synapse/lib/parser.py +1 -0
- synapse/lib/snap.py +1 -0
- synapse/lib/storm.lark +12 -6
- synapse/lib/storm.py +45 -9
- synapse/lib/storm_format.py +1 -0
- synapse/lib/stormlib/graph.py +17 -0
- synapse/lib/stormlib/stix.py +14 -5
- synapse/lib/stormtypes.py +65 -37
- synapse/lib/stormwhois.py +3 -0
- synapse/lib/version.py +2 -2
- synapse/models/doc.py +93 -0
- synapse/models/infotech.py +5 -1
- synapse/models/media.py +0 -1
- synapse/models/orgs.py +102 -5
- synapse/models/proj.py +56 -36
- synapse/models/risk.py +22 -0
- synapse/models/syn.py +64 -6
- synapse/tests/test_cortex.py +54 -45
- synapse/tests/test_lib_ast.py +58 -0
- synapse/tests/test_lib_autodoc.py +54 -0
- synapse/tests/test_lib_cell.py +44 -1
- synapse/tests/test_lib_grammar.py +2 -0
- synapse/tests/test_lib_storm.py +68 -1
- synapse/tests/test_lib_stormlib_modelext.py +52 -0
- synapse/tests/test_lib_stormlib_stix.py +3 -2
- synapse/tests/test_lib_stormwhois.py +4 -4
- synapse/tests/test_model_doc.py +51 -0
- synapse/tests/test_model_infotech.py +5 -1
- synapse/tests/test_model_orgs.py +78 -0
- synapse/tests/test_model_risk.py +3 -0
- synapse/tests/test_model_syn.py +43 -0
- synapse/tests/test_tools_promote.py +67 -0
- synapse/tests/utils.py +26 -0
- synapse/tools/promote.py +14 -1
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/METADATA +5 -10
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/RECORD +46 -43
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/WHEEL +1 -1
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/LICENSE +0 -0
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/top_level.txt +0 -0
synapse/tests/test_lib_storm.py
CHANGED
|
@@ -147,6 +147,20 @@ class StormTest(s_t_utils.SynTest):
|
|
|
147
147
|
retn = await core.callStorm('return(({"foo": "bar", "baz": 10 , }))')
|
|
148
148
|
self.eq(retn, {'foo': 'bar', 'baz': 10})
|
|
149
149
|
|
|
150
|
+
q = '''
|
|
151
|
+
$foo = ({"bar": ${[inet:fqdn=foo.com]}})
|
|
152
|
+
for $n in $foo.bar { return($n.repr()) }
|
|
153
|
+
'''
|
|
154
|
+
retn = await core.callStorm(q)
|
|
155
|
+
self.eq(retn, 'foo.com')
|
|
156
|
+
|
|
157
|
+
q = '''
|
|
158
|
+
$foo = ([${[inet:fqdn=foo.com]}])
|
|
159
|
+
for $n in $foo.0 { return($n.repr()) }
|
|
160
|
+
'''
|
|
161
|
+
retn = await core.callStorm(q)
|
|
162
|
+
self.eq(retn, 'foo.com')
|
|
163
|
+
|
|
150
164
|
with self.raises(s_exc.BadSyntax):
|
|
151
165
|
await core.callStorm('return((["foo" "foo"]))')
|
|
152
166
|
|
|
@@ -612,6 +626,12 @@ class StormTest(s_t_utils.SynTest):
|
|
|
612
626
|
''')
|
|
613
627
|
self.eq((0, 'haha'), await core.callStorm('return($lib.queue.get(bar).get())'))
|
|
614
628
|
|
|
629
|
+
await core.nodes('$foo = (foo,) background ${ $foo.append(bar) $lib.queue.get(bar).put($foo) }')
|
|
630
|
+
self.eq((1, ['foo', 'bar']), await core.callStorm('return($lib.queue.get(bar).get(1))'))
|
|
631
|
+
|
|
632
|
+
await core.nodes('$foo = ([["foo"]]) background ${ $foo.0.append(bar) $lib.queue.get(bar).put($foo) }')
|
|
633
|
+
self.eq((2, [['foo', 'bar']]), await core.callStorm('return($lib.queue.get(bar).get(2))'))
|
|
634
|
+
|
|
615
635
|
with self.raises(s_exc.StormRuntimeError):
|
|
616
636
|
await core.nodes('[ ou:org=*] $text = $node.repr() | background $text')
|
|
617
637
|
|
|
@@ -3586,7 +3606,7 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3586
3606
|
'quickly became his weapon of choice.'])
|
|
3587
3607
|
pars.help()
|
|
3588
3608
|
helptext = '\n'.join(pars.mesgs)
|
|
3589
|
-
self.isin('default
|
|
3609
|
+
self.isin('default:\n [', helptext)
|
|
3590
3610
|
|
|
3591
3611
|
pars = s_storm.Parser()
|
|
3592
3612
|
pars.add_argument('--ques', nargs='?')
|
|
@@ -3771,6 +3791,27 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3771
3791
|
opts = pars.parse_args(['faz', '--cat', 'cam', 'cool'])
|
|
3772
3792
|
self.nn(opts)
|
|
3773
3793
|
|
|
3794
|
+
pars = s_storm.Parser()
|
|
3795
|
+
pars.add_argument('--baz', nargs=3, help='''
|
|
3796
|
+
This is the top line, nothing special.
|
|
3797
|
+
This is my second line with sublines that should have some leading spaces:
|
|
3798
|
+
subline 1: this is a line which has three spaces.
|
|
3799
|
+
subline 2: this is another line with five leading spaces.
|
|
3800
|
+
subline 3: yet another line with only two leading spaces.
|
|
3801
|
+
subline 4: this line has one space and is long which should wrap around because it exceeds the default display width.
|
|
3802
|
+
This is the final line with no leading spaces.''')
|
|
3803
|
+
pars.add_argument('--taz', type='bool', default=True, help='Taz option')
|
|
3804
|
+
pars.help()
|
|
3805
|
+
self.eq(' --baz <baz> : This is the top line, nothing special.', pars.mesgs[5])
|
|
3806
|
+
self.eq(' This is my second line with sublines that should have some leading spaces:', pars.mesgs[6])
|
|
3807
|
+
self.eq(' subline 1: this is a line which has three spaces.', pars.mesgs[7])
|
|
3808
|
+
self.eq(' subline 2: this is another line with five leading spaces.', pars.mesgs[8])
|
|
3809
|
+
self.eq(' subline 3: yet another line with only two leading spaces.', pars.mesgs[9])
|
|
3810
|
+
self.eq(' subline 4: this line has one space and is long which should wrap around because it', pars.mesgs[10])
|
|
3811
|
+
self.eq(' exceeds the default display width.', pars.mesgs[11])
|
|
3812
|
+
self.eq(' This is the final line with no leading spaces.', pars.mesgs[12])
|
|
3813
|
+
self.eq(' --taz <taz> : Taz option (default: True)', pars.mesgs[13])
|
|
3814
|
+
|
|
3774
3815
|
async def test_storm_cmd_help(self):
|
|
3775
3816
|
|
|
3776
3817
|
async with self.getTestCore() as core:
|
|
@@ -3917,6 +3958,11 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3917
3958
|
self.stormIsInPrint('Warning', msgs)
|
|
3918
3959
|
self.stormIsInPrint('``$lib.infosec.cvss.saveVectToNode`` has been deprecated and will be removed in version v3.0.0.', msgs)
|
|
3919
3960
|
|
|
3961
|
+
msgs = await core.stormlist('help --verbose $lib.inet.whois.guid')
|
|
3962
|
+
self.stormIsInPrint('Warning', msgs)
|
|
3963
|
+
self.stormIsInPrint('``$lib.inet.whois.guid`` has been deprecated and will be removed in version v3.0.0.', msgs)
|
|
3964
|
+
self.stormIsInPrint('Please use the GUID constructor syntax.', msgs)
|
|
3965
|
+
|
|
3920
3966
|
msgs = await core.stormlist('help $lib.inet')
|
|
3921
3967
|
self.stormIsInPrint('The following libraries are available:\n\n'
|
|
3922
3968
|
'$lib.inet.http : A Storm Library exposing an HTTP client API.\n'
|
|
@@ -3947,6 +3993,15 @@ class StormTest(s_t_utils.SynTest):
|
|
|
3947
3993
|
msgs = await core.stormlist('$mod=$lib.import(foosmod) help $mod.f')
|
|
3948
3994
|
self.stormIsInErr('help does not currently support runtime defined functions.', msgs)
|
|
3949
3995
|
|
|
3996
|
+
msgs = await core.stormlist('help --verbose $lib.bytes')
|
|
3997
|
+
self.stormIsInPrint('Warning', msgs)
|
|
3998
|
+
self.stormIsInPrint('$lib.bytes.put`` has been deprecated and will be removed in version v3.0.0', msgs)
|
|
3999
|
+
self.stormIsInPrint('$lib.bytes.has`` has been deprecated and will be removed in version v3.0.0', msgs)
|
|
4000
|
+
self.stormIsInPrint('$lib.bytes.size`` has been deprecated and will be removed in version v3.0.0', msgs)
|
|
4001
|
+
self.stormIsInPrint('$lib.bytes.upload`` has been deprecated and will be removed in version v3.0.0', msgs)
|
|
4002
|
+
self.stormIsInPrint('$lib.bytes.hashset`` has been deprecated and will be removed in version v3.0.0', msgs)
|
|
4003
|
+
self.stormIsInPrint('Use the corresponding ``$lib.axon`` function.', msgs)
|
|
4004
|
+
|
|
3950
4005
|
async def test_liftby_edge(self):
|
|
3951
4006
|
async with self.getTestCore() as core:
|
|
3952
4007
|
|
|
@@ -5071,3 +5126,15 @@ class StormTest(s_t_utils.SynTest):
|
|
|
5071
5126
|
''')
|
|
5072
5127
|
|
|
5073
5128
|
self.none(await core.callStorm('return($lib.queue.gen(haha).get().1)'))
|
|
5129
|
+
|
|
5130
|
+
await core.nodes('''
|
|
5131
|
+
$foo = (foo,)
|
|
5132
|
+
$query = ${
|
|
5133
|
+
$foo.append(bar)
|
|
5134
|
+
$lib.queue.gen(hoho).put($foo)
|
|
5135
|
+
$lib.dmon.del($auto.iden)
|
|
5136
|
+
}
|
|
5137
|
+
$lib.dmon.add($query)
|
|
5138
|
+
''')
|
|
5139
|
+
|
|
5140
|
+
self.eq(['foo', 'bar'], await core.callStorm('return($lib.queue.gen(hoho).get().1)'))
|
|
@@ -510,3 +510,55 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
510
510
|
with self.raises(s_exc.BadArg) as exc:
|
|
511
511
|
await core.callStorm(query)
|
|
512
512
|
self.eq(err, exc.exception.get('mesg'))
|
|
513
|
+
|
|
514
|
+
async def test_lib_stormlib_modelext_interfaces(self):
|
|
515
|
+
async with self.getTestCore() as core:
|
|
516
|
+
|
|
517
|
+
await core.callStorm('''
|
|
518
|
+
$forminfo = ({"interfaces": ["test:interface"]})
|
|
519
|
+
$lib.model.ext.addForm(_test:iface, str, ({}), $forminfo)
|
|
520
|
+
$lib.model.ext.addFormProp(_test:iface, tick, (time, ({})), ({}))
|
|
521
|
+
''')
|
|
522
|
+
|
|
523
|
+
self.nn(core.model.form('_test:iface'))
|
|
524
|
+
self.nn(core.model.prop('_test:iface:flow'))
|
|
525
|
+
self.nn(core.model.prop('_test:iface:proc'))
|
|
526
|
+
self.nn(core.model.prop('_test:iface:tick'))
|
|
527
|
+
self.isin('_test:iface', core.model.formsbyiface['test:interface'])
|
|
528
|
+
self.isin('_test:iface', core.model.formsbyiface['inet:proto:request'])
|
|
529
|
+
self.isin('_test:iface', core.model.formsbyiface['it:host:activity'])
|
|
530
|
+
self.isin('_test:iface:flow', core.model.ifaceprops['inet:proto:request:flow'])
|
|
531
|
+
self.isin('_test:iface:proc', core.model.ifaceprops['test:interface:proc'])
|
|
532
|
+
self.isin('_test:iface:proc', core.model.ifaceprops['inet:proto:request:proc'])
|
|
533
|
+
self.isin('_test:iface:proc', core.model.ifaceprops['it:host:activity:proc'])
|
|
534
|
+
|
|
535
|
+
q = '$lib.model.ext.delForm(_test:iface)'
|
|
536
|
+
with self.raises(s_exc.CantDelForm) as exc:
|
|
537
|
+
await core.callStorm(q)
|
|
538
|
+
self.eq('Form has extended properties: tick', exc.exception.get('mesg'))
|
|
539
|
+
|
|
540
|
+
await core.callStorm('''
|
|
541
|
+
$lib.model.ext.delFormProp(_test:iface, tick)
|
|
542
|
+
$lib.model.ext.delForm(_test:iface)
|
|
543
|
+
''')
|
|
544
|
+
|
|
545
|
+
self.none(core.model.form('_test:iface'))
|
|
546
|
+
self.none(core.model.prop('_test:iface:flow'))
|
|
547
|
+
self.none(core.model.prop('_test:iface:proc'))
|
|
548
|
+
self.none(core.model.prop('_test:iface:tick'))
|
|
549
|
+
self.notin('_test:iface', core.model.formsbyiface['test:interface'])
|
|
550
|
+
self.notin('_test:iface', core.model.formsbyiface['inet:proto:request'])
|
|
551
|
+
self.notin('_test:iface', core.model.formsbyiface['it:host:activity'])
|
|
552
|
+
self.notin('_test:iface:flow', core.model.ifaceprops['inet:proto:request:flow'])
|
|
553
|
+
self.notin('_test:iface:proc', core.model.ifaceprops['test:interface:proc'])
|
|
554
|
+
self.notin('_test:iface:proc', core.model.ifaceprops['inet:proto:request:proc'])
|
|
555
|
+
self.notin('_test:iface:proc', core.model.ifaceprops['it:host:activity:proc'])
|
|
556
|
+
|
|
557
|
+
await core.stormlist('''
|
|
558
|
+
$forminfo = ({"interfaces": ["newp"]})
|
|
559
|
+
$lib.model.ext.addForm(_test:iface, str, ({}), $forminfo)
|
|
560
|
+
''')
|
|
561
|
+
self.nn(core.model.form('_test:iface'))
|
|
562
|
+
|
|
563
|
+
await core.callStorm('$lib.model.ext.delForm(_test:iface)')
|
|
564
|
+
self.none(core.model.form('_test:iface'))
|
|
@@ -55,6 +55,7 @@ class StormLibStixTest(s_test.SynTest):
|
|
|
55
55
|
async def test_stormlib_libstix(self, conf=None):
|
|
56
56
|
|
|
57
57
|
async with self.getTestCore(conf=conf) as core:
|
|
58
|
+
visi = await core.auth.addUser('visi')
|
|
58
59
|
opts = {'vars': {
|
|
59
60
|
'ind': '6ba7d8500964902bf2e03126ed0f6cb1',
|
|
60
61
|
'news': '840b9b003a765020705ea8d203a7659c',
|
|
@@ -228,9 +229,9 @@ class StormLibStixTest(s_test.SynTest):
|
|
|
228
229
|
opts = {'vars': {'config': config}}
|
|
229
230
|
await core.callStorm('$lib.stix.export.bundle(config=$config)', opts=opts)
|
|
230
231
|
|
|
231
|
-
with self.raises(s_exc.
|
|
232
|
+
with self.raises(s_exc.AuthDeny):
|
|
232
233
|
config = {'maxsize': 10000000}
|
|
233
|
-
opts = {'vars': {'config': config}}
|
|
234
|
+
opts = {'user': visi.iden, 'vars': {'config': config}}
|
|
234
235
|
await core.callStorm('$lib.stix.export.bundle(config=$config)', opts=opts)
|
|
235
236
|
|
|
236
237
|
with self.raises(s_exc.NoSuchForm):
|
|
@@ -84,8 +84,8 @@ class StormWhoisTest(s_test.SynTest):
|
|
|
84
84
|
'''
|
|
85
85
|
opts = {'vars': {'props': props}}
|
|
86
86
|
mesgs = await core.stormlist(stormcmd, opts=opts)
|
|
87
|
-
|
|
88
|
-
self.
|
|
87
|
+
self.stormIsInWarn('$lib.inet.whois.guid() is deprecated', mesgs)
|
|
88
|
+
self.stormIsInWarn('Insufficient guid vals identified, using random guid:', mesgs)
|
|
89
89
|
self.len(1, await core.nodes(f'inet:whois:ipquery:fqdn={props["fqdn"]}'))
|
|
90
90
|
|
|
91
91
|
props = {
|
|
@@ -97,8 +97,8 @@ class StormWhoisTest(s_test.SynTest):
|
|
|
97
97
|
'''
|
|
98
98
|
opts = {'vars': {'props': props}}
|
|
99
99
|
mesgs = await core.stormlist(stormcmd, opts=opts)
|
|
100
|
-
|
|
101
|
-
self.
|
|
100
|
+
self.stormIsInWarn('$lib.inet.whois.guid() is deprecated', mesgs)
|
|
101
|
+
self.stormIsInWarn('Insufficient guid vals identified, using random guid:', mesgs)
|
|
102
102
|
self.len(1, await core.nodes(f'inet:whois:ipcontact:asn={props["asn"]}'))
|
|
103
103
|
|
|
104
104
|
# Failure cases
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import synapse.tests.utils as s_tests
|
|
2
|
+
|
|
3
|
+
class DocModelTest(s_tests.SynTest):
|
|
4
|
+
|
|
5
|
+
async def test_model_doc(self):
|
|
6
|
+
|
|
7
|
+
async with self.getTestCore() as core:
|
|
8
|
+
|
|
9
|
+
nodes = await core.nodes('''
|
|
10
|
+
[ doc:policy=*
|
|
11
|
+
:id=V-41
|
|
12
|
+
:name="Rule 41"
|
|
13
|
+
:text="If you can AAAAAAAA..."
|
|
14
|
+
:file=*
|
|
15
|
+
:created=20241018
|
|
16
|
+
:updated=20241018
|
|
17
|
+
:author={[ ps:contact=* :name=visi ]}
|
|
18
|
+
:contributors={[ ps:contact=* :name=shuka ]}
|
|
19
|
+
:version=1.2.3
|
|
20
|
+
:supersedes={[ doc:policy=* doc:policy=* ]}
|
|
21
|
+
]
|
|
22
|
+
''')
|
|
23
|
+
self.len(1, nodes)
|
|
24
|
+
self.eq('V-41', nodes[0].get('id'))
|
|
25
|
+
self.eq('rule 41', nodes[0].get('name'))
|
|
26
|
+
self.eq('If you can AAAAAAAA...', nodes[0].get('text'))
|
|
27
|
+
self.eq(1729209600000, nodes[0].get('created'))
|
|
28
|
+
self.eq(1729209600000, nodes[0].get('updated'))
|
|
29
|
+
self.eq(1099513724931, nodes[0].get('version'))
|
|
30
|
+
|
|
31
|
+
self.nn(nodes[0].get('file'))
|
|
32
|
+
self.nn(nodes[0].get('author'))
|
|
33
|
+
|
|
34
|
+
self.len(2, nodes[0].get('supersedes'))
|
|
35
|
+
self.len(1, nodes[0].get('contributors'))
|
|
36
|
+
|
|
37
|
+
self.len(1, await core.nodes('doc:policy:id=V-41 :file -> file:bytes'))
|
|
38
|
+
self.len(2, await core.nodes('doc:policy:id=V-41 :supersedes -> doc:policy'))
|
|
39
|
+
self.len(1, await core.nodes('doc:policy:id=V-41 :author -> ps:contact +:name=visi'))
|
|
40
|
+
self.len(1, await core.nodes('doc:policy:id=V-41 :contributors -> ps:contact +:name=shuka'))
|
|
41
|
+
|
|
42
|
+
nodes = await core.nodes('''
|
|
43
|
+
[ doc:standard=*
|
|
44
|
+
:id=V-99
|
|
45
|
+
:policy={ doc:policy:id=V-41 }
|
|
46
|
+
]
|
|
47
|
+
''')
|
|
48
|
+
self.len(1, nodes)
|
|
49
|
+
self.eq('V-99', nodes[0].get('id'))
|
|
50
|
+
self.nn(nodes[0].get('policy'))
|
|
51
|
+
self.len(1, await core.nodes('doc:standard -> doc:policy'))
|
|
@@ -1675,8 +1675,12 @@ class InfotechModelTest(s_t_utils.SynTest):
|
|
|
1675
1675
|
self.eq(1640995200000, nodes[0].get('updated'))
|
|
1676
1676
|
self.nn(nodes[0].get('author'))
|
|
1677
1677
|
|
|
1678
|
-
nodes = await core.nodes('[ it:app:snort:hit=$hit
|
|
1678
|
+
nodes = await core.nodes('''[ it:app:snort:hit=$hit
|
|
1679
|
+
:rule=$rule :flow=$flow :src="tcp://[::ffff:0102:0304]:0"
|
|
1680
|
+
:dst="tcp://[::ffff:0505:0505]:80" :time=2015 :sensor=$host
|
|
1681
|
+
:version=1.2.3 :dropped=true ]''', opts=opts)
|
|
1679
1682
|
self.len(1, nodes)
|
|
1683
|
+
self.true(nodes[0].get('dropped'))
|
|
1680
1684
|
self.eq(rule, nodes[0].get('rule'))
|
|
1681
1685
|
self.eq(flow, nodes[0].get('flow'))
|
|
1682
1686
|
self.eq(host, nodes[0].get('sensor'))
|
synapse/tests/test_model_orgs.py
CHANGED
|
@@ -640,6 +640,7 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
640
640
|
|
|
641
641
|
nodes = await core.nodes('''[ ou:requirement=50b757fafe4a839ec499023ebcffe7c0
|
|
642
642
|
:name="acquire pizza toppings"
|
|
643
|
+
:type=foo.bar
|
|
643
644
|
:text="The team must acquire ANSI standard pizza toppings."
|
|
644
645
|
:goal={[ ou:goal=* :name=pizza ]}
|
|
645
646
|
:issuer={[ ps:contact=* :name=visi ]}
|
|
@@ -657,6 +658,7 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
657
658
|
self.eq('The team must acquire ANSI standard pizza toppings.', nodes[0].get('text'))
|
|
658
659
|
self.eq(1, nodes[0].get('deps:min'))
|
|
659
660
|
self.eq(50, nodes[0].get('priority'))
|
|
661
|
+
self.eq('foo.bar.', nodes[0].get('type'))
|
|
660
662
|
self.eq(True, nodes[0].get('optional'))
|
|
661
663
|
self.eq(1328140800000, nodes[0].get('issued'))
|
|
662
664
|
self.eq((1672531200000, 9223372036854775807), nodes[0].get('period'))
|
|
@@ -665,6 +667,80 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
665
667
|
self.len(1, await core.nodes('ou:requirement=50b757fafe4a839ec499023ebcffe7c0 -> ou:goal +:name=pizza'))
|
|
666
668
|
self.len(1, await core.nodes('ou:requirement=50b757fafe4a839ec499023ebcffe7c0 :issuer -> ps:contact +:name=visi'))
|
|
667
669
|
self.len(1, await core.nodes('ou:requirement=50b757fafe4a839ec499023ebcffe7c0 :assignee -> ps:contact +:orgname=ledos'))
|
|
670
|
+
self.len(1, await core.nodes('ou:requirement=50b757fafe4a839ec499023ebcffe7c0 -> ou:requirement:type:taxonomy'))
|
|
671
|
+
|
|
672
|
+
nodes = await core.nodes('''
|
|
673
|
+
[ ou:asset=*
|
|
674
|
+
:id=V-31337
|
|
675
|
+
:name="visi laptop"
|
|
676
|
+
:type=host.laptop
|
|
677
|
+
:priority=highest
|
|
678
|
+
:priority:confidentiality=highest
|
|
679
|
+
:priority:integrity=highest
|
|
680
|
+
:priority:availability=highest
|
|
681
|
+
:node = (it:host, *)
|
|
682
|
+
:period=(2016, ?)
|
|
683
|
+
:status=deployed
|
|
684
|
+
:org={[ ou:org=* :name=vertex ]}
|
|
685
|
+
:owner={[ ps:contact=* :name=foo ]}
|
|
686
|
+
:operator={[ ps:contact=* :name=bar ]}
|
|
687
|
+
]''')
|
|
688
|
+
self.len(1, nodes)
|
|
689
|
+
self.eq((1451606400000, 9223372036854775807), nodes[0].get('period'))
|
|
690
|
+
self.eq('visi laptop', nodes[0].get('name'))
|
|
691
|
+
self.eq('host.laptop.', nodes[0].get('type'))
|
|
692
|
+
self.eq('deployed.', nodes[0].get('status'))
|
|
693
|
+
self.eq(50, nodes[0].get('priority'))
|
|
694
|
+
self.eq(50, nodes[0].get('priority:confidentiality'))
|
|
695
|
+
self.eq(50, nodes[0].get('priority:integrity'))
|
|
696
|
+
self.eq(50, nodes[0].get('priority:availability'))
|
|
697
|
+
|
|
698
|
+
self.len(1, await core.nodes('ou:asset -> ou:asset:type:taxonomy'))
|
|
699
|
+
self.len(1, await core.nodes('ou:asset :node -> it:host'))
|
|
700
|
+
self.len(1, await core.nodes('ou:asset :org -> ou:org +:name=vertex'))
|
|
701
|
+
self.len(1, await core.nodes('ou:asset :owner -> ps:contact +:name=foo '))
|
|
702
|
+
self.len(1, await core.nodes('ou:asset :operator -> ps:contact +:name=bar '))
|
|
703
|
+
|
|
704
|
+
visi = await core.auth.addUser('visi')
|
|
705
|
+
|
|
706
|
+
nodes = await core.nodes('''
|
|
707
|
+
[ ou:enacted=*
|
|
708
|
+
:id=V-99
|
|
709
|
+
:project={[ proj:project=* ]}
|
|
710
|
+
:status=10
|
|
711
|
+
:priority=highest
|
|
712
|
+
:created=20241018
|
|
713
|
+
:updated=20241018
|
|
714
|
+
:due=20241018
|
|
715
|
+
:completed=20241018
|
|
716
|
+
:creator=root
|
|
717
|
+
:assignee=visi
|
|
718
|
+
:scope=(ou:team, *)
|
|
719
|
+
:ext:creator={[ ps:contact=* :name=root ]}
|
|
720
|
+
:ext:assignee={[ ps:contact=* :name=visi ]}
|
|
721
|
+
]
|
|
722
|
+
''')
|
|
723
|
+
self.len(1, nodes)
|
|
724
|
+
self.eq('V-99', nodes[0].get('id'))
|
|
725
|
+
self.eq(10, nodes[0].get('status'))
|
|
726
|
+
self.eq(50, nodes[0].get('priority'))
|
|
727
|
+
|
|
728
|
+
self.eq(1729209600000, nodes[0].get('due'))
|
|
729
|
+
self.eq(1729209600000, nodes[0].get('created'))
|
|
730
|
+
self.eq(1729209600000, nodes[0].get('updated'))
|
|
731
|
+
self.eq(1729209600000, nodes[0].get('completed'))
|
|
732
|
+
|
|
733
|
+
self.eq(visi.iden, nodes[0].get('assignee'))
|
|
734
|
+
self.eq(core.auth.rootuser.iden, nodes[0].get('creator'))
|
|
735
|
+
|
|
736
|
+
self.nn(nodes[0].get('scope'))
|
|
737
|
+
self.nn(nodes[0].get('ext:creator'))
|
|
738
|
+
self.nn(nodes[0].get('ext:assignee'))
|
|
739
|
+
|
|
740
|
+
self.len(1, await core.nodes('ou:enacted -> proj:project'))
|
|
741
|
+
self.len(1, await core.nodes('ou:enacted :scope -> ou:team'))
|
|
742
|
+
self.len(1, await core.nodes('ou:enacted :ext:creator -> ps:contact +:name=root'))
|
|
743
|
+
self.len(1, await core.nodes('ou:enacted :ext:assignee -> ps:contact +:name=visi'))
|
|
668
744
|
|
|
669
745
|
async def test_ou_code_prefixes(self):
|
|
670
746
|
guid0 = s_common.guid()
|
|
@@ -832,6 +908,7 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
832
908
|
:orgfqdn = wootwoot.com
|
|
833
909
|
:currency = USD
|
|
834
910
|
:costs = 200
|
|
911
|
+
:budget = 300
|
|
835
912
|
:revenue = 500
|
|
836
913
|
:profit = 300
|
|
837
914
|
:valuation = 1000000000
|
|
@@ -850,6 +927,7 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
850
927
|
self.eq(nodes[0].get('orgfqdn'), 'wootwoot.com')
|
|
851
928
|
self.eq(nodes[0].get('currency'), 'usd')
|
|
852
929
|
self.eq(nodes[0].get('costs'), '200')
|
|
930
|
+
self.eq(nodes[0].get('budget'), '300')
|
|
853
931
|
self.eq(nodes[0].get('revenue'), '500')
|
|
854
932
|
self.eq(nodes[0].get('profit'), '300')
|
|
855
933
|
self.eq(nodes[0].get('valuation'), '1000000000')
|
synapse/tests/test_model_risk.py
CHANGED
|
@@ -542,6 +542,7 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
542
542
|
risk:mitigation=*
|
|
543
543
|
:vuln=*
|
|
544
544
|
:name=" FooBar "
|
|
545
|
+
:type=foo.bar
|
|
545
546
|
:desc=BazFaz
|
|
546
547
|
:hardware=*
|
|
547
548
|
:software=*
|
|
@@ -552,11 +553,13 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
552
553
|
self.eq('foobar', nodes[0].props['name'])
|
|
553
554
|
self.eq('BazFaz', nodes[0].props['desc'])
|
|
554
555
|
self.eq('vertex', nodes[0].get('reporter:name'))
|
|
556
|
+
self.eq('foo.bar.', nodes[0].get('type'))
|
|
555
557
|
self.nn(nodes[0].get('reporter'))
|
|
556
558
|
self.len(1, await core.nodes('risk:mitigation -> risk:vuln'))
|
|
557
559
|
self.len(1, await core.nodes('risk:mitigation -> it:prod:softver'))
|
|
558
560
|
self.len(1, await core.nodes('risk:mitigation -> it:prod:hardware'))
|
|
559
561
|
self.len(1, await core.nodes('risk:mitigation -> it:mitre:attack:mitigation'))
|
|
562
|
+
self.len(1, await core.nodes('risk:mitigation -> risk:mitigation:type:taxonomy'))
|
|
560
563
|
|
|
561
564
|
async def test_model_risk_tool_software(self):
|
|
562
565
|
|
synapse/tests/test_model_syn.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import synapse.exc as s_exc
|
|
2
|
+
import synapse.common as s_common
|
|
2
3
|
import synapse.cortex as s_cortex
|
|
4
|
+
import synapse.datamodel as s_datamodel
|
|
3
5
|
|
|
4
6
|
import synapse.lib.stormsvc as s_stormsvc
|
|
5
7
|
|
|
@@ -46,6 +48,47 @@ class TestService(s_stormsvc.StormSvc):
|
|
|
46
48
|
|
|
47
49
|
class SynModelTest(s_t_utils.SynTest):
|
|
48
50
|
|
|
51
|
+
async def test_syn_userrole(self):
|
|
52
|
+
|
|
53
|
+
async with self.getTestCore() as core:
|
|
54
|
+
|
|
55
|
+
(ok, iden) = await core.callStorm('return($lib.trycast(syn:user, root))')
|
|
56
|
+
self.true(ok)
|
|
57
|
+
self.eq(iden, core.auth.rootuser.iden)
|
|
58
|
+
|
|
59
|
+
# coverage for iden taking precedence
|
|
60
|
+
(ok, iden) = await core.callStorm(f'return($lib.trycast(syn:user, {iden}))')
|
|
61
|
+
self.true(ok)
|
|
62
|
+
self.eq(iden, core.auth.rootuser.iden)
|
|
63
|
+
|
|
64
|
+
self.eq('root', await core.callStorm(f'return($lib.repr(syn:user, {iden}))'))
|
|
65
|
+
|
|
66
|
+
(ok, iden) = await core.callStorm('return($lib.trycast(syn:role, all))')
|
|
67
|
+
self.true(ok)
|
|
68
|
+
self.eq(iden, core.auth.allrole.iden)
|
|
69
|
+
|
|
70
|
+
# coverage for iden taking precedence
|
|
71
|
+
(ok, iden) = await core.callStorm(f'return($lib.trycast(syn:role, {iden}))')
|
|
72
|
+
self.true(ok)
|
|
73
|
+
self.eq(iden, core.auth.allrole.iden)
|
|
74
|
+
|
|
75
|
+
self.eq('all', await core.callStorm(f'return($lib.repr(syn:role, {iden}))'))
|
|
76
|
+
|
|
77
|
+
# coverage for DataModel without a cortex reference
|
|
78
|
+
iden = s_common.guid()
|
|
79
|
+
|
|
80
|
+
model = core.model
|
|
81
|
+
model.core = None
|
|
82
|
+
|
|
83
|
+
synuser = model.type('syn:user')
|
|
84
|
+
synrole = model.type('syn:user')
|
|
85
|
+
|
|
86
|
+
self.eq(iden, synuser.repr(iden))
|
|
87
|
+
self.eq(iden, synrole.repr(iden))
|
|
88
|
+
|
|
89
|
+
self.eq(iden, synuser.norm(iden)[0])
|
|
90
|
+
self.eq(iden, synrole.norm(iden)[0])
|
|
91
|
+
|
|
49
92
|
async def test_syn_tag(self):
|
|
50
93
|
|
|
51
94
|
async with self.getTestCore() as core:
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import synapse.common as s_common
|
|
2
|
+
|
|
3
|
+
import synapse.lib.base as s_base
|
|
4
|
+
import synapse.lib.cell as s_cell
|
|
5
|
+
|
|
6
|
+
import synapse.tools.promote as s_tools_promote
|
|
7
|
+
|
|
8
|
+
import synapse.tests.utils as s_t_utils
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class PromoteToolTest(s_t_utils.SynTest):
|
|
12
|
+
|
|
13
|
+
async def test_tool_promote_simple(self):
|
|
14
|
+
async with self.getTestAha() as aha:
|
|
15
|
+
async with await s_base.Base.anit() as base:
|
|
16
|
+
with self.getTestDir() as dirn:
|
|
17
|
+
dirn00 = s_common.genpath(dirn, '00.cell')
|
|
18
|
+
dirn01 = s_common.genpath(dirn, '01.cell')
|
|
19
|
+
|
|
20
|
+
cell00 = await base.enter_context(self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=dirn00))
|
|
21
|
+
cell01 = await base.enter_context(self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=dirn01,
|
|
22
|
+
provinfo={'mirror': 'cell'}))
|
|
23
|
+
self.true(cell00.isactive)
|
|
24
|
+
self.false(cell01.isactive)
|
|
25
|
+
await cell01.sync()
|
|
26
|
+
|
|
27
|
+
outp = self.getTestOutp()
|
|
28
|
+
argv = ['--svcurl', cell00.getLocalUrl()]
|
|
29
|
+
ret = await s_tools_promote.main(argv, outp=outp)
|
|
30
|
+
self.eq(1, ret)
|
|
31
|
+
outp.expect('Failed to promote service')
|
|
32
|
+
outp.expect('promote() called on non-mirror')
|
|
33
|
+
|
|
34
|
+
outp.clear()
|
|
35
|
+
argv = ['--svcurl', cell01.getLocalUrl()]
|
|
36
|
+
ret = await s_tools_promote.main(argv, outp=outp)
|
|
37
|
+
self.eq(0, ret)
|
|
38
|
+
self.false(cell00.isactive)
|
|
39
|
+
self.true(cell01.isactive)
|
|
40
|
+
await cell00.sync()
|
|
41
|
+
|
|
42
|
+
async def test_tool_promote_schism(self):
|
|
43
|
+
# Create a mirror of mirrors and try promoting the end mirror.
|
|
44
|
+
async with self.getTestAha() as aha:
|
|
45
|
+
async with await s_base.Base.anit() as base:
|
|
46
|
+
with self.getTestDir() as dirn:
|
|
47
|
+
dirn00 = s_common.genpath(dirn, '00.cell')
|
|
48
|
+
dirn01 = s_common.genpath(dirn, '01.cell')
|
|
49
|
+
dirn02 = s_common.genpath(dirn, '02.cell')
|
|
50
|
+
|
|
51
|
+
cell00 = await base.enter_context(self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=dirn00))
|
|
52
|
+
cell01 = await base.enter_context(self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=dirn01,
|
|
53
|
+
provinfo={'mirror': '00.cell'}))
|
|
54
|
+
cell02 = await base.enter_context(self.addSvcToAha(aha, '02.cell', s_cell.Cell, dirn=dirn02,
|
|
55
|
+
provinfo={'mirror': '01.cell'}))
|
|
56
|
+
self.true(cell00.isactive)
|
|
57
|
+
self.false(cell01.isactive)
|
|
58
|
+
self.false(cell02.isactive)
|
|
59
|
+
await cell02.sync()
|
|
60
|
+
|
|
61
|
+
outp = self.getTestOutp()
|
|
62
|
+
argv = ['--svcurl', cell02.getLocalUrl()]
|
|
63
|
+
ret = await s_tools_promote.main(argv, outp=outp)
|
|
64
|
+
self.eq(1, ret)
|
|
65
|
+
outp.expect('Failed to promote service')
|
|
66
|
+
# Note: The following message may change when SYN-7659 is addressed
|
|
67
|
+
outp.expect('ahaname=01.cell is not the current leader and cannot handoff leadership to aha://02.cell.synapse')
|
synapse/tests/utils.py
CHANGED
|
@@ -201,6 +201,32 @@ class LibTst(s_stormtypes.Lib):
|
|
|
201
201
|
ret = f'A {valu} beep which {bar} the {faz}!'
|
|
202
202
|
return ret
|
|
203
203
|
|
|
204
|
+
class LibDepr(s_stormtypes.Lib):
|
|
205
|
+
'''
|
|
206
|
+
Deprecate me!
|
|
207
|
+
'''
|
|
208
|
+
_storm_locals = (
|
|
209
|
+
{'name': 'boop',
|
|
210
|
+
'desc': '''
|
|
211
|
+
An example storm function that's not deprecated on its own, but the entire library is.
|
|
212
|
+
''',
|
|
213
|
+
'type': {'type': 'function', '_funcname': 'boop',
|
|
214
|
+
'args': (
|
|
215
|
+
{'name': 'valu', 'type': 'str', 'desc': 'What to boop.', },
|
|
216
|
+
),
|
|
217
|
+
'returns': {'type': 'str', 'desc': 'The booped.', }}},
|
|
218
|
+
)
|
|
219
|
+
_storm_lib_path = ('depr',)
|
|
220
|
+
_storm_lib_deprecation = {'eolvers': 'v3.0.0'}
|
|
221
|
+
|
|
222
|
+
def addLibFuncs(self): # pragma: no cover
|
|
223
|
+
self.locls.update({
|
|
224
|
+
'boop': self.boop,
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
async def boop(self, valu): # pragma: no cover
|
|
228
|
+
return f'You have been booped, {valu}!'
|
|
229
|
+
|
|
204
230
|
class TestType(s_types.Type):
|
|
205
231
|
|
|
206
232
|
stortype = s_layer.STOR_TYPE_UTF8
|
synapse/tools/promote.py
CHANGED
|
@@ -2,9 +2,12 @@ import sys
|
|
|
2
2
|
import asyncio
|
|
3
3
|
import argparse
|
|
4
4
|
|
|
5
|
+
import synapse.exc as s_exc
|
|
6
|
+
|
|
5
7
|
import synapse.telepath as s_telepath
|
|
6
8
|
|
|
7
9
|
import synapse.lib.output as s_output
|
|
10
|
+
import synapse.lib.urlhelp as s_urlhelp
|
|
8
11
|
|
|
9
12
|
descr = '''
|
|
10
13
|
Promote a mirror to the leader.
|
|
@@ -29,7 +32,17 @@ async def main(argv, outp=s_output.stdout):
|
|
|
29
32
|
graceful = not opts.failure
|
|
30
33
|
|
|
31
34
|
outp.printf(f'Promoting to leader: {opts.svcurl}')
|
|
32
|
-
|
|
35
|
+
try:
|
|
36
|
+
await cell.promote(graceful=graceful)
|
|
37
|
+
except s_exc.BadState as e:
|
|
38
|
+
mesg = f'Failed to promote service to being a leader; {e.get("mesg")}'
|
|
39
|
+
outp.printf(mesg)
|
|
40
|
+
return 1
|
|
41
|
+
except s_exc.SynErr as e:
|
|
42
|
+
outp.printf(f'Failed to promote service {s_urlhelp.sanitizeUrl(opts.svcurl)}: {e}')
|
|
43
|
+
return 1
|
|
44
|
+
|
|
45
|
+
return 0
|
|
33
46
|
|
|
34
47
|
if __name__ == '__main__': # pragma: no cover
|
|
35
48
|
sys.exit(asyncio.run(main(sys.argv[1:])))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: synapse
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.185.0
|
|
4
4
|
Summary: Synapse Intelligence Analysis Framework
|
|
5
5
|
Author-email: The Vertex Project LLC <root@vertex.link>
|
|
6
6
|
License: Apache License 2.0
|
|
@@ -59,15 +59,10 @@ Requires-Dist: bump2version<1.1.0,>=1.0.1; extra == "dev"
|
|
|
59
59
|
Requires-Dist: pytest-xdist<4.0.0,>=3.0.2; extra == "dev"
|
|
60
60
|
Requires-Dist: coverage<8.0.0,>=7.0.0; extra == "dev"
|
|
61
61
|
Provides-Extra: docs
|
|
62
|
-
Requires-Dist:
|
|
63
|
-
Requires-Dist:
|
|
64
|
-
Requires-Dist:
|
|
65
|
-
Requires-Dist:
|
|
66
|
-
Requires-Dist: nbstripout<1.0.0,>=0.3.3; extra == "docs"
|
|
67
|
-
Requires-Dist: sphinx<7.0.0,>=6.2.0; extra == "docs"
|
|
68
|
-
Requires-Dist: sphinx-rtd-theme<2.0.0,>=1.0.0; extra == "docs"
|
|
69
|
-
Requires-Dist: sphinx-notfound-page==0.8.3; extra == "docs"
|
|
70
|
-
Requires-Dist: jinja2<3.1.0; extra == "docs"
|
|
62
|
+
Requires-Dist: sphinx<9.0.0,>=8.0.0; extra == "docs"
|
|
63
|
+
Requires-Dist: sphinx-rtd-theme<4.0.0,>=3.0.0; extra == "docs"
|
|
64
|
+
Requires-Dist: sphinx-notfound-page<2.0.0,>=1.0.4; extra == "docs"
|
|
65
|
+
Requires-Dist: jinja2<4.0.0,>=3.1.4; extra == "docs"
|
|
71
66
|
|
|
72
67
|
Synapse
|
|
73
68
|
=======
|