synapse 2.165.0__py311-none-any.whl → 2.166.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.

Files changed (51) hide show
  1. synapse/cmds/cortex.py +1 -6
  2. synapse/common.py +6 -0
  3. synapse/cortex.py +73 -56
  4. synapse/datamodel.py +32 -0
  5. synapse/lib/agenda.py +81 -51
  6. synapse/lib/ast.py +21 -23
  7. synapse/lib/base.py +0 -6
  8. synapse/lib/cell.py +13 -22
  9. synapse/lib/httpapi.py +1 -0
  10. synapse/lib/nexus.py +3 -2
  11. synapse/lib/schemas.py +2 -0
  12. synapse/lib/snap.py +50 -0
  13. synapse/lib/storm.py +19 -17
  14. synapse/lib/stormlib/aha.py +4 -1
  15. synapse/lib/stormlib/auth.py +11 -4
  16. synapse/lib/stormlib/cache.py +202 -0
  17. synapse/lib/stormlib/cortex.py +69 -7
  18. synapse/lib/stormlib/spooled.py +109 -0
  19. synapse/lib/stormtypes.py +43 -15
  20. synapse/lib/trigger.py +10 -12
  21. synapse/lib/types.py +1 -1
  22. synapse/lib/version.py +2 -2
  23. synapse/lib/view.py +12 -0
  24. synapse/models/inet.py +74 -2
  25. synapse/models/orgs.py +52 -8
  26. synapse/models/person.py +30 -11
  27. synapse/models/risk.py +44 -3
  28. synapse/telepath.py +114 -32
  29. synapse/tests/test_cortex.py +40 -6
  30. synapse/tests/test_datamodel.py +22 -0
  31. synapse/tests/test_lib_agenda.py +8 -1
  32. synapse/tests/test_lib_aha.py +18 -4
  33. synapse/tests/test_lib_storm.py +95 -4
  34. synapse/tests/test_lib_stormlib_cache.py +272 -0
  35. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  36. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  37. synapse/tests/test_lib_stormtypes.py +27 -4
  38. synapse/tests/test_model_inet.py +67 -0
  39. synapse/tests/test_model_risk.py +6 -0
  40. synapse/tests/test_telepath.py +30 -7
  41. synapse/tests/test_tools_modrole.py +81 -0
  42. synapse/tests/test_tools_moduser.py +105 -0
  43. synapse/tools/modrole.py +59 -7
  44. synapse/tools/moduser.py +78 -10
  45. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
  46. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/RECORD +49 -47
  47. synapse/lib/provenance.py +0 -111
  48. synapse/tests/test_lib_provenance.py +0 -37
  49. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
  50. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +0 -0
  51. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,7 @@ import json
3
3
  import logging
4
4
 
5
5
  import synapse.exc as s_exc
6
+ import synapse.telepath as s_telepath
6
7
 
7
8
  import synapse.lib.storm as s_storm
8
9
  import synapse.lib.stormtypes as s_stormtypes
@@ -86,6 +87,7 @@ stormcmds = [
86
87
  $lib.print(`!View: No view found ({$err.info.iden})`)
87
88
  }
88
89
  $lib.print(`Readonly: {$api.readonly}`)
90
+ $lib.print(`Pool enabled: {$api.pool}`)
89
91
  $lib.print(`Authenticated: {$api.authenticated}`)
90
92
  $lib.print(`Name: {$api.name}`)
91
93
  $lib.print(`Description: {$api.desc}`)
@@ -224,6 +226,9 @@ class HttpApi(s_stormtypes.StormType):
224
226
  ''',
225
227
  'type': {'type': ['stor', 'gtor'], '_storfunc': '_storPath', '_gtorfunc': '_gtorPath',
226
228
  'returns': {'type': 'str'}}},
229
+ {'name': 'pool', 'desc': 'Boolean value indicating if the handler responses may be executed as part of a Storm pool.',
230
+ 'type': {'type': ['stor', 'gtor'], '_storfunc': '_storPool', '_gtorfunc': '_gtorPool',
231
+ 'returns': {'type': 'boolean'}}},
227
232
  {'name': 'vars', 'desc': 'The Storm runtime variables specific for the API instance.',
228
233
  'type': {'type': ['stor', 'ctor'], '_storfunc': '_storVars', '_ctorfunc': '_ctorVars',
229
234
  'returns': {'type': 'http:api:vars'}}},
@@ -242,6 +247,8 @@ class HttpApi(s_stormtypes.StormType):
242
247
  {'name': 'authenticated', 'desc': 'Boolean value indicating if the Extended HTTP API requires an authenticated user or session.',
243
248
  'type': {'type': ['stor', 'gtor'], '_storfunc': '_storAuthenticated', '_gtorfunc': '_gtorAuthenticated',
244
249
  'returns': {'type': 'boolean'}}},
250
+ {'name': 'methods', 'desc': 'The dictionary containing the Storm code used to implement the HTTP methods.',
251
+ 'type': {'type': ['ctor'], '_ctorfunc': '_ctorMethods', 'returns': {'type': 'http:api:methods'}}}
245
252
  )
246
253
 
247
254
  def __init__(self, runt, info):
@@ -257,6 +264,7 @@ class HttpApi(s_stormtypes.StormType):
257
264
  'name': self._storName,
258
265
  'desc': self._storDesc,
259
266
  'path': self._storPath,
267
+ 'pool': self._storPool,
260
268
  'vars': self._storVars,
261
269
  'view': self._storView,
262
270
  'runas': self._storRunas,
@@ -270,6 +278,7 @@ class HttpApi(s_stormtypes.StormType):
270
278
  'name': self._gtorName,
271
279
  'desc': self._gtorDesc,
272
280
  'path': self._gtorPath,
281
+ 'pool': self._gtorPool,
273
282
  'view': self._gtorView,
274
283
  'runas': self._gtorRunas,
275
284
  'owner': self._gtorOwner,
@@ -292,6 +301,13 @@ class HttpApi(s_stormtypes.StormType):
292
301
  'created': self.info.get('created'),
293
302
  })
294
303
 
304
+ async def stormrepr(self):
305
+ name = await self._gtorName()
306
+ if not name:
307
+ name = '<no name>'
308
+ path = await self._gtorPath()
309
+ return f'{self._storm_typename}: {name} ({self.iden}), path={path}'
310
+
295
311
  def getObjLocals(self):
296
312
  return {
297
313
  'pack': self._methPack,
@@ -299,7 +315,10 @@ class HttpApi(s_stormtypes.StormType):
299
315
 
300
316
  @s_stormtypes.stormfunc(readonly=True)
301
317
  async def _methPack(self):
302
- return copy.deepcopy(self.info)
318
+ # TODO: Remove this when we've migrated the HTTPAPI data to set this value.
319
+ ret = copy.deepcopy(self.info)
320
+ ret.setdefault('pool', False)
321
+ return ret
303
322
 
304
323
  @s_stormtypes.stormfunc(readonly=True)
305
324
  def _ctorMethods(self, path=None):
@@ -316,6 +335,17 @@ class HttpApi(s_stormtypes.StormType):
316
335
  async def _gtorPath(self):
317
336
  return self.info.get('path')
318
337
 
338
+ async def _storPool(self, pool):
339
+ s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'set'))
340
+ pool = await s_stormtypes.tobool(pool)
341
+ adef = await self.runt.snap.core.modHttpExtApi(self.iden, 'pool', pool)
342
+ self.info['pool'] = pool
343
+ self.info['updated'] = adef.get('updated')
344
+
345
+ @s_stormtypes.stormfunc(readonly=True)
346
+ async def _gtorPool(self):
347
+ return self.info.get('pool')
348
+
319
349
  async def _storName(self, name):
320
350
  s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'set'))
321
351
  name = await s_stormtypes.tostr(name)
@@ -1055,7 +1085,7 @@ class CortexHttpApi(s_stormtypes.Lib):
1055
1085
  {'name': 'readonly', 'type': 'boolean',
1056
1086
  'desc': 'Run the Extended HTTP Storm methods in readonly mode.', 'default': False},
1057
1087
  ),
1058
- 'returns': {'type': 'http:api', 'desc': 'A new http:api object.'}}},
1088
+ 'returns': {'type': 'http:api', 'desc': 'A new ``http:api`` object.'}}},
1059
1089
  {'name': 'del', 'desc': 'Delete an Extended HTTP API endpoint.',
1060
1090
  'type': {'type': 'function', '_funcname': 'delHttpApi',
1061
1091
  'args': (
@@ -1063,16 +1093,29 @@ class CortexHttpApi(s_stormtypes.Lib):
1063
1093
  'desc': 'The iden of the API to delete.'},
1064
1094
  ),
1065
1095
  'returns': {'type': 'null'}}},
1066
- {'name': 'get', 'desc': 'Get an Extended HTTP API object.',
1096
+ {'name': 'get', 'desc': 'Get an Extended ``http:api`` object.',
1067
1097
  'type': {'type': 'function', '_funcname': 'getHttpApi',
1068
1098
  'args': (
1069
1099
  {'name': 'iden', 'type': 'string',
1070
- 'desc': 'The iden of the API to retreive.'},
1100
+ 'desc': 'The iden of the API to retrieve.'},
1101
+ ),
1102
+ 'returns': {'type': 'http:api', 'desc': 'The ``http:api`` object.'}}},
1103
+ {'name': 'getByPath', 'desc': '''
1104
+ Get an Extended ``http:api`` object by path.
1105
+
1106
+ Notes:
1107
+ The path argument is evaluated as a regular expression input, and will be
1108
+ used to get the first HTTP API handler whose path value has a match.
1109
+ ''',
1110
+ 'type': {'type': 'function', '_funcname': 'getHttpApiByPath',
1111
+ 'args': (
1112
+ {'name': 'path', 'type': 'string',
1113
+ 'desc': 'Path to use to retrieve an object.'},
1071
1114
  ),
1072
- 'returns': {'type': 'http:api', 'desc': 'The http:api object.'}}},
1073
- {'name': 'list', 'desc': 'Get all the Extneded HTTP APIs on the Cortex',
1115
+ 'returns': {'type': ['http:api', 'null'], 'desc': 'The ``http:api`` object or ``$lib.null`` if there is no match.'}}},
1116
+ {'name': 'list', 'desc': 'Get all the Extended HTTP APIs on the Cortex',
1074
1117
  'type': {'type': 'function', '_funcname': 'listHttpApis', 'args': (),
1075
- 'returns': {'type': 'list', 'desc': 'A list of http:api objects'}}},
1118
+ 'returns': {'type': 'list', 'desc': 'A list of ``http:api`` objects'}}},
1076
1119
  {'name': 'index', 'desc': 'Set the index for a given Extended HTTP API.',
1077
1120
  'type': {'type': 'function', '_funcname': 'setHttpApiIndx',
1078
1121
  'args': (
@@ -1111,6 +1154,7 @@ class CortexHttpApi(s_stormtypes.Lib):
1111
1154
  'list': self.listHttpApis,
1112
1155
  'index': self.setHttpApiIndx,
1113
1156
  'response': self.makeHttpResponse,
1157
+ 'getByPath': self.getHttpApiByPath,
1114
1158
  }
1115
1159
 
1116
1160
  @s_stormtypes.stormfunc(readonly=True)
@@ -1125,6 +1169,15 @@ class CortexHttpApi(s_stormtypes.Lib):
1125
1169
  adef = await self.runt.snap.core.getHttpExtApi(iden)
1126
1170
  return HttpApi(self.runt, adef)
1127
1171
 
1172
+ @s_stormtypes.stormfunc(readonly=True)
1173
+ async def getHttpApiByPath(self, path):
1174
+ s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'get'))
1175
+ path = await s_stormtypes.tostr(path)
1176
+ adef, _ = await self.runt.snap.core.getHttpExtApiByPath(path)
1177
+ if adef is None:
1178
+ return None
1179
+ return HttpApi(self.runt, adef)
1180
+
1128
1181
  @s_stormtypes.stormfunc(readonly=True)
1129
1182
  async def listHttpApis(self):
1130
1183
  s_stormtypes.confirm(('storm', 'lib', 'cortex', 'httpapi', 'get'))
@@ -1195,6 +1248,11 @@ class StormPoolSetCmd(s_storm.Cmd):
1195
1248
  async for node, path in genr: # pragma: no cover
1196
1249
  yield node, path
1197
1250
 
1251
+ try:
1252
+ s_telepath.chopurl(self.opts.url)
1253
+ except s_exc.BadUrl as e:
1254
+ raise s_exc.BadArg(mesg=f'Unable to set Storm pool URL from url={self.opts.url} : {e.get("mesg")}') from None
1255
+
1198
1256
  opts = {
1199
1257
  'timeout:sync': self.opts.sync_timeout,
1200
1258
  'timeout:connection': self.opts.connection_timeout,
@@ -1206,6 +1264,10 @@ class StormPoolSetCmd(s_storm.Cmd):
1206
1264
  class StormPoolDelCmd(s_storm.Cmd):
1207
1265
  '''
1208
1266
  Remove a Storm query offload mirror pool configuration.
1267
+
1268
+ Notes:
1269
+ This will result in tearing down any Storm queries currently being serviced by the Storm pool.
1270
+ This may result in this command raising an exception if it was offloaded to a pool member. That would be an expected behavior.
1209
1271
  '''
1210
1272
  name = 'cortex.storm.pool.del'
1211
1273
 
@@ -0,0 +1,109 @@
1
+ import synapse.exc as s_exc
2
+ import synapse.lib.msgpack as s_msgpack
3
+ import synapse.lib.spooled as s_spooled
4
+ import synapse.lib.stormtypes as s_stormtypes
5
+
6
+ @s_stormtypes.registry.registerLib
7
+ class LibSpooled(s_stormtypes.Lib):
8
+ '''
9
+ A Storm Library for interacting with Spooled Objects.
10
+ '''
11
+ _storm_locals = (
12
+ {'name': 'set', 'desc': '''
13
+ Get a Spooled Storm Set object.
14
+
15
+ A Spooled Storm Set object is memory-safe to grow to extraordinarily large sizes,
16
+ as it will fallback to file backed storage, with two restrictions. First
17
+ is that all items in the set can be serialized to a file if the set grows too large,
18
+ so all items added must be a serializable Storm primitive. Second is that when an
19
+ item is added to the Set, because it could be immediately written disk,
20
+ do not hold any references to it outside of the Set itself, as the two objects could
21
+ differ.
22
+ ''',
23
+ 'type': {'type': 'function', '_funcname': '_methSet',
24
+ 'args': (
25
+ {'name': '*vals', 'type': 'any', 'desc': 'Initial values to place in the set.', },
26
+ ),
27
+ 'returns': {'type': 'set', 'desc': 'The new set.'}}},
28
+ )
29
+ _storm_lib_path = ('spooled',)
30
+
31
+ def getObjLocals(self):
32
+ return {
33
+ 'set': self._methSet,
34
+ }
35
+
36
+ @s_stormtypes.stormfunc(readonly=True)
37
+ async def _methSet(self, *vals):
38
+ core = self.runt.snap.core
39
+ spool = await s_spooled.Set.anit(dirn=core.dirn, cell=core, size=1000)
40
+
41
+ valu = list(vals)
42
+ for item in valu:
43
+ if s_stormtypes.ismutable(item):
44
+ mesg = f'{await s_stormtypes.torepr(item)} is mutable and cannot be used in a set.'
45
+ raise s_exc.StormRuntimeError(mesg=mesg)
46
+
47
+ if not s_msgpack.isok(item):
48
+ mesg = f'{await s_stormtypes.torepr(item)} is not safe to be used in a SpooledSet.'
49
+ raise s_exc.StormRuntimeError(mesg=mesg)
50
+
51
+ await spool.add(item)
52
+
53
+ return SpooledSet(spool)
54
+
55
+ @s_stormtypes.registry.registerType
56
+ class SpooledSet(s_stormtypes.Set):
57
+ '''
58
+ A StormLib API instance of a Storm Set object that can fallback to lmdb.
59
+ '''
60
+ _storm_typename = 'spooled:set'
61
+ _ismutable = True
62
+
63
+ def __init__(self, valu, path=None):
64
+
65
+ s_stormtypes.Prim.__init__(self, valu, path=path)
66
+ self.locls.update(self.getObjLocals())
67
+
68
+ async def iter(self):
69
+ async for item in self.valu:
70
+ yield item
71
+
72
+ @s_stormtypes.stormfunc(readonly=True)
73
+ async def _methSetAdd(self, *items):
74
+ for i in items:
75
+ if s_stormtypes.ismutable(i):
76
+ mesg = f'{await s_stormtypes.torepr(i)} is mutable and cannot be used in a set.'
77
+ raise s_exc.StormRuntimeError(mesg=mesg)
78
+
79
+ if not s_msgpack.isok(i):
80
+ mesg = f'{await s_stormtypes.torepr(i)} is not safe to be used in a SpooledSet.'
81
+ raise s_exc.StormRuntimeError(mesg=mesg)
82
+
83
+ await self.valu.add(i)
84
+
85
+ @s_stormtypes.stormfunc(readonly=True)
86
+ async def _methSetAdds(self, *items):
87
+ for item in items:
88
+ async for i in s_stormtypes.toiter(item):
89
+ if s_stormtypes.ismutable(i):
90
+ mesg = f'{await s_stormtypes.torepr(i)} is mutable and cannot be used in a set.'
91
+ raise s_exc.StormRuntimeError(mesg=mesg)
92
+
93
+ if not s_msgpack.isok(i):
94
+ mesg = f'{await s_stormtypes.torepr(i)} is not safe to be used in a SpooledSet.'
95
+ raise s_exc.StormRuntimeError(mesg=mesg)
96
+
97
+ await self.valu.add(i)
98
+
99
+ @s_stormtypes.stormfunc(readonly=True)
100
+ async def _methSetList(self):
101
+ return [x async for x in self.valu]
102
+
103
+ async def stormrepr(self):
104
+ reprs = [await s_stormtypes.torepr(k) async for k in self.valu]
105
+ rval = ', '.join(reprs)
106
+ return f'{{{rval}}}'
107
+
108
+ async def value(self):
109
+ return set([x async for x in self.valu])
synapse/lib/stormtypes.py CHANGED
@@ -36,7 +36,6 @@ import synapse.lib.trigger as s_trigger
36
36
  import synapse.lib.urlhelp as s_urlhelp
37
37
  import synapse.lib.version as s_version
38
38
  import synapse.lib.stormctrl as s_stormctrl
39
- import synapse.lib.provenance as s_provenance
40
39
 
41
40
  logger = logging.getLogger(__name__)
42
41
 
@@ -907,6 +906,18 @@ class LibService(Lib):
907
906
  'returns': {'type': 'boolean', 'desc': 'Returns true if the service is available, false on a '
908
907
  'timeout waiting for the service to be ready.', }}},
909
908
  )
909
+ _storm_lib_perms = (
910
+ {'perm': ('service', 'add'), 'gate': 'cortex',
911
+ 'desc': 'Controls the ability to add a Storm Service to the Cortex.'},
912
+ {'perm': ('service', 'del'), 'gate': 'cortex',
913
+ 'desc': 'Controls the ability to delete a Storm Service from the Cortex'},
914
+ {'perm': ('service', 'get'), 'gate': 'cortex',
915
+ 'desc': 'Controls the ability to get the Service object for any Storm Service.'},
916
+ {'perm': ('service', 'get', '<iden>'), 'gate': 'cortex',
917
+ 'desc': 'Controls the ability to get the Service object for a Storm Service by iden.'},
918
+ {'perm': ('service', 'list'), 'gate': 'cortex',
919
+ 'desc': 'Controls the ability to list all available Storm Services and their service definitions.'},
920
+ )
910
921
  _storm_lib_path = ('service',)
911
922
 
912
923
  def getObjLocals(self):
@@ -931,6 +942,7 @@ class LibService(Lib):
931
942
  except s_exc.AuthDeny:
932
943
  raise e from None
933
944
  else:
945
+ # TODO: Remove support for this permission in 3.0.0
934
946
  mesg = 'Use of service.get.<servicename> permissions are deprecated.'
935
947
  await self.runt.warnonce(mesg, svcname=ssvc.name, svciden=ssvc.iden)
936
948
 
@@ -3425,13 +3437,14 @@ class LibFeed(Lib):
3425
3437
  data = await toprim(data)
3426
3438
 
3427
3439
  self.runt.layerConfirm(('feed:data', *name.split('.')))
3428
- with s_provenance.claim('feed:data', name=name):
3429
- # small work around for the feed API consistency
3430
- if name == 'syn.nodes':
3431
- async for node in self.runt.snap.addNodes(data):
3432
- yield node
3433
- return
3434
- await self.runt.snap.addFeedData(name, data)
3440
+
3441
+ # small work around for the feed API consistency
3442
+ if name == 'syn.nodes':
3443
+ async for node in self.runt.snap.addNodes(data):
3444
+ yield node
3445
+ return
3446
+
3447
+ await self.runt.snap.addFeedData(name, data)
3435
3448
 
3436
3449
  @stormfunc(readonly=True)
3437
3450
  async def _libList(self):
@@ -3443,11 +3456,12 @@ class LibFeed(Lib):
3443
3456
  data = await toprim(data)
3444
3457
 
3445
3458
  self.runt.layerConfirm(('feed:data', *name.split('.')))
3446
- with s_provenance.claim('feed:data', name=name):
3447
- strict = self.runt.snap.strict
3448
- self.runt.snap.strict = False
3449
- await self.runt.snap.addFeedData(name, data)
3450
- self.runt.snap.strict = strict
3459
+
3460
+ # TODO this should be a reentrent safe with block
3461
+ strict = self.runt.snap.strict
3462
+ self.runt.snap.strict = False
3463
+ await self.runt.snap.addFeedData(name, data)
3464
+ self.runt.snap.strict = strict
3451
3465
 
3452
3466
  @registry.registerLib
3453
3467
  class LibPipe(Lib):
@@ -7486,7 +7500,7 @@ class View(Prim):
7486
7500
 
7487
7501
  {'name': 'getPropArrayCount',
7488
7502
  'desc': '''
7489
- Get the number of invidivual array property values in the View for the given array property name.
7503
+ Get the number of individual array property values in the View for the given array property name.
7490
7504
 
7491
7505
  Notes:
7492
7506
  This is a fast approximate count calculated by summing the number of
@@ -7580,6 +7594,10 @@ class View(Prim):
7580
7594
  'args': (),
7581
7595
  'returns': {'name': 'Yields', 'type': 'dict',
7582
7596
  'desc': 'Yields previously successful merges into the view.'}}},
7597
+ {'name': 'getMergingViews', 'desc': 'Get a list of idens of Views that have open merge requests to this View.',
7598
+ 'type': {'type': 'function', '_funcname': 'getMergingViews',
7599
+ 'args': (),
7600
+ 'returns': {'name': 'idens', 'type': 'list', 'desc': 'The list of View idens that have an open merge request into this View.'}}},
7583
7601
  {'name': 'setMergeVoteComment', 'desc': 'Set the comment associated with your vote on a merge request.',
7584
7602
  'type': {'type': 'function', '_funcname': 'setMergeVoteComment',
7585
7603
  'args': ({'name': 'comment', 'type': 'str', 'desc': 'The text comment to set for the merge vote'},),
@@ -7634,6 +7652,7 @@ class View(Prim):
7634
7652
  'delMergeRequest': self.delMergeRequest,
7635
7653
  'setMergeRequest': self.setMergeRequest,
7636
7654
  'setMergeComment': self.setMergeComment,
7655
+ 'getMergingViews': self.getMergingViews,
7637
7656
  }
7638
7657
 
7639
7658
  async def addNode(self, form, valu, props=None):
@@ -7951,6 +7970,12 @@ class View(Prim):
7951
7970
 
7952
7971
  return await view.setMergeComment((await tostr(comment)))
7953
7972
 
7973
+ async def getMergingViews(self):
7974
+ view = self._reqView()
7975
+ self.runt.confirm(('view', 'read'), gateiden=view.iden)
7976
+
7977
+ return await view.getMergingViews()
7978
+
7954
7979
  async def setMergeVote(self, approved=True, comment=None):
7955
7980
  view = self._reqView()
7956
7981
  quorum = view.reqParentQuorum()
@@ -8664,7 +8689,7 @@ class LibCron(Lib):
8664
8689
  'returns': {'type': 'str', 'desc': 'The iden of the CronJob which was moved.'}}},
8665
8690
  {'name': 'list', 'desc': 'List CronJobs in the Cortex.',
8666
8691
  'type': {'type': 'function', '_funcname': '_methCronList',
8667
- 'returns': {'type': 'list', 'desc': 'A list of ``cronjob`` objects..', }}},
8692
+ 'returns': {'type': 'list', 'desc': 'A list of ``cronjob`` objects.', }}},
8668
8693
  {'name': 'enable', 'desc': 'Enable a CronJob in the Cortex.',
8669
8694
  'type': {'type': 'function', '_funcname': '_methCronEnable',
8670
8695
  'args': (
@@ -8855,6 +8880,7 @@ class LibCron(Lib):
8855
8880
  incunit = None
8856
8881
  incval = None
8857
8882
  reqdict = {}
8883
+ pool = await tobool(kwargs.get('pool', False))
8858
8884
  valinfo = { # unit: (minval, next largest unit)
8859
8885
  'month': (1, 'year'),
8860
8886
  'dayofmonth': (1, 'month'),
@@ -8960,6 +8986,7 @@ class LibCron(Lib):
8960
8986
 
8961
8987
  cdef = {'storm': query,
8962
8988
  'reqs': reqdict,
8989
+ 'pool': pool,
8963
8990
  'incunit': incunit,
8964
8991
  'incvals': incval,
8965
8992
  'creator': self.runt.user.iden
@@ -9208,6 +9235,7 @@ class CronJob(Prim):
9208
9235
  'view': view,
9209
9236
  'viewshort': view[:8] + '..',
9210
9237
  'query': self.valu.get('query') or '<missing>',
9238
+ 'pool': self.valu.get('pool', False),
9211
9239
  'isrecur': 'Y' if self.valu.get('recur') else 'N',
9212
9240
  'isrunning': 'Y' if self.valu.get('isrunning') else 'N',
9213
9241
  'enabled': 'Y' if self.valu.get('enabled', True) else 'N',
synapse/lib/trigger.py CHANGED
@@ -11,7 +11,6 @@ import synapse.lib.chop as s_chop
11
11
  import synapse.lib.cache as s_cache
12
12
  import synapse.lib.config as s_config
13
13
  import synapse.lib.grammar as s_grammar
14
- import synapse.lib.provenance as s_provenance
15
14
 
16
15
  logger = logging.getLogger(__name__)
17
16
 
@@ -546,20 +545,19 @@ class Trigger:
546
545
 
547
546
  self.startcount += 1
548
547
 
549
- with s_provenance.claim('trig', cond=cond, form=form, tag=tag, prop=prop):
550
- try:
551
- async with self.view.core.getStormRuntime(query, opts=opts) as runt:
548
+ try:
549
+ async with self.view.core.getStormRuntime(query, opts=opts) as runt:
552
550
 
553
- runt.addInput(node)
554
- await s_common.aspin(runt.execute())
551
+ runt.addInput(node)
552
+ await s_common.aspin(runt.execute())
555
553
 
556
- except (asyncio.CancelledError, s_exc.RecursionLimitHit):
557
- raise
554
+ except (asyncio.CancelledError, s_exc.RecursionLimitHit):
555
+ raise
558
556
 
559
- except Exception as e:
560
- self.errcount += 1
561
- self.lasterrs.append(str(e))
562
- logger.exception('Trigger encountered exception running storm query %s', storm)
557
+ except Exception as e:
558
+ self.errcount += 1
559
+ self.lasterrs.append(str(e))
560
+ logger.exception('Trigger encountered exception running storm query %s', storm)
563
561
 
564
562
  def pack(self):
565
563
  tdef = self.tdef.copy()
synapse/lib/types.py CHANGED
@@ -1850,7 +1850,7 @@ class Tag(Str):
1850
1850
  mesg = f'Tag does not match tagre: [{s_grammar.tagre.pattern}]'
1851
1851
  raise s_exc.BadTypeValu(valu=norm, name=self.name, mesg=mesg)
1852
1852
 
1853
- return norm, {'subs': subs}
1853
+ return norm, {'subs': subs, 'toks': toks}
1854
1854
 
1855
1855
  def _normPyStr(self, text):
1856
1856
  toks = text.strip('#').split('.')
synapse/lib/version.py CHANGED
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
223
223
  ##############################################################################
224
224
  # The following are touched during the release process by bumpversion.
225
225
  # Do not modify these directly.
226
- version = (2, 165, 0)
226
+ version = (2, 166, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = 'bdf3f6320106318fe52f1803e969090d950e0fdf'
228
+ commit = '09f8a7b3ad1f2ed5949e7d1a9dc7d17161fab932'
synapse/lib/view.py CHANGED
@@ -167,6 +167,18 @@ class View(s_nexus.Pusher): # type: ignore
167
167
  if byts is not None:
168
168
  return s_msgpack.un(byts)
169
169
 
170
+ async def getMergingViews(self):
171
+ if self.info.get('quorum') is None:
172
+ mesg = f'View ({self.iden}) does not require quorum voting.'
173
+ raise s_exc.BadState(mesg=mesg)
174
+
175
+ idens = []
176
+ for view in list(self.core.views.values()):
177
+ await asyncio.sleep(0)
178
+ if view.parent == self and view.getMergeRequest() is not None:
179
+ idens.append(view.iden)
180
+ return idens
181
+
170
182
  async def setMergeRequest(self, mergeinfo):
171
183
  self.reqParentQuorum()
172
184
  mergeinfo['iden'] = s_common.guid()
synapse/models/inet.py CHANGED
@@ -1304,8 +1304,8 @@ class InetModule(s_module.CoreModule):
1304
1304
  }),
1305
1305
 
1306
1306
  ('inet:ssl:cert', ('comp', {'fields': (('server', 'inet:server'), ('file', 'file:bytes'))}), {
1307
- 'doc': 'An SSL certificate file served by a server.',
1308
- 'ex': '(1.2.3.4:443, guid:d41d8cd98f00b204e9800998ecf8427e)',
1307
+ 'deprecated': True,
1308
+ 'doc': 'Deprecated. Please use inet:tls:servercert or inet:tls:clientcert',
1309
1309
  }),
1310
1310
 
1311
1311
  ('inet:port', ('int', {'min': 0, 'max': 0xffff}), {
@@ -1489,6 +1489,24 @@ class InetModule(s_module.CoreModule):
1489
1489
  ('inet:ssl:jarmsample', ('comp', {'fields': (('server', 'inet:server'), ('jarmhash', 'inet:ssl:jarmhash'))}), {
1490
1490
  'doc': 'A JARM hash sample taken from a server.'}),
1491
1491
 
1492
+ ('inet:tls:handshake', ('guid', {}), {
1493
+ 'doc': 'An instance of a TLS handshake between a server and client.'}),
1494
+
1495
+ ('inet:tls:ja3s:sample', ('comp', {'fields': (('server', 'inet:server'), ('ja3s', 'hash:md5'))}), {
1496
+ 'doc': 'A JA3 sample taken from a server.'}),
1497
+
1498
+ ('inet:tls:ja3:sample', ('comp', {'fields': (('client', 'inet:client'), ('ja3', 'hash:md5'))}), {
1499
+ 'doc': 'A JA3 sample taken from a client.'}),
1500
+
1501
+ ('inet:tls:servercert', ('comp', {'fields': (('server', 'inet:server'), ('cert', 'crypto:x509:cert'))}), {
1502
+ 'doc': 'An x509 certificate sent by a server for TLS.',
1503
+ 'ex': '(1.2.3.4:443, c7437790af01ae1bb2f8f3b684c70bf8)',
1504
+ }),
1505
+
1506
+ ('inet:tls:clientcert', ('comp', {'fields': (('client', 'inet:client'), ('cert', 'crypto:x509:cert'))}), {
1507
+ 'doc': 'An x509 certificate sent by a client for TLS.',
1508
+ 'ex': '(1.2.3.4:443, 3fdf364e081c14997b291852d1f23868)',
1509
+ }),
1492
1510
  ),
1493
1511
 
1494
1512
  'interfaces': (
@@ -3234,6 +3252,60 @@ class InetModule(s_module.CoreModule):
3234
3252
  'doc': 'The server that was sampled to compute the JARM hash.'}),
3235
3253
  )),
3236
3254
 
3255
+ ('inet:tls:handshake', {}, (
3256
+ ('time', ('time', {}), {
3257
+ 'doc': 'The time the handshake was initiated.'}),
3258
+ ('flow', ('inet:flow', {}), {
3259
+ 'doc': 'The raw inet:flow associated with the handshake.'}),
3260
+ ('server', ('inet:server', {}), {
3261
+ 'doc': 'The TLS server during the handshake.'}),
3262
+ ('server:cert', ('crypto:x509:cert', {}), {
3263
+ 'doc': 'The x509 certificate sent by the server during the handshake.'}),
3264
+ ('server:fingerprint:ja3', ('hash:md5', {}), {
3265
+ 'doc': 'The JA3S finger of the server.'}),
3266
+ ('client', ('inet:client', {}), {
3267
+ 'doc': 'The TLS client during the handshake.'}),
3268
+ ('client:cert', ('crypto:x509:cert', {}), {
3269
+ 'doc': 'The x509 certificate sent by the client during the handshake.'}),
3270
+ ('client:fingerprint:ja3', ('hash:md5', {}), {
3271
+ 'doc': 'The JA3 fingerprint of the client.'}),
3272
+ )),
3273
+
3274
+ ('inet:tls:ja3s:sample', {}, (
3275
+ ('server', ('inet:server', {}), {
3276
+ 'ro': True,
3277
+ 'doc': 'The server that was sampled to produce the JA3S hash.'}),
3278
+ ('ja3s', ('hash:md5', {}), {
3279
+ 'ro': True,
3280
+ 'doc': "The JA3S hash computed from the server's TLS hello packet."})
3281
+ )),
3282
+
3283
+ ('inet:tls:ja3:sample', {}, (
3284
+ ('client', ('inet:client', {}), {
3285
+ 'ro': True,
3286
+ 'doc': 'The client that was sampled to produce the JA3 hash.'}),
3287
+ ('ja3', ('hash:md5', {}), {
3288
+ 'ro': True,
3289
+ 'doc': "The JA3 hash computed from the client's TLS hello packet."})
3290
+ )),
3291
+
3292
+ ('inet:tls:servercert', {}, (
3293
+ ('server', ('inet:server', {}), {
3294
+ 'ro': True,
3295
+ 'doc': 'The server associated with the x509 certificate.'}),
3296
+ ('cert', ('crypto:x509:cert', {}), {
3297
+ 'ro': True,
3298
+ 'doc': 'The x509 certificate sent by the server.'})
3299
+ )),
3300
+
3301
+ ('inet:tls:clientcert', {}, (
3302
+ ('client', ('inet:client', {}), {
3303
+ 'ro': True,
3304
+ 'doc': 'The client associated with the x509 certificate.'}),
3305
+ ('cert', ('crypto:x509:cert', {}), {
3306
+ 'ro': True,
3307
+ 'doc': 'The x509 certificate sent by the client.'})
3308
+ )),
3237
3309
  ),
3238
3310
  }),
3239
3311
  )