synapse 2.195.1__py311-none-any.whl → 2.196.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 (45) hide show
  1. synapse/axon.py +72 -5
  2. synapse/common.py +23 -0
  3. synapse/cortex.py +1 -0
  4. synapse/daemon.py +1 -0
  5. synapse/lib/aha.py +159 -4
  6. synapse/lib/cell.py +133 -8
  7. synapse/lib/jsonstor.py +2 -1
  8. synapse/lib/modelrev.py +5 -1
  9. synapse/lib/nexus.py +4 -1
  10. synapse/lib/reflect.py +4 -5
  11. synapse/lib/snap.py +14 -7
  12. synapse/lib/stormlib/aha.py +351 -1
  13. synapse/lib/stormlib/utils.py +37 -0
  14. synapse/lib/stormtypes.py +118 -0
  15. synapse/lib/version.py +2 -2
  16. synapse/models/base.py +3 -0
  17. synapse/models/infotech.py +55 -16
  18. synapse/models/orgs.py +14 -10
  19. synapse/models/risk.py +23 -10
  20. synapse/models/transport.py +8 -3
  21. synapse/telepath.py +12 -0
  22. synapse/tests/test_axon.py +23 -0
  23. synapse/tests/test_common.py +28 -0
  24. synapse/tests/test_datamodel.py +8 -0
  25. synapse/tests/test_lib_aha.py +241 -0
  26. synapse/tests/test_lib_cell.py +61 -0
  27. synapse/tests/test_lib_jsonstor.py +1 -0
  28. synapse/tests/test_lib_modelrev.py +6 -0
  29. synapse/tests/test_lib_stormlib_aha.py +188 -0
  30. synapse/tests/test_lib_stormlib_utils.py +14 -0
  31. synapse/tests/test_lib_stormtypes.py +90 -3
  32. synapse/tests/test_model_base.py +2 -0
  33. synapse/tests/test_model_infotech.py +28 -1
  34. synapse/tests/test_model_orgs.py +2 -0
  35. synapse/tests/test_model_risk.py +2 -0
  36. synapse/tests/test_model_transport.py +1 -0
  37. synapse/tests/test_telepath.py +26 -0
  38. synapse/tests/test_tools_aha.py +192 -0
  39. synapse/tools/aha/mirror.py +193 -0
  40. synapse/tools/changelog.py +32 -27
  41. {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/METADATA +1 -1
  42. {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/RECORD +45 -42
  43. {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/LICENSE +0 -0
  44. {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/WHEEL +0 -0
  45. {synapse-2.195.1.dist-info → synapse-2.196.0.dist-info}/top_level.txt +0 -0
@@ -784,6 +784,10 @@ class CellTest(s_t_utils.SynTest):
784
784
  cell.VERSION = (1, 2, 3)
785
785
  cell.VERSTRING = '1.2.3'
786
786
 
787
+ cell.features.update({
788
+ 'testvalu': 2
789
+ })
790
+
787
791
  http_info = []
788
792
  host, port = await cell.addHttpsPort(0)
789
793
  http_info.append({'host': host, 'port': port})
@@ -807,6 +811,9 @@ class CellTest(s_t_utils.SynTest):
807
811
  # A Cortex populated cellvers
808
812
  self.isin('cortex:defaults', cnfo.get('cellvers', {}))
809
813
 
814
+ self.eq(info.get('features'), cell.features)
815
+ self.eq(info.get('features', {}).get('testvalu'), 2)
816
+
810
817
  # Defaults aha data is
811
818
  self.eq(cnfo.get('aha'), {'name': None, 'leader': None, 'network': None})
812
819
 
@@ -3294,6 +3301,51 @@ class CellTest(s_t_utils.SynTest):
3294
3301
  await cell00.promote(graceful=True)
3295
3302
  self.isin('02.cell is not the current leader', cm.exception.get('mesg'))
3296
3303
 
3304
+ async def test_cell_get_aha_proxy(self):
3305
+
3306
+ async with self.getTestCell() as cell:
3307
+
3308
+ self.none(await cell.getAhaProxy())
3309
+
3310
+ class MockAhaClient:
3311
+ def __init__(self, proxy=None):
3312
+ self._proxy = proxy
3313
+
3314
+ async def proxy(self, timeout=None):
3315
+ return self._proxy
3316
+
3317
+ with self.getAsyncLoggerStream('synapse.lib.cell', 'AHA client connection failed.') as stream:
3318
+ cell.ahaclient = MockAhaClient()
3319
+ self.none(await cell.getAhaProxy())
3320
+ self.true(await stream.wait(timeout=1))
3321
+
3322
+ class MockProxyHasNot:
3323
+ def _hasTeleFeat(self, name, vers):
3324
+ return False
3325
+
3326
+ cell.ahaclient = MockAhaClient(proxy=MockProxyHasNot())
3327
+ self.none(await cell.getAhaProxy(feats=(('test', 1),)))
3328
+
3329
+ class MockProxyHas:
3330
+ def _hasTeleFeat(self, name, vers):
3331
+ return True
3332
+
3333
+ mock_proxy = MockProxyHas()
3334
+ cell.ahaclient = MockAhaClient(proxy=mock_proxy)
3335
+ self.eq(await cell.getAhaProxy(), mock_proxy)
3336
+ self.eq(await cell.getAhaProxy(feats=(('test', 1),)), mock_proxy)
3337
+
3338
+ async def test_lib_cell_sadaha(self):
3339
+
3340
+ async with self.getTestCell() as cell:
3341
+
3342
+ self.none(await cell.getAhaProxy())
3343
+ cell.ahaclient = await s_telepath.Client.anit('cell:///tmp/newp')
3344
+
3345
+ # coverage for failure of aha client to connect
3346
+ with self.raises(TimeoutError):
3347
+ self.none(await cell.getAhaProxy(timeout=0.1))
3348
+
3297
3349
  async def test_stream_backup_exception(self):
3298
3350
 
3299
3351
  with self.getTestDir() as dirn:
@@ -3356,3 +3408,12 @@ class CellTest(s_t_utils.SynTest):
3356
3408
  with self.raises(s_exc.BackupAlreadyRunning):
3357
3409
  async for _ in proxy.iterNewBackupArchive('newbackup', remove=True):
3358
3410
  pass
3411
+
3412
+ async def test_cell_peer_noaha(self):
3413
+
3414
+ todo = s_common.todo('newp')
3415
+ async with self.getTestCell() as cell:
3416
+ async for item in cell.callPeerApi(todo):
3417
+ pass
3418
+ async for item in cell.callPeerGenr(todo):
3419
+ pass
@@ -116,6 +116,7 @@ class JsonStorTest(s_test.SynTest):
116
116
  self.eq({'hehe': 'haha', 'zip': {}}, await prox.getPathObj('foo/bar'))
117
117
 
118
118
  self.false(await prox.delPathObjProp('newp/newp', 'newp'))
119
+ self.false(await prox.delPathObjProp('foo/bar', 'nested/newp'))
119
120
 
120
121
  await prox.delPathObj('foo/bar')
121
122
  self.none(await prox.getPathObj('foo/bar'))
@@ -1766,3 +1766,9 @@ class ModelRevTest(s_tests.SynTest):
1766
1766
  self.eq('foo bar', nodes[0].get('model'))
1767
1767
  nodes = await core.nodes('transport:sea:vessel')
1768
1768
  self.eq('foo bar', nodes[0].get('model'))
1769
+
1770
+ async def test_modelrev_0_2_33(self):
1771
+ async with self.getRegrCore('model-0.2.33') as core:
1772
+ nodes = await core.nodes('entity:name')
1773
+ self.len(1, nodes)
1774
+ self.eq('foo bar', nodes[0].repr())
@@ -6,6 +6,8 @@ import synapse.lib.cell as s_cell
6
6
 
7
7
  import synapse.tests.utils as s_test
8
8
 
9
+ import unittest.mock as mock
10
+
9
11
  class AhaLibTest(s_test.SynTest):
10
12
 
11
13
  async def test_stormlib_aha_basics(self):
@@ -193,3 +195,189 @@ Connection information:
193
195
 
194
196
  with self.raises(s_exc.NoSuchName):
195
197
  await core00.callStorm('$lib.aha.del(axon...)')
198
+
199
+ async def test_stormlib_aha_mirror(self):
200
+
201
+ async with self.getTestAha() as aha:
202
+
203
+ with self.getTestDir() as dirn:
204
+
205
+ dirn00 = s_common.genpath(dirn, 'cell00')
206
+ dirn01 = s_common.genpath(dirn, 'cell01')
207
+ dirn02 = s_common.genpath(dirn, 'cell02')
208
+
209
+ async with aha.waiter(3, 'aha:svcadd', timeout=10):
210
+
211
+ cell00 = await aha.enter_context(self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=dirn00))
212
+ cell01 = await aha.enter_context(self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=dirn01,
213
+ provinfo={'mirror': 'cell'}))
214
+ core00 = await aha.enter_context(self.addSvcToAha(aha, 'core', s_cortex.Cortex, dirn=dirn02))
215
+ await cell01.sync()
216
+
217
+ # PeerGenr
218
+ resp = await core00.callStorm('''
219
+ $resps = $lib.list()
220
+ $todo = $lib.utils.todo('getTasks')
221
+ for ($name, $info) in $lib.aha.callPeerGenr(cell..., $todo) {
222
+ $resps.append(($name, $info))
223
+ }
224
+ return($resps)
225
+ ''')
226
+ self.len(0, resp)
227
+
228
+ resp = await core00.callStorm('''
229
+ $resps = $lib.list()
230
+ $todo = $lib.utils.todo('getNexusChanges', (0), wait=(false))
231
+ for ($name, $info) in $lib.aha.callPeerGenr(cell..., $todo) {
232
+ $resps.append(($name, $info))
233
+ }
234
+ return($resps)
235
+ ''')
236
+ self.len(4, resp)
237
+
238
+ cell00_rid = (await cell00.getCellInfo())['cell']['run']
239
+ resp = await core00.callStorm('''
240
+ $resps = $lib.list()
241
+ $todo = $lib.utils.todo('getNexusChanges', (0), wait=(false))
242
+ for $info in $lib.aha.callPeerGenr(cell..., $todo, skiprun=$skiprun) {
243
+ $resps.append($info)
244
+ }
245
+ return($resps)
246
+ ''', opts={'vars': {'skiprun': cell00_rid}})
247
+ self.len(2, resp)
248
+
249
+ await self.asyncraises(s_exc.NoSuchName, core00.callStorm('''
250
+ $todo = $lib.utils.todo('getTasks')
251
+ $lib.aha.callPeerGenr(null, $todo)
252
+ '''))
253
+
254
+ # PeerApi
255
+ resp = await core00.callStorm('''
256
+ $resps = $lib.list()
257
+ $todo = $lib.utils.todo('getCellInfo')
258
+ for ($name, $info) in $lib.aha.callPeerApi(cell..., $todo) {
259
+ $resps.append(($name, $info))
260
+ }
261
+ return($resps)
262
+ ''')
263
+ self.len(2, resp)
264
+ self.eq(resp[0][0], '00.cell.synapse')
265
+ self.eq(resp[0][1][0], True)
266
+ self.isinstance(resp[0][1][1], dict)
267
+
268
+ resp = await core00.callStorm('''
269
+ $resps = $lib.list()
270
+ $todo = $lib.utils.todo(getCellInfo)
271
+ for ($name, $info) in $lib.aha.callPeerApi(cell..., $todo) {
272
+ $resps.append(($name, $info))
273
+ }
274
+ return($resps)
275
+ ''')
276
+ self.len(2, resp)
277
+
278
+ resp = await core00.callStorm('''
279
+ $resps = $lib.list()
280
+ $todo = $lib.utils.todo(getCellInfo)
281
+ for ($name, $info) in $lib.aha.callPeerApi(cell..., $todo, skiprun=$skiprun) {
282
+ $resps.append(($name, $info))
283
+ }
284
+ return($resps)
285
+ ''', opts={'vars': {'skiprun': cell00_rid}})
286
+ self.len(1, resp)
287
+
288
+ resp = await core00.callStorm('''
289
+ $resps = $lib.list()
290
+ $todo = $lib.utils.todo('getCellInfo')
291
+ for ($name, $info) in $lib.aha.callPeerApi(cell..., $todo, timeout=(10)) {
292
+ $resps.append(($name, $info))
293
+ }
294
+ return($resps)
295
+ ''')
296
+ self.len(2, resp)
297
+
298
+ await self.asyncraises(s_exc.NoSuchName, core00.callStorm('''
299
+ $todo = $lib.utils.todo('getCellInfo')
300
+ $lib.aha.callPeerApi(newp..., $todo)
301
+ '''))
302
+
303
+ await self.asyncraises(s_exc.NoSuchName, core00.callStorm('''
304
+ $todo = $lib.utils.todo('getCellInfo')
305
+ $lib.aha.callPeerApi(null, $todo)
306
+ '''))
307
+
308
+ await self.asyncraises(s_exc.NoSuchMeth, core00.callStorm('''
309
+ $todo = $lib.utils.todo('bogusMethod')
310
+ for $info in $lib.aha.callPeerApi(cell..., $todo) {
311
+ ($ok, $info) = $info.1
312
+ if (not $ok) {
313
+ $lib.raise($info.err, $info.errmsg)
314
+ }
315
+ }
316
+ '''))
317
+
318
+ await aha.addAhaSvc('noiden.cell', info={'urlinfo': {'scheme': 'tcp',
319
+ 'host': '0.0.0.0',
320
+ 'port': '3030'}},
321
+ network='synapse')
322
+ await self.asyncraises(s_exc.NoSuchName, core00.callStorm('''
323
+ $todo = $lib.utils.todo('getTasks')
324
+ $lib.aha.callPeerGenr(noiden.cell..., $todo)
325
+ '''))
326
+ await self.asyncraises(s_exc.NoSuchName, core00.callStorm('''
327
+ $todo = $lib.utils.todo('getCellInfo')
328
+ $lib.aha.callPeerApi(noiden.cell..., $todo)
329
+ '''))
330
+
331
+ msgs = await core00.stormlist('aha.svc.mirror')
332
+ self.stormIsInPrint('Service Mirror Groups:', msgs)
333
+ self.stormIsInPrint('cell.synapse', msgs)
334
+ self.stormIsInPrint('00.cell.synapse', msgs)
335
+ self.stormIsInPrint('01.cell.synapse', msgs)
336
+ self.stormIsInPrint('Group Status: In Sync', msgs)
337
+
338
+ msgs = await core00.stormlist('aha.svc.mirror --timeout 30')
339
+ self.stormIsInPrint('Service Mirror Groups:', msgs)
340
+ self.stormIsInPrint('Group Status: In Sync', msgs)
341
+
342
+ async def mockCellInfo():
343
+ return {
344
+ 'cell': {'ready': True, 'nexsindx': 10, 'uplink': None},
345
+ 'synapse': {'verstring': '2.190.0'},
346
+ }
347
+
348
+ async def mockOutOfSyncCellInfo():
349
+ return {
350
+ 'cell': {'ready': True, 'nexsindx': 5, 'uplink': cell00.iden},
351
+ 'synapse': {'verstring': '2.190.0'},
352
+ }
353
+
354
+ with mock.patch.object(cell00, 'getCellInfo', mockCellInfo):
355
+ with mock.patch.object(cell01, 'getCellInfo', mockOutOfSyncCellInfo):
356
+ async def mock_call_aha(*args, **kwargs):
357
+ todo = args[1]
358
+ if todo[0] == 'waitNexsOffs':
359
+ yield ('00.cell.synapse', (True, True))
360
+ yield ('01.cell.synapse', (True, True))
361
+ elif todo[0] == 'getCellInfo':
362
+ if not hasattr(mock_call_aha, 'called'):
363
+ mock_call_aha.called = True
364
+ yield ('00.cell.synapse', (True, await mockCellInfo()))
365
+ yield ('01.cell.synapse', (True, await mockOutOfSyncCellInfo()))
366
+ else:
367
+ yield ('00.cell.synapse', (True, await mockCellInfo()))
368
+ yield ('01.cell.synapse', (True, await mockCellInfo()))
369
+
370
+ with mock.patch.object(aha, 'callAhaPeerApi', mock_call_aha):
371
+ msgs = await core00.stormlist('aha.svc.mirror --wait')
372
+ self.stormIsInPrint('Group Status: Out of Sync', msgs)
373
+ self.stormIsInPrint('Updated status:', msgs)
374
+ self.stormIsInPrint('Group Status: In Sync', msgs)
375
+
376
+ with mock.patch.object(cell00, 'getCellInfo', mockCellInfo):
377
+ with mock.patch.object(cell01, 'getCellInfo', mockOutOfSyncCellInfo):
378
+ msgs = await core00.stormlist('aha.svc.mirror --timeout 1')
379
+ self.stormIsInPrint('Group Status: Out of Sync', msgs)
380
+
381
+ await aha.delAhaSvc('00.cell', network='synapse')
382
+ msgs = await core00.stormlist('aha.svc.mirror')
383
+ self.stormNotInPrint('Service Mirror Groups:', msgs)
@@ -0,0 +1,14 @@
1
+ import synapse.exc as s_exc
2
+ import synapse.tests.utils as s_test
3
+
4
+ class UtilsTest(s_test.SynTest):
5
+
6
+ async def test_lib_stormlib_utils_todo(self):
7
+
8
+ async with self.getTestCore() as core:
9
+
10
+ valu = await core.callStorm('return($lib.utils.todo(foo))')
11
+ self.eq(valu, ('foo', (), {}))
12
+
13
+ valu = await core.callStorm('return($lib.utils.todo(fooName, arg1, arg2, keyword=bar, anotherkeyword=hehe))')
14
+ self.eq(valu, ('fooName', ('arg1', 'arg2'), {'keyword': 'bar', 'anotherkeyword': 'hehe'}))
@@ -3,6 +3,7 @@ import bz2
3
3
  import gzip
4
4
  import json
5
5
  import base64
6
+ import struct
6
7
  import asyncio
7
8
  import hashlib
8
9
  import binascii
@@ -6467,13 +6468,29 @@ words\tword\twrd'''
6467
6468
  async with self.getTestCore() as core:
6468
6469
 
6469
6470
  viewiden = await core.callStorm('return($lib.view.get().fork().iden)')
6470
- await core.nodes('[ ou:org=* :name=foobar +#hehe ]')
6471
+ q = '[ ou:org=* :name=foobar +#hehe ] $node.data.set(foo, bar) return($node.iden())'
6472
+ basenode = await core.callStorm(q)
6471
6473
 
6472
6474
  opts = {'view': viewiden}
6473
- nodeiden = await core.callStorm('[ ou:org=* :name=foobar +#hehe ] return($node.iden())', opts=opts)
6475
+ nodeiden = await core.callStorm('''
6476
+ [ ou:org=* :name=foobar +#hehe ]
6477
+ $node.data.set(foo, bar)
6478
+ return($node.iden())
6479
+ ''', opts=opts)
6480
+
6481
+ nodeiden2 = await core.callStorm('[test:str=yup] $node.data.set(foo, yup) return ($node.iden())',
6482
+ opts=opts)
6474
6483
 
6475
6484
  self.len(2, await core.nodes('ou:org +:name=foobar +#hehe', opts=opts))
6476
6485
 
6486
+ nodes = await core.nodes('yield $lib.layer.get().liftByNodeData(foo)', opts=opts)
6487
+ self.len(2, nodes)
6488
+ self.eq(set((nodeiden, nodeiden2)), {node.iden() for node in nodes})
6489
+
6490
+ nodes = await core.nodes('yield $lib.layer.get().liftByNodeData(foo)')
6491
+ self.len(1, nodes)
6492
+ self.eq(nodes[0].iden(), basenode)
6493
+
6477
6494
  nodes = await core.nodes('yield $lib.layer.get().liftByProp(ou:org)', opts=opts)
6478
6495
  self.len(1, nodes)
6479
6496
  self.eq(nodes[0].iden(), nodeiden)
@@ -6487,7 +6504,7 @@ words\tword\twrd'''
6487
6504
  self.eq(nodes[0].iden(), nodeiden)
6488
6505
 
6489
6506
  nodes = await core.nodes('yield $lib.layer.get().liftByProp(".created")', opts=opts)
6490
- self.len(1, nodes)
6507
+ self.len(2, nodes)
6491
6508
  self.eq(nodes[0].iden(), nodeiden)
6492
6509
 
6493
6510
  nodes = await core.nodes('yield $lib.layer.get().liftByTag(hehe)', opts=opts)
@@ -7084,3 +7101,73 @@ words\tword\twrd'''
7084
7101
 
7085
7102
  with self.raises(s_exc.BadState):
7086
7103
  await core.callStorm(merging)
7104
+
7105
+ async def test_storm_lib_axon_read_unpack(self):
7106
+
7107
+ async with self.getTestCore() as core:
7108
+
7109
+ visi = await core.auth.addUser('visi')
7110
+
7111
+ orig_axoninfo = core.axoninfo
7112
+ core.axoninfo = {'features': {}}
7113
+ data = struct.pack('>Q', 1)
7114
+ size, sha256 = await core.axon.put(data)
7115
+ sha256_s = s_common.ehex(sha256)
7116
+ q = 'return($lib.axon.unpack($sha256, fmt=">Q"))'
7117
+ await self.asyncraises(s_exc.FeatureNotSupported,
7118
+ core.callStorm(q, opts={'vars': {'sha256': sha256_s}}))
7119
+ core.axoninfo = orig_axoninfo
7120
+
7121
+ data = b'vertex.link'
7122
+ size, sha256 = await core.axon.put(data)
7123
+ sha256_s = s_common.ehex(sha256)
7124
+
7125
+ _, emptyhash = await core.axon.put(b'')
7126
+ emptyhash = s_common.ehex(emptyhash)
7127
+
7128
+ opts = {'user': visi.iden, 'vars': {'sha256': sha256_s, 'emptyhash': emptyhash}}
7129
+ await self.asyncraises(s_exc.AuthDeny,
7130
+ core.callStorm('return($lib.axon.read($sha256, offs=3, size=3))', opts=opts))
7131
+ await visi.addRule((True, ('storm', 'lib', 'axon', 'get')))
7132
+
7133
+ q = 'return($lib.axon.read($sha256, offs=3, size=3))'
7134
+ self.eq(b'tex', await core.callStorm(q, opts=opts))
7135
+ q = 'return($lib.axon.read($sha256, offs=7, size=4))'
7136
+ self.eq(b'link', await core.callStorm(q, opts=opts))
7137
+ q = 'return($lib.axon.read($sha256, offs=11, size=1))'
7138
+ self.eq(b'', await core.callStorm(q, opts=opts))
7139
+
7140
+ q = 'return($lib.axon.read($emptyhash))'
7141
+ self.eq(b'', await core.callStorm(q, opts=opts))
7142
+
7143
+ q = 'return($lib.axon.read($sha256, size=0))'
7144
+ await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
7145
+ q = 'return($lib.axon.read($sha256, offs=-1, size=1))'
7146
+ await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
7147
+ q = 'return($lib.axon.read($sha256, size=2097152))'
7148
+ await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
7149
+
7150
+ intdata = struct.pack('>QQQ', 1, 2, 3)
7151
+ size, sha256 = await core.axon.put(intdata)
7152
+ sha256_s = s_common.ehex(sha256)
7153
+ opts = {'user': visi.iden, 'vars': {'sha256': sha256_s}}
7154
+
7155
+ await visi.delRule((True, ('storm', 'lib', 'axon', 'get')))
7156
+ q = 'return($lib.axon.unpack($sha256, fmt=">Q"))'
7157
+ await self.asyncraises(s_exc.AuthDeny, core.callStorm(q, opts=opts))
7158
+ await visi.addRule((True, ('storm', 'lib', 'axon', 'get')))
7159
+
7160
+ q = 'return($lib.axon.unpack($sha256, fmt=">Q"))'
7161
+ self.eq((1,), await core.callStorm(q, opts=opts))
7162
+ q = 'return($lib.axon.unpack($sha256, fmt=">Q", offs=8))'
7163
+ self.eq((2,), await core.callStorm(q, opts=opts))
7164
+ q = 'return($lib.axon.unpack($sha256, fmt=">Q", offs=16))'
7165
+ self.eq((3,), await core.callStorm(q, opts=opts))
7166
+ q = 'return($lib.axon.unpack($sha256, fmt=">QQ", offs=8))'
7167
+ self.eq((2, 3), await core.callStorm(q, opts=opts))
7168
+
7169
+ q = 'return($lib.axon.unpack($sha256, fmt="not a valid format"))'
7170
+ await self.asyncraises(s_exc.BadArg, core.callStorm(q, opts=opts))
7171
+
7172
+ q = 'return($lib.axon.unpack($sha256, fmt=">Q", offs=24))'
7173
+ await self.asyncraises(s_exc.BadDataValu, core.callStorm(q, opts=opts))
@@ -227,6 +227,7 @@ class BaseTest(s_t_utils.SynTest):
227
227
  :name="FOO Bar"
228
228
  :type=osint
229
229
  :url="https://foo.bar/index.html"
230
+ :ingest:cursor="Woot Woot "
230
231
  :ingest:latest=20241205
231
232
  :ingest:offset=17
232
233
  ]
@@ -238,6 +239,7 @@ class BaseTest(s_t_utils.SynTest):
238
239
  self.eq(sorc.get('name'), 'foo bar')
239
240
  self.eq(sorc.get('url'), 'https://foo.bar/index.html')
240
241
  self.eq(sorc.get('ingest:offset'), 17)
242
+ self.eq(sorc.get('ingest:cursor'), 'Woot Woot ')
241
243
  self.eq(sorc.get('ingest:latest'), 1733356800000)
242
244
 
243
245
  valu = (sorc.ndef[1], ('inet:fqdn', 'woot.com'))
@@ -342,6 +342,7 @@ class InfotechModelTest(s_t_utils.SynTest):
342
342
  :verdict=suspicious
343
343
  :scanner={[ it:prod:softver=* :name="visi scan" ]}
344
344
  :scanner:name="visi scan"
345
+ :categories=("Foo Bar", "baz faz")
345
346
  :signame=omgwtfbbq
346
347
  :target:file=*
347
348
  :target:proc={[ it:exec:proc=* :cmd="foo.exe --bar" ]}
@@ -367,6 +368,7 @@ class InfotechModelTest(s_t_utils.SynTest):
367
368
  self.eq(0x01020304, nodes[0].get('target:ipv4'))
368
369
  self.eq('::1', nodes[0].get('target:ipv6'))
369
370
  self.eq('omgwtfbbq', nodes[0].get('signame'))
371
+ self.eq(('baz faz', 'foo bar'), nodes[0].get('categories'))
370
372
 
371
373
  self.len(1, await core.nodes('it:av:scan:result:scanner:name="visi scan" -> it:host'))
372
374
  self.len(1, await core.nodes('it:av:scan:result:scanner:name="visi scan" -> inet:url'))
@@ -617,11 +619,36 @@ class InfotechModelTest(s_t_utils.SynTest):
617
619
  node = nodes[0]
618
620
  self.eq(node.ndef, ('it:dev:int', 1640531528))
619
621
 
620
- nodes = await core.nodes('[it:sec:cve=CVE-2013-9999 :desc="Some words."]')
622
+ nodes = await core.nodes('''[
623
+ it:sec:cve=CVE-2013-9999
624
+ :desc="Some words."
625
+
626
+ :nist:nvd:source=NistSource
627
+ :nist:nvd:published=2021-10-11
628
+ :nist:nvd:modified=2021-10-11
629
+
630
+ :cisa:kev:name=KevName
631
+ :cisa:kev:desc=KevDesc
632
+ :cisa:kev:action=KevAction
633
+ :cisa:kev:vendor=KevVendor
634
+ :cisa:kev:product=KevProduct
635
+ :cisa:kev:added=2022-01-02
636
+ :cisa:kev:duedate=2022-01-02
637
+ ]''')
621
638
  self.len(1, nodes)
622
639
  node = nodes[0]
623
640
  self.eq(node.ndef, ('it:sec:cve', 'cve-2013-9999'))
624
641
  self.eq(node.get('desc'), 'Some words.')
642
+ self.eq(node.get('nist:nvd:source'), 'nistsource')
643
+ self.eq(node.get('nist:nvd:published'), 1633910400000)
644
+ self.eq(node.get('nist:nvd:modified'), 1633910400000)
645
+ self.eq(node.get('cisa:kev:name'), 'KevName')
646
+ self.eq(node.get('cisa:kev:desc'), 'KevDesc')
647
+ self.eq(node.get('cisa:kev:action'), 'KevAction')
648
+ self.eq(node.get('cisa:kev:vendor'), 'kevvendor')
649
+ self.eq(node.get('cisa:kev:product'), 'kevproduct')
650
+ self.eq(node.get('cisa:kev:added'), 1641081600000)
651
+ self.eq(node.get('cisa:kev:duedate'), 1641081600000)
625
652
 
626
653
  nodes = await core.nodes('[it:sec:cve=$valu]', opts={'vars': {'valu': 'CVE\u20122013\u20131138'}})
627
654
  self.len(1, nodes)
@@ -640,6 +640,7 @@ class OuModelTest(s_t_utils.SynTest):
640
640
  ou:contest:result=(*, *)
641
641
  :rank=1
642
642
  :score=20
643
+ :period=(20250101, 20250102)
643
644
  :url=http://vertex.link/contest/result
644
645
  ]''')
645
646
  self.len(1, nodes)
@@ -647,6 +648,7 @@ class OuModelTest(s_t_utils.SynTest):
647
648
  self.nn(nodes[0].get('participant'))
648
649
  self.eq(1, nodes[0].get('rank'))
649
650
  self.eq(20, nodes[0].get('score'))
651
+ self.eq((1735689600000, 1735776000000), nodes[0].get('period'))
650
652
  self.eq('http://vertex.link/contest/result', nodes[0].get('url'))
651
653
  self.len(1, await core.nodes('ou:contest:result -> ps:contact'))
652
654
  self.len(1, await core.nodes('ou:contest:result -> ou:contest'))
@@ -111,12 +111,14 @@ class RiskModelTest(s_t_utils.SynTest):
111
111
  :cvss:v3 ?= "newp3.1"
112
112
  :priority=high
113
113
  :severity=high
114
+ :tag=cno.vuln.woot
114
115
  ]''')
115
116
 
116
117
  self.none(node.get('cvss:v2'))
117
118
  self.none(node.get('cvss:v3'))
118
119
  self.eq(40, node.get('severity'))
119
120
  self.eq(40, node.get('priority'))
121
+ self.eq('cno.vuln.woot', node.get('tag'))
120
122
 
121
123
  with self.raises(s_exc.BadTypeValu):
122
124
  node = await addNode(f'''[
@@ -110,6 +110,7 @@ class TransportTest(s_test.SynTest):
110
110
  self.nn(vessel.get('operator'))
111
111
 
112
112
  self.len(1, await core.nodes('transport:sea:vessel:imo^="IMO 123"'))
113
+ self.len(1, await core.nodes('transport:sea:vessel :name -> entity:name'))
113
114
  self.len(1, await core.nodes('transport:sea:vessel -> transport:sea:vessel:type:taxonomy'))
114
115
 
115
116
  seatelem = (await core.nodes('''[
@@ -54,6 +54,9 @@ class Beep:
54
54
  def beep(self):
55
55
  return f'{self.path}: beep'
56
56
 
57
+ def genbeep(self):
58
+ yield self.beep()
59
+
57
60
  class Foo:
58
61
 
59
62
  def __init__(self):
@@ -138,6 +141,9 @@ class TeleApi:
138
141
  def getFooBar(self, x, y):
139
142
  return x - y
140
143
 
144
+ def genGetFooBar(self, x, y):
145
+ yield self.getFooBar(x, y)
146
+
141
147
  async def customshare(self):
142
148
  return await CustomShare.anit(self.link, 42)
143
149
 
@@ -160,6 +166,11 @@ class TeleAware(s_telepath.Aware):
160
166
 
161
167
  return self._initBeep(path[0])
162
168
 
169
+ async def getTeleFeats(self):
170
+ return {
171
+ 'aware': 1,
172
+ }
173
+
163
174
  class TeleAuth(s_telepath.Aware):
164
175
 
165
176
  def getTeleApi(self, link, mesg, path):
@@ -632,7 +643,15 @@ class TeleTest(s_t_utils.SynTest):
632
643
  self.len(1, snfo)
633
644
  self.eq(snfo[0].get('items'), {None: 'synapse.tests.test_telepath.TeleApi'})
634
645
 
646
+ self.true(proxy._hasTeleFeat('aware'))
647
+ self.false(proxy._hasTeleFeat('aware', vers=2))
648
+ self.false(proxy._hasTeleFeat('newp'))
649
+
650
+ self.true(proxy._hasTeleMeth('getFooBar'))
651
+ self.false(proxy._hasTeleMeth('getBarBaz'))
652
+
635
653
  self.eq(10, await proxy.getFooBar(20, 10))
654
+ self.eq([10], [m async for m in await proxy.genGetFooBar(20, 10)])
636
655
 
637
656
  # check a custom share works
638
657
  obj = await proxy.customshare()
@@ -674,7 +693,14 @@ class TeleTest(s_t_utils.SynTest):
674
693
 
675
694
  # check that a dynamic share works
676
695
  async with await self.getTestProxy(dmon, 'woke/up') as proxy:
696
+ self.isin('synapse.tests.test_telepath.Beep', proxy._getClasses())
697
+ self.notin('synapse.tests.test_telepath.TeleApi', proxy._getClasses())
677
698
  self.eq('up: beep', await proxy.beep())
699
+ self.eq(['up: beep'], [m async for m in await proxy.genbeep()])
700
+ # Telepath features are a function of the base object, not the result of getTeleApi
701
+ self.true(proxy._hasTeleFeat('aware'))
702
+ self.false(proxy._hasTeleFeat('aware', vers=2))
703
+ self.false(proxy._hasTeleFeat('newp'))
678
704
 
679
705
  async def test_telepath_auth(self):
680
706