synapse 2.196.0__py311-none-any.whl → 2.198.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 (61) hide show
  1. synapse/axon.py +3 -0
  2. synapse/common.py +3 -0
  3. synapse/cortex.py +13 -11
  4. synapse/cryotank.py +2 -2
  5. synapse/lib/aha.py +3 -0
  6. synapse/lib/ast.py +277 -165
  7. synapse/lib/auth.py +39 -11
  8. synapse/lib/cell.py +24 -6
  9. synapse/lib/config.py +3 -3
  10. synapse/lib/hive.py +2 -1
  11. synapse/lib/hiveauth.py +10 -1
  12. synapse/lib/jsonstor.py +6 -5
  13. synapse/lib/layer.py +6 -5
  14. synapse/lib/multislabseqn.py +2 -2
  15. synapse/lib/node.py +10 -4
  16. synapse/lib/parser.py +46 -21
  17. synapse/lib/schemas.py +491 -1
  18. synapse/lib/snap.py +68 -26
  19. synapse/lib/storm.lark +13 -11
  20. synapse/lib/storm.py +13 -395
  21. synapse/lib/storm_format.py +3 -2
  22. synapse/lib/stormlib/graph.py +0 -61
  23. synapse/lib/stormlib/index.py +52 -0
  24. synapse/lib/stormtypes.py +16 -5
  25. synapse/lib/task.py +13 -2
  26. synapse/lib/urlhelp.py +1 -1
  27. synapse/lib/version.py +2 -2
  28. synapse/models/doc.py +62 -0
  29. synapse/models/infotech.py +18 -0
  30. synapse/models/orgs.py +6 -4
  31. synapse/models/risk.py +9 -0
  32. synapse/models/syn.py +18 -2
  33. synapse/tests/files/stormpkg/badendpoints.yaml +7 -0
  34. synapse/tests/files/stormpkg/testpkg.yaml +8 -0
  35. synapse/tests/test_cortex.py +108 -0
  36. synapse/tests/test_datamodel.py +7 -0
  37. synapse/tests/test_lib_aha.py +12 -42
  38. synapse/tests/test_lib_ast.py +57 -0
  39. synapse/tests/test_lib_auth.py +143 -2
  40. synapse/tests/test_lib_boss.py +15 -6
  41. synapse/tests/test_lib_cell.py +43 -0
  42. synapse/tests/test_lib_grammar.py +54 -2
  43. synapse/tests/test_lib_lmdbslab.py +24 -0
  44. synapse/tests/test_lib_storm.py +20 -0
  45. synapse/tests/test_lib_stormlib_index.py +39 -0
  46. synapse/tests/test_lib_stormlib_macro.py +3 -3
  47. synapse/tests/test_lib_stormtypes.py +14 -2
  48. synapse/tests/test_lib_task.py +31 -13
  49. synapse/tests/test_model_doc.py +38 -0
  50. synapse/tests/test_model_infotech.py +13 -0
  51. synapse/tests/test_model_orgs.py +7 -0
  52. synapse/tests/test_model_risk.py +6 -0
  53. synapse/tests/test_model_syn.py +58 -0
  54. synapse/tests/test_tools_genpkg.py +10 -0
  55. synapse/tools/genpkg.py +2 -2
  56. synapse/tools/hive/load.py +1 -0
  57. {synapse-2.196.0.dist-info → synapse-2.198.0.dist-info}/METADATA +1 -1
  58. {synapse-2.196.0.dist-info → synapse-2.198.0.dist-info}/RECORD +61 -58
  59. {synapse-2.196.0.dist-info → synapse-2.198.0.dist-info}/LICENSE +0 -0
  60. {synapse-2.196.0.dist-info → synapse-2.198.0.dist-info}/WHEEL +0 -0
  61. {synapse-2.196.0.dist-info → synapse-2.198.0.dist-info}/top_level.txt +0 -0
@@ -1,9 +1,15 @@
1
1
  import string
2
2
  import pathlib
3
3
 
4
+ from unittest import mock
5
+
4
6
  import synapse.exc as s_exc
7
+ import synapse.common as s_common
5
8
  import synapse.telepath as s_telepath
6
- import synapse.lib.hiveauth as s_hiveauth
9
+
10
+ import synapse.lib.auth as s_auth
11
+ import synapse.lib.cell as s_cell
12
+ import synapse.lib.lmdbslab as s_lmdbslab
7
13
 
8
14
  import synapse.tests.utils as s_test
9
15
 
@@ -426,6 +432,126 @@ class AuthTest(s_test.SynTest):
426
432
  with self.raises(s_exc.SchemaViolation):
427
433
  await core.auth.allrole.setRules([(True, )])
428
434
 
435
+ async def test_auth_archived_locked_interaction(self):
436
+
437
+ # Check that we can't unlock an archived user
438
+ async with self.getTestCore() as core:
439
+ lowuser = await core.addUser('lowuser')
440
+ useriden = lowuser.get('iden')
441
+
442
+ await core.setUserArchived(useriden, True)
443
+
444
+ udef = await core.getUserDef(useriden)
445
+ self.true(udef.get('archived'))
446
+ self.true(udef.get('locked'))
447
+
448
+ # Unlocking an archived user is invalid
449
+ with self.raises(s_exc.BadArg) as exc:
450
+ await core.setUserLocked(useriden, False)
451
+ self.eq(exc.exception.get('mesg'), 'Cannot unlock archived user.')
452
+ self.eq(exc.exception.get('user'), useriden)
453
+ self.eq(exc.exception.get('username'), 'lowuser')
454
+
455
+ # Check our cell migration that locks archived users
456
+ async with self.getRegrCore('unlocked-archived-users') as core:
457
+ for ii in range(10):
458
+ user = await core.getUserDefByName(f'lowuser{ii:02d}')
459
+ self.nn(user)
460
+ self.true(user.get('archived'))
461
+ self.true(user.get('locked'))
462
+
463
+ # Check behavior of upgraded mirrors and non-upgraded leader
464
+ async with self.getTestAha() as aha:
465
+
466
+ with self.getTestDir() as dirn:
467
+ path00 = s_common.gendir(dirn, 'cell00')
468
+ path01 = s_common.gendir(dirn, 'cell01')
469
+
470
+ with mock.patch('synapse.lib.cell.NEXUS_VERSION', (2, 177)):
471
+ async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
472
+ lowuser = await cell00.addUser('lowuser')
473
+ useriden = lowuser.get('iden')
474
+ await cell00.setUserArchived(useriden, True)
475
+
476
+ with mock.patch('synapse.lib.cell.NEXUS_VERSION', (2, 198)):
477
+ async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
478
+ await cell01.sync()
479
+ udef = await cell01.getUserDef(useriden)
480
+ self.true(udef.get('locked'))
481
+ self.true(udef.get('archived'))
482
+
483
+ # Simulate a call to cell00.setUserLocked(useriden, False) to bypass
484
+ # the check in cell00.auth.setUserInfo()
485
+ await cell00.auth._push('user:info', useriden, 'locked', False)
486
+ await cell01.sync()
487
+
488
+ udef00 = await cell00.getUserDef(useriden)
489
+ self.true(udef00.get('archived'))
490
+ self.false(udef00.get('locked'))
491
+
492
+ udef01 = await cell01.getUserDef(useriden)
493
+ self.true(udef01.get('archived'))
494
+ self.false(udef01.get('locked'))
495
+
496
+ # Check that we don't blowup/schism if an upgraded mirror is behind a leader with a pending
497
+ # user:info event that unlocks an archived user
498
+ async with self.getTestAha() as aha:
499
+
500
+ with self.getTestDir() as dirn:
501
+ path00 = s_common.gendir(dirn, 'cell00')
502
+ path01 = s_common.gendir(dirn, 'cell01')
503
+
504
+ async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
505
+ lowuser = await cell00.addUser('lowuser')
506
+ useriden = lowuser.get('iden')
507
+ await cell00.setUserLocked(useriden, True)
508
+
509
+ async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
510
+ await cell01.sync()
511
+ udef = await cell01.getUserDef(useriden)
512
+ self.true(udef.get('locked'))
513
+ self.false(udef.get('archived'))
514
+
515
+ # Set user locked while cell01 is offline so it will get the edit when it comes
516
+ # back
517
+ await cell00.setUserLocked(useriden, False)
518
+ await cell00.sync()
519
+
520
+ # Edit the slabs on both cells directly to archive the user
521
+ lmdb00 = s_common.genpath(path00, 'slabs', 'cell.lmdb')
522
+ lmdb01 = s_common.genpath(path01, 'slabs', 'cell.lmdb')
523
+
524
+ slab00 = await s_lmdbslab.Slab.anit(lmdb00, map_size=s_cell.SLAB_MAP_SIZE)
525
+ slab01 = await s_lmdbslab.Slab.anit(lmdb01, map_size=s_cell.SLAB_MAP_SIZE)
526
+
527
+ # Simulate the cell migration which locks archived users
528
+ for slab in (slab00, slab01):
529
+ authkv = slab.getSafeKeyVal('auth')
530
+ userkv = authkv.getSubKeyVal('user:info:')
531
+
532
+ info = userkv.get(useriden)
533
+ info['archived'] = True
534
+ info['locked'] = True
535
+ userkv.set(useriden, info)
536
+
537
+ await slab00.fini()
538
+ await slab01.fini()
539
+
540
+ # Spin the cells back up and wait for the edit to sync to cell01
541
+ async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
542
+ udef = await cell00.getUserDef(useriden)
543
+ self.true(udef.get('archived'))
544
+ self.true(udef.get('locked'))
545
+
546
+ async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
547
+ await cell01.sync()
548
+ udef = await cell01.getUserDef(useriden)
549
+ self.true(udef.get('archived'))
550
+ self.true(udef.get('locked'))
551
+
552
+ self.ge(cell00.nexsvers, (2, 198))
553
+ self.ge(cell01.nexsvers, (2, 198))
554
+
429
555
  async def test_auth_password_policy(self):
430
556
  policy = {
431
557
  'complexity': {
@@ -446,6 +572,21 @@ class AuthTest(s_test.SynTest):
446
572
  pass3 = 'ZXN-pyv7ber-kzq2kgh'
447
573
 
448
574
  conf = {'auth:passwd:policy': policy}
575
+ async with self.getTestCore(conf=conf) as core:
576
+
577
+ user = await core.auth.addUser('blackout@vertex.link')
578
+
579
+ self.none(user.info.get('policy:previous'))
580
+ await user.setPasswd(pass1, nexs=False)
581
+ await user.setPasswd(pass2, nexs=False)
582
+ await user.setPasswd(pass3, nexs=False)
583
+ self.len(2, user.info.get('policy:previous'))
584
+
585
+ await user.tryPasswd('newp')
586
+ self.eq(1, user.info.get('policy:attempts'))
587
+ await user.setLocked(False, logged=False)
588
+ self.eq(0, user.info.get('policy:attempts'))
589
+
449
590
  async with self.getTestCore(conf=conf) as core:
450
591
  auth = core.auth
451
592
  self.nn(auth.policy)
@@ -708,7 +849,7 @@ class AuthTest(s_test.SynTest):
708
849
  await core.callStorm('auth.role.addrule ninjas --gate $gate another.rule',
709
850
  opts={'vars': {'gate': fork}})
710
851
 
711
- user = await core.auth.getUserByName('lowuser') # type: s_hiveauth.HiveUser
852
+ user = await core.auth.getUserByName('lowuser') # type: s_auth.User
712
853
  self.false(user.allowed(('hehe',)))
713
854
  self.false(user.allowed(('hehe',), deepdeny=True))
714
855
  self.true(user.allowed(('hehe', 'haha')))
@@ -3,13 +3,21 @@ import asyncio
3
3
  import synapse.exc as s_exc
4
4
  import synapse.common as s_common
5
5
  import synapse.lib.boss as s_boss
6
+ import synapse.lib.cell as s_cell
6
7
  import synapse.tests.utils as s_test
7
8
 
9
+ class BossCell(s_cell.Cell):
10
+ async def initServiceRuntime(self):
11
+ self.cboss = await s_boss.Boss.anit()
12
+ self.onfini(self.cboss)
13
+
8
14
  class BossTest(s_test.SynTest):
9
15
 
10
16
  async def test_boss_base(self):
11
17
 
12
- async with await s_boss.Boss.anit() as boss:
18
+ async with self.getTestCell(BossCell) as bcell:
19
+ boss = bcell.cboss
20
+ root = await bcell.auth.getUserByName('root')
13
21
 
14
22
  evnt = asyncio.Event()
15
23
 
@@ -20,18 +28,19 @@ class BossTest(s_test.SynTest):
20
28
 
21
29
  self.len(0, boss.ps())
22
30
 
23
- synt = await boss.promote('test', None, info={'hehe': 'haha'})
31
+ synt = await boss.promote('test', root, info={'hehe': 'haha'})
24
32
 
25
33
  self.len(1, boss.ps())
26
34
 
27
35
  self.eq('test', synt.name)
28
36
  self.eq('haha', synt.info.get('hehe'))
37
+ self.eq(root.iden, synt.user.iden)
29
38
 
30
- synt0 = await boss.execute(testloop(), 'testloop', None, info={'foo': 'bar'})
39
+ synt0 = await boss.execute(testloop(), 'testloop', root, info={'foo': 'bar'})
31
40
  iden = synt0.iden
32
41
 
33
42
  with self.raises(s_exc.BadArg):
34
- _ = await boss.execute(asyncio.sleep(1), 'testsleep', None, iden=iden)
43
+ _ = await boss.execute(asyncio.sleep(1), 'testsleep', root, iden=iden)
35
44
 
36
45
  await evnt.wait()
37
46
 
@@ -47,8 +56,8 @@ class BossTest(s_test.SynTest):
47
56
  iden = s_common.guid()
48
57
 
49
58
  async def double_promote():
50
- await boss.promote(f'double', None, taskiden=iden)
51
- await boss.promote(f'double', None, taskiden=iden + iden)
59
+ await boss.promote(f'double', root, taskiden=iden)
60
+ await boss.promote(f'double', root, taskiden=iden + iden)
52
61
 
53
62
  coro = boss.schedCoro(double_promote())
54
63
  self.true(await stream.wait(timeout=6))
@@ -3417,3 +3417,46 @@ class CellTest(s_t_utils.SynTest):
3417
3417
  pass
3418
3418
  async for item in cell.callPeerGenr(todo):
3419
3419
  pass
3420
+
3421
+ async def test_cell_task_apis(self):
3422
+ async with self.getTestAha() as aha:
3423
+
3424
+ # test some of the gather API implementations...
3425
+ purl00 = await aha.addAhaSvcProv('00.cell')
3426
+ purl01 = await aha.addAhaSvcProv('01.cell', provinfo={'mirror': 'cell'})
3427
+
3428
+ cell00 = await aha.enter_context(self.getTestCell(conf={'aha:provision': purl00}))
3429
+ cell01 = await aha.enter_context(self.getTestCell(conf={'aha:provision': purl01}))
3430
+
3431
+ await cell01.sync()
3432
+
3433
+ async def sleep99(cell):
3434
+ await cell.boss.promote('sleep99', cell.auth.rootuser)
3435
+ await cell00.fire('sleep99')
3436
+ await asyncio.sleep(99)
3437
+
3438
+ async with cell00.waiter(2, 'sleep99', timeout=6):
3439
+ task00 = cell00.schedCoro(sleep99(cell00))
3440
+ task01 = cell01.schedCoro(sleep99(cell01))
3441
+
3442
+ tasks = [task async for task in cell00.getTasks(timeout=6)]
3443
+
3444
+ self.len(2, tasks)
3445
+ self.eq(tasks[0]['service'], '00.cell.synapse')
3446
+ self.eq(tasks[1]['service'], '01.cell.synapse')
3447
+ self.eq(('sleep99', 'sleep99'), [task.get('name') for task in tasks])
3448
+ self.eq(('root', 'root'), [task.get('username') for task in tasks])
3449
+
3450
+ self.eq(tasks[0], await cell00.getTask(tasks[0].get('iden')))
3451
+ self.eq(tasks[1], await cell00.getTask(tasks[1].get('iden')))
3452
+ self.none(await cell00.getTask(tasks[1].get('iden'), peers=False))
3453
+
3454
+ self.true(await cell00.killTask(tasks[0].get('iden')))
3455
+
3456
+ task01 = tasks[1].get('iden')
3457
+ self.false(await cell00.killTask(task01, peers=False))
3458
+
3459
+ self.true(await cell00.killTask(task01))
3460
+
3461
+ self.none(await cell00.getTask(task01))
3462
+ self.false(await cell00.killTask(task01))
@@ -735,6 +735,17 @@ Queries = [
735
735
  '[test:str=foo :$foo*$bar.baz=heval]',
736
736
  '[test:str=foo :$foo*$bar.("baz")=heval]',
737
737
  '[test:str=foo :$foo*$bar.baz()=heval]',
738
+ '[test:str=foo +(refs)> $n]',
739
+ '[test:str=foo +(refs)> $n.baz()]',
740
+ '[test:str=foo -(refs)> $n]',
741
+ '[test:str=foo <(refs)+ $n]',
742
+ '[test:str=foo <(refs)+ $n.baz()]',
743
+ '[test:str=foo <(refs)- $n]',
744
+ '[test:str=foo :bar++=([1, 2])]',
745
+ '[test:str=foo :$foo++=([1, 2])]',
746
+ '[test:str=foo :bar--=(foo, bar)]',
747
+ '[test:str=foo :bar?++=$baz]',
748
+ '[test:str=foo :bar?--={[it:dev:str=foo]}]',
738
749
  ]
739
750
 
740
751
  # Generated with print_parse_list below
@@ -778,7 +789,7 @@ _ParseResults = [
778
789
  'Query: [TryCatch: [Query: [LiftPropBy: [Const: inet:ipv4, Const: =, Const: asdf]], CatchBlock: [Const: TypeError, Const: err, Query: []]]]',
779
790
  'Query: [TryCatch: [Query: [LiftPropBy: [Const: inet:ipv4, Const: =, Const: asdf]], CatchBlock: [Const: FooBar, Const: err, Query: []], CatchBlock: [Const: *, Const: err, Query: []]]]',
780
791
  'Query: [LiftByArray: [Const: test:array, Const: =, Const: 1.2.3.4]]',
781
- 'Query: [CmdOper: [Const: macro.set, List: [Const: hehe, EmbedQuery: inet:ipv4]]]',
792
+ 'Query: [CmdOper: [Const: macro.set, List: [Const: hehe, EmbedQuery: inet:ipv4 ]]]',
782
793
  'Query: [SetVarOper: [Const: q, EmbedQuery: #foo.bar]]',
783
794
  'Query: [CmdOper: [Const: metrics.edits.byprop, List: [Const: inet:fqdn:domain, Const: --newv, VarDeref: [VarValue: [Const: lib], Const: null]]]]',
784
795
  'Query: [CmdOper: [Const: tee, Const: ()]]',
@@ -1364,7 +1375,7 @@ _ParseResults = [
1364
1375
  'Query: [SetVarOper: [Const: p, Const: names], LiftPropBy: [Const: ps:contact:name, Const: =, Const: foo], EditPropSet: [RelProp: [VarValue: [Const: p]], Const: ?-=, Const: bar]]',
1365
1376
  'Query: [SetVarOper: [Const: pvar, Const: stuff], LiftProp: [Const: test:arrayprop], FiltOper: [Const: +, ArrayCond: [RelProp: [VarValue: [Const: pvar]], Const: =, Const: neato]]]',
1366
1377
  'Query: [SetVarOper: [Const: pvar, Const: ints], LiftProp: [Const: test:arrayprop], FiltOper: [Const: +, ArrayCond: [RelProp: [VarValue: [Const: pvar]], Const: =, VarValue: [Const: othervar]]]]',
1367
- 'Query: [SetVarOper: [Const: foo, DollarExpr: [ExprDict: [Const: foo, EmbedQuery: inet:fqdn]]]]',
1378
+ 'Query: [SetVarOper: [Const: foo, DollarExpr: [ExprDict: [Const: foo, EmbedQuery: inet:fqdn ]]]]',
1368
1379
  'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [Const: hehe], CondSetOper: [Const: unset], Const: heval]]',
1369
1380
  'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [Const: hehe], CondSetOper: [VarValue: [Const: foo]], Const: heval]]',
1370
1381
  'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [Const: unset], Const: heval]]',
@@ -1372,6 +1383,17 @@ _ParseResults = [
1372
1383
  'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [VarDeref: [VarValue: [Const: bar], Const: baz]], Const: heval]]',
1373
1384
  'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [VarDeref: [VarValue: [Const: bar], DollarExpr: [Const: baz]]], Const: heval]]',
1374
1385
  'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditCondPropSet: [RelProp: [VarValue: [Const: foo]], CondSetOper: [FuncCall: [VarDeref: [VarValue: [Const: bar], Const: baz], CallArgs: [], CallKwargs: []]], Const: heval]]',
1386
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, VarValue: [Const: n]]]',
1387
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, FuncCall: [VarDeref: [VarValue: [Const: n], Const: baz], CallArgs: [], CallKwargs: []]]]',
1388
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeDel: [Const: refs, VarValue: [Const: n]]]',
1389
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, VarValue: [Const: n]]]',
1390
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeAdd: [Const: refs, FuncCall: [VarDeref: [VarValue: [Const: n], Const: baz], CallArgs: [], CallKwargs: []]]]',
1391
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditEdgeDel: [Const: refs, VarValue: [Const: n]]]',
1392
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: ++=, DollarExpr: [ExprList: [Const: 1, Const: 2]]]]',
1393
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [VarValue: [Const: foo]], Const: ++=, DollarExpr: [ExprList: [Const: 1, Const: 2]]]]',
1394
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: --=, List: [Const: foo, Const: bar]]]',
1395
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: ?++=, VarValue: [Const: baz]]]',
1396
+ 'Query: [EditNodeAdd: [FormName: [Const: test:str], Const: =, Const: foo], EditPropSetMulti: [RelProp: [Const: bar], Const: ?--=, SubQuery: [Query: [EditNodeAdd: [FormName: [Const: it:dev:str], Const: =, Const: foo]]]]]',
1375
1397
  ]
1376
1398
 
1377
1399
  class GrammarTest(s_t_utils.SynTest):
@@ -1663,6 +1685,27 @@ class GrammarTest(s_t_utils.SynTest):
1663
1685
  errinfo = cm.exception.errinfo
1664
1686
  self.eq(1, errinfo.get('mesg').count('#'))
1665
1687
 
1688
+ query = '$q = ${ /* secret comment */ $lib.print([hello) } $lib.macro.set(hehe, $q)'
1689
+ parser = s_parser.Parser(query)
1690
+ with self.raises(s_exc.BadSyntax) as cm:
1691
+ _ = parser.query()
1692
+ info = cm.exception.errinfo.get('highlight')
1693
+ self.eq((40, 41), info['offsets'])
1694
+ self.eq((1, 1), info['lines'])
1695
+ self.eq((41, 42), info['columns'])
1696
+
1697
+ query = """function test(hello) {
1698
+ +'''asdf
1699
+ asdfasdf'''
1700
+ }"""
1701
+ parser = s_parser.Parser(query)
1702
+ with self.raises(s_exc.BadSyntax) as cm:
1703
+ _ = parser.query()
1704
+ info = cm.exception.errinfo.get('highlight')
1705
+ self.eq((44, 83), info['offsets'])
1706
+ self.eq((2, 3), info['lines'])
1707
+ self.eq((22, 31), info['columns'])
1708
+
1666
1709
  async def test_quotes(self):
1667
1710
 
1668
1711
  # Test vectors
@@ -1766,6 +1809,15 @@ class GrammarTest(s_t_utils.SynTest):
1766
1809
  self.false(s_grammar.isPropName('.hehe'))
1767
1810
  self.false(s_grammar.isPropName('testcmd'))
1768
1811
 
1812
+ async def test_embed_offsets(self):
1813
+
1814
+ embq = ' /* secret comment */ $lib.print(hello) /* haha */ $lib.print(goodbye) /*foo */ '
1815
+ query = f'$q = ${{{embq}}} $lib.print($q)'
1816
+ parser = s_parser.Parser(query)
1817
+ q = parser.query()
1818
+ embed = q.kids[0].kids[1]
1819
+ self.eq(embq, embed.getAstText())
1820
+
1769
1821
  def gen_parse_list():
1770
1822
  '''
1771
1823
  Prints out the Asts for a list of queries in order to compare ASTs between versions of parsers
@@ -371,6 +371,30 @@ class LmdbSlabTest(s_t_utils.SynTest):
371
371
  'vm.dirty_ratio',
372
372
  ], msgs[0].get('sysctls', {}).keys())
373
373
 
374
+ async def test_lmdbslab_commit_over_max_xactops(self):
375
+
376
+ # Make sure that we don't confuse the periodic commit with the max replay log commit
377
+ with (self.getTestDir() as dirn,
378
+ patch('synapse.lib.lmdbslab.Slab.WARN_COMMIT_TIME_MS', 1),
379
+ patch('synapse.lib.lmdbslab.Slab.COMMIT_PERIOD', 100)
380
+ ):
381
+ path = os.path.join(dirn, 'test.lmdb')
382
+
383
+ async with await s_lmdbslab.Slab.anit(path, max_replay_log=100, map_size=100_000_000) as slab:
384
+ foo = slab.initdb('foo', dupsort=True)
385
+
386
+ byts = b'\x00' * 256
387
+ for i in range(1000):
388
+ slab.put(b'\xff\xff\xff\xff' + s_common.guid(i).encode('utf8'), byts, db=foo)
389
+ await asyncio.sleep(0)
390
+
391
+ # Let the slab close and then grab its stats
392
+ stats = slab.statinfo()
393
+ commitstats = stats.get('commitstats', ())
394
+ self.gt(len(commitstats), 0)
395
+ commitstats = [x[1] for x in commitstats if x[1] != 0]
396
+ self.eq(commitstats, (100, 100, 100, 100, 100, 100, 100, 100, 100, 100))
397
+
374
398
  async def test_lmdbslab_max_replay(self):
375
399
  with self.getTestDir() as dirn:
376
400
  path = os.path.join(dirn, 'test.lmdb')
@@ -143,6 +143,26 @@ class StormTest(s_t_utils.SynTest):
143
143
  self.eq(props.get('name'), 'org name 77')
144
144
  self.eq(props.get('desc'), 'an org desc')
145
145
 
146
+ nodes = await core.nodes('ou:org=({"name": "the vertex project", "type": "lulz"})')
147
+ self.len(1, nodes)
148
+ orgn = nodes[0].ndef
149
+ self.eq(orgn, nodes11[0].ndef)
150
+
151
+ q = '[ ps:contact=* :org={ ou:org=({"name": "the vertex project", "type": "lulz"}) } ]'
152
+ nodes = await core.nodes(q)
153
+ self.len(1, nodes)
154
+ cont = nodes[0]
155
+ self.eq(cont.get('org'), orgn[1])
156
+
157
+ nodes = await core.nodes('ps:contact:org=({"name": "the vertex project", "type": "lulz"})')
158
+ self.len(1, nodes)
159
+ self.eq(nodes[0].ndef, cont.ndef)
160
+
161
+ self.len(0, await core.nodes('ps:contact:org=({"name": "vertex", "type": "newp"})'))
162
+
163
+ with self.raises(s_exc.BadTypeValu):
164
+ await core.nodes('inet:flow:from=({"name": "vertex", "type": "newp"})')
165
+
146
166
  async def test_lib_storm_jsonexpr(self):
147
167
  async with self.getTestCore() as core:
148
168
 
@@ -0,0 +1,39 @@
1
+ import synapse.tests.utils as s_test
2
+
3
+ count_prop_00 = '''
4
+ Count | Layer Iden | Layer Name
5
+ ==============|==================================|============
6
+ 16 | 5cc56afbb22fad9b96c51110812af8f7 |
7
+ 16 | 2371390b1fd0162ba6820f85a863e7b2 | default
8
+ Total: 32
9
+ '''
10
+
11
+ count_prop_01 = '''
12
+ Count | Layer Iden | Layer Name
13
+ ==============|==================================|============
14
+ 16 | 9782c920718d3059b8806fddaf917bd8 |
15
+ 0 | 511122a9b2d576c5be2cdfcaef541bb9 | default
16
+ Total: 16
17
+ '''
18
+
19
+ class StormIndexTest(s_test.SynTest):
20
+
21
+ async def test_lib_stormlib_index(self):
22
+
23
+ async with self.getTestCore() as core:
24
+ viewiden = await core.callStorm('return($lib.view.get().fork().iden)')
25
+ viewopts = {'view': viewiden}
26
+ await core.nodes('[ inet:ipv4=1.2.3.0/28 :asn=19 ]')
27
+ await core.nodes('[ inet:ipv4=1.2.4.0/28 :asn=42 ]', opts=viewopts)
28
+
29
+ msgs = await core.stormlist('index.count.prop inet:ipv4', opts=viewopts)
30
+ self.stormIsInPrint(count_prop_00, msgs, deguid=True, whitespace=False)
31
+
32
+ msgs = await core.stormlist('index.count.prop inet:ipv4:asn', opts=viewopts)
33
+ self.stormIsInPrint(count_prop_00, msgs, deguid=True, whitespace=False)
34
+
35
+ msgs = await core.stormlist('index.count.prop inet:ipv4:asn --value 42', opts=viewopts)
36
+ self.stormIsInPrint(count_prop_01, msgs, deguid=True, whitespace=False)
37
+
38
+ msgs = await core.stormlist('index.count.prop inet:ipv4:newp', opts=viewopts)
39
+ self.stormIsInErr('No property named inet:ipv4:newp', msgs)
@@ -89,7 +89,7 @@ class MacroTest(s_test.SynTest):
89
89
  name = 'v' * 491
90
90
  q = '$lib.macro.set($name, ${ help }) return ( $lib.macro.get($name) )'
91
91
  mdef = await core.callStorm(q, opts={'vars': {'name': name}})
92
- self.eq(mdef.get('storm'), 'help')
92
+ self.eq(mdef.get('storm'), ' help ')
93
93
 
94
94
  badname = 'v' * 492
95
95
  with self.raises(s_exc.BadArg):
@@ -381,7 +381,7 @@ class MacroTest(s_test.SynTest):
381
381
  self.eq('storm:macro:add', addmesg['data']['event'])
382
382
  macro = addmesg['data']['info']['macro']
383
383
  self.eq(macro['name'], 'foobar')
384
- self.eq(macro['storm'], 'file:bytes | [+#neato]')
384
+ self.eq(macro['storm'], ' file:bytes | [+#neato] ')
385
385
  self.ne(visi.iden, macro['user'])
386
386
  self.ne(visi.iden, macro['creator'])
387
387
  self.nn(macro['iden'])
@@ -390,7 +390,7 @@ class MacroTest(s_test.SynTest):
390
390
  self.eq('storm:macro:mod', setmesg['data']['event'])
391
391
  event = setmesg['data']['info']
392
392
  self.nn(event['macro'])
393
- self.eq(event['info']['storm'], 'inet:ipv4 | [+#burrito]')
393
+ self.eq(event['info']['storm'], ' inet:ipv4 | [+#burrito] ')
394
394
  self.nn(event['info']['updated'])
395
395
 
396
396
  modmesg = await sock.receive_json()
@@ -749,7 +749,7 @@ class StormTypesTest(s_test.SynTest):
749
749
  self.stormIsInPrint("['1', 2, '3']", mesgs)
750
750
 
751
751
  mesgs = await core.stormlist('$lib.print(${ $foo=bar })')
752
- self.stormIsInPrint('storm:query: "$foo=bar"', mesgs)
752
+ self.stormIsInPrint('storm:query: " $foo=bar "', mesgs)
753
753
 
754
754
  mesgs = await core.stormlist('$lib.print($lib.set(1,2,3))')
755
755
  self.stormIsInPrint("'1'", mesgs)
@@ -1168,7 +1168,7 @@ class StormTypesTest(s_test.SynTest):
1168
1168
  fires = [m for m in msgs if m[0] == 'storm:fire']
1169
1169
  self.len(1, fires)
1170
1170
  self.eq(fires[0][1].get('data').get('q'),
1171
- "$lib.print('fire in the hole')")
1171
+ " $lib.print('fire in the hole') ")
1172
1172
 
1173
1173
  q = '''
1174
1174
  $q=${ [test:int=1 test:int=2] }
@@ -1409,6 +1409,18 @@ class StormTypesTest(s_test.SynTest):
1409
1409
  with self.raises(s_exc.BadJsonText):
1410
1410
  await core.callStorm('return(("foo").json())')
1411
1411
 
1412
+ with self.raises(s_exc.BadArg):
1413
+ await core.nodes("$lib.regex.search('?id=([0-9]+)', 'foo')")
1414
+
1415
+ with self.raises(s_exc.BadArg):
1416
+ await core.nodes("$lib.regex.search('(?au)\\w', 'foo')")
1417
+
1418
+ with self.raises(s_exc.BadArg):
1419
+ await core.nodes("$lib.regex.replace('(?P<a>x)', '\\g<ab>', 'xx')")
1420
+
1421
+ with self.raises(s_exc.BadArg):
1422
+ await core.nodes("$lib.regex.replace('(?P<a>x)', '(?au)\\w', 'xx')")
1423
+
1412
1424
  async def test_storm_lib_bytes_gzip(self):
1413
1425
  async with self.getTestCore() as core:
1414
1426
  hstr = 'ohhai'
@@ -2,12 +2,14 @@ import asyncio
2
2
 
3
3
  import synapse.exc as s_exc
4
4
  import synapse.lib.boss as s_boss
5
+ import synapse.lib.cell as s_cell
5
6
  import synapse.lib.task as s_task
6
7
  import synapse.tests.utils as s_test
7
8
 
8
- class FakeUser:
9
- def __init__(self, name):
10
- self.name = name
9
+ class BossCell(s_cell.Cell):
10
+ async def initServiceRuntime(self):
11
+ self.cboss = await s_boss.Boss.anit()
12
+ self.onfini(self.cboss)
11
13
 
12
14
  class TaskTest(s_test.SynTest):
13
15
 
@@ -19,15 +21,27 @@ class TaskTest(s_test.SynTest):
19
21
 
20
22
  async def test_task_module(self):
21
23
 
22
- async with await s_boss.Boss.anit() as boss:
24
+ async with self.getTestCell(BossCell) as bcell:
25
+ boss = bcell.cboss
26
+ root = await bcell.auth.getUserByName('root')
23
27
 
24
- user = FakeUser('visi')
28
+ synt = await boss.promote('test', root, info={'hehe': 'haha'})
25
29
 
26
- synt = await boss.promote('test', user, info={'hehe': 'haha'})
27
-
28
- self.eq(s_task.user(), user)
30
+ self.eq(s_task.user(), root)
29
31
  self.eq(s_task.current(), synt)
30
- self.eq(s_task.username(), 'visi')
32
+ self.eq(s_task.username(), 'root')
33
+
34
+ ret = synt.pack()
35
+ self.nn(ret.pop('iden'))
36
+ self.nn(ret.pop('tick'))
37
+ self.eq(ret, {'name': 'test', 'info': {'hehe': 'haha'},
38
+ 'user': 'root', 'kids': {}})
39
+
40
+ ret = synt.packv2()
41
+ self.nn(ret.pop('iden'))
42
+ self.nn(ret.pop('tick'))
43
+ self.eq(ret, {'name': 'test', 'info': {'hehe': 'haha'},
44
+ 'user': root.iden, 'username': 'root', 'kids': {}})
31
45
 
32
46
  async def test_taskvars(self):
33
47
  s_task.varset('test', 'foo')
@@ -51,7 +65,11 @@ class TaskTest(s_test.SynTest):
51
65
  self.eq(s_task.varget('test'), 'foo')
52
66
 
53
67
  async def test_task_iden(self):
54
- with self.raises(s_exc.BadArg):
55
- await s_task.Task.anit(None, asyncio.current_task(), None, None, iden=10)
56
- with self.raises(s_exc.BadArg):
57
- await s_task.Task.anit(None, asyncio.current_task(), None, None, iden='woot')
68
+ async with self.getTestCell(BossCell) as bcell:
69
+ root = await bcell.auth.getUserByName('root')
70
+ boss = bcell.cboss
71
+
72
+ with self.raises(s_exc.BadArg):
73
+ await s_task.Task.anit(boss, asyncio.current_task(), None, root, iden=10)
74
+ with self.raises(s_exc.BadArg):
75
+ await s_task.Task.anit(boss, asyncio.current_task(), None, root, iden='woot')
@@ -49,3 +49,41 @@ class DocModelTest(s_tests.SynTest):
49
49
  self.eq('V-99', nodes[0].get('id'))
50
50
  self.nn(nodes[0].get('policy'))
51
51
  self.len(1, await core.nodes('doc:standard -> doc:policy'))
52
+
53
+ nodes = await core.nodes('''
54
+ [ doc:requirement=*
55
+ :id=V-99
56
+ :priority=low
57
+ :optional=(false)
58
+ :summary="Some requirement text."
59
+ :standard={doc:standard}
60
+ ]
61
+ ''')
62
+ self.eq('V-99', nodes[0].get('id'))
63
+ self.eq('Some requirement text.', nodes[0].get('summary'))
64
+ self.eq(20, nodes[0].get('priority'))
65
+ self.false(nodes[0].get('optional'))
66
+ self.nn(nodes[0].get('standard'))
67
+ self.len(1, await core.nodes('doc:requirement -> doc:standard'))
68
+
69
+ nodes = await core.nodes('''
70
+ [ doc:resume=*
71
+ :id=V-99
72
+ :contact={[ ps:contact=* :name=visi ]}
73
+ :summary="Thought leader seeks..."
74
+ :workhist={[ ps:workhist=* ]}
75
+ :education={[ ps:education=* ]}
76
+ :achievements={[ ps:achievement=* ]}
77
+ ]
78
+ ''')
79
+ self.eq('V-99', nodes[0].get('id'))
80
+ self.eq('Thought leader seeks...', nodes[0].get('summary'))
81
+ self.nn(nodes[0].get('contact'))
82
+ self.len(1, nodes[0].get('workhist'))
83
+ self.len(1, nodes[0].get('education'))
84
+ self.len(1, nodes[0].get('achievements'))
85
+
86
+ self.len(1, await core.nodes('doc:resume :contact -> ps:contact'))
87
+ self.len(1, await core.nodes('doc:resume :workhist -> ps:workhist'))
88
+ self.len(1, await core.nodes('doc:resume :education -> ps:education'))
89
+ self.len(1, await core.nodes('doc:resume :achievements -> ps:achievement'))