synapse 2.165.0__py311-none-any.whl → 2.166.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (51) hide show
  1. synapse/cmds/cortex.py +1 -6
  2. synapse/common.py +6 -0
  3. synapse/cortex.py +73 -56
  4. synapse/datamodel.py +32 -0
  5. synapse/lib/agenda.py +81 -51
  6. synapse/lib/ast.py +21 -23
  7. synapse/lib/base.py +0 -6
  8. synapse/lib/cell.py +13 -22
  9. synapse/lib/httpapi.py +1 -0
  10. synapse/lib/nexus.py +3 -2
  11. synapse/lib/schemas.py +2 -0
  12. synapse/lib/snap.py +50 -0
  13. synapse/lib/storm.py +19 -17
  14. synapse/lib/stormlib/aha.py +4 -1
  15. synapse/lib/stormlib/auth.py +11 -4
  16. synapse/lib/stormlib/cache.py +202 -0
  17. synapse/lib/stormlib/cortex.py +69 -7
  18. synapse/lib/stormlib/spooled.py +109 -0
  19. synapse/lib/stormtypes.py +43 -15
  20. synapse/lib/trigger.py +10 -12
  21. synapse/lib/types.py +1 -1
  22. synapse/lib/version.py +2 -2
  23. synapse/lib/view.py +12 -0
  24. synapse/models/inet.py +74 -2
  25. synapse/models/orgs.py +52 -8
  26. synapse/models/person.py +30 -11
  27. synapse/models/risk.py +44 -3
  28. synapse/telepath.py +114 -32
  29. synapse/tests/test_cortex.py +40 -6
  30. synapse/tests/test_datamodel.py +22 -0
  31. synapse/tests/test_lib_agenda.py +8 -1
  32. synapse/tests/test_lib_aha.py +18 -4
  33. synapse/tests/test_lib_storm.py +95 -4
  34. synapse/tests/test_lib_stormlib_cache.py +272 -0
  35. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  36. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  37. synapse/tests/test_lib_stormtypes.py +27 -4
  38. synapse/tests/test_model_inet.py +67 -0
  39. synapse/tests/test_model_risk.py +6 -0
  40. synapse/tests/test_telepath.py +30 -7
  41. synapse/tests/test_tools_modrole.py +81 -0
  42. synapse/tests/test_tools_moduser.py +105 -0
  43. synapse/tools/modrole.py +59 -7
  44. synapse/tools/moduser.py +78 -10
  45. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
  46. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/RECORD +49 -47
  47. synapse/lib/provenance.py +0 -111
  48. synapse/tests/test_lib_provenance.py +0 -37
  49. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
  50. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +0 -0
  51. {synapse-2.165.0.dist-info → synapse-2.166.0.dist-info}/top_level.txt +0 -0
@@ -361,10 +361,13 @@ class AgendaTest(s_t_utils.SynTest):
361
361
 
362
362
  # schedule a query to run every Wednesday and Friday at 10:15am
363
363
  cdef = {'creator': visi.iden, 'iden': s_common.guid(), 'storm': '$lib.queue.gen(visi).put(bar)',
364
+ 'pool': True,
364
365
  'reqs': {s_tu.HOUR: 10, s_tu.MINUTE: 15},
365
366
  'incunit': s_agenda.TimeUnit.DAYOFWEEK,
366
367
  'incvals': (2, 4)}
367
368
  adef = await agenda.add(cdef)
369
+
370
+ self.true(adef['pool'])
368
371
  guid = adef.get('iden')
369
372
 
370
373
  self.len(1, agenda.apptheap)
@@ -634,7 +637,7 @@ class AgendaTest(s_t_utils.SynTest):
634
637
  nodes = await core.nodes('test:int=97', opts={'view': newview})
635
638
  self.len(0, nodes)
636
639
 
637
- async def test_agenda_edit_creator(self):
640
+ async def test_agenda_edit(self):
638
641
 
639
642
  async with self.getTestCore() as core:
640
643
 
@@ -645,8 +648,12 @@ class AgendaTest(s_t_utils.SynTest):
645
648
  self.stormHasNoWarnErr(msgs)
646
649
 
647
650
  cdef = await core.callStorm('for $cron in $lib.cron.list() { return($cron) }')
651
+ self.false(cdef['pool'])
648
652
  self.eq(cdef['creator'], core.auth.rootuser.iden)
649
653
 
654
+ cdef = await core.callStorm('for $cron in $lib.cron.list() { $cron.set(pool, (true)) return($cron) }')
655
+ self.true(cdef['pool'])
656
+
650
657
  opts = {'vars': {'lowuser': lowuser}}
651
658
  cdef = await core.callStorm('for $cron in $lib.cron.list() { return($cron.set(creator, $lowuser)) }',
652
659
  opts=opts)
@@ -186,8 +186,8 @@ class AhaTest(s_test.SynTest):
186
186
  self.nn(await proxy.getCellIden())
187
187
 
188
188
  with self.raises(s_exc.BadArg):
189
- await cryo.ahaclient.waitready(timeout=2)
190
- await cryo.ahaclient.modAhaSvcInfo('cryo.mynet', {'newp': 'newp'})
189
+ _proxy = await cryo.ahaclient.proxy(timeout=2)
190
+ await _proxy.modAhaSvcInfo('cryo.mynet', {'newp': 'newp'})
191
191
 
192
192
  async with await s_telepath.openurl('aha://root:secret@0.cryo.mynet') as proxy:
193
193
  self.nn(await proxy.getCellIden())
@@ -1169,13 +1169,24 @@ class AhaTest(s_test.SynTest):
1169
1169
  self.stormHasNoWarnErr(msgs)
1170
1170
  self.stormIsInPrint('Created AHA service pool: pool00.loop.vertex.link', msgs)
1171
1171
 
1172
- with self.raises(s_exc.BadArg):
1173
- await s_telepath.open('aha://pool00...')
1172
+ # Pool has no members....
1173
+ pool = await s_telepath.open('aha://pool00...')
1174
+ self.eq(0, pool.size())
1175
+ waiter = pool.waiter(0, 'svc:add')
1174
1176
 
1175
1177
  msgs = await core00.stormlist('aha.pool.svc.add pool00... 00...')
1176
1178
  self.stormHasNoWarnErr(msgs)
1177
1179
  self.stormIsInPrint('AHA service (00...) added to service pool (pool00.loop.vertex.link)', msgs)
1178
1180
 
1181
+ self.len(1, await waiter.wait(timeout=12))
1182
+ prox = await pool.proxy(timeout=12)
1183
+ info = await prox.getCellInfo()
1184
+ self.eq('00', info.get('cell').get('aha').get('name'))
1185
+ self.eq(1, pool.size())
1186
+ await pool.fini()
1187
+ self.eq(0, pool.size())
1188
+ self.true(prox.isfini)
1189
+
1179
1190
  poolinfo = await aha.getAhaPool('pool00...')
1180
1191
  self.len(1, poolinfo['services'])
1181
1192
 
@@ -1184,6 +1195,9 @@ class AhaTest(s_test.SynTest):
1184
1195
  self.stormIsInPrint(' 00.loop.vertex.link', msgs)
1185
1196
  self.stormIsInPrint('1 pools', msgs)
1186
1197
 
1198
+ msgs = await core00.stormlist('$lib.print($lib.aha.pool.get(pool00.loop.vertex.link))')
1199
+ self.stormIsInPrint('aha:pool: pool00.loop.vertex.link', msgs)
1200
+
1187
1201
  async with await s_telepath.open('aha://pool00...') as pool:
1188
1202
 
1189
1203
  replay = s_common.envbool('SYNDEV_NEXUS_REPLAY')
@@ -1262,7 +1262,7 @@ class StormTest(s_t_utils.SynTest):
1262
1262
  query = await core.getStormQuery('')
1263
1263
  async with snap.getStormRuntime(query) as runt:
1264
1264
  with self.raises(s_exc.AuthDeny):
1265
- runt.reqAdmin(gateiden='cortex')
1265
+ runt.reqAdmin(gateiden=layr)
1266
1266
 
1267
1267
  await core.stormlist('[ inet:fqdn=vertex.link ]')
1268
1268
  fork = await core.callStorm('return($lib.view.get().fork().iden)')
@@ -1772,13 +1772,92 @@ class StormTest(s_t_utils.SynTest):
1772
1772
  self.eq('796d67b92a6ffe9b88fa19d115b46ab6712d673a06ae602d41de84b1464782f2', node[1]['embeds']['asn']['*'])
1773
1773
 
1774
1774
  opts = {'embeds': {'ou:org': {'hq::email': ('user',)}}}
1775
- msgs = await core.stormlist('[ ou:org=* :hq=* ] { -> ps:contact [ :email=visi@vertex.link ] }', opts=opts)
1775
+ msgs = await core.stormlist('[ ou:org=* :country=* :hq=* ] { -> ps:contact [ :email=visi@vertex.link ] }', opts=opts)
1776
1776
  nodes = [m[1] for m in msgs if m[0] == 'node']
1777
-
1778
1777
  node = nodes[0]
1778
+
1779
1779
  self.eq('visi', node[1]['embeds']['hq::email']['user'])
1780
1780
  self.eq('2346d7bed4b0fae05e00a413bbf8716c9e08857eb71a1ecf303b8972823f2899', node[1]['embeds']['hq::email']['*'])
1781
1781
 
1782
+ fork = await core.callStorm('return($lib.view.get().fork().iden)')
1783
+
1784
+ opts['vars'] = {
1785
+ 'md5': '12345a5758eea935f817dd1490a322a5',
1786
+ 'sha1': '40b8e76cff472e593bd0ba148c09fec66ae72362'
1787
+ }
1788
+ opts['view'] = fork
1789
+ opts['show:storage'] = True
1790
+ opts['embeds']['ou:org']['lol::nope'] = ('notreal',)
1791
+ opts['embeds']['ou:org']['country::flag'] = ('md5', 'sha1')
1792
+ opts['embeds']['ou:org']['country::tld'] = ('domain',)
1793
+
1794
+ await core.stormlist('pol:country [ :flag={[ file:bytes=* :md5=fa818a259cbed7ce8bc2a22d35a464fc ]} ]')
1795
+
1796
+ msgs = await core.stormlist('''
1797
+ ou:org {
1798
+ -> pol:country
1799
+ [ :tld=co.uk ]
1800
+ {
1801
+ :flag -> file:bytes [ :md5=$md5 :sha1=$sha1 ]
1802
+ }
1803
+ }
1804
+ ''', opts=opts)
1805
+ nodes = [m[1] for m in msgs if m[0] == 'node']
1806
+ node = nodes[0]
1807
+
1808
+ storage = node[1]['storage']
1809
+ self.len(2, storage)
1810
+ top = storage[0].get('embeds')
1811
+ bot = storage[1].get('embeds')
1812
+ self.nn(top)
1813
+ self.nn(bot)
1814
+
1815
+ self.nn(top.get('country::flag::md5'))
1816
+ self.eq(top['country::flag::md5'][0], '12345a5758eea935f817dd1490a322a5')
1817
+
1818
+ self.nn(top.get('country::flag::sha1'))
1819
+ self.eq(top['country::flag::sha1'][0], '40b8e76cff472e593bd0ba148c09fec66ae72362')
1820
+
1821
+ self.nn(top.get('country::tld::domain'))
1822
+ self.eq(top['country::tld::domain'][0], 'uk')
1823
+
1824
+ self.nn(bot.get('hq::email::user'))
1825
+ self.eq(bot['hq::email::user'][0], 'visi')
1826
+
1827
+ self.nn(bot.get('country::flag::md5'))
1828
+ self.eq(bot['country::flag::md5'][0], 'fa818a259cbed7ce8bc2a22d35a464fc')
1829
+
1830
+ empty = await core.callStorm('return($lib.view.get().fork().iden)', opts=opts)
1831
+ opts['view'] = empty
1832
+
1833
+ msgs = await core.stormlist('ou:org', opts=opts)
1834
+ nodes = [m[1] for m in msgs if m[0] == 'node']
1835
+ node = nodes[0]
1836
+ storage = node[1]['storage']
1837
+ self.len(3, storage)
1838
+ top = storage[0].get('embeds')
1839
+ mid = storage[1].get('embeds')
1840
+ bot = storage[2].get('embeds')
1841
+ self.none(top)
1842
+
1843
+ self.nn(mid)
1844
+ self.nn(bot)
1845
+
1846
+ self.nn(mid.get('country::flag::md5'))
1847
+ self.eq(mid['country::flag::md5'][0], '12345a5758eea935f817dd1490a322a5')
1848
+
1849
+ self.nn(mid.get('country::flag::sha1'))
1850
+ self.eq(mid['country::flag::sha1'][0], '40b8e76cff472e593bd0ba148c09fec66ae72362')
1851
+
1852
+ self.nn(mid.get('country::tld::domain'))
1853
+ self.eq(mid['country::tld::domain'][0], 'uk')
1854
+
1855
+ self.nn(bot.get('hq::email::user'))
1856
+ self.eq(bot['hq::email::user'][0], 'visi')
1857
+
1858
+ self.nn(bot.get('country::flag::md5'))
1859
+ self.eq(bot['country::flag::md5'][0], 'fa818a259cbed7ce8bc2a22d35a464fc')
1860
+
1782
1861
  async def test_storm_wget(self):
1783
1862
 
1784
1863
  async def _getRespFromSha(core, mesgs):
@@ -2151,7 +2230,7 @@ class StormTest(s_t_utils.SynTest):
2151
2230
 
2152
2231
  # Max recursion fail
2153
2232
  q = '[ inet:fqdn=www.vertex.link ] | tree { inet:fqdn=www.vertex.link }'
2154
- await self.asyncraises(s_exc.StormRuntimeError, core.nodes(q))
2233
+ await self.asyncraises(s_exc.RecursionLimitHit, core.nodes(q))
2155
2234
 
2156
2235
  # Runtsafety test
2157
2236
  q = '[ inet:fqdn=www.vertex.link ] $q=:domain | tree $q'
@@ -2359,6 +2438,18 @@ class StormTest(s_t_utils.SynTest):
2359
2438
  with self.raises(s_exc.BadOperArg):
2360
2439
  await core.nodes('movetag this is')
2361
2440
 
2441
+ async with self.getTestCore() as core:
2442
+ await core.nodes('[ syn:tag=hehe :isnow=haha ]')
2443
+ nodes = await core.nodes('[ ou:org=* +#hehe.qwer ]')
2444
+ self.len(1, nodes)
2445
+ self.nn(nodes[0].getTag('haha.qwer'))
2446
+ self.none(nodes[0].getTag('hehe.qwer'))
2447
+ self.len(1, await core.nodes('syn:tag=haha.qwer'))
2448
+
2449
+ # this should hit the already existing redirected tag now...
2450
+ nodes = await core.nodes('[ ou:org=* +#hehe.qwer ]')
2451
+ self.len(1, nodes)
2452
+
2362
2453
  # Sad path
2363
2454
  async with self.getTestCore() as core:
2364
2455
  # Test moving a tag to itself
@@ -0,0 +1,272 @@
1
+ import synapse.exc as s_exc
2
+
3
+ import synapse.tests.utils as s_test
4
+
5
+ class StormlibCacheTest(s_test.SynTest):
6
+
7
+ async def test_storm_lib_cache_fixed(self):
8
+
9
+ async with self.getTestCore() as core:
10
+
11
+ # basics
12
+
13
+ rets = await core.callStorm('''
14
+ $rets = ([])
15
+ $cache = $lib.cache.fixed("return(`{$cache_key}-ret`)")
16
+
17
+ $cache.clear()
18
+
19
+ $rets.append($lib.len($cache))
20
+
21
+ $rets.append($cache.get(key))
22
+ $rets.append($lib.len($cache))
23
+
24
+ $cache.put(key, key-put)
25
+ $rets.append($cache.get(key))
26
+
27
+ $cache.clear()
28
+ $rets.append($cache.get(key))
29
+
30
+ $cache.put(key, key-put)
31
+ $rets.append($cache.get(key))
32
+ $rets.append($cache.pop(key))
33
+ $rets.append($cache.get(key))
34
+
35
+ $rets.append($cache.pop(newp))
36
+
37
+ $rets.append($cache.query)
38
+
39
+ return($rets)
40
+ ''')
41
+ self.eq([
42
+ 0,
43
+ 'key-ret', 1,
44
+ 'key-put',
45
+ 'key-ret',
46
+ 'key-put', 'key-put', 'key-ret',
47
+ None,
48
+ 'return(`{$cache_key}-ret`)'
49
+ ], rets)
50
+
51
+ # exhaust size
52
+
53
+ rets = await core.callStorm('''
54
+ $rets = ([])
55
+ $cache = $lib.cache.fixed("return(`{$cache_key}-ret`)", size=2)
56
+
57
+ $cache.put(one, one-put)
58
+ $cache.put(two, two-put)
59
+ $rets.append($cache.get(one))
60
+ $rets.append($cache.get(two))
61
+
62
+ $rets.append($cache.get(three))
63
+ $rets.append($cache.get(one))
64
+
65
+ return($rets)
66
+ ''')
67
+ self.eq(['one-put', 'two-put', 'three-ret', 'one-ret'], rets)
68
+
69
+ # also accept a storm query object
70
+
71
+ ret = await core.callStorm('''
72
+ $cache = $lib.cache.fixed(${ $suf=ret return(`{$cache_key}-{$suf}`)})
73
+ return($cache.get(foo))
74
+ ''')
75
+ self.eq('foo-ret', ret)
76
+
77
+ # callback runtime scoping
78
+
79
+ ## a function still has the outer scope as its root
80
+ rets = await core.callStorm('''
81
+ $val = zero
82
+ $sent = $lib.null
83
+
84
+ function cb(key) {
85
+ $sent = $val
86
+ return(`{$key}-{$val}`)
87
+ }
88
+
89
+ $cache = $lib.cache.fixed("return($cb($cache_key))")
90
+
91
+ $rets = ([])
92
+
93
+ $rets.append($cache.get(foo))
94
+ $rets.append($sent)
95
+
96
+ $val = one
97
+ $rets.append($cache.get(bar))
98
+ $rets.append($sent)
99
+
100
+ return($rets)
101
+ ''')
102
+ self.eq([
103
+ 'foo-zero', 'zero',
104
+ 'bar-one', 'one'
105
+ ], rets)
106
+
107
+ ## runtime also can modify refs to the outer scope
108
+ rets = await core.callStorm('''
109
+ $val = zero
110
+ $vals = ([])
111
+ $sent = $lib.null
112
+
113
+ $cache = $lib.cache.fixed(${
114
+ $sent = $val
115
+ $vals.append($cache_key)
116
+ return(`{$cache_key}-{$val}`)
117
+ })
118
+
119
+ $rets = ([])
120
+
121
+ $rets.append($cache.get(foo))
122
+ $rets.append($sent)
123
+ $rets.append($lib.str.join(",", $vals))
124
+
125
+ $val = one
126
+ $rets.append($cache.get(bar))
127
+ $rets.append($sent)
128
+ $rets.append($lib.str.join(",", $vals))
129
+
130
+ return($rets)
131
+ ''')
132
+ self.eq([
133
+ 'foo-zero', None, 'foo',
134
+ 'bar-one', None, 'foo,bar',
135
+ ], rets)
136
+
137
+ ## default to null w/o a return
138
+ self.none(await core.callStorm('return($lib.cache.fixed("if (0) { return(yup) }").get(foo))'))
139
+
140
+ ## control flow exceptions don't propagate up
141
+ rets = await core.callStorm('''
142
+ $cache = $lib.cache.fixed( ${ if ($cache_key < (2)) { return (`key={$cache_key}`) } else { break } } )
143
+
144
+ $rets = ([])
145
+
146
+ for $i in $lib.range(4) {
147
+ $rets.append($cache.get($i))
148
+ }
149
+
150
+ $rets.append(`i={$i}`)
151
+ return($rets)
152
+ ''')
153
+ self.eq(['key=0', 'key=1', None, None, 'i=3'], rets)
154
+
155
+ ## control flow scoped inside the callback
156
+ rets = await core.callStorm("""
157
+ $cache = $lib.cache.fixed('''
158
+ $vals = ([])
159
+ for $i in $lib.range(3) {
160
+ $vals.append(`key={$cache_key} i={$i}`)
161
+ break
162
+ }
163
+ return($vals)
164
+ ''')
165
+
166
+ $rets = ([])
167
+
168
+ for $k in (foo, bar, baz) {
169
+ $rets.append($cache.get($k))
170
+ }
171
+
172
+ return($rets)
173
+ """)
174
+ self.eq([('key=foo i=0',), ('key=bar i=0',), ('key=baz i=0',),], rets)
175
+
176
+ ## coverage for the cb runtime emiting nodes
177
+ rets = await core.callStorm('''
178
+ $rets = ([])
179
+ $cache = $lib.cache.fixed(${ if (0) { return(yup) } [ inet:ipv4=$cache_key ] })
180
+
181
+ for $i in (0, 1) {
182
+ $rets.append($cache.get($i))
183
+ }
184
+ return($rets)
185
+ ''')
186
+ self.eq([None, None], rets)
187
+
188
+ # stormrepr
189
+
190
+ msgs = await core.stormlist('''
191
+ $lib.print($lib.cache.fixed(${return(cool)}))
192
+ $lib.print($lib.cache.fixed($longq))
193
+ ''', opts={'vars': {'longq': f'return({"a" * 150})'}})
194
+ self.stormIsInPrint('cache:fixed: size=10000 query="return(cool)"', msgs)
195
+ self.stormIsInPrint('aaaaa...', msgs)
196
+
197
+ # sad
198
+
199
+ ## bad storm query
200
+
201
+ with self.raises(s_exc.BadArg) as ectx:
202
+ await core.nodes('$lib.cache.fixed("function x -> newp")')
203
+ self.isin('Invalid callback query', ectx.exception.errinfo.get('mesg'))
204
+
205
+ ## no return
206
+
207
+ with self.raises(s_exc.BadArg) as ectx:
208
+ await core.nodes('$lib.cache.fixed("$x=1")')
209
+ self.eq('Callback query must return a value', ectx.exception.errinfo.get('mesg'))
210
+
211
+ ## bad size
212
+
213
+ with self.raises(s_exc.BadArg) as ectx:
214
+ await core.nodes('$lib.cache.fixed("return()", size=(-1))')
215
+ self.eq('Cache size must be between 1-10000', ectx.exception.errinfo.get('mesg'))
216
+
217
+ with self.raises(s_exc.BadArg) as ectx:
218
+ await core.nodes('$lib.cache.fixed("return()", size=(1000000))')
219
+ self.eq('Cache size must be between 1-10000', ectx.exception.errinfo.get('mesg'))
220
+
221
+ ## callback raises an exception
222
+
223
+ rets = await core.callStorm('''
224
+ function cb(key) {
225
+ if ($key = "sad") {
226
+ $lib.raise(Bad, Time)
227
+ }
228
+ return(`{$key}-happy`)
229
+ }
230
+ $cache = $lib.cache.fixed("return($cb($cache_key))")
231
+
232
+ $rets = ([])
233
+
234
+ try {
235
+ $rets.append($cache.get(sad))
236
+ } catch Bad as e {
237
+ $rets.append(badtime)
238
+ }
239
+
240
+ $rets.append($cache.get(foo))
241
+
242
+ return($rets)
243
+ ''')
244
+ self.eq(['badtime', 'foo-happy'], rets)
245
+
246
+ with self.raises(s_exc.BadCast) as ectx:
247
+ await core.nodes('$lib.cache.fixed(${ return(($cache_key * 3)) }).get(foo)')
248
+ self.eq('Failed to make an integer from \'foo\'.', ectx.exception.errinfo.get('mesg'))
249
+
250
+ ## mutable key
251
+
252
+ with self.raises(s_exc.BadArg) as ectx:
253
+ await core.nodes('$lib.cache.fixed("return()").get((foo,))')
254
+ self.eq('Mutable values are not allowed as cache keys', ectx.exception.errinfo.get('mesg'))
255
+
256
+ with self.raises(s_exc.BadArg) as ectx:
257
+ await core.nodes('$lib.cache.fixed("return()").put((foo,), bar)')
258
+ self.eq('Mutable values are not allowed as cache keys', ectx.exception.errinfo.get('mesg'))
259
+
260
+ with self.raises(s_exc.BadArg) as ectx:
261
+ await core.nodes('$lib.cache.fixed("return()").pop((foo,))')
262
+ self.eq('Mutable values are not allowed as cache keys', ectx.exception.errinfo.get('mesg'))
263
+
264
+ ## non-primable key
265
+
266
+ with self.raises(s_exc.NoSuchType) as ectx:
267
+ await core.nodes('$cache = $lib.cache.fixed("return()") $cache.get($cache)')
268
+ self.eq('Unable to convert object to Storm primitive.', ectx.exception.errinfo.get('mesg'))
269
+
270
+ ## missing use of $cache_key - no error
271
+
272
+ self.eq('newp', await core.callStorm('return($lib.cache.fixed("return(newp)").get(foo))'))
@@ -1,5 +1,7 @@
1
1
  import json
2
2
 
3
+ import unittest.mock as mock
4
+
3
5
  import aiohttp
4
6
 
5
7
  import synapse.common as s_common
@@ -393,6 +395,9 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
393
395
  return ( $api.iden )
394
396
  '''
395
397
  iden0 = await core.callStorm(q)
398
+ msgs = await core.stormlist('$lib.print($lib.cortex.httpapi.get($iden))', opts={'vars': {'iden': iden0}})
399
+ mesg = 'http:api: the hehe wildcard handler (********************************), path=hehe/([a-z0-9]*)'
400
+ self.stormIsInPrint(mesg, msgs, deguid=True)
396
401
 
397
402
  q = '''
398
403
  $api = $lib.cortex.httpapi.add('hehe/haha')
@@ -401,6 +406,7 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
401
406
  $api.name = 'the hehe/haha handler'
402
407
  $api.desc = 'beep boop zoop robot captain'
403
408
  $api.runas = user
409
+ $api.pool = (true)
404
410
  $api.perms = (
405
411
  ({"perm": ["hehe", "haha"]}),
406
412
  ({"perm": ["some", "thing"], "default": $lib.true}),
@@ -428,6 +434,9 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
428
434
  return ( $api.iden )
429
435
  '''
430
436
  iden3 = await core.callStorm(q)
437
+ msgs = await core.stormlist('$lib.print($lib.cortex.httpapi.get($iden))', opts={'vars': {'iden': iden3}})
438
+ mesg = 'http:api: <no name> (********************************), path=wow'
439
+ self.stormIsInPrint(mesg, msgs, deguid=True)
431
440
 
432
441
  # $lib.dict accessor methods
433
442
  q = '$api=$lib.cortex.httpapi.get($iden) return ($lib.dict.keys($api.vars))'
@@ -473,6 +482,15 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
473
482
  self.stormIsInPrint(f'2 {iden2}', msgs)
474
483
  self.stormIsInPrint(f'3 {iden3}', msgs)
475
484
 
485
+ q = '''
486
+ $ret = $lib.null $api = $lib.cortex.httpapi.getByPath($path)
487
+ if $api { $ret = $api.iden}
488
+ return ( $ret )
489
+ '''
490
+ self.eq(iden0, await core.callStorm(q, opts={'vars': {'path': 'hehe/haha'}}))
491
+ self.eq(iden0, await core.callStorm(q, opts={'vars': {'path': 'hehe/ohmy'}}))
492
+ self.none(await core.callStorm(q, opts={'vars': {'path': 'newpnewpnewp'}}))
493
+
476
494
  # Order matters. The hehe/haha path occurs after the wildcard.
477
495
  async with self.getHttpSess(auth=('root', 'root'), port=hport) as sess:
478
496
  resp = await sess.get(f'https://localhost:{hport}/api/ext/hehe/haha')
@@ -494,6 +512,9 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
494
512
  msgs = await core.stormlist('cortex.httpapi.index $iden 1', opts={'vars': {'iden': iden0}})
495
513
  self.stormIsInPrint(f'Set HTTP API {iden0} to index 1', msgs)
496
514
 
515
+ self.eq(iden1, await core.callStorm(q, opts={'vars': {'path': 'hehe/haha'}}))
516
+ self.eq(iden0, await core.callStorm(q, opts={'vars': {'path': 'hehe/ohmy'}}))
517
+
497
518
  msgs = await core.stormlist('cortex.httpapi.list')
498
519
  self.stormIsInPrint(f'0 {iden1}', msgs)
499
520
  self.stormIsInPrint(f'1 {iden0}', msgs)
@@ -562,6 +583,7 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
562
583
  self.stormIsInPrint('Owner: root', msgs)
563
584
  self.stormIsInPrint('Runas: owner', msgs)
564
585
  self.stormIsInPrint('Readonly: false', msgs)
586
+ self.stormIsInPrint('Pool enabled: false', msgs)
565
587
  self.stormIsInPrint('Authenticated: true', msgs)
566
588
  self.stormIsInPrint('Name: the hehe wildcard handler', msgs)
567
589
  self.stormIsInPrint('Description: wildcard words', msgs)
@@ -596,6 +618,7 @@ $request.reply(206, headers=$headers, body=({"no":"body"}))
596
618
  self.stormIsInPrint('Owner: root', msgs)
597
619
  self.stormIsInPrint('Runas: user', msgs)
598
620
  self.stormIsInPrint('Readonly: false', msgs)
621
+ self.stormIsInPrint('Pool enabled: true', msgs)
599
622
  self.stormIsInPrint('Authenticated: true', msgs)
600
623
  self.stormIsInPrint('Name: the hehe/haha handler', msgs)
601
624
  self.stormIsInPrint('Description: beep boop zoop robot captain', msgs)
@@ -1373,3 +1396,51 @@ for $i in $values {
1373
1396
  self.none(resp.headers.get('X-Content-Type-Options'))
1374
1397
  # Server is still omitted though
1375
1398
  self.none(resp.headers.get('Server'))
1399
+
1400
+ async def test_cortex_httpapi_pool(self):
1401
+
1402
+ # Test if we pass the mirror value in opts or not.
1403
+ async with self.getTestCore(conf={'https:headers': {'Key1': 'Valu1'}}) as core:
1404
+ await core.setUserPasswd(core.auth.rootuser.iden, 'root')
1405
+ addr, hport = await core.addHttpsPort(0)
1406
+
1407
+ q = '''$api = $lib.cortex.httpapi.add(stuff)
1408
+ $api.methods.get = ${
1409
+ $request.reply(200, headers=({"Weee": "valu"}) )
1410
+ }
1411
+ return ( ($api.iden) )'''
1412
+ iden00 = await core.callStorm(q)
1413
+ opts_iden00 = {'vars': {'iden': iden00}}
1414
+
1415
+ data = {}
1416
+
1417
+ oldstorm = core.storm
1418
+ async def storm(self, text, opts=None):
1419
+ data['opts'] = opts
1420
+ async for mesg in oldstorm(text, opts=opts):
1421
+ yield mesg
1422
+
1423
+ with mock.patch('synapse.cortex.Cortex.storm', new=storm) as patch:
1424
+ async with self.getHttpSess(auth=('root', 'root'), port=hport) as sess:
1425
+ resp = await sess.get(f'https://localhost:{hport}/api/ext/stuff') # type: aiohttp.ClientResponse
1426
+ self.eq(resp.status, 200)
1427
+ self.false(data['opts'].get('mirror'))
1428
+ data.clear()
1429
+
1430
+ q = '$api=$lib.cortex.httpapi.get($iden) $api.pool = (true) return ( $api.pack() ) '
1431
+ adef = await core.callStorm(q, opts=opts_iden00)
1432
+ self.true(adef.get('pool'))
1433
+
1434
+ resp = await sess.get(f'https://localhost:{hport}/api/ext/stuff') # type: aiohttp.ClientResponse
1435
+ self.eq(resp.status, 200)
1436
+ self.true(data['opts'].get('mirror'))
1437
+ data.clear()
1438
+
1439
+ q = '$api=$lib.cortex.httpapi.get($iden) $api.pool = (false) return ( $api.pack() ) '
1440
+ adef = await core.callStorm(q, opts=opts_iden00)
1441
+ self.false(adef.get('pool'))
1442
+
1443
+ resp = await sess.get(f'https://localhost:{hport}/api/ext/stuff') # type: aiohttp.ClientResponse
1444
+ self.eq(resp.status, 200)
1445
+ self.false(data['opts'].get('mirror'))
1446
+ data.clear()