synapse 2.172.0__py311-none-any.whl → 2.174.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 (52) hide show
  1. synapse/axon.py +1 -1
  2. synapse/common.py +19 -5
  3. synapse/cortex.py +46 -10
  4. synapse/lib/agenda.py +6 -0
  5. synapse/lib/ast.py +1 -1
  6. synapse/lib/hiveauth.py +81 -4
  7. synapse/lib/layer.py +8 -8
  8. synapse/lib/lmdbslab.py +11 -1
  9. synapse/lib/modelrev.py +17 -1
  10. synapse/lib/modules.py +1 -0
  11. synapse/lib/msgpack.py +25 -3
  12. synapse/lib/nexus.py +26 -22
  13. synapse/lib/schemas.py +31 -0
  14. synapse/lib/stormsvc.py +30 -11
  15. synapse/lib/stormtypes.py +23 -9
  16. synapse/lib/trigger.py +0 -4
  17. synapse/lib/version.py +2 -2
  18. synapse/lib/view.py +2 -0
  19. synapse/models/crypto.py +22 -0
  20. synapse/models/economic.py +23 -2
  21. synapse/models/entity.py +16 -0
  22. synapse/models/files.py +4 -1
  23. synapse/models/geopol.py +3 -0
  24. synapse/models/orgs.py +7 -5
  25. synapse/models/person.py +5 -2
  26. synapse/models/planning.py +5 -0
  27. synapse/tests/test_cortex.py +13 -0
  28. synapse/tests/test_lib_agenda.py +129 -1
  29. synapse/tests/test_lib_ast.py +21 -0
  30. synapse/tests/test_lib_grammar.py +4 -0
  31. synapse/tests/test_lib_hiveauth.py +139 -1
  32. synapse/tests/test_lib_httpapi.py +1 -0
  33. synapse/tests/test_lib_layer.py +67 -13
  34. synapse/tests/test_lib_lmdbslab.py +16 -1
  35. synapse/tests/test_lib_modelrev.py +57 -0
  36. synapse/tests/test_lib_msgpack.py +58 -8
  37. synapse/tests/test_lib_nexus.py +44 -1
  38. synapse/tests/test_lib_storm.py +7 -7
  39. synapse/tests/test_lib_stormsvc.py +128 -51
  40. synapse/tests/test_lib_stormtypes.py +43 -4
  41. synapse/tests/test_lib_trigger.py +23 -4
  42. synapse/tests/test_model_crypto.py +6 -0
  43. synapse/tests/test_model_economic.py +14 -1
  44. synapse/tests/test_model_geopol.py +3 -0
  45. synapse/tests/test_model_orgs.py +8 -2
  46. synapse/tests/test_model_person.py +2 -0
  47. synapse/tools/changelog.py +236 -0
  48. {synapse-2.172.0.dist-info → synapse-2.174.0.dist-info}/METADATA +1 -1
  49. {synapse-2.172.0.dist-info → synapse-2.174.0.dist-info}/RECORD +52 -50
  50. {synapse-2.172.0.dist-info → synapse-2.174.0.dist-info}/WHEEL +1 -1
  51. {synapse-2.172.0.dist-info → synapse-2.174.0.dist-info}/LICENSE +0 -0
  52. {synapse-2.172.0.dist-info → synapse-2.174.0.dist-info}/top_level.txt +0 -0
@@ -2,9 +2,10 @@ import pathlib
2
2
 
3
3
  import synapse.exc as s_exc
4
4
  import synapse.telepath as s_telepath
5
+ import synapse.lib.hiveauth as s_hiveauth
5
6
 
6
7
  import synapse.tests.utils as s_test
7
- from synapse.tests.utils import alist
8
+
8
9
 
9
10
  class AuthTest(s_test.SynTest):
10
11
 
@@ -371,3 +372,140 @@ class AuthTest(s_test.SynTest):
371
372
  await core.auth.allrole.setRules([(True, ('hehe', 'haha'), 'newp')])
372
373
  with self.raises(s_exc.SchemaViolation):
373
374
  await core.auth.allrole.setRules([(True, )])
375
+
376
+ async def test_hive_auth_deepdeny(self):
377
+ async with self.getTestCore() as core:
378
+
379
+ # Create an authgate we can later test against
380
+ fork = await core.callStorm('return( $lib.view.get().fork().iden )')
381
+ await core.callStorm('auth.user.add lowuser')
382
+ await core.callStorm('auth.user.addrule lowuser "!hehe.haha.specific"')
383
+ await core.callStorm('auth.user.addrule lowuser "hehe.something.else"')
384
+ await core.callStorm('auth.user.addrule lowuser "hehe.haha"')
385
+ await core.callStorm('auth.user.addrule lowuser "some.perm"')
386
+ await core.callStorm('auth.role.add ninjas')
387
+ await core.callStorm('auth.role.add clowns')
388
+ await core.callStorm('auth.user.grant --index 0 lowuser ninjas')
389
+ await core.callStorm('auth.user.grant --index 1 lowuser clowns')
390
+ await core.callStorm('auth.role.addrule ninjas some.rule')
391
+ await core.callStorm('auth.role.addrule ninjas --gate $gate another.rule',
392
+ opts={'vars': {'gate': fork}})
393
+
394
+ user = await core.auth.getUserByName('lowuser') # type: s_hiveauth.HiveUser
395
+ self.false(user.allowed(('hehe',)))
396
+ self.false(user.allowed(('hehe',), deepdeny=True))
397
+ self.true(user.allowed(('hehe', 'haha')))
398
+ self.false(user.allowed(('hehe', 'haha'), deepdeny=True))
399
+ self.true(user.allowed(('hehe', 'haha', 'wow')))
400
+ self.true(user.allowed(('hehe', 'haha', 'wow'), deepdeny=True))
401
+ self.true(user.allowed(('some', 'perm')))
402
+ self.true(user.allowed(('some', 'perm'), deepdeny=True))
403
+ self.true(user.allowed(('some', 'perm', 'here')))
404
+ self.true(user.allowed(('some', 'perm', 'here'), deepdeny=True))
405
+
406
+ await core.callStorm('auth.user.delrule lowuser hehe.haha')
407
+ await core.callStorm('auth.user.addrule lowuser hehe')
408
+ self.true(user.allowed(('hehe',)))
409
+ self.false(user.allowed(('hehe',), deepdeny=True))
410
+ self.true(user.allowed(('hehe', 'haha')))
411
+ self.false(user.allowed(('hehe', 'haha'), deepdeny=True))
412
+ self.true(user.allowed(('hehe', 'haha', 'wow')))
413
+ self.true(user.allowed(('hehe', 'haha', 'wow'), deepdeny=True))
414
+ self.false(user.allowed(('weee',)))
415
+ self.false(user.allowed(('weee',), deepdeny=True))
416
+ await core.callStorm('auth.user.delrule lowuser hehe')
417
+
418
+ await core.callStorm('auth.role.addrule all "!hehe.something.else.very.specific"')
419
+ self.false(user.allowed(('hehe',)))
420
+ self.false(user.allowed(('hehe',), deepdeny=True))
421
+
422
+ self.false(user.allowed(('hehe', 'something')))
423
+ self.true(user.allowed(('hehe', 'something', 'else')))
424
+ self.true(user.allowed(('hehe', 'something', 'else', 'very')))
425
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific')))
426
+
427
+ self.false(user.allowed(('hehe', 'something')))
428
+ self.false(user.allowed(('hehe', 'something', 'else'), deepdeny=True))
429
+ self.false(user.allowed(('hehe', 'something', 'else', 'very'), deepdeny=True))
430
+
431
+ # There is NOT a deeper permission here, even though there is a deny rule on the role.
432
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), deepdeny=True))
433
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific', 'more')))
434
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific', 'more'), deepdeny=True))
435
+ await core.callStorm('auth.role.delrule all "!hehe.something.else.very.specific"')
436
+
437
+ await core.callStorm('auth.role.addrule --gate $gate all "beep.boop"',
438
+ opts={'vars': {'gate': fork}})
439
+ await core.callStorm('auth.role.addrule --gate $gate all "!hehe.something.else.very.specific"',
440
+ opts={'vars': {'gate': fork}})
441
+ self.false(user.allowed(('hehe',), gateiden=fork))
442
+ self.false(user.allowed(('hehe', 'something'), gateiden=fork))
443
+ self.true(user.allowed(('hehe', 'something', 'else'), gateiden=fork))
444
+ self.true(user.allowed(('hehe', 'something', 'else', 'very'), gateiden=fork))
445
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), gateiden=fork))
446
+ self.false(user.allowed(('hehe',), gateiden=fork, deepdeny=True))
447
+ self.false(user.allowed(('hehe', 'something'), gateiden=fork, deepdeny=True))
448
+ self.false(user.allowed(('hehe', 'something', 'else'), gateiden=fork, deepdeny=True))
449
+ self.false(user.allowed(('hehe', 'something', 'else', 'very'), gateiden=fork, deepdeny=True))
450
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), gateiden=fork, deepdeny=True))
451
+ await core.callStorm('auth.role.delrule --gate $gate all "!hehe.something.else.very.specific"',
452
+ opts={'vars': {'gate': fork}})
453
+ await core.callStorm('auth.role.delrule --gate $gate all "beep.boop"',
454
+ opts={'vars': {'gate': fork}})
455
+
456
+ await core.callStorm('auth.user.addrule --gate $gate lowuser "beep.boop"',
457
+ opts={'vars': {'gate': fork}})
458
+ await core.callStorm('auth.user.addrule --gate $gate lowuser "!hehe.something.else.very.specific"',
459
+ opts={'vars': {'gate': fork}})
460
+ self.false(user.allowed(('hehe',), gateiden=fork))
461
+ self.false(user.allowed(('hehe', 'something'), gateiden=fork))
462
+ self.true(user.allowed(('hehe', 'something', 'else'), gateiden=fork))
463
+ self.true(user.allowed(('hehe', 'something', 'else', 'very'), gateiden=fork))
464
+ self.false(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), gateiden=fork))
465
+ self.false(user.allowed(('hehe',), gateiden=fork, deepdeny=True))
466
+ self.false(user.allowed(('hehe', 'something'), gateiden=fork, deepdeny=True))
467
+ self.false(user.allowed(('hehe', 'something', 'else'), gateiden=fork, deepdeny=True))
468
+ self.false(user.allowed(('hehe', 'something', 'else', 'very'), gateiden=fork, deepdeny=True))
469
+ # This differs from earlier check as the dd is false; but the user authgate deny is earlier in precedence
470
+ # than the user specific allow
471
+ self.false(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), gateiden=fork, deepdeny=True))
472
+
473
+ await core.callStorm('auth.user.delrule --gate $gate lowuser "!hehe.something.else.very.specific"',
474
+ opts={'vars': {'gate': fork}})
475
+ await core.callStorm('auth.user.delrule --gate $gate lowuser "beep.boop"',
476
+ opts={'vars': {'gate': fork}})
477
+
478
+ await core.callStorm('auth.user.mod --admin (true) lowuser --gate $gate', opts={'vars': {'gate': fork}})
479
+ self.true(user.allowed(('hehe',), gateiden=fork))
480
+ self.true(user.allowed(('hehe', 'something'), gateiden=fork))
481
+ self.true(user.allowed(('hehe', 'something', 'else'), gateiden=fork))
482
+ self.true(user.allowed(('hehe', 'something', 'else', 'very'), gateiden=fork))
483
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), gateiden=fork))
484
+
485
+ self.true(user.allowed(('hehe',), gateiden=fork, deepdeny=True))
486
+ self.true(user.allowed(('hehe', 'something'), gateiden=fork, deepdeny=True))
487
+ self.true(user.allowed(('hehe', 'something', 'else'), gateiden=fork, deepdeny=True))
488
+ self.true(user.allowed(('hehe', 'something', 'else', 'very'), gateiden=fork, deepdeny=True))
489
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), gateiden=fork, deepdeny=True))
490
+
491
+ await core.callStorm('auth.user.mod --admin (false) lowuser --gate $gate', opts={'vars': {'gate': fork}})
492
+
493
+ await core.callStorm('auth.user.mod --admin (true) lowuser')
494
+ self.true(user.allowed(('hehe',)))
495
+ self.true(user.allowed(('hehe', 'something')))
496
+ self.true(user.allowed(('hehe', 'something', 'else')))
497
+ self.true(user.allowed(('hehe', 'something', 'else', 'very')))
498
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific')))
499
+ self.true(user.allowed(('hehe',), deepdeny=True))
500
+ self.true(user.allowed(('hehe', 'something')))
501
+ self.true(user.allowed(('hehe', 'something', 'else'), deepdeny=True))
502
+ self.true(user.allowed(('hehe', 'something', 'else', 'very'), deepdeny=True))
503
+ self.true(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), deepdeny=True))
504
+ await core.callStorm('auth.user.mod --admin (false) lowuser')
505
+
506
+ await core.callStorm('auth.user.mod --locked (true) lowuser')
507
+ self.false(user.allowed(('hehe',), deepdeny=True))
508
+ self.false(user.allowed(('hehe', 'something'), deepdeny=True))
509
+ self.false(user.allowed(('hehe', 'something', 'else'), deepdeny=True))
510
+ self.false(user.allowed(('hehe', 'something', 'else', 'very'), deepdeny=True))
511
+ self.false(user.allowed(('hehe', 'something', 'else', 'very', 'specific'), deepdeny=True))
@@ -916,6 +916,7 @@ class HttpApiTest(s_tests.SynTest):
916
916
  await core.callStorm('$c = $lib.cron.get($cron) $c.set("doc", "some docs")', opts=opts)
917
917
  await core.callStorm('cron.del $cron', opts=opts)
918
918
 
919
+ await core.addStormPkg(spkg)
919
920
  await core.addStormPkg(spkg)
920
921
  await core.addStormSvc(ssvc)
921
922
 
@@ -1920,6 +1920,19 @@ class LayerTest(s_t_utils.SynTest):
1920
1920
  async def __anit__(self, dirn=None, size=1, cell=None):
1921
1921
  await super().__anit__(dirn=dirn, size=size, cell=cell)
1922
1922
 
1923
+ seen = set()
1924
+ def confirm(self, perm, default=None, gateiden=None):
1925
+ seen.add(perm)
1926
+ return True
1927
+
1928
+ def confirmPropSet(self, user, prop, layriden):
1929
+ seen.add(prop.setperms[0])
1930
+ seen.add(prop.setperms[1])
1931
+
1932
+ def confirmPropDel(self, user, prop, layriden):
1933
+ seen.add(prop.delperms[0])
1934
+ seen.add(prop.delperms[1])
1935
+
1923
1936
  with mock.patch('synapse.lib.spooled.Dict', Dict):
1924
1937
  async with self.getTestCore() as core:
1925
1938
 
@@ -1952,19 +1965,7 @@ class LayerTest(s_t_utils.SynTest):
1952
1965
 
1953
1966
  parent = core.view.layers[0]
1954
1967
 
1955
- seen = set()
1956
- def confirm(self, perm, default=None, gateiden=None):
1957
- seen.add(perm)
1958
- return True
1959
-
1960
- def confirmPropSet(self, user, prop, layriden):
1961
- seen.add(prop.setperms[0])
1962
- seen.add(prop.setperms[1])
1963
-
1964
- def confirmPropDel(self, user, prop, layriden):
1965
- seen.add(prop.delperms[0])
1966
- seen.add(prop.delperms[1])
1967
-
1968
+ seen.clear()
1968
1969
  with mock.patch.object(s_hiveauth.HiveUser, 'confirm', confirm):
1969
1970
  with mock.patch.object(s_cortex.Cortex, 'confirmPropSet', confirmPropSet):
1970
1971
  with mock.patch.object(s_cortex.Cortex, 'confirmPropDel', confirmPropDel):
@@ -2075,6 +2076,59 @@ class LayerTest(s_t_utils.SynTest):
2075
2076
  ('node', 'tag', 'del', 'foo', 'bar'),
2076
2077
  })
2077
2078
 
2079
+ async with self.getTestCore() as core:
2080
+
2081
+ user = await core.auth.addUser('blackout@vertex.link')
2082
+ await user.addRule((False, ('node', 'edge', 'add', 'haha')))
2083
+ await user.addRule((False, ('node', 'data', 'set', 'hehe')))
2084
+ await user.addRule((True, ('node',)))
2085
+
2086
+ viewiden = await core.callStorm('''
2087
+ $lyr = $lib.layer.add()
2088
+ $view = $lib.view.add(($lyr.iden,))
2089
+ return($view.iden)
2090
+ ''')
2091
+
2092
+ layr = core.views[viewiden].layers[0]
2093
+
2094
+ opts = {'view': viewiden}
2095
+
2096
+ await core.nodes('[ test:str=bar +#foo.bar ]', opts=opts)
2097
+
2098
+ await core.nodes('''
2099
+ [ test:str=foo
2100
+ :hehe=bar
2101
+ +#foo.bar.baz
2102
+ <(refs)+ { test:str=bar }
2103
+ ]
2104
+ $node.data.set(foo, bar)
2105
+ ''', opts=opts)
2106
+
2107
+ parent = core.view.layers[0]
2108
+
2109
+ seen.clear()
2110
+ with mock.patch.object(s_hiveauth.HiveUser, 'confirm', confirm):
2111
+ with mock.patch.object(s_cortex.Cortex, 'confirmPropSet', confirmPropSet):
2112
+ with mock.patch.object(s_cortex.Cortex, 'confirmPropDel', confirmPropDel):
2113
+ await layr.confirmLayerEditPerms(user, parent.iden)
2114
+
2115
+ self.eq(seen, {
2116
+ # node.edge.add.* and node.data.set.* because of the deny rules
2117
+ ('node', 'edge', 'add', 'refs'),
2118
+ ('node', 'data', 'set', 'foo'),
2119
+ })
2120
+
2121
+ await user.delRule((False, ('node', 'edge', 'add', 'haha')))
2122
+ await user.delRule((False, ('node', 'data', 'set', 'hehe')))
2123
+
2124
+ seen.clear()
2125
+ with mock.patch.object(s_hiveauth.HiveUser, 'confirm', confirm):
2126
+ with mock.patch.object(s_cortex.Cortex, 'confirmPropSet', confirmPropSet):
2127
+ with mock.patch.object(s_cortex.Cortex, 'confirmPropDel', confirmPropDel):
2128
+ await layr.confirmLayerEditPerms(user, parent.iden)
2129
+
2130
+ self.eq(seen, set())
2131
+
2078
2132
  async def test_layer_v9(self):
2079
2133
  async with self.getRegrCore('2.101.1-hugenum-indxprec') as core:
2080
2134
 
@@ -1,4 +1,5 @@
1
1
  import os
2
+ import json
2
3
  import asyncio
3
4
  import pathlib
4
5
  import multiprocessing
@@ -350,7 +351,7 @@ class LmdbSlabTest(s_t_utils.SynTest):
350
351
  with self.getTestDir() as dirn, patch('synapse.lib.lmdbslab.Slab.WARN_COMMIT_TIME_MS', 1), \
351
352
  patch('synapse.common.now', self.simplenow):
352
353
  path = os.path.join(dirn, 'test.lmdb')
353
- with self.getAsyncLoggerStream('synapse.lib.lmdbslab', 'Commit with') as stream:
354
+ with self.getStructuredAsyncLoggerStream('synapse.lib.lmdbslab', 'Commit with') as stream:
354
355
  async with await s_lmdbslab.Slab.anit(path, map_size=100000) as slab:
355
356
  foo = slab.initdb('foo', dupsort=True)
356
357
  byts = b'\x00' * 256
@@ -358,6 +359,20 @@ class LmdbSlabTest(s_t_utils.SynTest):
358
359
  slab.put(b'\xff\xff\xff\xff' + s_common.guid(i).encode('utf8'), byts, db=foo)
359
360
  self.true(await stream.wait(timeout=1))
360
361
 
362
+ data = stream.getvalue()
363
+ msgs = [json.loads(m) for m in data.split('\\n') if m]
364
+ self.gt(len(msgs), 0)
365
+ self.nn(msgs[0].get('delta'))
366
+ self.nn(msgs[0].get('path'))
367
+ self.nn(msgs[0].get('xactopslen'))
368
+ self.sorteq([
369
+ 'vm.swappiness',
370
+ 'vm.dirty_expire_centisecs',
371
+ 'vm.dirty_writeback_centisecs',
372
+ 'vm.dirty_background_ratio',
373
+ 'vm.dirty_ratio',
374
+ ], msgs[0].get('sysctls', {}).keys())
375
+
361
376
  async def test_lmdbslab_max_replay(self):
362
377
  with self.getTestDir() as dirn:
363
378
  path = os.path.join(dirn, 'test.lmdb')
@@ -473,3 +473,60 @@ class ModelRevTest(s_tests.SynTest):
473
473
  nodes = await core.nodes('it:mitre:attack:technique=T0100')
474
474
  self.len(1, nodes)
475
475
  self.eq('lockpicking', nodes[0].get('name'))
476
+
477
+ async def test_modelrev_0_2_25(self):
478
+ async with self.getRegrCore('model-0.2.25') as core:
479
+
480
+ self.len(1, await core.nodes('econ:currency=usd'))
481
+
482
+ nodes = await core.nodes('ou:conference')
483
+ self.len(3, nodes)
484
+ names = [n.get('name') for n in nodes]
485
+ self.sorteq(names, (
486
+ 'sleuthcon',
487
+ 'defcon',
488
+ 'recon',
489
+ ))
490
+
491
+ namess = [n.get('names') for n in nodes]
492
+ self.sorteq(namess, (
493
+ ('defcon 2024',),
494
+ ('recon 2024 conference',),
495
+ ('sleuthcon 2024',),
496
+ ))
497
+
498
+ connames = (
499
+ 'sleuthcon', 'sleuthcon 2024',
500
+ 'defcon', 'defcon 2024',
501
+ 'recon', 'recon 2024 conference',
502
+ )
503
+
504
+ nodes = await core.nodes('entity:name')
505
+ self.len(6, nodes)
506
+ names = [n.ndef[1] for n in nodes]
507
+ self.sorteq(names, connames)
508
+
509
+ nodes = await core.nodes('ou:conference -> entity:name')
510
+ self.len(6, nodes)
511
+ names = [n.ndef[1] for n in nodes]
512
+ self.sorteq(names, connames)
513
+
514
+ positions = (
515
+ 'president of the united states',
516
+ 'vice president of the united states',
517
+ )
518
+
519
+ nodes = await core.nodes('ou:position')
520
+ self.len(2, nodes)
521
+ titles = [n.get('title') for n in nodes]
522
+ self.sorteq(titles, positions)
523
+
524
+ nodes = await core.nodes('ou:jobtitle')
525
+ self.len(2, nodes)
526
+ titles = [n.ndef[1] for n in nodes]
527
+ self.sorteq(titles, positions)
528
+
529
+ nodes = await core.nodes('ou:position -> ou:jobtitle')
530
+ self.len(2, nodes)
531
+ titles = [n.ndef[1] for n in nodes]
532
+ self.sorteq(titles, positions)
@@ -17,6 +17,50 @@ class MsgPackTest(s_t_utils.SynTest):
17
17
  byts = s_msgpack._fallback_en(('hehe', 10))
18
18
  self.eq(byts, b'\x92\xa4hehe\n')
19
19
 
20
+ def test_msgpack_ext(self):
21
+ valu = 0xffffffffffffffffffffffffffffffff
22
+ item = ('woot', valu)
23
+ byts = s_msgpack.en(item)
24
+ self.eq(item, s_msgpack.un(byts))
25
+ self.eq(byts, s_msgpack._fallback_en(item))
26
+
27
+ unpk = s_msgpack.Unpk()
28
+ self.eq(((24, item),), unpk.feed(byts))
29
+ with self.raises(s_exc.SynErr):
30
+ s_msgpack._ext_un(99, b'red baloons')
31
+
32
+ # Negative number support as well.
33
+ negvalu = -1 * valu
34
+ negitem = ('woot', negvalu)
35
+ negbytes = s_msgpack.en(negitem)
36
+ self.eq(negitem, s_msgpack.un(negbytes))
37
+ self.eq(negbytes, s_msgpack._fallback_en(negitem))
38
+
39
+ # Check across item.bit_length() boundaries
40
+ v = 0xffffffffffffffff
41
+ for i in (1, 0xffffffffffffffff + 1, 0xffffffffffffffff + 2):
42
+ nv = v + i
43
+ buf = s_msgpack.en(nv)
44
+ self.eq(nv, s_msgpack.un(buf))
45
+ v = -0x8000000000000000
46
+ for i in (1, 0x7fffffffffffffff, 0x7fffffffffffffff + 1):
47
+ nv = v - i
48
+ buf = s_msgpack.en(nv)
49
+ self.eq(nv, s_msgpack.un(buf))
50
+
51
+ # We can also support values > 128 bits in width
52
+ valu = 0xfffffffffffffffffffffffffffffffff
53
+ item = ('woot', valu)
54
+ byts = s_msgpack.en(item)
55
+ self.eq(item, s_msgpack.un(byts))
56
+ self.eq(byts, s_msgpack._fallback_en(item))
57
+
58
+ negvalu = -1 * valu
59
+ negitem = ('woot', negvalu)
60
+ negbytes = s_msgpack.en(negitem)
61
+ self.eq(negitem, s_msgpack.un(negbytes))
62
+ self.eq(negbytes, s_msgpack._fallback_en(negitem))
63
+
20
64
  def test_msgpack_un(self):
21
65
  item = s_msgpack.un(b'\x92\xa4hehe\n')
22
66
  self.eq(item, ('hehe', 10))
@@ -106,8 +150,8 @@ class MsgPackTest(s_t_utils.SynTest):
106
150
  self.checkLoadfile(s_msgpack._fallback_en)
107
151
 
108
152
  def checkTypes(self, enfunc):
109
- # This is a future-proofing test for msgpack to ensure that
110
- buf = b'\x92\xa4hehe\x85\xa3str\xa41234\xa3int\xcd\x04\xd2\xa5float\xcb@(\xae\x14z\xe1G\xae\xa3bin\xc4\x041234\xa9realworld\xac\xc7\x8b\xef\xbf\xbd\xed\xa1\x82\xef\xbf\xbd\x12'
153
+ # This is a future-proofing test for msgpack to ensure that we have stability with msgpack-python
154
+ buf = b'\x92\xa4hehe\x8b\xa3str\xa41234\xa3int\xcd\x04\xd2\xa5float\xcb@(\xae\x14z\xe1G\xae\xa3bin\xc4\x041234\xa9realworld\xac\xc7\x8b\xef\xbf\xbd\xed\xa1\x82\xef\xbf\xbd\x12\xabalmostlarge\xcf\xff\xff\xff\xff\xff\xff\xff\xfe\xb1extlargeThreshold\xcf\xff\xff\xff\xff\xff\xff\xff\xff\xa8extlarge\xc7\t\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\xabalmostsmall\xd3\x80\x00\x00\x00\x00\x00\x00\x01\xb4almostsmallThreshold\xd3\x80\x00\x00\x00\x00\x00\x00\x00\xa8extsmall\xc7\t\x01\xff\x7f\xff\xff\xff\xff\xff\xff\xff'
111
155
  struct = (
112
156
  'hehe',
113
157
  {
@@ -115,7 +159,15 @@ class MsgPackTest(s_t_utils.SynTest):
115
159
  'int': 1234,
116
160
  'float': 12.34,
117
161
  'bin': b'1234',
118
- 'realworld': '\u01cb\ufffd\ud842\ufffd\u0012'
162
+ 'realworld': '\u01cb\ufffd\ud842\ufffd\u0012',
163
+ 'almostlarge': 0xffffffffffffffff - 1,
164
+ 'extlargeThreshold': 0xffffffffffffffff,
165
+ # extlarge is handled with our custom extension type
166
+ 'extlarge': 0xffffffffffffffff + 1,
167
+ 'almostsmall': -0x8000000000000000 + 1,
168
+ 'almostsmallThreshold': -0x8000000000000000,
169
+ # extsmall is handled with our custom extension type
170
+ 'extsmall': -0x8000000000000000 - 1,
119
171
  }
120
172
  )
121
173
  unode = s_msgpack.un(buf)
@@ -135,7 +187,7 @@ class MsgPackTest(s_t_utils.SynTest):
135
187
  unpk = s_msgpack.Unpk()
136
188
  objs = unpk.feed(buf)
137
189
  self.len(1, objs)
138
- self.eq(objs[0], (71, struct))
190
+ self.eq(objs[0], (212, struct))
139
191
 
140
192
  # Generic isok helper
141
193
  self.true(s_msgpack.isok(1))
@@ -148,6 +200,8 @@ class MsgPackTest(s_t_utils.SynTest):
148
200
  self.true(s_msgpack.isok([1]))
149
201
  self.true(s_msgpack.isok((1,)))
150
202
  self.true(s_msgpack.isok({1: 1}))
203
+ self.true(s_msgpack.isok(0xffffffffffffffff + 1))
204
+ self.true(s_msgpack.isok(-0x8000000000000000 - 1))
151
205
  # unpackage types
152
206
  self.false(s_msgpack.isok({1, 2})) # set
153
207
  self.false(s_msgpack.isok(print)) # function
@@ -198,10 +252,6 @@ class MsgPackTest(s_t_utils.SynTest):
198
252
  self.raises(s_exc.NotMsgpackSafe, enfunc, {1, 2})
199
253
  self.raises(s_exc.NotMsgpackSafe, enfunc, Exception())
200
254
  self.raises(s_exc.NotMsgpackSafe, enfunc, s_msgpack.en)
201
- # too long
202
- with self.raises(s_exc.NotMsgpackSafe) as cm:
203
- enfunc({'longlong': 45234928034723904723906})
204
- self.isin('OverflowError', cm.exception.get('mesg'))
205
255
 
206
256
  def test_msgpack_bad_types(self):
207
257
  self.checkBadTypes(s_msgpack.en)
@@ -3,7 +3,6 @@ from unittest import mock
3
3
 
4
4
  import synapse.exc as s_exc
5
5
  import synapse.common as s_common
6
- import synapse.cortex as s_cortex
7
6
 
8
7
  import synapse.lib.cell as s_cell
9
8
  import synapse.lib.nexus as s_nexus
@@ -302,3 +301,47 @@ class NexusTest(s_t_utils.SynTest):
302
301
  with self.raises(s_exc.IsReadOnly):
303
302
  await cell01.sync()
304
303
  self.isin(s_nexus.leaderversion, cell01.nexsroot.writeholds)
304
+
305
+ async def test_mirror_nexus_loop_failure(self):
306
+ with self.getTestDir() as dirn:
307
+
308
+ s_common.yamlsave({'nexslog:en': True}, dirn, 'cell.yaml')
309
+ async with await s_cell.Cell.anit(dirn=dirn) as cell00:
310
+
311
+ await cell00.runBackup(name='cell01')
312
+
313
+ path = s_common.genpath(dirn, 'backups', 'cell01')
314
+
315
+ conf = s_common.yamlload(path, 'cell.yaml')
316
+ conf['mirror'] = f'cell://{dirn}'
317
+ s_common.yamlsave(conf, path, 'cell.yaml')
318
+
319
+ seen = False
320
+ restarted = False
321
+ orig = s_nexus.NexsRoot.delWriteHold
322
+
323
+ # Patch NexsRoot.delWriteHold so we can cause an exception in
324
+ # the setup part of the nexus loop (NexsRoot.runMirrorLoop). The
325
+ # exception should only happen one time so we can check that the
326
+ # proxy and the nexus loop were both restarted
327
+ async def delWriteHold(self, reason):
328
+ nonlocal seen
329
+ nonlocal restarted
330
+ if not seen:
331
+ seen = True
332
+ raise Exception('Knock over the nexus setup.')
333
+
334
+ restarted = True
335
+ return await orig(self, reason)
336
+
337
+ with mock.patch('synapse.lib.nexus.NexsRoot.delWriteHold', delWriteHold):
338
+ with self.getLoggerStream('synapse.lib.nexus') as stream:
339
+ async with await s_cell.Cell.anit(dirn=path) as cell01:
340
+ await cell01.sync()
341
+
342
+ stream.seek(0)
343
+ data = stream.read()
344
+ mesg = 'Unknown error during mirror loop startup: Knock over the nexus setup.'
345
+ self.isin(mesg, data)
346
+
347
+ self.true(restarted)
@@ -2283,9 +2283,9 @@ class StormTest(s_t_utils.SynTest):
2283
2283
  msgs = await core.stormlist(f'pkg.load --ssl-noverify https://127.0.0.1:{port}/api/v1/pkgtest/notok')
2284
2284
  self.stormIsInWarn('pkg.load got JSON error: FooBar', msgs)
2285
2285
 
2286
- replay = s_common.envbool('SYNDEV_NEXUS_REPLAY')
2287
- nevents = 4 if replay else 2
2288
- waiter = core.waiter(nevents, 'core:pkg:onload:complete')
2286
+ # onload will on fire once. all other pkg.load events will effectively bounce
2287
+ # because the pkg hasn't changed so no loading occurs
2288
+ waiter = core.waiter(1, 'core:pkg:onload:complete')
2289
2289
 
2290
2290
  with self.getAsyncLoggerStream('synapse.cortex') as stream:
2291
2291
  msgs = await core.stormlist(f'pkg.load --ssl-noverify https://127.0.0.1:{port}/api/v1/pkgtest/yep')
@@ -2301,10 +2301,10 @@ class StormTest(s_t_utils.SynTest):
2301
2301
  self.isin("No var with name: newp", buf)
2302
2302
  self.len(1, await core.nodes(f'ps:contact={cont}'))
2303
2303
 
2304
- evnts = await waiter.wait(timeout=2)
2305
- exp = []
2306
- for _ in range(nevents):
2307
- exp.append(('core:pkg:onload:complete', {'pkg': 'testload'}))
2304
+ evnts = await waiter.wait(timeout=4)
2305
+ exp = [
2306
+ ('core:pkg:onload:complete', {'pkg': 'testload'})
2307
+ ]
2308
2308
  self.eq(exp, evnts)
2309
2309
 
2310
2310
  async def test_storm_tree(self):