synapse 2.213.0__py311-none-any.whl → 2.215.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 (76) hide show
  1. synapse/cortex.py +37 -6
  2. synapse/daemon.py +6 -6
  3. synapse/exc.py +13 -1
  4. synapse/lib/aha.py +5 -0
  5. synapse/lib/ast.py +2 -6
  6. synapse/lib/boss.py +47 -2
  7. synapse/lib/cell.py +193 -3
  8. synapse/lib/certdir.py +44 -1
  9. synapse/lib/cmd.py +24 -0
  10. synapse/lib/coro.py +8 -2
  11. synapse/lib/drive.py +7 -2
  12. synapse/lib/jsonstor.py +4 -1
  13. synapse/lib/layer.py +3 -1
  14. synapse/lib/link.py +11 -3
  15. synapse/lib/schemas.py +1 -1
  16. synapse/lib/snap.py +76 -65
  17. synapse/lib/storm.py +2 -1
  18. synapse/lib/stormlib/imap.py +3 -2
  19. synapse/lib/stormlib/spooled.py +1 -0
  20. synapse/lib/task.py +1 -0
  21. synapse/lib/version.py +2 -2
  22. synapse/models/inet.py +5 -0
  23. synapse/models/infotech.py +45 -0
  24. synapse/tests/files/testpkg_build_docs/docs/bar.rst +15 -0
  25. synapse/tests/files/testpkg_build_docs/docs/foo.rst +4 -0
  26. synapse/tests/files/testpkg_build_docs/storm/commands/testcmd.storm +0 -0
  27. synapse/tests/files/testpkg_build_docs/storm/modules/apimod.storm +0 -0
  28. synapse/tests/files/testpkg_build_docs/storm/modules/testmod.storm +0 -0
  29. synapse/tests/files/testpkg_build_docs/storm/testcmd.storm +5 -0
  30. synapse/tests/files/testpkg_build_docs/testpkg.yaml +69 -0
  31. synapse/tests/test_cortex.py +20 -1
  32. synapse/tests/test_daemon.py +1 -1
  33. synapse/tests/test_exc.py +6 -0
  34. synapse/tests/test_lib_ast.py +69 -14
  35. synapse/tests/test_lib_boss.py +8 -0
  36. synapse/tests/test_lib_cell.py +104 -5
  37. synapse/tests/test_lib_certdir.py +8 -0
  38. synapse/tests/test_lib_coro.py +5 -0
  39. synapse/tests/test_lib_httpapi.py +10 -2
  40. synapse/tests/test_lib_jsonstor.py +45 -0
  41. synapse/tests/test_lib_layer.py +10 -0
  42. synapse/tests/test_lib_link.py +1 -1
  43. synapse/tests/test_lib_storm.py +121 -1
  44. synapse/tests/test_lib_stormlib_iters.py +1 -1
  45. synapse/tests/test_lib_stormlib_spooled.py +20 -0
  46. synapse/tests/test_lib_stormtypes.py +15 -0
  47. synapse/tests/test_lib_types.py +5 -1
  48. synapse/tests/test_model_inet.py +7 -0
  49. synapse/tests/test_model_infotech.py +31 -0
  50. synapse/tests/test_telepath.py +32 -5
  51. synapse/tests/test_tools_axon.py +304 -0
  52. synapse/tests/test_tools_cortex_layer.py +419 -0
  53. synapse/tests/test_tools_demote.py +114 -0
  54. synapse/tests/test_tools_pkgs_gendocs.py +100 -0
  55. synapse/tests/test_tools_shutdown.py +95 -0
  56. synapse/tests/test_utils.py +22 -1
  57. synapse/tests/utils.py +44 -29
  58. synapse/tools/aha/easycert.py +2 -0
  59. synapse/tools/aha/enroll.py +3 -0
  60. synapse/tools/axon/__init__.py +0 -0
  61. synapse/tools/axon/dump.py +155 -0
  62. synapse/tools/axon/load.py +89 -0
  63. synapse/tools/cortex/__init__.py +0 -0
  64. synapse/tools/cortex/layer/__init__.py +0 -0
  65. synapse/tools/cortex/layer/dump.py +184 -0
  66. synapse/tools/cortex/layer/load.py +129 -0
  67. synapse/tools/demote.py +52 -0
  68. synapse/tools/healthcheck.py +1 -1
  69. synapse/tools/pkgs/gendocs.py +176 -0
  70. synapse/tools/pkgs/pandoc_filter.py +79 -0
  71. synapse/tools/shutdown.py +52 -0
  72. {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/METADATA +1 -1
  73. {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/RECORD +76 -53
  74. {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/WHEEL +0 -0
  75. {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/licenses/LICENSE +0 -0
  76. {synapse-2.213.0.dist-info → synapse-2.215.0.dist-info}/top_level.txt +0 -0
synapse/lib/cmd.py CHANGED
@@ -1,6 +1,11 @@
1
+ import sys
2
+ import asyncio
1
3
  import argparse
2
4
 
3
5
  import synapse.exc as s_exc
6
+ import synapse.common as s_common
7
+
8
+ import synapse.lib.coro as s_coro
4
9
  import synapse.lib.output as s_output
5
10
 
6
11
  class Parser(argparse.ArgumentParser):
@@ -25,6 +30,7 @@ class Parser(argparse.ArgumentParser):
25
30
 
26
31
  if message is not None:
27
32
  self.outp.printf(message)
33
+
28
34
  raise s_exc.ParserExit(mesg=message, status=status)
29
35
 
30
36
  def _print_message(self, text, fd=None):
@@ -32,3 +38,21 @@ class Parser(argparse.ArgumentParser):
32
38
  Note: this overrides an existing method in ArgumentParser
33
39
  '''
34
40
  self.outp.printf(text)
41
+
42
+ async def wrapmain(func): # pragma: no cover
43
+
44
+ try:
45
+ return await func(sys.argv[1:])
46
+
47
+ except s_exc.ParserExit:
48
+ return 1
49
+
50
+ except Exception as e:
51
+ print(f'ERROR: {s_exc.reprexc(e)}')
52
+ return 1
53
+
54
+ finally:
55
+ await s_coro.await_bg_tasks(timeout=10)
56
+
57
+ def exitmain(func): # pragma: no cover
58
+ sys.exit(asyncio.run(wrapmain(func)))
synapse/lib/coro.py CHANGED
@@ -175,10 +175,16 @@ def create_task(coro):
175
175
 
176
176
  return task
177
177
 
178
- async def await_bg_tasks():
178
+ async def await_bg_tasks(timeout=None):
179
+
179
180
  if not bgtasks:
180
181
  return []
181
- return await asyncio.gather(*tuple(bgtasks), return_exceptions=True)
182
+
183
+ coro = asyncio.gather(*tuple(bgtasks), return_exceptions=True)
184
+ try:
185
+ return await s_common.wait_for(coro, timeout)
186
+ except (asyncio.CancelledError, asyncio.TimeoutError):
187
+ return []
182
188
 
183
189
  class GenrHelp:
184
190
 
synapse/lib/drive.py CHANGED
@@ -69,6 +69,9 @@ class Drive(s_base.Base):
69
69
 
70
70
  def getItemInfo(self, iden, typename=None):
71
71
  info = self._getItemInfo(s_common.uhex(iden))
72
+ if not info:
73
+ return
74
+
72
75
  if typename is not None:
73
76
  self._reqInfoType(info, typename)
74
77
  return info
@@ -210,7 +213,7 @@ class Drive(s_base.Base):
210
213
 
211
214
  def _setItemPerm(self, bidn, perm):
212
215
  info = self._reqItemInfo(bidn)
213
- info['perm'] = perm
216
+ info['permissions'] = perm
214
217
  s_schemas.reqValidDriveInfo(info)
215
218
  self.slab.put(LKEY_INFO + bidn, s_msgpack.en(info), db=self.dbname)
216
219
  return info
@@ -286,7 +289,7 @@ class Drive(s_base.Base):
286
289
  info['kids'] = 0
287
290
  info['parent'] = pariden
288
291
 
289
- info.setdefault('perm', {'users': {}, 'roles': {}})
292
+ info.setdefault('permissions', {'users': {}, 'roles': {}})
290
293
  info.setdefault('version', (0, 0, 0))
291
294
 
292
295
  s_schemas.reqValidDriveInfo(info)
@@ -447,6 +450,8 @@ class Drive(s_base.Base):
447
450
 
448
451
  if vers is None:
449
452
  info = self._getItemInfo(bidn)
453
+ if info is None:
454
+ return None
450
455
  vers = info.get('version')
451
456
 
452
457
  versindx = getVersIndx(vers)
synapse/lib/jsonstor.py CHANGED
@@ -220,6 +220,7 @@ class JsonStor(s_base.Base):
220
220
 
221
221
  step[name] = valu
222
222
  self.dirty[buid] = item
223
+ self.slab.dirty = True
223
224
  return True
224
225
 
225
226
  async def delPathObjProp(self, path, prop):
@@ -241,6 +242,7 @@ class JsonStor(s_base.Base):
241
242
  step.pop(names[-1], None)
242
243
 
243
244
  self.dirty[buid] = item
245
+ self.slab.dirty = True
244
246
  return True
245
247
 
246
248
  async def cmpDelPathObjProp(self, path, prop, valu):
@@ -264,6 +266,7 @@ class JsonStor(s_base.Base):
264
266
 
265
267
  step.pop(name, None)
266
268
  self.dirty[buid] = item
269
+ self.slab.dirty = True
267
270
  return True
268
271
 
269
272
  async def popPathObjProp(self, path, prop, defv=None):
@@ -285,7 +288,7 @@ class JsonStor(s_base.Base):
285
288
 
286
289
  retn = step.pop(names[-1], defv)
287
290
  self.dirty[buid] = item
288
-
291
+ self.slab.dirty = True
289
292
  return retn
290
293
 
291
294
  class JsonStorApi(s_cell.CellApi):
synapse/lib/layer.py CHANGED
@@ -3569,6 +3569,7 @@ class Layer(s_nexus.Pusher):
3569
3569
 
3570
3570
  if not self.mayDelBuid(buid, sode):
3571
3571
  self.setSodeDirty(buid, sode, form)
3572
+ self.layrslab.dirty = True
3572
3573
 
3573
3574
  return (
3574
3575
  (EDIT_NODE_DEL, (valu, stortype), ()),
@@ -3842,8 +3843,9 @@ class Layer(s_nexus.Pusher):
3842
3843
  return ()
3843
3844
 
3844
3845
  oldv, oldt = tp_dict.pop(prop, (None, None))
3845
- if not tp_dict.get(tag):
3846
+ if not tp_dict:
3846
3847
  sode['tagprops'].pop(tag, None)
3848
+
3847
3849
  if oldv is None:
3848
3850
  self.mayDelBuid(buid, sode)
3849
3851
  return ()
synapse/lib/link.py CHANGED
@@ -61,7 +61,15 @@ async def unixconnect(path):
61
61
  '''
62
62
  Connect to a PF_UNIX server listening on the given path.
63
63
  '''
64
- reader, writer = await asyncio.open_unix_connection(path=path)
64
+ try:
65
+ reader, writer = await asyncio.open_unix_connection(path=path)
66
+ except ConnectionRefusedError as e:
67
+ mesg = f'Cell path is not listening: {path}'
68
+ raise s_exc.LinkErr(mesg=mesg) from e
69
+ except FileNotFoundError as e:
70
+ mesg = f'Cell path does not exist: {path}'
71
+ raise s_exc.NoSuchPath(mesg=mesg) from e
72
+
65
73
  info = {'path': path, 'unix': True}
66
74
  return await Link.anit(reader, writer, info=info)
67
75
 
@@ -321,9 +329,9 @@ class Link(s_base.Base):
321
329
  raise
322
330
 
323
331
  except Exception as e:
324
- mesg = f'rx error {e} link={self.getAddrInfo()}'
332
+ mesg = f'rx closed unexpectedly {e} link={self.getAddrInfo()}'
325
333
  if isinstance(e, (BrokenPipeError, ConnectionResetError)):
326
- logger.warning(mesg)
334
+ logger.debug(mesg)
327
335
  else:
328
336
  logger.exception(mesg)
329
337
  await self.fini()
synapse/lib/schemas.py CHANGED
@@ -469,7 +469,7 @@ driveInfoSchema = {
469
469
  'parent': {'type': 'string', 'pattern': s_config.re_iden},
470
470
  'type': {'type': 'string', 'pattern': re_drivename},
471
471
  'name': {'type': 'string', 'pattern': re_drivename},
472
- 'perm': s_msgpack.deepcopy(easyPermSchema),
472
+ 'permissions': s_msgpack.deepcopy(easyPermSchema),
473
473
  'kids': {'type': 'number', 'minimum': 0},
474
474
  'created': {'type': 'number'},
475
475
  'creator': {'type': 'string', 'pattern': s_config.re_iden},
synapse/lib/snap.py CHANGED
@@ -1454,7 +1454,9 @@ class Snap(s_base.Base):
1454
1454
  if isinstance(valu, dict):
1455
1455
  form = self.core.model.reqForm(name)
1456
1456
  if isinstance(form.type, s_types.Guid):
1457
- return await self._addGuidNodeByDict(form, valu, props=props)
1457
+ norms, props = await self._normGuidNodeDict(form, valu, props=props)
1458
+ valu = await self._addGuidNodeByDict(form, norms, props)
1459
+ return await self.getNodeByNdef((name, valu))
1458
1460
 
1459
1461
  async with self.getEditor() as editor:
1460
1462
  protonode = await editor.addNode(name, valu, props=props, norminfo=norminfo)
@@ -1464,100 +1466,109 @@ class Snap(s_base.Base):
1464
1466
  # the newly constructed node is cached
1465
1467
  return await self.getNodeByBuid(protonode.buid)
1466
1468
 
1467
- async def _addGuidNodeByDict(self, form, vals, props=None):
1469
+ async def _addGuidNodeByDict(self, form, norms, props):
1468
1470
 
1469
- if props is None:
1470
- props = {}
1471
-
1472
- trycast = vals.pop('$try', False)
1473
- addprops = vals.pop('$props', None)
1474
-
1475
- if not vals:
1476
- mesg = f'No values provided for form {form.full}'
1477
- raise s_exc.BadTypeValu(mesg=mesg)
1478
-
1479
- for name, valu in list(props.items()):
1480
- try:
1481
- props[name] = form.reqProp(name).type.norm(valu)
1482
- except s_exc.BadTypeValu as e:
1483
- mesg = e.get('mesg')
1484
- e.update({
1485
- 'prop': name,
1486
- 'form': form.name,
1487
- 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}',
1488
- })
1489
- raise e
1490
-
1491
- if addprops is not None:
1492
- for name, valu in addprops.items():
1493
- try:
1494
- props[name] = form.reqProp(name).type.norm(valu)
1495
- except s_exc.BadTypeValu as e:
1496
- mesg = e.get("mesg")
1497
- if not trycast:
1498
- e.update({
1499
- 'prop': name,
1500
- 'form': form.name,
1501
- 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}'
1502
- })
1503
- raise e
1504
- await self.warn(f'Skipping bad value for prop {form.name}:{name}: {mesg}')
1471
+ for name, info in norms.items():
1472
+ if info[0].isform:
1473
+ valu = await self._addGuidNodeByDict(*info)
1474
+ norms[name] = (form.prop(name), valu, {})
1505
1475
 
1506
- norms, proplist = self._normGuidNodeDict(form, vals)
1476
+ for name, info in props.items():
1477
+ if info[0].isform:
1478
+ valu = await self._addGuidNodeByDict(*info)
1479
+ props[name] = (form.prop(name), valu, {})
1507
1480
 
1508
- iden = s_common.guid(proplist)
1509
- node = await self._getGuidNodeByNorms(form, iden, norms)
1481
+ node = await self._getGuidNodeByNorms(form, norms)
1510
1482
 
1511
1483
  async with self.getEditor() as editor:
1512
1484
 
1513
1485
  if node is not None:
1514
1486
  proto = editor.loadNode(node)
1515
1487
  else:
1516
- proto = await editor.addNode(form.name, iden)
1488
+ proplist = [(name, info[1]) for name, info in norms.items()]
1489
+ proplist.sort()
1490
+
1491
+ proto = await editor.addNode(form.name, proplist)
1517
1492
  for name, (prop, valu, info) in norms.items():
1518
1493
  await proto.set(name, valu, norminfo=info)
1519
1494
 
1520
1495
  # ensure the non-deconf props are set
1521
- for name, (valu, info) in props.items():
1496
+ for name, (prop, valu, info) in props.items():
1522
1497
  await proto.set(name, valu, norminfo=info)
1523
1498
 
1524
- return await self.getNodeByBuid(proto.buid)
1499
+ return proto.valu
1500
+
1501
+ async def _normGuidNodeDict(self, form, vals, props=None):
1502
+
1503
+ if props is None:
1504
+ props = {}
1505
+
1506
+ trycast = vals.pop('$try', False)
1507
+ addprops = vals.pop('$props', None)
1508
+
1509
+ if not vals:
1510
+ mesg = f'No values provided for form {form.full}'
1511
+ raise s_exc.BadTypeValu(mesg=mesg)
1512
+
1513
+ props |= await self._normGuidNodeProps(form, props)
1525
1514
 
1526
- def _normGuidNodeDict(self, form, props):
1515
+ if addprops:
1516
+ props |= await self._normGuidNodeProps(form, addprops, trycast=trycast)
1517
+
1518
+ norms = await self._normGuidNodeProps(form, vals)
1519
+
1520
+ return norms, props
1521
+
1522
+ async def _normGuidNodeProps(self, form, props, trycast=False):
1527
1523
 
1528
1524
  norms = {}
1529
- proplist = []
1530
1525
 
1531
- for name, valu in props.items():
1526
+ for name, valu in list(props.items()):
1527
+ prop = form.reqProp(name)
1528
+
1529
+ if isinstance(valu, dict) and isinstance(prop.type, s_types.Guid):
1530
+ pform = self.core.model.reqForm(prop.type.name)
1531
+ gnorm, gprop = await self._normGuidNodeDict(pform, valu)
1532
+ norms[name] = (pform, gnorm, gprop)
1533
+ continue
1532
1534
 
1533
1535
  try:
1534
- prop = form.reqProp(name)
1535
- norm, norminfo = prop.type.norm(valu)
1536
+ norms[name] = (prop, *prop.type.norm(valu))
1536
1537
 
1537
- norms[name] = (prop, norm, norminfo)
1538
- proplist.append((name, norm))
1539
1538
  except s_exc.BadTypeValu as e:
1540
- mesg = e.get('mesg')
1541
- e.update({
1542
- 'prop': name,
1543
- 'form': form.name,
1544
- 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}',
1545
- })
1546
- raise e
1547
-
1548
- proplist.sort()
1539
+ if not trycast:
1540
+ if 'prop' not in e.errinfo:
1541
+ mesg = e.get('mesg')
1542
+ e.update({
1543
+ 'prop': name,
1544
+ 'form': form.name,
1545
+ 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}',
1546
+ })
1547
+ raise e
1549
1548
 
1550
- return norms, proplist
1549
+ return norms
1551
1550
 
1552
1551
  async def _getGuidNodeByDict(self, form, props):
1553
- norms, proplist = self._normGuidNodeDict(form, props)
1554
- return await self._getGuidNodeByNorms(form, s_common.guid(proplist), norms)
1552
+ norms, _ = await self._normGuidNodeDict(form, props)
1553
+ return await self._getGuidNodeByNorms(form, norms)
1554
+
1555
+ async def _getGuidNodeByNorms(self, form, norms):
1555
1556
 
1556
- async def _getGuidNodeByNorms(self, form, iden, norms):
1557
+ proplist = []
1558
+ for name, info in norms.items():
1559
+ if info[0].isform:
1560
+ if (node := await self._getGuidNodeByNorms(*info[:2])) is None:
1561
+ return
1562
+ valu = node.ndef[1]
1563
+ norms[name] = (form.prop(name), valu, {})
1564
+ proplist.append((name, valu))
1565
+ else:
1566
+ proplist.append((name, info[1]))
1557
1567
 
1558
1568
  # check first for an exact match via our same deconf strategy
1569
+ proplist.sort()
1559
1570
 
1560
- node = await self.getNodeByNdef((form.full, iden))
1571
+ node = await self.getNodeByNdef((form.full, s_common.guid(proplist)))
1561
1572
  if node is not None:
1562
1573
 
1563
1574
  # ensure we still match the property deconf criteria
synapse/lib/storm.py CHANGED
@@ -1454,7 +1454,8 @@ class StormDmon(s_base.Base):
1454
1454
  viewiden = opts.get('view')
1455
1455
 
1456
1456
  info = {'iden': self.iden, 'name': self.ddef.get('name', 'storm dmon'), 'view': viewiden}
1457
- await self.core.boss.promote('storm:dmon', user=self.user, info=info)
1457
+
1458
+ await self.core.boss.promote('storm:dmon', user=self.user, info=info, background=True)
1458
1459
 
1459
1460
  def dmonPrint(evnt):
1460
1461
  self._runLogAdd(evnt)
@@ -4,6 +4,7 @@ import aioimaplib
4
4
 
5
5
  import synapse.exc as s_exc
6
6
  import synapse.common as s_common
7
+ import synapse.lib.coro as s_coro
7
8
  import synapse.lib.stormtypes as s_stormtypes
8
9
 
9
10
  async def run_imap_coro(coro):
@@ -88,8 +89,8 @@ class ImapLib(s_stormtypes.Lib):
88
89
  imap_cli = aioimaplib.IMAP4(host=host, port=port, timeout=timeout)
89
90
 
90
91
  async def fini():
91
- # call protocol.logout() so fini() doesn't hang
92
- await s_common.wait_for(imap_cli.protocol.logout(), 5)
92
+ # call protocol.logout() via a background task
93
+ s_coro.create_task(s_common.wait_for(imap_cli.protocol.logout(), 5))
93
94
 
94
95
  self.runt.snap.onfini(fini)
95
96
 
@@ -37,6 +37,7 @@ class LibSpooled(s_stormtypes.Lib):
37
37
  async def _methSet(self, *vals):
38
38
  core = self.runt.snap.core
39
39
  spool = await s_spooled.Set.anit(dirn=core.dirn, cell=core, size=1000)
40
+ self.runt.snap.onfini(spool)
40
41
 
41
42
  valu = list(vals)
42
43
  for item in valu:
synapse/lib/task.py CHANGED
@@ -22,6 +22,7 @@ class Task(s_base.Base):
22
22
  info = {}
23
23
 
24
24
  self.boss = boss
25
+ self.background = False
25
26
 
26
27
  task._syn_task = self
27
28
 
synapse/lib/version.py CHANGED
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
223
223
  ##############################################################################
224
224
  # The following are touched during the release process by bumpversion.
225
225
  # Do not modify these directly.
226
- version = (2, 213, 0)
226
+ version = (2, 215, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = 'e3d843a470b137e9d2094b69a7878101afb4f8b1'
228
+ commit = 'f4d48839f7e5f74bacdcc2d1b122d9ade6f1def7'
synapse/models/inet.py CHANGED
@@ -1780,6 +1780,8 @@ class InetModule(s_module.CoreModule):
1780
1780
  ('remover', ('inet:service:account', {}), {
1781
1781
  'doc': 'The service account which removed or decommissioned the {service:base}.'}),
1782
1782
 
1783
+ ('app', ('inet:service:app', {}), {
1784
+ 'doc': 'The app which contains the {service:base}.'}),
1783
1785
  ),
1784
1786
  }),
1785
1787
 
@@ -3748,6 +3750,9 @@ class InetModule(s_module.CoreModule):
3748
3750
 
3749
3751
  ('tenant', ('inet:service:tenant', {}), {
3750
3752
  'doc': 'The tenant which contains the instance.'}),
3753
+
3754
+ ('app', ('inet:service:app', {}), {
3755
+ 'doc': 'The app which contains the instance.'}),
3751
3756
  )),
3752
3757
 
3753
3758
  ('inet:service:app', {}, (
@@ -849,6 +849,14 @@ class ItModule(s_module.CoreModule):
849
849
  ('it:adid', ('str', {'lower': True, 'strip': True}), {
850
850
  'doc': 'An advertising identification string.'}),
851
851
 
852
+ # https://learn.microsoft.com/en-us/windows-hardware/drivers/install/hklm-system-currentcontrolset-services-registry-tree
853
+ ('it:os:windows:service', ('guid', {}), {
854
+ 'doc': 'A Microsoft Windows service configuration on a host.'}),
855
+
856
+ # TODO
857
+ # ('it:os:windows:task', ('guid', {}), {
858
+ # 'doc': 'A Microsoft Windows scheduled task configuration.'}),
859
+
852
860
  # https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/c92a27b1-c772-4fa7-a432-15df5f1b66a1
853
861
  ('it:os:windows:sid', ('str', {'regex': r'^S-1-(?:\d{1,10}|0x[0-9a-fA-F]{12})(?:-(?:\d+|0x[0-9a-fA-F]{2,}))*$'}), {
854
862
  'doc': 'A Microsoft Windows Security Identifier.',
@@ -2582,7 +2590,44 @@ class ItModule(s_module.CoreModule):
2582
2590
  ('sandbox:file', ('file:bytes', {}), {
2583
2591
  'doc': 'The initial sample given to a sandbox environment to analyze.'
2584
2592
  }),
2593
+
2594
+ # TODO
2595
+ # ('windows:task', ('it:os:windows:task', {}), {
2596
+ # 'doc': 'The Microsoft Windows scheduled task responsible for starting the process.'}),
2597
+
2598
+ ('windows:service', ('it:os:windows:service', {}), {
2599
+ 'doc': 'The Microsoft Windows service responsible for starting the process.'}),
2600
+ )),
2601
+
2602
+ ('it:os:windows:service', {}, (
2603
+
2604
+ ('host', ('it:host', {}), {
2605
+ 'doc': 'The host that the service was configured on.'}),
2606
+
2607
+ ('name', ('str', {'lower': True, 'onespace': True}), {
2608
+ 'doc': 'The name of the service from the registry key within Services.'}),
2609
+
2610
+ # TODO flags...
2611
+ ('type', ('int', {'min': 0}), {
2612
+ 'doc': 'The type of service from the Type registry key.'}),
2613
+
2614
+ ('start', ('int', {'min': 0}), {
2615
+ 'doc': 'The start configuration of the service from the Start registry key.'}),
2616
+
2617
+ ('errorcontrol', ('int', {'min': 0}), {
2618
+ 'doc': 'The service error handling behavior from the ErrorControl registry key.'}),
2619
+
2620
+ ('displayname', ('str', {'lower': True, 'onespace': True}), {
2621
+ 'doc': 'The friendly name of the service from the DisplayName registry key.'}),
2622
+
2623
+ # TODO 3.0 text
2624
+ ('description', ('str', {}), {
2625
+ 'doc': 'The description of the service from the Description registry key.'}),
2626
+
2627
+ ('imagepath', ('file:path', {}), {
2628
+ 'doc': 'The path to the service binary from the ImagePath registry key.'}),
2585
2629
  )),
2630
+
2586
2631
  ('it:query', {}, ()),
2587
2632
  ('it:exec:query', {}, (
2588
2633
 
@@ -0,0 +1,15 @@
1
+ :tocdepth: 2
2
+
3
+ :orphan:
4
+
5
+ .. highlight:: none
6
+ .. storm-cortex:: default
7
+
8
+ Bar
9
+ ---
10
+
11
+ A wild node appears!
12
+
13
+ .. storm-cli:: [inet:asn=1]
14
+
15
+ Words!
@@ -0,0 +1,4 @@
1
+ Hello world
2
+ -----------
3
+
4
+ Words
@@ -0,0 +1,5 @@
1
+ $lib.debug = $cmdopts.debug
2
+
3
+ $lib.print('Testcmd!')
4
+
5
+ if $lib.debug { $lib.print('Debug enabled!') }
@@ -0,0 +1,69 @@
1
+ name: testpkg
2
+ version: 1.2.3
3
+ synapse_version: ">=2.64.0,<3.0.0"
4
+
5
+ genopts:
6
+ dotstorm: true
7
+
8
+ author:
9
+ url: https://vertex.link
10
+ name: The Vertex Project, LLC.
11
+
12
+ desc: The test package does things
13
+
14
+ docs:
15
+ - title: Foo
16
+ path: docs/_build/foo.md
17
+ - title: Bar
18
+ path: docs/_build/bar.md
19
+ - title: Package Documentation
20
+ path: docs/_build/stormpackage.md
21
+
22
+ modules:
23
+ - name: testmod
24
+ - name: apimod
25
+ apidefs:
26
+ - name: search
27
+ desc: |
28
+ Execute a search
29
+
30
+ This API will foo the bar.
31
+
32
+ Examples:
33
+ Foo the ``bar``::
34
+
35
+ yield $lib.import(apimod).search(bar)
36
+
37
+ Baz the bam::
38
+
39
+ yield $lib.import(apimod).search(bam)
40
+
41
+ type:
42
+ type: function
43
+ args:
44
+ - { name: text, type: str, desc: "The text." }
45
+ - { name: mintime, type: [str, int], desc: "The mintime.", default: "-30days" }
46
+ - { name: foo, type: str, desc: "The foo." }
47
+ - { name: bar, type: str, desc: "The bar." }
48
+ - { name: baz, type: str, desc: "The baz." }
49
+ returns:
50
+ name: yields
51
+ type: node
52
+ desc: Yields it:dev:str nodes.
53
+ - name: status
54
+ desc: Get the status of the foo.
55
+ type:
56
+ type: function
57
+ returns:
58
+ type: dict
59
+ desc: A status dictionary.
60
+
61
+ commands:
62
+ - name: testcmd
63
+ descr: |
64
+ A testcmd!
65
+ cmdargs:
66
+ - - --debug
67
+ - default: false
68
+ action: store_true
69
+ help: Show verbose debug output.
@@ -5785,6 +5785,12 @@ class CortexBasicTest(s_t_utils.SynTest):
5785
5785
  ddef = await core01.callStorm('return($lib.dmon.get($iden))', opts=opts)
5786
5786
  self.none(ddef)
5787
5787
 
5788
+ await core00.callStorm('queue.del hehe')
5789
+ await core01.sync()
5790
+
5791
+ self.none(await core00.getAuthGate('queue:hehe'))
5792
+ self.none(await core01.getAuthGate('queue:hehe'))
5793
+
5788
5794
  # now lets start up in the opposite order...
5789
5795
  async with self.getTestCore(dirn=path01, conf=core01conf) as core01:
5790
5796
 
@@ -5889,7 +5895,7 @@ class CortexBasicTest(s_t_utils.SynTest):
5889
5895
 
5890
5896
  # consumer offline
5891
5897
  await asyncio.sleep(0)
5892
- await self.asyncraises(ConnectionRefusedError, core00.callStorm(strim, opts=opts))
5898
+ await self.asyncraises(s_exc.LinkErr, core00.callStorm(strim, opts=opts))
5893
5899
 
5894
5900
  # admin can still cull and break the mirror
5895
5901
  await core00.nodes('[ inet:ipv4=127.0.0.1/28 ]')
@@ -8478,6 +8484,14 @@ class CortexBasicTest(s_t_utils.SynTest):
8478
8484
  self.eq(msgs[1].get('hash'), qhash)
8479
8485
  self.eq(msgs[1].get('pool:from'), f'00.core.{ahanet}')
8480
8486
 
8487
+ with self.getLoggerStream('synapse') as stream:
8488
+ core01.boss.is_shutdown = True
8489
+ self.stormHasNoWarnErr(await core00.stormlist('inet:asn=0'))
8490
+ core01.boss.is_shutdown = False
8491
+
8492
+ stream.seek(0)
8493
+ self.isin('Proxy for pool mirror [01.core.synapse] is shutting down. Skipping.', stream.read())
8494
+
8481
8495
  with patch('synapse.cortex.CoreApi.getNexsIndx', _hang):
8482
8496
 
8483
8497
  with self.getLoggerStream('synapse') as stream:
@@ -8761,3 +8775,8 @@ class CortexBasicTest(s_t_utils.SynTest):
8761
8775
  self.eq(core._test_post_service_storage_index, offs)
8762
8776
  self.eq(core._test_pre_nexus_index, offs)
8763
8777
  self.ge(core._test_post_nexus_index, core._test_pre_nexus_index)
8778
+
8779
+ async def test_cortex_queue_mirror_authgates(self):
8780
+ async with self.getRegrCore('2.213.0-queue-authgates') as core:
8781
+ self.nn(await core.getAuthGate('queue:stillhere'))
8782
+ self.none(await core.getAuthGate('queue:authtest'))