synapse 2.165.0__py311-none-any.whl → 2.167.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 (77) hide show
  1. synapse/axon.py +4 -10
  2. synapse/cmds/cortex.py +1 -6
  3. synapse/common.py +6 -0
  4. synapse/cortex.py +104 -57
  5. synapse/datamodel.py +32 -0
  6. synapse/exc.py +1 -0
  7. synapse/lib/agenda.py +81 -51
  8. synapse/lib/aha.py +2 -0
  9. synapse/lib/ast.py +21 -23
  10. synapse/lib/base.py +11 -10
  11. synapse/lib/cell.py +24 -24
  12. synapse/lib/hive.py +11 -0
  13. synapse/lib/httpapi.py +1 -0
  14. synapse/lib/nexus.py +3 -2
  15. synapse/lib/node.py +4 -2
  16. synapse/lib/schemas.py +3 -1
  17. synapse/lib/snap.py +50 -0
  18. synapse/lib/storm.py +19 -17
  19. synapse/lib/stormlib/aha.py +370 -17
  20. synapse/lib/stormlib/auth.py +11 -4
  21. synapse/lib/stormlib/cache.py +202 -0
  22. synapse/lib/stormlib/cortex.py +69 -7
  23. synapse/lib/stormlib/macro.py +11 -18
  24. synapse/lib/stormlib/spooled.py +109 -0
  25. synapse/lib/stormlib/stix.py +1 -1
  26. synapse/lib/stormtypes.py +61 -17
  27. synapse/lib/trigger.py +10 -12
  28. synapse/lib/types.py +3 -1
  29. synapse/lib/version.py +2 -2
  30. synapse/lib/view.py +16 -3
  31. synapse/models/base.py +8 -0
  32. synapse/models/files.py +3 -0
  33. synapse/models/inet.py +74 -2
  34. synapse/models/orgs.py +52 -8
  35. synapse/models/person.py +30 -11
  36. synapse/models/risk.py +44 -3
  37. synapse/telepath.py +115 -32
  38. synapse/tests/files/stormpkg/dotstorm/dotstorm.yaml +3 -0
  39. synapse/tests/test_cortex.py +79 -8
  40. synapse/tests/test_datamodel.py +22 -0
  41. synapse/tests/test_lib_agenda.py +8 -1
  42. synapse/tests/test_lib_aha.py +19 -6
  43. synapse/tests/test_lib_cell.py +6 -2
  44. synapse/tests/test_lib_grammar.py +62 -64
  45. synapse/tests/test_lib_httpapi.py +1 -1
  46. synapse/tests/test_lib_rstorm.py +4 -4
  47. synapse/tests/test_lib_storm.py +98 -7
  48. synapse/tests/test_lib_stormlib_aha.py +196 -0
  49. synapse/tests/test_lib_stormlib_cache.py +272 -0
  50. synapse/tests/test_lib_stormlib_compression.py +12 -12
  51. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  52. synapse/tests/test_lib_stormlib_macro.py +94 -0
  53. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  54. synapse/tests/test_lib_stormtypes.py +71 -37
  55. synapse/tests/test_lib_view.py +50 -3
  56. synapse/tests/test_model_files.py +3 -0
  57. synapse/tests/test_model_inet.py +67 -0
  58. synapse/tests/test_model_risk.py +6 -0
  59. synapse/tests/test_telepath.py +30 -7
  60. synapse/tests/test_tools_genpkg.py +26 -0
  61. synapse/tests/test_tools_hiveload.py +1 -0
  62. synapse/tests/test_tools_hivesave.py +1 -0
  63. synapse/tests/test_tools_modrole.py +81 -0
  64. synapse/tests/test_tools_moduser.py +105 -0
  65. synapse/tests/utils.py +22 -3
  66. synapse/tools/autodoc.py +1 -1
  67. synapse/tools/hive/load.py +3 -0
  68. synapse/tools/hive/save.py +3 -0
  69. synapse/tools/modrole.py +59 -7
  70. synapse/tools/moduser.py +78 -10
  71. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/METADATA +3 -3
  72. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/RECORD +75 -72
  73. synapse/lib/provenance.py +0 -111
  74. synapse/tests/test_lib_provenance.py +0 -37
  75. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/LICENSE +0 -0
  76. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/WHEEL +0 -0
  77. {synapse-2.165.0.dist-info → synapse-2.167.0.dist-info}/top_level.txt +0 -0
@@ -11,18 +11,21 @@ from synapse.tests.utils import alist
11
11
 
12
12
  class ViewTest(s_t_utils.SynTest):
13
13
 
14
- async def test_view_nomerge(self):
14
+ async def test_view_protected(self):
15
15
  async with self.getTestCore() as core:
16
16
  view = await core.callStorm('return($lib.view.get().fork().iden)')
17
17
  opts = {'view': view}
18
18
 
19
19
  await core.nodes('[ ou:org=* ]', opts=opts)
20
- await core.nodes('$lib.view.get().set(nomerge, $lib.true)', opts=opts)
20
+ await core.nodes('$lib.view.get().set(protected, $lib.true)', opts=opts)
21
21
 
22
22
  with self.raises(s_exc.CantMergeView):
23
23
  await core.nodes('$lib.view.get().merge()', opts=opts)
24
24
 
25
- await core.nodes('$lib.view.get().set(nomerge, $lib.false)', opts=opts)
25
+ with self.raises(s_exc.CantDelView):
26
+ await core.nodes('$lib.view.del($lib.view.get().iden)', opts=opts)
27
+
28
+ await core.nodes('$lib.view.get().set(protected, $lib.false)', opts=opts)
26
29
  await core.nodes('$lib.view.get().merge()', opts=opts)
27
30
 
28
31
  self.len(1, await core.nodes('ou:org'))
@@ -31,6 +34,50 @@ class ViewTest(s_t_utils.SynTest):
31
34
  with self.raises(s_exc.BadOptValu):
32
35
  await core.view.setViewInfo('hehe', 10)
33
36
 
37
+ async with self.getTestCore() as core:
38
+ # Delete this block when nomerge is removed
39
+ view = await core.callStorm('return($lib.view.get().fork().iden)')
40
+ opts = {'view': view}
41
+
42
+ # Setting/getting nomerge should be redirected to protected
43
+ getnomerge = 'return($lib.view.get().get(nomerge))'
44
+ setnomerge = '$lib.view.get().set(nomerge, $valu)'
45
+
46
+ getprotected = 'return($lib.view.get().get(protected))'
47
+ setprotected = '$lib.view.get().set(protected, $valu)'
48
+
49
+ nomerge = await core.callStorm(getnomerge, opts=opts)
50
+ protected = await core.callStorm(getprotected, opts=opts)
51
+ self.false(nomerge)
52
+ self.false(protected)
53
+
54
+ opts['vars'] = {'valu': True}
55
+ await core.callStorm(setnomerge, opts=opts)
56
+
57
+ nomerge = await core.callStorm(getnomerge, opts=opts)
58
+ protected = await core.callStorm(getprotected, opts=opts)
59
+ self.true(nomerge)
60
+ self.true(protected)
61
+
62
+ opts['vars'] = {'valu': False}
63
+ await core.callStorm(setprotected, opts=opts)
64
+
65
+ nomerge = await core.callStorm(getnomerge, opts=opts)
66
+ protected = await core.callStorm(getprotected, opts=opts)
67
+ self.false(nomerge)
68
+ self.false(protected)
69
+
70
+ async def test_view_nomerge_migration(self):
71
+ async with self.getRegrCore('cortex-defaults-v2') as core:
72
+ view = core.getView('0df16dd693c74109da0d58ab87ba768a')
73
+ self.none(view.info.get('nomerge'))
74
+ self.true(view.info.get('protected'))
75
+
76
+ with self.raises(s_exc.CantMergeView):
77
+ await core.callStorm('return($lib.view.get(0df16dd693c74109da0d58ab87ba768a).merge())')
78
+ with self.raises(s_exc.CantDelView):
79
+ await core.callStorm('return($lib.view.del(0df16dd693c74109da0d58ab87ba768a))')
80
+
34
81
  async def test_view_set_parent(self):
35
82
 
36
83
  async with self.getTestCore() as core:
@@ -247,6 +247,9 @@ class FileTest(s_t_utils.SynTest):
247
247
  self.raises(s_exc.BadTypeValu, base.norm, 'foo/bar.exe')
248
248
  self.raises(s_exc.BadTypeValu, base.norm, '/haha')
249
249
 
250
+ norm, info = path.norm('../.././..')
251
+ self.eq(norm, '')
252
+
250
253
  norm, info = path.norm('c:\\Windows\\System32\\calc.exe')
251
254
 
252
255
  self.eq(norm, 'c:/windows/system32/calc.exe')
@@ -2767,3 +2767,70 @@ class InetModelTest(s_t_utils.SynTest):
2767
2767
  self.eq(nodes[0].get('client'), 'tcp://1.2.3.4')
2768
2768
  self.eq(nodes[0].get('client:ipv4'), 0x01020304)
2769
2769
  self.eq(nodes[0].get('client:ipv6'), '::1')
2770
+
2771
+ async def test_model_inet_tls_handshake(self):
2772
+
2773
+ async with self.getTestCore() as core:
2774
+ props = {
2775
+ 'ja3': '1' * 32,
2776
+ 'ja3s': '2' * 32,
2777
+ 'client': 'tcp://1.2.3.4:8888',
2778
+ 'server': 'tcp://5.6.7.8:9999'
2779
+ }
2780
+
2781
+ nodes = await core.nodes('''
2782
+ [
2783
+ inet:tls:handshake=*
2784
+ :time=now
2785
+ :flow=*
2786
+ :server=$server
2787
+ :server:cert=*
2788
+ :server:fingerprint:ja3=$ja3s
2789
+ :client=$client
2790
+ :client:cert=*
2791
+ :client:fingerprint:ja3=$ja3
2792
+ ]
2793
+ ''', opts={'vars': props})
2794
+ self.len(1, nodes)
2795
+ self.nn(nodes[0].get('time'))
2796
+ self.nn(nodes[0].get('flow'))
2797
+ self.nn(nodes[0].get('server:cert'))
2798
+ self.nn(nodes[0].get('client:cert'))
2799
+
2800
+ self.eq(props['ja3'], nodes[0].get('client:fingerprint:ja3'))
2801
+ self.eq(props['ja3s'], nodes[0].get('server:fingerprint:ja3'))
2802
+
2803
+ self.eq(props['client'], nodes[0].get('client'))
2804
+ self.eq(props['server'], nodes[0].get('server'))
2805
+
2806
+ async def test_model_inet_ja3(self):
2807
+
2808
+ async with self.getTestCore() as core:
2809
+
2810
+ ja3 = '76e7b0cb0994d60a4b3f360a088fac39'
2811
+ nodes = await core.nodes('[ inet:tls:ja3:sample=(tcp://1.2.3.4, $md5) ]', opts={'vars': {'md5': ja3}})
2812
+ self.len(1, nodes)
2813
+ self.eq(nodes[0].get('client'), 'tcp://1.2.3.4')
2814
+ self.eq(nodes[0].get('ja3'), ja3)
2815
+
2816
+ ja3 = '4769ad08107979c719d86270e706fed5'
2817
+ nodes = await core.nodes('[ inet:tls:ja3s:sample=(tcp://2.2.2.2, $md5) ]', opts={'vars': {'md5': ja3}})
2818
+ self.len(1, nodes)
2819
+ self.eq(nodes[0].get('server'), 'tcp://2.2.2.2')
2820
+ self.eq(nodes[0].get('ja3s'), ja3)
2821
+
2822
+ async def test_model_inet_tls_certs(self):
2823
+
2824
+ async with self.getTestCore() as core:
2825
+
2826
+ server = 'e4f6db65dbaa7a4598f7379f75dcd5f5'
2827
+ client = 'df8d1f7e04f7c4a322e04b0b252e2851'
2828
+ nodes = await core.nodes('[inet:tls:servercert=(tcp://1.2.3.4:1234, $server)]', opts={'vars': {'server': server}})
2829
+ self.len(1, nodes)
2830
+ self.eq(nodes[0].get('server'), 'tcp://1.2.3.4:1234')
2831
+ self.eq(nodes[0].get('cert'), server)
2832
+
2833
+ nodes = await core.nodes('[inet:tls:clientcert=(tcp://5.6.7.8:5678, $client)]', opts={'vars': {'client': client}})
2834
+ self.len(1, nodes)
2835
+ self.eq(nodes[0].get('client'), 'tcp://5.6.7.8:5678')
2836
+ self.eq(nodes[0].get('cert'), client)
@@ -435,6 +435,8 @@ class RiskModelTest(s_t_utils.SynTest):
435
435
  :public:url=https://wikileaks.org/acme
436
436
  :reporter={ gen.ou.org vertex }
437
437
  :reporter:name=vertex
438
+ :size:bytes=99
439
+ :extortion=*
438
440
  ]''')
439
441
  self.len(1, nodes)
440
442
  self.eq('wikileaks acme leak', nodes[0].get('name'))
@@ -442,9 +444,11 @@ class RiskModelTest(s_t_utils.SynTest):
442
444
  self.eq(1698883200000, nodes[0].get('disclosed'))
443
445
  self.eq('public.', nodes[0].get('type'))
444
446
  self.eq(1, nodes[0].get('public'))
447
+ self.eq(99, nodes[0].get('size:bytes'))
445
448
  self.eq('https://wikileaks.org/acme', nodes[0].get('public:url'))
446
449
  self.eq('vertex', nodes[0].get('reporter:name'))
447
450
 
451
+ self.len(1, await core.nodes('risk:leak -> risk:extortion'))
448
452
  self.len(1, await core.nodes('risk:leak -> risk:leak:type:taxonomy'))
449
453
  self.len(1, await core.nodes('risk:leak :owner -> ps:contact +:orgname=acme'))
450
454
  self.len(1, await core.nodes('risk:leak :leaker -> ps:contact +:orgname=wikileaks'))
@@ -454,6 +458,7 @@ class RiskModelTest(s_t_utils.SynTest):
454
458
 
455
459
  nodes = await core.nodes('''[ risk:extortion=*
456
460
  :demanded=20231102
461
+ :deadline=20240329
457
462
  :name="APT99 Extorted ACME"
458
463
  :desc="APT99 extorted ACME for a zillion vertex coins."
459
464
  :type=fingain
@@ -474,6 +479,7 @@ class RiskModelTest(s_t_utils.SynTest):
474
479
  self.eq('apt99 extorted acme', nodes[0].get('name'))
475
480
  self.eq('APT99 extorted ACME for a zillion vertex coins.', nodes[0].get('desc'))
476
481
  self.eq(1698883200000, nodes[0].get('demanded'))
482
+ self.eq(1711670400000, nodes[0].get('deadline'))
477
483
  self.eq('fingain.', nodes[0].get('type'))
478
484
  self.eq(1, nodes[0].get('public'))
479
485
  self.eq(1, nodes[0].get('success'))
@@ -831,15 +831,17 @@ class TeleTest(s_t_utils.SynTest):
831
831
 
832
832
  await targ.waitready()
833
833
 
834
- self.eq(110, await targ.dostuff(100))
834
+ prox00 = await targ.proxy(timeout=12)
835
+ self.eq(110, await prox00.dostuff(100))
836
+
835
837
  self.eq(1, fail0.count)
836
838
  self.eq(0, fail1.count)
837
839
 
838
- _prox = await targ.proxy()
839
840
  await dmon0.fini()
840
- self.true(await _prox.waitfini(10))
841
+ self.true(await prox00.waitfini(10))
841
842
 
842
- self.eq(110, await targ.dostuff(100))
843
+ prox01 = await targ.proxy(timeout=12)
844
+ self.eq(110, await prox01.dostuff(100))
843
845
  self.eq(1, fail0.count)
844
846
  self.eq(1, fail1.count)
845
847
 
@@ -855,15 +857,36 @@ class TeleTest(s_t_utils.SynTest):
855
857
  mesgs = stream.read()
856
858
  self.notin('password', mesgs)
857
859
 
858
- self.eq(110, await targ.dostuff(100))
860
+ prox00 = await targ.proxy(timeout=12)
861
+ self.eq(110, await prox00.dostuff(100))
859
862
 
860
863
  self.eq(1, fail0.count)
861
864
  self.eq(2, fail1.count)
862
865
 
863
866
  async with await s_telepath.open(url1) as targ:
864
- await targ.waitready()
865
- self.eq(110, await targ.dostuff(100))
867
+ await targ.waitready(timeout=12)
868
+ prox00 = await targ.proxy(timeout=12)
869
+ self.eq(110, await prox00.dostuff(100))
870
+
871
+ async def onlink(proxy, urlinfo):
872
+ self.eq(110, await proxy.dostuff(100))
873
+ _url = s_telepath.zipurl(urlinfo)
874
+ logger.info(f'Connected to url={_url}')
875
+
876
+ with self.getAsyncLoggerStream('synapse.tests.test_telepath',
877
+ f'Connected to url=tcp://127.0.0.1:{addr1[1]}/foo') as stream:
878
+ async with await s_telepath.open(url1, onlink=onlink) as targ:
879
+ self.true(await stream.wait(timeout=12))
880
+
881
+ # Coverage
882
+ async def badonlink(proxy, urlinfo):
883
+ raise ValueError('oopsie')
884
+
885
+ with self.getAsyncLoggerStream('synapse.telepath', 'onlink: ') as stream:
886
+ async with await s_telepath.open(url1, onlink=badonlink) as targ:
887
+ self.true(await stream.wait(timeout=12))
866
888
 
889
+ await dmon0.fini()
867
890
  await dmon1.fini()
868
891
 
869
892
  async def test_telepath_poolsize(self):
@@ -254,7 +254,33 @@ class TestStormPkgTest(s_test.StormPkgTest):
254
254
  assetdir = s_common.genpath(dirname, 'files', 'stormpkg', 'dotstorm', 'testassets')
255
255
  pkgprotos = (s_common.genpath(dirname, 'files', 'stormpkg', 'dotstorm', 'dotstorm.yaml'),)
256
256
 
257
+ async def initTestCore(self, core):
258
+ await core.callStorm('$lib.globals.set(inittestcore, frob)')
259
+
257
260
  async def test_stormpkg_base(self):
258
261
  async with self.getTestCore() as core:
259
262
  msgs = await core.stormlist('dotstorm.bar')
260
263
  self.stormHasNoWarnErr(msgs)
264
+ self.eq('frob', await core.callStorm('return($lib.globals.get(inittestcore))'))
265
+
266
+ async def stormpkg_preppkghook(self, core):
267
+ await core.callStorm('$lib.globals.set(stormpkg_preppkghook, boundmethod)')
268
+
269
+ async def test_stormpkg_preppkghook(self):
270
+
271
+ # inline example
272
+ async def hook(core):
273
+ await core.callStorm('$lib.globals.set(inlinehook, haha)')
274
+
275
+ async with self.getTestCore(prepkghook=hook) as core:
276
+ msgs = await core.stormlist('dotstorm.bar')
277
+ self.stormHasNoWarnErr(msgs)
278
+ self.eq('haha', await core.callStorm('return($lib.globals.get(inlinehook))'))
279
+ self.eq('frob', await core.callStorm('return($lib.globals.get(inittestcore))'))
280
+
281
+ # bound method example
282
+ async with self.getTestCore(prepkghook=self.stormpkg_preppkghook) as core:
283
+ msgs = await core.stormlist('dotstorm.bar')
284
+ self.stormHasNoWarnErr(msgs)
285
+ self.eq('boundmethod', await core.callStorm('return($lib.globals.get(stormpkg_preppkghook))'))
286
+ self.eq('frob', await core.callStorm('return($lib.globals.get(inittestcore))'))
@@ -48,6 +48,7 @@ class HiveLoadTest(s_test.SynTest):
48
48
  with mock.patch('synapse.telepath.Proxy._getSynVers', _getOldSynVers):
49
49
  outp = self.getTestOutp()
50
50
  retn = await s_hiveload.main(argv, outp=outp)
51
+ outp.expect('WARNING: "synapse.tools.hive.load" is deprecated in 2.167.0 and will be removed in 3.0.0')
51
52
  outp.expect('Hive version 0.0.0 is outside of the hive.load supported range')
52
53
  self.eq(1, retn)
53
54
 
@@ -28,6 +28,7 @@ class HiveSaveTest(s_test.SynTest):
28
28
  with mock.patch('synapse.telepath.Proxy._getSynVers', _getOldSynVers):
29
29
  outp = self.getTestOutp()
30
30
  retn = await s_hivesave.main(argv, outp=outp)
31
+ outp.expect('WARNING: "synapse.tools.hive.save" is deprecated in 2.167.0 and will be removed in 3.0.0')
31
32
  outp.expect('Hive version 0.0.0 is outside of the hive.save supported range')
32
33
  self.eq(1, retn)
33
34
 
@@ -2,6 +2,26 @@ import synapse.lib.output as s_output
2
2
  import synapse.tests.utils as s_test
3
3
  import synapse.tools.modrole as s_t_modrole
4
4
 
5
+ rolelist = s_test.deguidify('''
6
+ Roles:
7
+ ce6928dfe88cace918c405bbef51e72f - all
8
+ 0f316b3f3e6ec970fcdb9a085fcd5b77 - visi
9
+ '''.strip())
10
+
11
+ roleinfo = s_test.deguidify('''
12
+ Role: visi (145c3321a0cd0cd06de19174415a7aeb)
13
+
14
+ Rules:
15
+ [0 ] - !foo.bar.baz
16
+ [1 ] - foo.bar
17
+
18
+ Gates:
19
+ 3ad191c63a201df3246c6d6ff81763ad
20
+ Admin: False
21
+ [0 ] - !bar.baz.faz
22
+ [1 ] - bar.baz
23
+ '''.strip())
24
+
5
25
  class ModRoleTest(s_test.SynTest):
6
26
 
7
27
  async def test_tools_modrole(self):
@@ -40,6 +60,60 @@ class ModRoleTest(s_test.SynTest):
40
60
  self.true(bool(visi.allowed('foo.bar.gaz'.split('.'))))
41
61
  self.false(bool(visi.allowed('foo.bar.baz'.split('.'))))
42
62
 
63
+ gateiden = core.getLayer().iden
64
+ argv = (
65
+ '--svcurl', svcurl,
66
+ 'visi',
67
+ '--allow', 'bar.baz',
68
+ '--deny', 'bar.baz.faz',
69
+ '--gate', gateiden,
70
+ )
71
+ outp = s_output.OutPutStr()
72
+ self.eq(0, await s_t_modrole.main(argv, outp=outp))
73
+ self.isin(f'...adding allow rule: bar.baz on gate {gateiden}', str(outp))
74
+ self.isin(f'...adding deny rule: bar.baz.faz on gate {gateiden}', str(outp))
75
+
76
+ gate = await core.getAuthGate(gateiden)
77
+ for role in gate['roles']:
78
+ if role['iden'] == visi.iden:
79
+ self.isin((True, ('bar', 'baz')), role['rules'])
80
+ self.isin((False, ('bar', 'baz', 'faz')), role['rules'])
81
+
82
+ argv = (
83
+ '--svcurl', svcurl,
84
+ '--list',
85
+ )
86
+ outp = s_output.OutPutStr()
87
+ self.eq(0, await s_t_modrole.main(argv, outp=outp))
88
+ self.isin(rolelist, s_test.deguidify(str(outp)))
89
+
90
+ argv = (
91
+ '--svcurl', svcurl,
92
+ '--list',
93
+ 'visi',
94
+ )
95
+ outp = s_output.OutPutStr()
96
+ self.eq(0, await s_t_modrole.main(argv, outp=outp))
97
+ self.isin(roleinfo, s_test.deguidify(str(outp)))
98
+
99
+ argv = (
100
+ '--svcurl', svcurl,
101
+ '--list',
102
+ 'newprole',
103
+ )
104
+ outp = s_output.OutPutStr()
105
+ self.eq(1, await s_t_modrole.main(argv, outp=outp))
106
+ self.isin('ERROR: Role not found: newprole', str(outp))
107
+
108
+ argv = (
109
+ '--svcurl', svcurl,
110
+ 'visi',
111
+ '--gate', 'newp',
112
+ )
113
+ outp = s_output.OutPutStr()
114
+ self.eq(1, await s_t_modrole.main(argv, outp=outp))
115
+ self.isin('ERROR: No auth gate found with iden: newp', str(outp))
116
+
43
117
  argv = (
44
118
  '--svcurl', svcurl,
45
119
  '--add',
@@ -59,3 +133,10 @@ class ModRoleTest(s_test.SynTest):
59
133
  self.eq(0, await s_t_modrole.main(argv, outp=outp))
60
134
  self.isin('...deleting role: visi', str(outp))
61
135
  self.none(await core.auth.getRoleByName('visi'))
136
+
137
+ argv = (
138
+ '--svcurl', svcurl,
139
+ )
140
+ outp = s_output.OutPutStr()
141
+ self.eq(1, await s_t_modrole.main(argv, outp=outp))
142
+ self.isin('ERROR: A rolename argument is required when --list is not specified.', str(outp))
@@ -2,6 +2,32 @@ import synapse.lib.output as s_output
2
2
  import synapse.tests.utils as s_test
3
3
  import synapse.tools.moduser as s_t_moduser
4
4
 
5
+ userlist = '''
6
+ Users:
7
+ root
8
+ visi
9
+ '''.strip()
10
+
11
+ userinfo = s_test.deguidify('''
12
+ User: visi (04dddd4ff39e4ce00b36c7d526b9eac7)
13
+
14
+ Locked: False
15
+ Admin: False
16
+ Email: visi@test.com
17
+ Rules:
18
+ [0 ] - !foo.bar.baz
19
+ [1 ] - foo.bar
20
+
21
+ Roles:
22
+ 576a948f9944c58d3953f0d36bc2da81 - all
23
+
24
+ Gates:
25
+ c7b276154c0c799430668cb3c4cd259d
26
+ Admin: False
27
+ [0 ] - !bar.baz.faz
28
+ [1 ] - bar.baz
29
+ '''.strip())
30
+
5
31
  class ModUserTest(s_test.SynTest):
6
32
 
7
33
  async def test_tools_moduser(self):
@@ -124,6 +150,78 @@ class ModUserTest(s_test.SynTest):
124
150
  self.true(bool(visi.allowed('foo.bar.gaz'.split('.'))))
125
151
  self.false(bool(visi.allowed('foo.bar.baz'.split('.'))))
126
152
 
153
+ gateiden = core.getLayer().iden
154
+ argv = (
155
+ '--svcurl', svcurl,
156
+ 'visi',
157
+ '--admin', 'true',
158
+ '--gate', gateiden,
159
+ )
160
+ outp = s_output.OutPutStr()
161
+ self.eq(0, await s_t_moduser.main(argv, outp=outp))
162
+ self.isin(f'...setting admin: true on gate {gateiden}', str(outp))
163
+
164
+ gate = await core.getAuthGate(gateiden)
165
+ for user in gate['users']:
166
+ if user['iden'] == visi.iden:
167
+ self.true(user['admin'])
168
+
169
+ gateiden = core.getLayer().iden
170
+ argv = (
171
+ '--svcurl', svcurl,
172
+ 'visi',
173
+ '--admin', 'false',
174
+ '--allow', 'bar.baz',
175
+ '--deny', 'bar.baz.faz',
176
+ '--gate', gateiden,
177
+ )
178
+ outp = s_output.OutPutStr()
179
+ self.eq(0, await s_t_moduser.main(argv, outp=outp))
180
+ self.isin(f'...setting admin: false on gate {gateiden}', str(outp))
181
+ self.isin(f'...adding allow rule: bar.baz on gate {gateiden}', str(outp))
182
+ self.isin(f'...adding deny rule: bar.baz.faz on gate {gateiden}', str(outp))
183
+
184
+ gate = await core.getAuthGate(gateiden)
185
+ for user in gate['users']:
186
+ if user['iden'] == visi.iden:
187
+ self.isin((True, ('bar', 'baz')), user['rules'])
188
+ self.isin((False, ('bar', 'baz', 'faz')), user['rules'])
189
+
190
+ argv = (
191
+ '--svcurl', svcurl,
192
+ '--list',
193
+ )
194
+ outp = s_output.OutPutStr()
195
+ self.eq(0, await s_t_moduser.main(argv, outp=outp))
196
+ self.isin(userlist, str(outp))
197
+
198
+ argv = (
199
+ '--svcurl', svcurl,
200
+ '--list',
201
+ 'visi',
202
+ )
203
+ outp = s_output.OutPutStr()
204
+ self.eq(0, await s_t_moduser.main(argv, outp=outp))
205
+ self.isin(userinfo, s_test.deguidify(str(outp)))
206
+
207
+ argv = (
208
+ '--svcurl', svcurl,
209
+ '--list',
210
+ 'newpuser',
211
+ )
212
+ outp = s_output.OutPutStr()
213
+ self.eq(1, await s_t_moduser.main(argv, outp=outp))
214
+ self.isin('ERROR: User not found: newpuser', str(outp))
215
+
216
+ argv = (
217
+ '--svcurl', svcurl,
218
+ 'visi',
219
+ '--gate', 'newp',
220
+ )
221
+ outp = s_output.OutPutStr()
222
+ self.eq(1, await s_t_moduser.main(argv, outp=outp))
223
+ self.isin('ERROR: No auth gate found with iden: newp', str(outp))
224
+
127
225
  argv = (
128
226
  '--svcurl', svcurl,
129
227
  'visi',
@@ -151,3 +249,10 @@ class ModUserTest(s_test.SynTest):
151
249
  outp = s_output.OutPutStr()
152
250
  self.eq(1, await s_t_moduser.main(argv, outp=outp))
153
251
  self.isin('ERROR: User not found (need --add?): visi', str(outp))
252
+
253
+ argv = (
254
+ '--svcurl', svcurl,
255
+ )
256
+ outp = s_output.OutPutStr()
257
+ self.eq(1, await s_t_moduser.main(argv, outp=outp))
258
+ self.isin('ERROR: A username argument is required when --list is not specified.', str(outp))
synapse/tests/utils.py CHANGED
@@ -1444,7 +1444,7 @@ class SynTest(unittest.TestCase):
1444
1444
  Get an Aha cell that is configured for provisioning on aha.loop.vertex.link.
1445
1445
 
1446
1446
  Args:
1447
- conf: Optional configuraiton information for the Aha cell.
1447
+ conf: Optional configuration information for the Aha cell.
1448
1448
  dirn: Optional path to create the Aha cell in.
1449
1449
 
1450
1450
  Returns:
@@ -2344,6 +2344,8 @@ class SynTest(unittest.TestCase):
2344
2344
  return await core.nodes(query, opts)
2345
2345
  return await core.schedCoro(coro())
2346
2346
 
2347
+ ONLOAD_TIMEOUT = int(os.getenv('SYNDEV_PKG_LOAD_TIMEOUT', 30)) # seconds
2348
+
2347
2349
  class StormPkgTest(SynTest):
2348
2350
 
2349
2351
  vcr = None
@@ -2351,12 +2353,26 @@ class StormPkgTest(SynTest):
2351
2353
  pkgprotos = ()
2352
2354
 
2353
2355
  @contextlib.asynccontextmanager
2354
- async def getTestCore(self, conf=None, dirn=None):
2356
+ async def getTestCore(self, conf=None, dirn=None, prepkghook=None):
2355
2357
 
2356
2358
  async with SynTest.getTestCore(self, conf=None, dirn=None) as core:
2357
2359
 
2360
+ if prepkghook is not None:
2361
+ await prepkghook(core)
2362
+
2358
2363
  for pkgproto in self.pkgprotos:
2359
- self.eq(0, await s_genpkg.main((pkgproto, '--no-docs', '--push', core.getLocalUrl())))
2364
+
2365
+ pkgdef = s_genpkg.loadPkgProto(pkgproto, no_docs=True, readonly=True)
2366
+
2367
+ waiter = None
2368
+ if pkgdef.get('onload') is not None:
2369
+ waiter = core.waiter(1, 'core:pkg:onload:complete')
2370
+
2371
+ await core.addStormPkg(pkgdef)
2372
+
2373
+ if waiter is not None:
2374
+ self.nn(await waiter.wait(timeout=ONLOAD_TIMEOUT),
2375
+ f'Package onload failed to run for {pkgdef.get("name")}')
2360
2376
 
2361
2377
  if self.assetdir is not None:
2362
2378
 
@@ -2372,4 +2388,7 @@ class StormPkgTest(SynTest):
2372
2388
  yield core
2373
2389
 
2374
2390
  async def initTestCore(self, core):
2391
+ '''
2392
+ This is executed after the package has been loaded and a VCR context has been entered.
2393
+ '''
2375
2394
  pass
synapse/tools/autodoc.py CHANGED
@@ -717,7 +717,7 @@ async def docModel(outp,
717
717
  raise s_exc.SynErr(mesg='Invalid example', form=form, example=example, info=mnfo)
718
718
  if mtyp == 'node':
719
719
  node = True
720
- if not node: # pramga: no cover
720
+ if not node: # pragma: no cover
721
721
  raise s_exc.SynErr(mesg='Unable to make a node from example.', form=form, example=example)
722
722
 
723
723
  rst = s_autodoc.RstHelp()
@@ -14,6 +14,9 @@ reqver = '>=0.2.0,<3.0.0'
14
14
 
15
15
  async def main(argv, outp=s_output.stdout):
16
16
 
17
+ mesg = s_common.deprecated('synapse.tools.hive.load', curv='2.167.0')
18
+ outp.printf(f'WARNING: {mesg}')
19
+
17
20
  pars = argparse.ArgumentParser(prog='synapse.tools.hive.load',
18
21
  description='Load data into a remote hive from a previous hivesave.')
19
22
 
@@ -14,6 +14,9 @@ reqver = '>=0.2.0,<3.0.0'
14
14
 
15
15
  async def main(argv, outp=s_output.stdout):
16
16
 
17
+ mesg = s_common.deprecated('synapse.tools.hive.save', curv='2.167.0')
18
+ outp.printf(f'WARNING: {mesg}')
19
+
17
20
  pars = argparse.ArgumentParser(prog='synapse.tools.hive.save',
18
21
  description='Save tree data from a remote hive to file.')
19
22