synapse 2.187.0__py311-none-any.whl → 2.188.1__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 +131 -7
- synapse/datamodel.py +20 -4
- synapse/exc.py +14 -1
- synapse/lib/ast.py +6 -4
- synapse/lib/auth.py +9 -0
- synapse/lib/drive.py +1 -1
- synapse/lib/httpapi.py +2 -1
- synapse/lib/nexus.py +6 -0
- synapse/lib/node.py +5 -3
- synapse/lib/scrape.py +18 -104
- synapse/lib/storm.py +44 -28
- synapse/lib/stormlib/modelext.py +31 -0
- synapse/lib/stormlib/scrape.py +1 -4
- synapse/lib/stormtypes.py +17 -1
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +9 -3
- synapse/models/base.py +27 -0
- synapse/models/files.py +22 -0
- synapse/models/inet.py +49 -4
- synapse/models/orgs.py +64 -2
- synapse/models/proj.py +1 -6
- synapse/models/risk.py +65 -0
- synapse/tests/test_cortex.py +21 -0
- synapse/tests/test_lib_agenda.py +13 -0
- synapse/tests/test_lib_auth.py +15 -0
- synapse/tests/test_lib_cell.py +170 -159
- synapse/tests/test_lib_httpapi.py +6 -0
- synapse/tests/test_lib_nexus.py +26 -0
- synapse/tests/test_lib_scrape.py +14 -6
- synapse/tests/test_lib_storm.py +48 -0
- synapse/tests/test_lib_stormlib_modelext.py +76 -1
- synapse/tests/test_lib_stormlib_scrape.py +0 -8
- synapse/tests/test_lib_stormtypes.py +1 -1
- synapse/tests/test_lib_trigger.py +8 -0
- synapse/tests/test_lib_view.py +24 -0
- synapse/tests/test_model_base.py +11 -0
- synapse/tests/test_model_files.py +19 -0
- synapse/tests/test_model_inet.py +33 -0
- synapse/tests/test_model_orgs.py +39 -0
- synapse/tests/test_model_proj.py +11 -1
- synapse/tests/test_model_risk.py +32 -0
- {synapse-2.187.0.dist-info → synapse-2.188.1.dist-info}/METADATA +1 -1
- {synapse-2.187.0.dist-info → synapse-2.188.1.dist-info}/RECORD +46 -46
- {synapse-2.187.0.dist-info → synapse-2.188.1.dist-info}/WHEEL +1 -1
- {synapse-2.187.0.dist-info → synapse-2.188.1.dist-info}/LICENSE +0 -0
- {synapse-2.187.0.dist-info → synapse-2.188.1.dist-info}/top_level.txt +0 -0
|
@@ -25,6 +25,13 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
25
25
|
|
|
26
26
|
$edgeinfo = ({"doc": "A test edge."})
|
|
27
27
|
$lib.model.ext.addEdge(inet:user, _copies, *, $edgeinfo)
|
|
28
|
+
|
|
29
|
+
$typeopts = ({"lower": true, "onespace": true})
|
|
30
|
+
$typeinfo = ({"doc": "A test type doc."})
|
|
31
|
+
$forminfo = ({"doc": "A test type form doc."})
|
|
32
|
+
$lib.model.ext.addType(_test:type, str, $typeopts, $typeinfo)
|
|
33
|
+
$lib.model.ext.addForm(_test:typeform, _test:type, ({}), $forminfo)
|
|
34
|
+
$lib.model.ext.addForm(_test:typearry, array, ({"type": "_test:type"}), $forminfo)
|
|
28
35
|
''')
|
|
29
36
|
|
|
30
37
|
nodes = await core.nodes('[ _visi:int=10 :tick=20210101 ._woot=30 +#lol:score=99 ]')
|
|
@@ -39,6 +46,18 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
39
46
|
self.eq(nodes[0].ndef, ('test:int', 1234))
|
|
40
47
|
self.eq(nodes[0].get('_tick'), 1609459200000)
|
|
41
48
|
|
|
49
|
+
nodes = await core.nodes('[_test:typeform=" FoO BaR "]')
|
|
50
|
+
self.len(1, nodes)
|
|
51
|
+
self.eq(nodes[0].ndef, ('_test:typeform', 'foo bar'))
|
|
52
|
+
|
|
53
|
+
with self.raises(s_exc.DupTypeName):
|
|
54
|
+
q = '$lib.model.ext.addType(_test:type, str, ({}), ({}))'
|
|
55
|
+
await core.callStorm(q)
|
|
56
|
+
|
|
57
|
+
with self.raises(s_exc.DupTypeName):
|
|
58
|
+
q = '$lib.model.ext.addForm(_test:type, str, ({}), ({}))'
|
|
59
|
+
await core.callStorm(q)
|
|
60
|
+
|
|
42
61
|
with self.raises(s_exc.DupPropName):
|
|
43
62
|
q = '''$lib.model.ext.addFormProp(_visi:int, tick, (time, ({})), ({}))'''
|
|
44
63
|
await core.callStorm(q)
|
|
@@ -69,7 +88,7 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
69
88
|
await core._delAllTagProp('score', {})
|
|
70
89
|
self.len(0, await core.nodes('#lol:score'))
|
|
71
90
|
|
|
72
|
-
await core.callStorm('_visi:int=10 test:int=1234 | delnode')
|
|
91
|
+
await core.callStorm('_visi:int=10 test:int=1234 _test:typeform | delnode')
|
|
73
92
|
await core.callStorm('''
|
|
74
93
|
$lib.model.ext.delTagProp(score, force=(true))
|
|
75
94
|
$lib.model.ext.delUnivProp(_woot, force=(true))
|
|
@@ -79,6 +98,22 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
79
98
|
$lib.model.ext.delEdge(inet:user, _copies, *)
|
|
80
99
|
''')
|
|
81
100
|
|
|
101
|
+
with self.raises(s_exc.CantDelType) as cm:
|
|
102
|
+
await core.callStorm('$lib.model.ext.delType(_test:type)')
|
|
103
|
+
self.isin('still in use by other types', cm.exception.get('mesg'))
|
|
104
|
+
|
|
105
|
+
await core.callStorm('$lib.model.ext.delForm(_test:typeform)')
|
|
106
|
+
|
|
107
|
+
with self.raises(s_exc.CantDelType) as cm:
|
|
108
|
+
await core.callStorm('$lib.model.ext.delType(_test:type)')
|
|
109
|
+
self.isin('still in use by array types', cm.exception.get('mesg'))
|
|
110
|
+
|
|
111
|
+
await core.callStorm('$lib.model.ext.delForm(_test:typearry)')
|
|
112
|
+
await core.callStorm('$lib.model.ext.delType(_test:type)')
|
|
113
|
+
|
|
114
|
+
self.none(core.model.type('_test:type'))
|
|
115
|
+
self.none(core.model.form('_test:typeform'))
|
|
116
|
+
self.none(core.model.form('_test:typearry'))
|
|
82
117
|
self.none(core.model.form('_visi:int'))
|
|
83
118
|
self.none(core.model.prop('._woot'))
|
|
84
119
|
self.none(core.model.prop('_visi:int:tick'))
|
|
@@ -100,6 +135,14 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
100
135
|
q = '''$lib.model.ext.addTagProp(some:_score, (int, ({})), ({}))'''
|
|
101
136
|
self.none(await core.callStorm(q))
|
|
102
137
|
|
|
138
|
+
with self.raises(s_exc.BadTypeDef):
|
|
139
|
+
q = '$lib.model.ext.addType(test:type, str, ({}), ({}))'
|
|
140
|
+
await core.callStorm(q)
|
|
141
|
+
|
|
142
|
+
with self.raises(s_exc.BadTypeDef):
|
|
143
|
+
q = '$lib.model.ext.delType(test:type)'
|
|
144
|
+
await core.callStorm(q)
|
|
145
|
+
|
|
103
146
|
with self.raises(s_exc.BadPropDef):
|
|
104
147
|
q = '''$l =$lib.list('str', ({})) $d=({"doc": "Foo"})
|
|
105
148
|
$lib.model.ext.addFormProp('test:str', '_test:_my^prop', $l, $d)
|
|
@@ -158,6 +201,18 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
158
201
|
$lib.model.ext.addForm(_visi:int, int, $typeinfo, $forminfo)
|
|
159
202
|
''', opts=opts)
|
|
160
203
|
|
|
204
|
+
with self.raises(s_exc.AuthDeny) as cm:
|
|
205
|
+
await core.callStorm('''
|
|
206
|
+
$lib.model.ext.addType(_test:type, str, ({}), ({}))
|
|
207
|
+
''', opts=opts)
|
|
208
|
+
self.isin('permission model.type.add._test:type', cm.exception.get('mesg'))
|
|
209
|
+
|
|
210
|
+
with self.raises(s_exc.AuthDeny) as cm:
|
|
211
|
+
await core.callStorm('''
|
|
212
|
+
$lib.model.ext.delType(_test:type)
|
|
213
|
+
''', opts=opts)
|
|
214
|
+
self.isin('permission model.type.del._test:type', cm.exception.get('mesg'))
|
|
215
|
+
|
|
161
216
|
with self.raises(s_exc.AuthDeny):
|
|
162
217
|
await core.callStorm('''
|
|
163
218
|
$propinfo = ({"doc": "A test prop doc."})
|
|
@@ -206,6 +261,10 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
206
261
|
# Add props which conflict with what was previously dumped
|
|
207
262
|
async with self.getTestCore() as core:
|
|
208
263
|
await core.callStorm('''
|
|
264
|
+
$typeopts = ({"lower": true})
|
|
265
|
+
$typeinfo = ({"doc": "A test type doc."})
|
|
266
|
+
$lib.model.ext.addType(_test:type, str, $typeopts, $typeinfo)
|
|
267
|
+
|
|
209
268
|
$typeinfo = ({})
|
|
210
269
|
$forminfo = ({"doc": "NEWP"})
|
|
211
270
|
$lib.model.ext.addForm(_visi:int, int, $typeinfo, $forminfo)
|
|
@@ -226,6 +285,11 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
226
285
|
$lib.model.ext.addEdge(inet:user, _copies, *, $edgeinfo)
|
|
227
286
|
''')
|
|
228
287
|
|
|
288
|
+
q = '''return ($lib.model.ext.addExtModel($model_defs))'''
|
|
289
|
+
with self.raises(s_exc.BadTypeDef) as cm:
|
|
290
|
+
opts = {'vars': {'model_defs': {'types': model_defs['types']}}}
|
|
291
|
+
await core.callStorm(q, opts)
|
|
292
|
+
|
|
229
293
|
q = '''return ($lib.model.ext.addExtModel($model_defs))'''
|
|
230
294
|
with self.raises(s_exc.BadFormDef) as cm:
|
|
231
295
|
opts = {'vars': {'model_defs': {'forms': model_defs['forms']}}}
|
|
@@ -255,6 +319,9 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
255
319
|
async with self.getTestCore() as core:
|
|
256
320
|
opts = {'vars': {'model_defs': model_defs}}
|
|
257
321
|
q = '''
|
|
322
|
+
for ($name, $type, $opts, $info) in $model_defs.types {
|
|
323
|
+
$lib.model.ext.addType($name, $type, $opts, $info)
|
|
324
|
+
}
|
|
258
325
|
for ($name, $type, $opts, $info) in $model_defs.forms {
|
|
259
326
|
$lib.model.ext.addForm($name, $type, $opts, $info)
|
|
260
327
|
}
|
|
@@ -473,6 +540,14 @@ class StormtypesModelextTest(s_test.SynTest):
|
|
|
473
540
|
'$lib.model.ext.addForm(inet:fqdn, _foo:bar, ({}), ())',
|
|
474
541
|
'Form type info should be a dict.'
|
|
475
542
|
),
|
|
543
|
+
(
|
|
544
|
+
'$lib.model.ext.addType(_test:type, str, (guid, ()), ())',
|
|
545
|
+
'Type options should be a dict.'
|
|
546
|
+
),
|
|
547
|
+
(
|
|
548
|
+
'$lib.model.ext.addType(_test:type, str, ({}), ())',
|
|
549
|
+
'Type info should be a dict.'
|
|
550
|
+
),
|
|
476
551
|
(
|
|
477
552
|
'$lib.model.ext.addFormProp(inet:fqdn, _foo:bar, ({}), ())',
|
|
478
553
|
'Form property type definitions should be a tuple.'
|
|
@@ -105,14 +105,6 @@ class StormScrapeTest(s_test.SynTest):
|
|
|
105
105
|
self.stormIsInPrint('inet:url=https://giggles.com/mallory.html', msgs)
|
|
106
106
|
self.stormIsInPrint("'match': 'hzzps[:]\\\\giggles.com/mallory.html'", msgs)
|
|
107
107
|
|
|
108
|
-
with mock.patch('synapse.lib.scrape.SCRAPE_SPAWN_LENGTH', 0):
|
|
109
|
-
msgs = await core.stormlist(q, opts={'vars': {'text': text}})
|
|
110
|
-
self.stormIsInPrint('ps:name=alice', msgs)
|
|
111
|
-
self.stormIsInPrint('inet:fqdn=foo.bar.com', msgs)
|
|
112
|
-
self.stormIsInPrint('inet:url=https://1.2.3.4/alice.html', msgs)
|
|
113
|
-
self.stormIsInPrint('inet:url=https://giggles.com/mallory.html', msgs)
|
|
114
|
-
self.stormIsInPrint("'match': 'hzzps[:]\\\\giggles.com/mallory.html'", msgs)
|
|
115
|
-
|
|
116
108
|
cq = '''$ret=$lib.list()
|
|
117
109
|
for ($form, $valu) in $lib.scrape.ndefs($text) {
|
|
118
110
|
$ret.append(($form, $valu))
|
|
@@ -2342,7 +2342,7 @@ class StormTypesTest(s_test.SynTest):
|
|
|
2342
2342
|
path = pode[1]['path']
|
|
2343
2343
|
self.len(1, path)
|
|
2344
2344
|
key = list(path.keys())[0]
|
|
2345
|
-
self.true(key.startswith(
|
|
2345
|
+
self.true(key.startswith('vertex.link'))
|
|
2346
2346
|
self.eq(('foo', 'bar'), path[key])
|
|
2347
2347
|
|
|
2348
2348
|
q = '''
|
|
@@ -264,6 +264,14 @@ class TrigTest(s_t_utils.SynTest):
|
|
|
264
264
|
await view.addTrigger(tdef)
|
|
265
265
|
self.eq(pdef0.get('storm'), (await view.getTrigger(iden)).tdef.get('storm'))
|
|
266
266
|
|
|
267
|
+
with self.raises(s_exc.DupIden):
|
|
268
|
+
tdef = {'cond': 'node:add', 'storm': '[ +#dupiden ]', 'form': 'test:int', 'iden': view.iden}
|
|
269
|
+
await view.addTrigger(tdef)
|
|
270
|
+
|
|
271
|
+
with self.raises(s_exc.NoSuchIden):
|
|
272
|
+
await view.delTrigger(view.iden)
|
|
273
|
+
self.nn(core.auth.getAuthGate(view.iden))
|
|
274
|
+
|
|
267
275
|
# Bad trigger parms
|
|
268
276
|
with self.raises(s_exc.SchemaViolation):
|
|
269
277
|
await view.addTrigger({'cond': 'nocond', 'storm': 'test:int=4', 'form': 'test:str'})
|
synapse/tests/test_lib_view.py
CHANGED
|
@@ -905,3 +905,27 @@ class ViewTest(s_t_utils.SynTest):
|
|
|
905
905
|
|
|
906
906
|
with self.raises(s_exc.BadState):
|
|
907
907
|
await core.callStorm('return($lib.view.get().insertParentFork().iden)')
|
|
908
|
+
|
|
909
|
+
async def test_view_children(self):
|
|
910
|
+
|
|
911
|
+
async with self.getTestCore() as core:
|
|
912
|
+
|
|
913
|
+
view00 = core.getView()
|
|
914
|
+
view01 = core.getView((await view00.fork())['iden'])
|
|
915
|
+
view02 = core.getView((await view01.fork())['iden'])
|
|
916
|
+
view03 = core.getView((await view01.fork())['iden'])
|
|
917
|
+
|
|
918
|
+
q = '''
|
|
919
|
+
$kids = ([])
|
|
920
|
+
for $child in $lib.view.get($iden).children() { $kids.append($child.iden) }
|
|
921
|
+
return($kids)
|
|
922
|
+
'''
|
|
923
|
+
|
|
924
|
+
opts = {'vars': {'iden': view00.iden}}
|
|
925
|
+
self.eq([view01.iden], await core.callStorm(q, opts=opts))
|
|
926
|
+
|
|
927
|
+
opts['vars']['iden'] = view01.iden
|
|
928
|
+
self.eq([view02.iden, view03.iden], await core.callStorm(q, opts=opts))
|
|
929
|
+
|
|
930
|
+
opts['vars']['iden'] = view02.iden
|
|
931
|
+
self.eq([], await core.callStorm(q, opts=opts))
|
synapse/tests/test_model_base.py
CHANGED
|
@@ -391,3 +391,14 @@ class BaseTest(s_t_utils.SynTest):
|
|
|
391
391
|
for node in nodes:
|
|
392
392
|
form = core.model.form(node.ndef[1])
|
|
393
393
|
self.true(form.deprecated, msg=form)
|
|
394
|
+
|
|
395
|
+
async def test_model_aggregate(self):
|
|
396
|
+
|
|
397
|
+
async with self.getTestCore() as core:
|
|
398
|
+
|
|
399
|
+
nodes = await core.nodes('[ meta:aggregate=* :count=99 :type=bottles :time=20240202 ]')
|
|
400
|
+
self.len(1, nodes)
|
|
401
|
+
self.eq(99, nodes[0].get('count'))
|
|
402
|
+
self.eq('bottles.', nodes[0].get('type'))
|
|
403
|
+
self.eq(1706832000000, nodes[0].get('time'))
|
|
404
|
+
self.len(1, await core.nodes('meta:aggregate -> meta:aggregate:type:taxonomy'))
|
|
@@ -638,3 +638,22 @@ class FileTest(s_t_utils.SynTest):
|
|
|
638
638
|
self.eq(node.get('iconindex'), 1)
|
|
639
639
|
|
|
640
640
|
self.len(1, await core.nodes('file:mime:lnk -> it:hostname'))
|
|
641
|
+
|
|
642
|
+
async def test_model_file_attachment(self):
|
|
643
|
+
|
|
644
|
+
async with self.getTestCore() as core:
|
|
645
|
+
|
|
646
|
+
nodes = await core.nodes('''
|
|
647
|
+
[ file:attachment=*
|
|
648
|
+
:name=Foo/Bar.exe
|
|
649
|
+
:text="foo bar"
|
|
650
|
+
:file=*
|
|
651
|
+
]
|
|
652
|
+
''')
|
|
653
|
+
self.len(1, nodes)
|
|
654
|
+
self.nn(nodes[0].get('file'))
|
|
655
|
+
self.eq('foo bar', nodes[0].get('text'))
|
|
656
|
+
self.eq('foo/bar.exe', nodes[0].get('name'))
|
|
657
|
+
|
|
658
|
+
self.len(1, await core.nodes('file:attachment -> file:bytes'))
|
|
659
|
+
self.len(1, await core.nodes('file:attachment -> file:path'))
|
synapse/tests/test_model_inet.py
CHANGED
|
@@ -455,6 +455,8 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
455
455
|
:src:rdp:hostname=SYNCODER
|
|
456
456
|
:src:rdp:keyboard:layout=AZERTY
|
|
457
457
|
:raw=((10), (20))
|
|
458
|
+
:src:txfiles={[ file:attachment=* :name=foo.exe ]}
|
|
459
|
+
:dst:txfiles={[ file:attachment=* :name=bar.exe ]}
|
|
458
460
|
)]'''
|
|
459
461
|
nodes = await core.nodes(q, opts={'vars': {'valu': valu, 'p': props}})
|
|
460
462
|
self.len(1, nodes)
|
|
@@ -501,6 +503,8 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
501
503
|
self.len(2, await core.nodes('inet:flow -> crypto:x509:cert'))
|
|
502
504
|
self.len(1, await core.nodes('inet:flow :src:ssh:key -> crypto:key'))
|
|
503
505
|
self.len(1, await core.nodes('inet:flow :dst:ssh:key -> crypto:key'))
|
|
506
|
+
self.len(1, await core.nodes('inet:flow :src:txfiles -> file:attachment +:name=foo.exe'))
|
|
507
|
+
self.len(1, await core.nodes('inet:flow :dst:txfiles -> file:attachment +:name=bar.exe'))
|
|
504
508
|
|
|
505
509
|
async def test_fqdn(self):
|
|
506
510
|
formname = 'inet:fqdn'
|
|
@@ -3374,3 +3378,32 @@ class InetModelTest(s_t_utils.SynTest):
|
|
|
3374
3378
|
:channel -> inet:service:channel
|
|
3375
3379
|
+:name="/r/synapse"
|
|
3376
3380
|
'''))
|
|
3381
|
+
|
|
3382
|
+
nodes = await core.nodes('''
|
|
3383
|
+
[ inet:service:relationship=*
|
|
3384
|
+
:source={ inet:service:account:user=visi }
|
|
3385
|
+
:target={ inet:service:account:user=visi }
|
|
3386
|
+
:type=follows
|
|
3387
|
+
]
|
|
3388
|
+
''')
|
|
3389
|
+
self.nn(nodes[0].get('source'))
|
|
3390
|
+
self.nn(nodes[0].get('target'))
|
|
3391
|
+
self.eq('follows.', nodes[0].get('type'))
|
|
3392
|
+
self.len(1, await core.nodes('inet:service:relationship :source -> inet:service:account +:user=visi'))
|
|
3393
|
+
self.len(1, await core.nodes('inet:service:relationship :target -> inet:service:account +:user=visi'))
|
|
3394
|
+
|
|
3395
|
+
nodes = await core.nodes('''
|
|
3396
|
+
[ inet:service:emote=*
|
|
3397
|
+
:creator={ inet:service:account:user=visi }
|
|
3398
|
+
:about={[ it:dev:repo=* :name=vertex ]}
|
|
3399
|
+
:text=":gothparrot:"
|
|
3400
|
+
]
|
|
3401
|
+
''')
|
|
3402
|
+
self.nn(nodes[0].get('about'))
|
|
3403
|
+
self.nn(nodes[0].get('creator'))
|
|
3404
|
+
self.eq(':gothparrot:', nodes[0].get('text'))
|
|
3405
|
+
self.len(1, await core.nodes('inet:service:emote :about -> it:dev:repo +:name=vertex'))
|
|
3406
|
+
self.len(1, await core.nodes('inet:service:emote :creator -> inet:service:account +:user=visi'))
|
|
3407
|
+
|
|
3408
|
+
with self.raises(s_exc.BadTypeValu):
|
|
3409
|
+
await core.nodes('[ inet:service:relationship=* :source={[it:dev:str=foo]} ]')
|
synapse/tests/test_model_orgs.py
CHANGED
|
@@ -742,6 +742,32 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
742
742
|
self.len(1, await core.nodes('ou:enacted :ext:creator -> ps:contact +:name=root'))
|
|
743
743
|
self.len(1, await core.nodes('ou:enacted :ext:assignee -> ps:contact +:name=visi'))
|
|
744
744
|
|
|
745
|
+
nodes = await core.nodes('''
|
|
746
|
+
[ ou:candidate=*
|
|
747
|
+
:org={ ou:org:name=vertex | limit 1 }
|
|
748
|
+
:contact={ ps:contact:name=visi | limit 1 }
|
|
749
|
+
:intro=" Hi there!"
|
|
750
|
+
:submitted=20241104
|
|
751
|
+
:method=referral.employee
|
|
752
|
+
:resume=*
|
|
753
|
+
:opening=*
|
|
754
|
+
:agent={[ ps:contact=* :name=agent ]}
|
|
755
|
+
:recruiter={[ ps:contact=* :name=recruiter ]}
|
|
756
|
+
:attachments={[ file:attachment=* :name=questions.pdf ]}
|
|
757
|
+
]
|
|
758
|
+
''')
|
|
759
|
+
self.len(1, nodes)
|
|
760
|
+
self.eq('Hi there!', nodes[0].get('intro'))
|
|
761
|
+
self.eq(1730678400000, nodes[0].get('submitted'))
|
|
762
|
+
self.eq('referral.employee.', nodes[0].get('method'))
|
|
763
|
+
self.len(1, await core.nodes('ou:candidate :org -> ou:org +:name=vertex'))
|
|
764
|
+
self.len(1, await core.nodes('ou:candidate :agent -> ps:contact +:name=agent'))
|
|
765
|
+
self.len(1, await core.nodes('ou:candidate :contact -> ps:contact +:name=visi'))
|
|
766
|
+
self.len(1, await core.nodes('ou:candidate :recruiter -> ps:contact +:name=recruiter'))
|
|
767
|
+
|
|
768
|
+
self.len(1, await core.nodes('ou:candidate :method -> ou:candidate:method:taxonomy'))
|
|
769
|
+
self.len(1, await core.nodes('ou:candidate :attachments -> file:attachment'))
|
|
770
|
+
|
|
745
771
|
async def test_ou_code_prefixes(self):
|
|
746
772
|
guid0 = s_common.guid()
|
|
747
773
|
guid1 = s_common.guid()
|
|
@@ -839,16 +865,21 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
839
865
|
:sic="1234,5678"
|
|
840
866
|
:isic=C1393
|
|
841
867
|
:desc="Moldy cheese"
|
|
868
|
+
:reporter={[ ou:org=* :name=vertex ]}
|
|
869
|
+
:reporter:name=vertex
|
|
842
870
|
] '''
|
|
843
871
|
nodes = await core.nodes(q)
|
|
844
872
|
self.len(1, nodes)
|
|
873
|
+
self.nn(nodes[0].get('reporter'))
|
|
845
874
|
self.eq('foo bar', nodes[0].get('name'))
|
|
875
|
+
self.eq('vertex', nodes[0].get('reporter:name'))
|
|
846
876
|
self.sorteq(('1234', '5678'), nodes[0].get('sic'))
|
|
847
877
|
self.sorteq(('11111', '22222'), nodes[0].get('naics'))
|
|
848
878
|
self.sorteq(('C1393', ), nodes[0].get('isic'))
|
|
849
879
|
self.len(2, nodes[0].get('subs'))
|
|
850
880
|
self.eq('Moldy cheese', nodes[0].get('desc'))
|
|
851
881
|
|
|
882
|
+
self.len(1, await core.nodes('ou:industry :reporter -> ou:org'))
|
|
852
883
|
nodes = await core.nodes('ou:industry:name="foo bar" | tree { :subs -> ou:industry } | uniq')
|
|
853
884
|
self.len(3, nodes)
|
|
854
885
|
self.len(3, await core.nodes('ou:industryname=baz -> ou:industry -> ou:industryname'))
|
|
@@ -989,3 +1020,11 @@ class OuModelTest(s_t_utils.SynTest):
|
|
|
989
1020
|
self.len(1, await core.nodes('ou:contribution -> econ:acct:payment'))
|
|
990
1021
|
self.len(1, await core.nodes('ou:contribution -> mat:spec'))
|
|
991
1022
|
self.len(1, await core.nodes('ou:contribution -> ou:jobtitle +ou:jobtitle=analysts'))
|
|
1023
|
+
|
|
1024
|
+
async def test_ou_technique(self):
|
|
1025
|
+
|
|
1026
|
+
async with self.getTestCore() as core:
|
|
1027
|
+
nodes = await core.nodes('''
|
|
1028
|
+
[ ou:technique=* :name=foo +(uses)> { [ risk:vuln=* :name=bar ] } ]
|
|
1029
|
+
''')
|
|
1030
|
+
self.len(1, await core.nodes('ou:technique:name=foo -(uses)> risk:vuln:name=bar'))
|
synapse/tests/test_model_proj.py
CHANGED
|
@@ -334,7 +334,7 @@ class ProjModelTest(s_test.SynTest):
|
|
|
334
334
|
self.true(await core.callStorm('return($lib.projects.del($proj))', opts=opts))
|
|
335
335
|
self.false(await core.callStorm('return($lib.projects.del(newp))', opts=opts))
|
|
336
336
|
|
|
337
|
-
self.
|
|
337
|
+
self.nn(core.auth.getAuthGate(proj))
|
|
338
338
|
|
|
339
339
|
self.len(1, await core.nodes('yield $lib.projects.add(proj)'))
|
|
340
340
|
self.len(1, await core.nodes('yield $lib.projects.get(proj).epics.add(epic)'))
|
|
@@ -345,6 +345,16 @@ class ProjModelTest(s_test.SynTest):
|
|
|
345
345
|
name = await core.callStorm('$p=$lib.projects.get(proj) $p.name=newproj return ( $p.name )')
|
|
346
346
|
self.eq(name, 'newproj')
|
|
347
347
|
|
|
348
|
+
viewiden = core.getView().iden
|
|
349
|
+
self.len(1, await core.nodes(f'[ proj:project={viewiden}]'))
|
|
350
|
+
gate = core.auth.getAuthGate(viewiden)
|
|
351
|
+
self.eq(gate.type, 'view')
|
|
352
|
+
|
|
353
|
+
await core.nodes(f'proj:project={viewiden} | delnode')
|
|
354
|
+
gate = core.auth.getAuthGate(viewiden)
|
|
355
|
+
self.nn(gate)
|
|
356
|
+
self.eq(gate.type, 'view')
|
|
357
|
+
|
|
348
358
|
async def test_model_proj_attachment(self):
|
|
349
359
|
|
|
350
360
|
async with self.getTestCore() as core:
|
synapse/tests/test_model_risk.py
CHANGED
|
@@ -536,6 +536,31 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
536
536
|
self.len(1, await core.nodes('risk:vuln:name=redtree -> risk:vulnerable :node -> *'))
|
|
537
537
|
self.len(1, await core.nodes('risk:vulnerable -> risk:mitigation'))
|
|
538
538
|
|
|
539
|
+
nodes = await core.nodes('''
|
|
540
|
+
[ risk:outage=*
|
|
541
|
+
:name="The Big One"
|
|
542
|
+
:period=(2023, 2024)
|
|
543
|
+
:type=service.power
|
|
544
|
+
:cause=nature.earthquake
|
|
545
|
+
:provider={[ ou:org=* :name="desert power" ]}
|
|
546
|
+
:provider:name="desert power"
|
|
547
|
+
:reporter={ ou:org:name=vertex }
|
|
548
|
+
:reporter:name=vertex
|
|
549
|
+
]
|
|
550
|
+
''')
|
|
551
|
+
self.len(1, nodes)
|
|
552
|
+
self.nn(nodes[0].get('reporter'))
|
|
553
|
+
self.eq('the big one', nodes[0].get('name'))
|
|
554
|
+
self.eq('vertex', nodes[0].get('reporter:name'))
|
|
555
|
+
self.eq('desert power', nodes[0].get('provider:name'))
|
|
556
|
+
self.eq('service.power.', nodes[0].get('type'))
|
|
557
|
+
self.eq('nature.earthquake.', nodes[0].get('cause'))
|
|
558
|
+
self.eq((1672531200000, 1704067200000), nodes[0].get('period'))
|
|
559
|
+
|
|
560
|
+
self.len(1, await core.nodes('risk:outage -> risk:outage:cause:taxonomy'))
|
|
561
|
+
self.len(1, await core.nodes('risk:outage :reporter -> ou:org +:name=vertex'))
|
|
562
|
+
self.len(1, await core.nodes('risk:outage :provider -> ou:org +:name="desert power"'))
|
|
563
|
+
|
|
539
564
|
async def test_model_risk_mitigation(self):
|
|
540
565
|
async with self.getTestCore() as core:
|
|
541
566
|
nodes = await core.nodes('''[
|
|
@@ -618,3 +643,10 @@ class RiskModelTest(s_t_utils.SynTest):
|
|
|
618
643
|
self.nn(nodes[0].get('version:min'))
|
|
619
644
|
self.nn(nodes[0].get('version:max'))
|
|
620
645
|
self.len(2, await core.nodes('risk:vuln:name=woot -> risk:vuln:soft:range -> it:prod:softver'))
|
|
646
|
+
|
|
647
|
+
async def test_model_risk_vuln_technique(self):
|
|
648
|
+
async with self.getTestCore() as core:
|
|
649
|
+
nodes = await core.nodes('''
|
|
650
|
+
[ risk:vuln=* :name=foo <(uses)+ { [ ou:technique=* :name=bar ] } ]
|
|
651
|
+
''')
|
|
652
|
+
self.len(1, await core.nodes('risk:vuln:name=foo <(uses)- ou:technique:name=bar'))
|