synapse 2.187.0__py311-none-any.whl → 2.188.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 +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/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 +1 -1
- 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.0.dist-info}/METADATA +1 -1
- {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/RECORD +45 -45
- {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/LICENSE +0 -0
- {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/WHEEL +0 -0
- {synapse-2.187.0.dist-info → synapse-2.188.0.dist-info}/top_level.txt +0 -0
synapse/models/orgs.py
CHANGED
|
@@ -249,8 +249,24 @@ class OuModule(s_module.CoreModule):
|
|
|
249
249
|
'doc': 'Vital statistics about an org for a given time period.',
|
|
250
250
|
}),
|
|
251
251
|
('ou:opening', ('guid', {}), {
|
|
252
|
-
'doc': 'A job/work opening within an org.',
|
|
253
|
-
|
|
252
|
+
'doc': 'A job/work opening within an org.'}),
|
|
253
|
+
|
|
254
|
+
('ou:candidate:method:taxonomy', ('taxonomy', {}), {
|
|
255
|
+
'interfaces': ('meta:taxonomy',),
|
|
256
|
+
'doc': 'A taxonomy of methods by which a candidate came under consideration.'}),
|
|
257
|
+
|
|
258
|
+
('ou:candidate', ('guid', {}), {
|
|
259
|
+
'doc': 'A candidate being considered for a role within an organization.',
|
|
260
|
+
'display': {
|
|
261
|
+
'columns': (
|
|
262
|
+
{'type': 'prop', 'opts': {'name': 'contact::name'}},
|
|
263
|
+
{'type': 'prop', 'opts': {'name': 'contact::email'}},
|
|
264
|
+
{'type': 'prop', 'opts': {'name': 'submitted'}},
|
|
265
|
+
{'type': 'prop', 'opts': {'name': 'org::name'}},
|
|
266
|
+
{'type': 'prop', 'opts': {'name': 'opening::jobtitle'}},
|
|
267
|
+
),
|
|
268
|
+
}}),
|
|
269
|
+
|
|
254
270
|
('ou:jobtype', ('taxonomy', {}), {
|
|
255
271
|
'ex': 'it.dev.python',
|
|
256
272
|
'doc': 'A taxonomy of job types.',
|
|
@@ -287,6 +303,8 @@ class OuModule(s_module.CoreModule):
|
|
|
287
303
|
'doc': 'The campaign used the technique.'}),
|
|
288
304
|
(('ou:org', 'uses', 'ou:technique'), {
|
|
289
305
|
'doc': 'The org uses the technique.'}),
|
|
306
|
+
(('risk:vuln', 'uses', 'ou:technique'), {
|
|
307
|
+
'doc': 'The vulnerability uses the technique.'}),
|
|
290
308
|
|
|
291
309
|
(('ou:org', 'uses', None), {
|
|
292
310
|
'doc': 'The ou:org makes use of the target node.'}),
|
|
@@ -354,6 +372,44 @@ class OuModule(s_module.CoreModule):
|
|
|
354
372
|
}),
|
|
355
373
|
# TODO a way to encode/normalize requirements.
|
|
356
374
|
)),
|
|
375
|
+
('ou:candidate:method:taxonomy', {}, ()),
|
|
376
|
+
('ou:candidate', {}, (
|
|
377
|
+
|
|
378
|
+
('org', ('ou:org', {}), {
|
|
379
|
+
'doc': 'The organization considering the candidate.'}),
|
|
380
|
+
|
|
381
|
+
('contact', ('ps:contact', {}), {
|
|
382
|
+
'doc': 'The contact information of the candidate.'}),
|
|
383
|
+
|
|
384
|
+
('method', ('ou:candidate:method:taxonomy', {}), {
|
|
385
|
+
'doc': 'The method by which the candidate came under consideration.'}),
|
|
386
|
+
|
|
387
|
+
('submitted', ('time', {}), {
|
|
388
|
+
'doc': 'The time the candidate was submitted for consideration.'}),
|
|
389
|
+
|
|
390
|
+
('intro', ('str', {'strip': True}), {
|
|
391
|
+
'doc': 'An introduction or cover letter text submitted by the candidate.'}),
|
|
392
|
+
|
|
393
|
+
('resume', ('file:bytes', {}), {
|
|
394
|
+
'doc': "The candidate's resume or CV."}),
|
|
395
|
+
|
|
396
|
+
('opening', ('ou:opening', {}), {
|
|
397
|
+
'doc': 'The opening that the candidate is being considered for.'}),
|
|
398
|
+
|
|
399
|
+
('agent', ('ps:contact', {}), {
|
|
400
|
+
'doc': 'The contact information of an agent who advocates for the candidate.'}),
|
|
401
|
+
|
|
402
|
+
('recruiter', ('ps:contact', {}), {
|
|
403
|
+
'doc': 'The contact information of a recruiter who works on behalf of the organization.'}),
|
|
404
|
+
|
|
405
|
+
('attachments', ('array', {'type': 'file:attachment', 'sorted': True, 'uniq': True}), {
|
|
406
|
+
'doc': 'An array of additional files submitted by the candidate.'}),
|
|
407
|
+
|
|
408
|
+
# TODO: doc:questionare / responses
|
|
409
|
+
# TODO: :skills=[<ps:skill>]? vs :contact -> ps:proficiency?
|
|
410
|
+
# TODO: proj:task to track evaluation of the candidate?
|
|
411
|
+
|
|
412
|
+
)),
|
|
357
413
|
('ou:vitals', {}, (
|
|
358
414
|
|
|
359
415
|
('asof', ('time', {}), {
|
|
@@ -876,6 +932,12 @@ class OuModule(s_module.CoreModule):
|
|
|
876
932
|
('names', ('array', {'type': 'ou:industryname', 'uniq': True, 'sorted': True}), {
|
|
877
933
|
'doc': 'An array of alternative names for the industry.'}),
|
|
878
934
|
|
|
935
|
+
('reporter', ('ou:org', {}), {
|
|
936
|
+
'doc': 'The organization reporting on the industry.'}),
|
|
937
|
+
|
|
938
|
+
('reporter:name', ('ou:name', {}), {
|
|
939
|
+
'doc': 'The name of the organization reporting on the industry.'}),
|
|
940
|
+
|
|
879
941
|
('subs', ('array', {'type': 'ou:industry', 'split': ',', 'uniq': True, 'sorted': True}), {
|
|
880
942
|
'deprecated': True,
|
|
881
943
|
'doc': 'Deprecated. Please use ou:industry:type taxonomy.'}),
|
synapse/models/proj.py
CHANGED
|
@@ -16,10 +16,9 @@ class ProjectModule(s_module.CoreModule):
|
|
|
16
16
|
|
|
17
17
|
async def initCoreModule(self):
|
|
18
18
|
self.model.form('proj:project').onAdd(self._onAddProj)
|
|
19
|
-
self.model.form('proj:project').onDel(self._onDelProj)
|
|
20
19
|
|
|
21
20
|
async def _onAddProj(self, node):
|
|
22
|
-
#
|
|
21
|
+
# TODO: remove all storm:project authgates in 3.x migration
|
|
23
22
|
gateiden = node.ndef[1]
|
|
24
23
|
|
|
25
24
|
await self.core.auth.addAuthGate(node.ndef[1], 'storm:project')
|
|
@@ -29,10 +28,6 @@ class ProjectModule(s_module.CoreModule):
|
|
|
29
28
|
rule = (True, ('project', 'admin'))
|
|
30
29
|
await node.snap.user.addRule(rule, gateiden=gateiden)
|
|
31
30
|
|
|
32
|
-
async def _onDelProj(self, node):
|
|
33
|
-
gateiden = node.ndef[1]
|
|
34
|
-
await self.core.auth.delAuthGate(gateiden)
|
|
35
|
-
|
|
36
31
|
def getModelDefs(self):
|
|
37
32
|
return (
|
|
38
33
|
|
synapse/models/risk.py
CHANGED
|
@@ -159,6 +159,27 @@ class RiskModule(s_module.CoreModule):
|
|
|
159
159
|
('risk:extortion', ('guid', {}), {
|
|
160
160
|
'doc': 'An event where an attacker attempted to extort a victim.'}),
|
|
161
161
|
|
|
162
|
+
('risk:outage:cause:taxonomy', ('taxonomy', {}), {
|
|
163
|
+
'interfaces': ('meta:taxonomy',),
|
|
164
|
+
'doc': 'An outage cause taxonomy.'}),
|
|
165
|
+
|
|
166
|
+
('risk:outage:type:taxonomy', ('taxonomy', {}), {
|
|
167
|
+
'interfaces': ('meta:taxonomy',),
|
|
168
|
+
'doc': 'An outage type taxonomy.'}),
|
|
169
|
+
|
|
170
|
+
('risk:outage', ('guid', {}), {
|
|
171
|
+
'display': {
|
|
172
|
+
'columns': (
|
|
173
|
+
{'type': 'prop', 'opts': {'name': 'name'}},
|
|
174
|
+
{'type': 'prop', 'opts': {'name': 'type'}},
|
|
175
|
+
{'type': 'prop', 'opts': {'name': 'cause'}},
|
|
176
|
+
{'type': 'prop', 'opts': {'name': 'period'}},
|
|
177
|
+
{'type': 'prop', 'opts': {'name': 'provider:name'}},
|
|
178
|
+
{'type': 'prop', 'opts': {'name': 'reporter:name'}},
|
|
179
|
+
),
|
|
180
|
+
},
|
|
181
|
+
'doc': 'An outage event which affected resource availability.'}),
|
|
182
|
+
|
|
162
183
|
('risk:extortion:type:taxonomy', ('taxonomy', {}), {
|
|
163
184
|
'interfaces': ('meta:taxonomy',),
|
|
164
185
|
'doc': 'A taxonomy of extortion event types.'}),
|
|
@@ -185,6 +206,8 @@ class RiskModule(s_module.CoreModule):
|
|
|
185
206
|
'doc': 'The threat cluster uses the vulnerability.'}),
|
|
186
207
|
(('risk:tool:software', 'uses', 'risk:vuln'), {
|
|
187
208
|
'doc': 'The tool uses the vulnerability.'}),
|
|
209
|
+
(('ou:technique', 'uses', 'risk:vuln'), {
|
|
210
|
+
'doc': 'The technique uses the vulnerability.'}),
|
|
188
211
|
|
|
189
212
|
(('risk:attack', 'targets', 'ou:industry'), {
|
|
190
213
|
'doc': 'The attack targeted the industry.'}),
|
|
@@ -224,6 +247,15 @@ class RiskModule(s_module.CoreModule):
|
|
|
224
247
|
|
|
225
248
|
(('risk:extortion', 'leveraged', None), {
|
|
226
249
|
'doc': 'The extortion event was based on attacker access to the target node.'}),
|
|
250
|
+
|
|
251
|
+
(('meta:event', 'caused', 'risk:outage'), {
|
|
252
|
+
'doc': 'The event caused the outage.'}),
|
|
253
|
+
|
|
254
|
+
(('risk:attack', 'caused', 'risk:outage'), {
|
|
255
|
+
'doc': 'The attack caused the outage.'}),
|
|
256
|
+
|
|
257
|
+
(('risk:outage', 'impacted', None), {
|
|
258
|
+
'doc': 'The outage event impacted the availability of the target node.'}),
|
|
227
259
|
),
|
|
228
260
|
'forms': (
|
|
229
261
|
|
|
@@ -1025,6 +1057,39 @@ class RiskModule(s_module.CoreModule):
|
|
|
1025
1057
|
|
|
1026
1058
|
)),
|
|
1027
1059
|
|
|
1060
|
+
('risk:outage:type:taxonomy', {}, ()),
|
|
1061
|
+
('risk:outage:cause:taxonomy', {}, ()),
|
|
1062
|
+
('risk:outage', {}, (
|
|
1063
|
+
|
|
1064
|
+
('name', ('str', {'lower': True, 'onespace': True}), {
|
|
1065
|
+
'doc': 'A name for the outage event.'}),
|
|
1066
|
+
|
|
1067
|
+
('period', ('ival', {}), {
|
|
1068
|
+
'doc': 'The time period where the outage impacted availability.'}),
|
|
1069
|
+
|
|
1070
|
+
('type', ('risk:outage:type:taxonomy', {}), {
|
|
1071
|
+
'ex': 'service.power',
|
|
1072
|
+
'doc': 'The type of outage.'}),
|
|
1073
|
+
|
|
1074
|
+
('cause', ('risk:outage:cause:taxonomy', {}), {
|
|
1075
|
+
'ex': 'nature.earthquake',
|
|
1076
|
+
'doc': 'The outage cause type.'}),
|
|
1077
|
+
|
|
1078
|
+
('provider', ('ou:org', {}), {
|
|
1079
|
+
'doc': 'The organization which experienced the outage event.'}),
|
|
1080
|
+
|
|
1081
|
+
('provider:name', ('ou:name', {}), {
|
|
1082
|
+
'doc': 'The name of the organization which experienced the outage event.'}),
|
|
1083
|
+
|
|
1084
|
+
('reporter', ('ou:org', {}), {
|
|
1085
|
+
'doc': 'The organization reporting on the outage event.'}),
|
|
1086
|
+
|
|
1087
|
+
('reporter:name', ('ou:name', {}), {
|
|
1088
|
+
'doc': 'The name of the organization reporting on the outage event.'}),
|
|
1089
|
+
)),
|
|
1090
|
+
|
|
1091
|
+
# TODO risk:outage:vitals to track outage stats over time
|
|
1092
|
+
|
|
1028
1093
|
('risk:extortion:type:taxonomy', {}, ()),
|
|
1029
1094
|
('risk:extortion', {}, (
|
|
1030
1095
|
|
synapse/tests/test_cortex.py
CHANGED
|
@@ -5801,6 +5801,13 @@ class CortexBasicTest(s_t_utils.SynTest):
|
|
|
5801
5801
|
# but getTypeNorm won't handle that
|
|
5802
5802
|
await self.asyncraises(s_exc.NoSuchType, core.getTypeNorm('test:str:tick', '3001'))
|
|
5803
5803
|
|
|
5804
|
+
# specify typeopts to getTypeNorm/getPropNorm
|
|
5805
|
+
norm, info = await prox.getTypeNorm('array', (' TIME ', ' pass ', ' the '), {'uniq': True, 'sorted': True, 'type': 'str', 'typeopts': {'strip': True, 'lower': True}})
|
|
5806
|
+
self.eq(norm, ('pass', 'the', 'time'))
|
|
5807
|
+
|
|
5808
|
+
norm, info = await prox.getPropNorm('test:comp', "1234:comedy", {'sepr': ':'})
|
|
5809
|
+
self.eq(norm, (1234, "comedy"))
|
|
5810
|
+
|
|
5804
5811
|
# getTypeNorm can norm types which aren't defined as forms/props
|
|
5805
5812
|
norm, info = await core.getTypeNorm('test:lower', 'ASDF')
|
|
5806
5813
|
self.eq(norm, 'asdf')
|
|
@@ -6191,7 +6198,17 @@ class CortexBasicTest(s_t_utils.SynTest):
|
|
|
6191
6198
|
with self.raises(s_exc.DupEdgeType):
|
|
6192
6199
|
await core.addEdge(('test:int', '_goes', None), {})
|
|
6193
6200
|
|
|
6201
|
+
await core.addType('_test:type', 'str', {}, {'interfaces': ['taxonomy']})
|
|
6202
|
+
self.eq(['meta:taxonomy'], core.model.type('_test:type').info.get('interfaces'))
|
|
6203
|
+
|
|
6204
|
+
with self.raises(s_exc.NoSuchType):
|
|
6205
|
+
await core.addType('_test:newp', 'newp', {}, {})
|
|
6206
|
+
|
|
6207
|
+
with self.raises(s_exc.BadTypeDef):
|
|
6208
|
+
await core.addType('_test:newp', 'array', {'type': 'newp'}, {})
|
|
6209
|
+
|
|
6194
6210
|
# manually edit in borked entries
|
|
6211
|
+
core.exttypes.set('_type:bork', ('_type:bork', None, None, None))
|
|
6195
6212
|
core.extforms.set('_hehe:bork', ('_hehe:bork', None, None, None))
|
|
6196
6213
|
core.extedges.set(s_common.guid('newp'), ((None, '_does', 'newp'), {}))
|
|
6197
6214
|
|
|
@@ -6219,6 +6236,7 @@ class CortexBasicTest(s_t_utils.SynTest):
|
|
|
6219
6236
|
|
|
6220
6237
|
await core.nodes('._woot [ -._woot ]')
|
|
6221
6238
|
|
|
6239
|
+
self.nn(core.model.type('_test:type'))
|
|
6222
6240
|
self.nn(core.model.prop('._woot'))
|
|
6223
6241
|
self.nn(core.model.prop('inet:ipv4._woot'))
|
|
6224
6242
|
self.nn(core.model.form('inet:ipv4').prop('._woot'))
|
|
@@ -6256,6 +6274,9 @@ class CortexBasicTest(s_t_utils.SynTest):
|
|
|
6256
6274
|
with self.raises(s_exc.NoSuchEdge):
|
|
6257
6275
|
await core.delEdge(('newp', 'newp', 'newp'))
|
|
6258
6276
|
|
|
6277
|
+
with self.raises(s_exc.NoSuchType):
|
|
6278
|
+
await core.delType('_newp')
|
|
6279
|
+
|
|
6259
6280
|
await core._delEdge(('newp', 'newp', 'newp'))
|
|
6260
6281
|
|
|
6261
6282
|
await core.nodes('_hehe:haha [ -:visi ]')
|
synapse/tests/test_lib_agenda.py
CHANGED
|
@@ -432,6 +432,19 @@ class AgendaTest(s_t_utils.SynTest):
|
|
|
432
432
|
|
|
433
433
|
self.eq(2, appt.startcount)
|
|
434
434
|
|
|
435
|
+
# Can't use an existing authgate iden
|
|
436
|
+
viewiden = core.getView().iden
|
|
437
|
+
cdef = {'creator': core.auth.rootuser.iden,
|
|
438
|
+
'storm': '[test:str=bar]',
|
|
439
|
+
'reqs': {'hour': 10},
|
|
440
|
+
'incunit': 'dayofweek',
|
|
441
|
+
'incvals': (2, 4),
|
|
442
|
+
'iden': viewiden}
|
|
443
|
+
await self.asyncraises(s_exc.DupIden, core.addCronJob(cdef))
|
|
444
|
+
await core.delCronJob(viewiden)
|
|
445
|
+
|
|
446
|
+
self.nn(core.getAuthGate(viewiden))
|
|
447
|
+
|
|
435
448
|
async def test_agenda_persistence(self):
|
|
436
449
|
''' Test we can make/change/delete appointments and they are persisted to storage '''
|
|
437
450
|
|
synapse/tests/test_lib_auth.py
CHANGED
|
@@ -31,6 +31,21 @@ class AuthTest(s_test.SynTest):
|
|
|
31
31
|
with self.raises(s_exc.DupRoleName):
|
|
32
32
|
await auth.addRole('ninjas')
|
|
33
33
|
|
|
34
|
+
viewiden = core.getView().iden
|
|
35
|
+
with self.raises(s_exc.DupIden):
|
|
36
|
+
await auth.addUser('view', iden=viewiden)
|
|
37
|
+
|
|
38
|
+
with self.raises(s_exc.NoSuchUser):
|
|
39
|
+
await auth.delUser(viewiden)
|
|
40
|
+
self.nn(core.auth.getAuthGate(viewiden))
|
|
41
|
+
|
|
42
|
+
with self.raises(s_exc.DupIden):
|
|
43
|
+
await auth.addRole('view', iden=viewiden)
|
|
44
|
+
|
|
45
|
+
with self.raises(s_exc.NoSuchRole):
|
|
46
|
+
await auth.delRole(viewiden)
|
|
47
|
+
self.nn(core.auth.getAuthGate(viewiden))
|
|
48
|
+
|
|
34
49
|
self.none(await auth._addUser(user.iden, 'visi@vertex.link'))
|
|
35
50
|
self.none(await auth._addRole(user.iden, 'ninjas'))
|
|
36
51
|
|
synapse/tests/test_lib_cell.py
CHANGED
|
@@ -2993,7 +2993,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2993
2993
|
self.eq('barprof', valu)
|
|
2994
2994
|
|
|
2995
2995
|
msgs = await core.stormlist('cron.list')
|
|
2996
|
-
self.stormIsInPrint('visi
|
|
2996
|
+
self.stormIsInPrint(' visi 8437c35a.. ', msgs)
|
|
2997
2997
|
self.stormIsInPrint('[tel:mob:telem=*]', msgs)
|
|
2998
2998
|
|
|
2999
2999
|
msgs = await core.stormlist('dmon.list')
|
|
@@ -777,6 +777,12 @@ class HttpApiTest(s_tests.SynTest):
|
|
|
777
777
|
retn = await resp.json()
|
|
778
778
|
self.eq('MissingField', retn.get('code'))
|
|
779
779
|
|
|
780
|
+
body = {'prop': 'test:comp', 'value': '3^foobar', 'typeopts': {'sepr': '^'}}
|
|
781
|
+
async with sess.get(f'https://localhost:{port}/api/v1/model/norm', json=body) as resp:
|
|
782
|
+
retn = await resp.json()
|
|
783
|
+
self.eq('ok', retn.get('status'))
|
|
784
|
+
self.eq([3, 'foobar'], retn['result']['norm'])
|
|
785
|
+
|
|
780
786
|
# Norm via POST
|
|
781
787
|
body = {'prop': 'inet:ipv4', 'value': '1.2.3.4'}
|
|
782
788
|
async with sess.post(f'https://localhost:{port}/api/v1/model/norm', json=body) as resp:
|
synapse/tests/test_lib_nexus.py
CHANGED
|
@@ -310,6 +310,32 @@ class NexusTest(s_t_utils.SynTest):
|
|
|
310
310
|
await cell01.sync()
|
|
311
311
|
self.isin(s_nexus.leaderversion, cell01.nexsroot.writeholds)
|
|
312
312
|
|
|
313
|
+
cell00.getCellInfo = getCellInfo
|
|
314
|
+
|
|
315
|
+
# test case where a mirror which is updated first may push events
|
|
316
|
+
# the leader does not yet have handlers for
|
|
317
|
+
async with await s_cell.Cell.anit(dirn=path) as cell01:
|
|
318
|
+
cell01.nexsiden = 'newp'
|
|
319
|
+
with self.raises(s_exc.NoSuchIden) as cm:
|
|
320
|
+
await cell01.sync()
|
|
321
|
+
self.eq(cm.exception.get('mesg'), 'No Nexus Pusher with iden newp.')
|
|
322
|
+
|
|
323
|
+
self.none(await cell00.nexsroot.nexslog.last())
|
|
324
|
+
self.none(await cell01.nexsroot.nexslog.last())
|
|
325
|
+
|
|
326
|
+
cell01.nexsiden = cell00.nexsiden
|
|
327
|
+
await cell01.sync()
|
|
328
|
+
|
|
329
|
+
self.eq(0, (await cell00.nexsroot.nexslog.last())[0])
|
|
330
|
+
self.eq(0, (await cell01.nexsroot.nexslog.last())[0])
|
|
331
|
+
|
|
332
|
+
with self.raises(s_exc.NoSuchName) as cm:
|
|
333
|
+
await cell01._push('newp')
|
|
334
|
+
self.eq(cm.exception.get('mesg'), 'No Nexus handler for event newp.')
|
|
335
|
+
|
|
336
|
+
self.eq(0, (await cell00.nexsroot.nexslog.last())[0])
|
|
337
|
+
self.eq(0, (await cell01.nexsroot.nexslog.last())[0])
|
|
338
|
+
|
|
313
339
|
async def test_mirror_nexus_loop_failure(self):
|
|
314
340
|
with self.getTestDir() as dirn:
|
|
315
341
|
|
synapse/tests/test_lib_scrape.py
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from unittest import mock
|
|
2
2
|
|
|
3
|
+
import regex
|
|
4
|
+
|
|
3
5
|
import synapse.exc as s_exc
|
|
4
6
|
|
|
5
7
|
import synapse.lib.scrape as s_scrape
|
|
@@ -889,14 +891,20 @@ class ScrapeTest(s_t_utils.SynTest):
|
|
|
889
891
|
nodes.remove(('inet:url', 'smb://1:2:3:4:5:6:7:8/share'))
|
|
890
892
|
|
|
891
893
|
async def test_scrape_async(self):
|
|
894
|
+
text = 'log4j vuln CVE-2021-44228 is pervasive'
|
|
895
|
+
ndefs = await s_t_utils.alist(s_scrape.scrapeAsync(text))
|
|
896
|
+
self.eq(ndefs, (('it:sec:cve', 'CVE-2021-44228'),))
|
|
892
897
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
898
|
+
regx = regex.compile('(?P<valu>CVE-[0-9]{4}-[0-9]{4,})(?:[^a-z0-9]|$)')
|
|
899
|
+
infos = s_scrape._genMatchList(text, regx, {})
|
|
900
|
+
self.eq(infos, [{'match': 'CVE-2021-44228', 'offset': 11, 'valu': 'CVE-2021-44228'}])
|
|
896
901
|
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
902
|
+
text = 'endashs are a vulnerability CVE\u20132022\u20131138 '
|
|
903
|
+
infos = await s_t_utils.alist(s_scrape.contextScrapeAsync(text))
|
|
904
|
+
self.eq(infos, [{'match': 'CVE–2022–1138', 'offset': 29, 'valu': 'CVE-2022-1138', 'form': 'it:sec:cve'}])
|
|
905
|
+
|
|
906
|
+
infos = s_scrape._contextScrapeList(text)
|
|
907
|
+
self.eq(infos, [{'match': 'CVE–2022–1138', 'offset': 29, 'valu': 'CVE-2022-1138', 'form': 'it:sec:cve'}])
|
|
900
908
|
|
|
901
909
|
def test_scrape_sequential(self):
|
|
902
910
|
md5 = ('a' * 32, 'b' * 32,)
|
synapse/tests/test_lib_storm.py
CHANGED
|
@@ -638,6 +638,8 @@ class StormTest(s_t_utils.SynTest):
|
|
|
638
638
|
with self.raises(s_exc.NoSuchVar):
|
|
639
639
|
await core.nodes('background { $lib.print($foo) }')
|
|
640
640
|
|
|
641
|
+
await core.nodes('background ${ $foo=test $lib.print($foo) }')
|
|
642
|
+
|
|
641
643
|
await core.nodes('background { $lib.time.sleep(4) }')
|
|
642
644
|
task = await core.callStorm('for $t in $lib.ps.list() { if $t.info.background { return($t) } }')
|
|
643
645
|
self.nn(task)
|
|
@@ -667,6 +669,9 @@ class StormTest(s_t_utils.SynTest):
|
|
|
667
669
|
q = '[ inet:fqdn=www.vertex.link ] $q=:domain | parallel $q'
|
|
668
670
|
await self.asyncraises(s_exc.StormRuntimeError, core.nodes(q))
|
|
669
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
|
+
|
|
670
675
|
# test $lib.exit() and the StormExit handlers
|
|
671
676
|
msgs = [m async for m in core.view.storm('$lib.exit()')]
|
|
672
677
|
self.eq(msgs[-1][0], 'fini')
|
|
@@ -2137,6 +2142,49 @@ class StormTest(s_t_utils.SynTest):
|
|
|
2137
2142
|
self.nn(bot.get('country::flag::md5'))
|
|
2138
2143
|
self.eq(bot['country::flag::md5'][0], 'fa818a259cbed7ce8bc2a22d35a464fc')
|
|
2139
2144
|
|
|
2145
|
+
await core.nodes('''
|
|
2146
|
+
[( risk:vulnerable=*
|
|
2147
|
+
:mitigated=true
|
|
2148
|
+
:node={ [ it:prod:hardware=* :name=foohw ] return($node.ndef()) }
|
|
2149
|
+
:vuln={[ risk:vuln=* :name=barvuln ]}
|
|
2150
|
+
+#test
|
|
2151
|
+
)]
|
|
2152
|
+
[( inet:service:rule=*
|
|
2153
|
+
:object={ risk:vulnerable#test return($node.ndef()) }
|
|
2154
|
+
:grantee={ [ inet:service:account=* :id=foocon ] return($node.ndef()) }
|
|
2155
|
+
+#test
|
|
2156
|
+
)]
|
|
2157
|
+
''')
|
|
2158
|
+
|
|
2159
|
+
opts = {
|
|
2160
|
+
'embeds': {
|
|
2161
|
+
'risk:vulnerable': {
|
|
2162
|
+
'vuln': ['name'],
|
|
2163
|
+
'node': ['name'],
|
|
2164
|
+
},
|
|
2165
|
+
'inet:service:rule': {
|
|
2166
|
+
'object': ['mitigated', 'newp'],
|
|
2167
|
+
'object::node': ['name', 'newp'],
|
|
2168
|
+
'grantee': ['id', 'newp'],
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
msgs = await core.stormlist('inet:service:rule#test :object -+> risk:vulnerable', opts=opts)
|
|
2173
|
+
nodes = sorted([m[1] for m in msgs if m[0] == 'node'], key=lambda p: p[0][0])
|
|
2174
|
+
self.eq(['inet:service:rule', 'risk:vulnerable'], [n[0][0] for n in nodes])
|
|
2175
|
+
|
|
2176
|
+
embeds = nodes[0][1]['embeds']
|
|
2177
|
+
self.eq(1, embeds['object']['mitigated'])
|
|
2178
|
+
self.eq(None, embeds['object']['newp'])
|
|
2179
|
+
self.eq('foohw', embeds['object::node']['name'])
|
|
2180
|
+
self.eq(None, embeds['object::node']['newp'])
|
|
2181
|
+
self.eq('foocon', embeds['grantee']['id'])
|
|
2182
|
+
self.eq(None, embeds['grantee']['newp'])
|
|
2183
|
+
|
|
2184
|
+
embeds = nodes[1][1]['embeds']
|
|
2185
|
+
self.eq('barvuln', embeds['vuln']['name'])
|
|
2186
|
+
self.eq('foohw', embeds['node']['name'])
|
|
2187
|
+
|
|
2140
2188
|
async def test_storm_wget(self):
|
|
2141
2189
|
|
|
2142
2190
|
async def _getRespFromSha(core, mesgs):
|
|
@@ -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'})
|