synapse 2.214.0__py311-none-any.whl → 2.216.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 (69) hide show
  1. synapse/cortex.py +17 -2
  2. synapse/lib/cell.py +12 -0
  3. synapse/lib/cmd.py +6 -2
  4. synapse/lib/jsonstor.py +4 -1
  5. synapse/lib/layer.py +13 -6
  6. synapse/lib/schemas.py +9 -2
  7. synapse/lib/snap.py +15 -5
  8. synapse/lib/storm.py +1 -1
  9. synapse/lib/types.py +3 -0
  10. synapse/lib/version.py +2 -2
  11. synapse/lib/view.py +16 -7
  12. synapse/models/inet.py +7 -1
  13. synapse/models/infotech.py +45 -0
  14. synapse/models/risk.py +2 -0
  15. synapse/tests/test_cortex.py +262 -0
  16. synapse/tests/test_lib_auth.py +2 -0
  17. synapse/tests/test_lib_jsonstor.py +45 -0
  18. synapse/tests/test_lib_layer.py +10 -0
  19. synapse/tests/test_lib_storm.py +52 -1
  20. synapse/tests/test_lib_stormlib_iters.py +1 -1
  21. synapse/tests/test_lib_stormsvc.py +2 -2
  22. synapse/tests/test_lib_stormtypes.py +15 -0
  23. synapse/tests/test_lib_types.py +11 -1
  24. synapse/tests/test_model_inet.py +2 -0
  25. synapse/tests/test_model_infotech.py +31 -0
  26. synapse/tests/test_tools_cryo_cat.py +3 -8
  27. synapse/tests/test_tools_storm.py +3 -2
  28. synapse/tests/utils.py +2 -0
  29. synapse/tools/aha/clone.py +3 -13
  30. synapse/tools/aha/easycert.py +5 -18
  31. synapse/tools/aha/enroll.py +3 -12
  32. synapse/tools/aha/list.py +2 -15
  33. synapse/tools/aha/mirror.py +3 -14
  34. synapse/tools/aha/provision/service.py +3 -13
  35. synapse/tools/aha/provision/user.py +3 -12
  36. synapse/tools/apikey.py +3 -13
  37. synapse/tools/autodoc.py +7 -19
  38. synapse/tools/axon2axon.py +1 -9
  39. synapse/tools/cellauth.py +5 -14
  40. synapse/tools/changelog.py +12 -16
  41. synapse/tools/cmdr.py +2 -6
  42. synapse/tools/cryo/cat.py +5 -15
  43. synapse/tools/cryo/list.py +3 -10
  44. synapse/tools/csvtool.py +40 -49
  45. synapse/tools/demote.py +1 -6
  46. synapse/tools/docker/validate.py +0 -1
  47. synapse/tools/easycert.py +3 -8
  48. synapse/tools/feed.py +7 -18
  49. synapse/tools/genpkg.py +3 -12
  50. synapse/tools/guid.py +4 -6
  51. synapse/tools/healthcheck.py +4 -11
  52. synapse/tools/json2mpk.py +1 -5
  53. synapse/tools/livebackup.py +3 -13
  54. synapse/tools/modrole.py +3 -12
  55. synapse/tools/moduser.py +3 -12
  56. synapse/tools/pkgs/gendocs.py +1 -1
  57. synapse/tools/promote.py +3 -13
  58. synapse/tools/pullfile.py +6 -18
  59. synapse/tools/pushfile.py +6 -18
  60. synapse/tools/reload.py +5 -14
  61. synapse/tools/rstorm.py +4 -12
  62. synapse/tools/shutdown.py +1 -2
  63. synapse/tools/snapshot.py +3 -14
  64. synapse/tools/storm.py +4 -12
  65. {synapse-2.214.0.dist-info → synapse-2.216.0.dist-info}/METADATA +1 -1
  66. {synapse-2.214.0.dist-info → synapse-2.216.0.dist-info}/RECORD +69 -69
  67. {synapse-2.214.0.dist-info → synapse-2.216.0.dist-info}/WHEEL +0 -0
  68. {synapse-2.214.0.dist-info → synapse-2.216.0.dist-info}/licenses/LICENSE +0 -0
  69. {synapse-2.214.0.dist-info → synapse-2.216.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py CHANGED
@@ -758,6 +758,12 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
758
758
  confbase['mirror']['hidedocs'] = False # type: ignore
759
759
  confbase['mirror']['hidecmdl'] = False # type: ignore
760
760
 
761
+ confbase['safemode']['hidecmdl'] = False
762
+ confbase['safemode']['description'] = (
763
+ 'Enable safe-mode which disables crons, triggers, dmons, storm '
764
+ 'package onload handlers, view merge tasks, and storm pools.'
765
+ )
766
+
761
767
  confdefs = {
762
768
  'axon': {
763
769
  'description': 'A telepath URL for a remote axon.',
@@ -1572,9 +1578,11 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1572
1578
  if self.isactive:
1573
1579
  await self._checkLayerModels()
1574
1580
 
1575
- self.addActiveCoro(self.agenda.runloop)
1581
+ if not self.safemode:
1582
+ self.addActiveCoro(self.agenda.runloop)
1576
1583
 
1577
1584
  await self._initStormDmons()
1585
+
1578
1586
  await self._initStormSvcs()
1579
1587
 
1580
1588
  # share ourself via the cell dmon as "cortex"
@@ -1621,6 +1629,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1621
1629
 
1622
1630
  async def initStormPool(self):
1623
1631
 
1632
+ if self.safemode:
1633
+ return
1634
+
1624
1635
  try:
1625
1636
 
1626
1637
  byts = self.slab.get(b'storm:pool', db='cell:conf')
@@ -1959,7 +1970,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
1959
1970
 
1960
1971
  try:
1961
1972
  await self.auth.delAuthGate(f'queue:{name}')
1962
- except NoSuchAuthGate: # pragma: no cover
1973
+ except s_exc.NoSuchAuthGate:
1963
1974
  pass
1964
1975
 
1965
1976
  await self.multiqueue.rem(name)
@@ -2961,6 +2972,10 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
2961
2972
 
2962
2973
  if onload is not None and self.isactive:
2963
2974
  async def _onload():
2975
+ if self.safemode:
2976
+ await self.fire('core:pkg:onload:skipped', pkg=name, reason='safemode')
2977
+ return
2978
+
2964
2979
  await self.fire('core:pkg:onload:start', pkg=name)
2965
2980
  try:
2966
2981
  async for mesg in self.storm(onload):
synapse/lib/cell.py CHANGED
@@ -930,6 +930,12 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
930
930
 
931
931
  confdefs = {} # type: ignore # This should be a JSONSchema properties list for an object.
932
932
  confbase = {
933
+ 'safemode': {
934
+ 'default': False,
935
+ 'description': 'Boot the service in safe-mode.',
936
+ 'type': 'boolean',
937
+ 'hidecmdl': True,
938
+ },
933
939
  'cell:guid': {
934
940
  'description': 'An optional hard-coded GUID to store as the permanent GUID for the service.',
935
941
  'type': 'string',
@@ -1200,6 +1206,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
1200
1206
  'tasks': 1,
1201
1207
  }
1202
1208
 
1209
+ self.safemode = self.conf.req('safemode')
1210
+ if self.safemode:
1211
+ mesg = f'Booting {self.getCellType()} in safe-mode. Some functionality may be disabled.'
1212
+ logger.warning(mesg)
1213
+
1203
1214
  self.minfree = self.conf.get('limit:disk:free')
1204
1215
  if self.minfree is not None:
1205
1216
  self.minfree = self.minfree / 100
@@ -4816,6 +4827,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
4816
4827
  'iden': self.getCellIden(),
4817
4828
  'paused': self.paused,
4818
4829
  'active': self.isactive,
4830
+ 'safemode': self.safemode,
4819
4831
  'started': self.startms,
4820
4832
  'ready': self.nexsroot.ready.is_set(),
4821
4833
  'commit': self.COMMIT,
synapse/lib/cmd.py CHANGED
@@ -3,15 +3,19 @@ import asyncio
3
3
  import argparse
4
4
 
5
5
  import synapse.exc as s_exc
6
- import synapse.common as s_common
7
6
 
8
7
  import synapse.lib.coro as s_coro
9
8
  import synapse.lib.output as s_output
10
9
 
11
10
  class Parser(argparse.ArgumentParser):
11
+ '''
12
+ argparse.ArgumentParser helper class.
12
13
 
14
+ - exit() is overriden to raise a SynErr ( ParserExit )
15
+ - _print_message prints to an outp object
16
+ - description formatter uses argparse.RawDescriptionHelpFormatter
17
+ '''
13
18
  def __init__(self, prog=None, outp=s_output.stdout, **kwargs):
14
-
15
19
  self.outp = outp
16
20
  self.exited = False
17
21
 
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
@@ -3489,7 +3489,10 @@ class Layer(s_nexus.Pusher):
3489
3489
 
3490
3490
  valt = edit[1]
3491
3491
  valu, stortype = valt
3492
- if sode.get('valu') == valt:
3492
+
3493
+ isarray = stortype & STOR_FLAG_ARRAY
3494
+
3495
+ if not isarray and sode.get('valu') == valt:
3493
3496
  return ()
3494
3497
 
3495
3498
  abrv = self.setPropAbrv(form, None)
@@ -3500,7 +3503,7 @@ class Layer(s_nexus.Pusher):
3500
3503
  sode['valu'] = valt
3501
3504
  self.setSodeDirty(buid, sode, form)
3502
3505
 
3503
- if stortype & STOR_FLAG_ARRAY:
3506
+ if isarray:
3504
3507
 
3505
3508
  for indx in self.getStorIndx(stortype, valu):
3506
3509
  self.layrslab.put(abrv + indx, buid, db=self.byarray)
@@ -3569,6 +3572,7 @@ class Layer(s_nexus.Pusher):
3569
3572
 
3570
3573
  if not self.mayDelBuid(buid, sode):
3571
3574
  self.setSodeDirty(buid, sode, form)
3575
+ self.layrslab.dirty = True
3572
3576
 
3573
3577
  return (
3574
3578
  (EDIT_NODE_DEL, (valu, stortype), ()),
@@ -3586,6 +3590,8 @@ class Layer(s_nexus.Pusher):
3586
3590
  if prop[0] == '.': # '.' to detect universal props (as quickly as possible)
3587
3591
  univabrv = self.setPropAbrv(None, prop)
3588
3592
 
3593
+ isarray = stortype & STOR_FLAG_ARRAY
3594
+
3589
3595
  if oldv is not None:
3590
3596
 
3591
3597
  # merge intervals and min times
@@ -3598,7 +3604,7 @@ class Layer(s_nexus.Pusher):
3598
3604
  elif stortype == STOR_TYPE_MAXTIME:
3599
3605
  valu = max(valu, oldv)
3600
3606
 
3601
- if valu == oldv and stortype == oldt:
3607
+ if not isarray and valu == oldv and stortype == oldt:
3602
3608
  return ()
3603
3609
 
3604
3610
  if oldt & STOR_FLAG_ARRAY:
@@ -3637,7 +3643,7 @@ class Layer(s_nexus.Pusher):
3637
3643
  sode['props'][prop] = (valu, stortype)
3638
3644
  self.setSodeDirty(buid, sode, form)
3639
3645
 
3640
- if stortype & STOR_FLAG_ARRAY:
3646
+ if isarray:
3641
3647
 
3642
3648
  realtype = stortype & 0x7fff
3643
3649
 
@@ -3827,7 +3833,7 @@ class Layer(s_nexus.Pusher):
3827
3833
  kvpairs.append((tp_abrv + indx, buid))
3828
3834
  kvpairs.append((ftp_abrv + indx, buid))
3829
3835
 
3830
- await self.layrslab.putmulti(kvpairs, db=self.bytagprop)
3836
+ self.layrslab._putmulti(kvpairs, db=self.bytagprop)
3831
3837
 
3832
3838
  return (
3833
3839
  (EDIT_TAGPROP_SET, (tag, prop, valu, oldv, stortype), ()),
@@ -3842,8 +3848,9 @@ class Layer(s_nexus.Pusher):
3842
3848
  return ()
3843
3849
 
3844
3850
  oldv, oldt = tp_dict.pop(prop, (None, None))
3845
- if not tp_dict.get(tag):
3851
+ if not tp_dict:
3846
3852
  sode['tagprops'].pop(tag, None)
3853
+
3847
3854
  if oldv is None:
3848
3855
  self.mayDelBuid(buid, sode)
3849
3856
  return ()
synapse/lib/schemas.py CHANGED
@@ -297,11 +297,18 @@ _authRulesSchema = {
297
297
  'type': 'array',
298
298
  'items': [
299
299
  {'type': 'boolean'},
300
- {'type': 'array', 'items': {'type': 'string'}},
300
+ {
301
+ 'type': 'array',
302
+ 'items': {
303
+ 'type': 'string',
304
+ 'minLength': 1
305
+ },
306
+ 'minItems': 1
307
+ },
301
308
  ],
302
309
  'minItems': 2,
303
310
  'maxItems': 2,
304
- }
311
+ },
305
312
  }
306
313
  reqValidRules = s_config.getJsValidator(_authRulesSchema)
307
314
 
synapse/lib/snap.py CHANGED
@@ -384,12 +384,22 @@ class ProtoNode:
384
384
 
385
385
  if norminfo is None:
386
386
  try:
387
- valu, norminfo = prop.type.norm(valu)
387
+ if (isinstance(valu, dict) and isinstance(prop.type, s_types.Guid)
388
+ and (form := self.ctx.snap.core.model.form(prop.type.name)) is not None):
389
+
390
+ norms, props = await self.ctx.snap._normGuidNodeDict(form, valu)
391
+ valu = await self.ctx.snap._addGuidNodeByDict(form, norms, props)
392
+ norminfo = {}
393
+ else:
394
+ valu, norminfo = prop.type.norm(valu)
395
+
388
396
  except s_exc.BadTypeValu as e:
389
- oldm = e.get('mesg')
390
- e.update({'prop': prop.name,
391
- 'form': prop.form.name,
392
- 'mesg': f'Bad prop value {prop.full}={valu!r} : {oldm}'})
397
+ if 'prop' not in e.errinfo:
398
+ oldm = e.get('mesg')
399
+ e.update({'prop': prop.name,
400
+ 'form': prop.form.name,
401
+ 'mesg': f'Bad prop value {prop.full}={valu!r} : {oldm}'})
402
+
393
403
  if self.ctx.snap.strict:
394
404
  raise e
395
405
  await self.ctx.snap.warn(e)
synapse/lib/storm.py CHANGED
@@ -1363,7 +1363,7 @@ class DmonManager(s_base.Base):
1363
1363
  '''
1364
1364
  Start all the dmons.
1365
1365
  '''
1366
- if self.enabled:
1366
+ if self.enabled or self.core.safemode:
1367
1367
  return
1368
1368
  dmons = list(self.dmons.values())
1369
1369
  if not dmons:
synapse/lib/types.py CHANGED
@@ -625,6 +625,9 @@ class Guid(Type):
625
625
  )
626
626
 
627
627
  def _normPyList(self, valu):
628
+ if not valu:
629
+ mesg = 'Guid list values cannot be empty.'
630
+ raise s_exc.BadTypeValu(name=self.name, valu=valu, mesg=mesg)
628
631
  return s_common.guid(valu), {}
629
632
 
630
633
  def _normPyStr(self, valu):
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, 214, 0)
226
+ version = (2, 216, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = '41e2ed0599236256e9452b8afeb152660e68e2c2'
228
+ commit = '2a44a91a495a7daf2e4e6e44d32c1c3030db3fd2'
synapse/lib/view.py CHANGED
@@ -260,6 +260,9 @@ class View(s_nexus.Pusher): # type: ignore
260
260
  if self.merging: # pragma: no cover
261
261
  return
262
262
 
263
+ if self.core.safemode:
264
+ return
265
+
263
266
  if not await self.isMergeReady():
264
267
  return
265
268
 
@@ -380,6 +383,9 @@ class View(s_nexus.Pusher): # type: ignore
380
383
  if not await self.core.isCellActive():
381
384
  return
382
385
 
386
+ if self.core.safemode:
387
+ return
388
+
383
389
  self.mergetask = self.core.schedCoro(self.runViewMerge())
384
390
 
385
391
  async def finiMergeTask(self):
@@ -568,6 +574,9 @@ class View(s_nexus.Pusher): # type: ignore
568
574
  if not await self.core.isCellActive():
569
575
  return
570
576
 
577
+ if self.core.safemode:
578
+ return
579
+
571
580
  self.trigtask = self.schedCoro(self._trigQueueLoop())
572
581
 
573
582
  async def finiTrigTask(self):
@@ -1577,7 +1586,7 @@ class View(s_nexus.Pusher): # type: ignore
1577
1586
 
1578
1587
  async def runTagAdd(self, node, tag, valu):
1579
1588
 
1580
- if self.core.migration:
1589
+ if self.core.migration or self.core.safemode:
1581
1590
  return
1582
1591
 
1583
1592
  # Run any trigger handlers
@@ -1585,21 +1594,21 @@ class View(s_nexus.Pusher): # type: ignore
1585
1594
 
1586
1595
  async def runTagDel(self, node, tag, valu):
1587
1596
 
1588
- if self.core.migration:
1597
+ if self.core.migration or self.core.safemode:
1589
1598
  return
1590
1599
 
1591
1600
  await self.triggers.runTagDel(node, tag)
1592
1601
 
1593
1602
  async def runNodeAdd(self, node):
1594
1603
 
1595
- if self.core.migration:
1604
+ if self.core.migration or self.core.safemode:
1596
1605
  return
1597
1606
 
1598
1607
  await self.triggers.runNodeAdd(node)
1599
1608
 
1600
1609
  async def runNodeDel(self, node):
1601
1610
 
1602
- if self.core.migration:
1611
+ if self.core.migration or self.core.safemode:
1603
1612
  return
1604
1613
 
1605
1614
  await self.triggers.runNodeDel(node)
@@ -1608,21 +1617,21 @@ class View(s_nexus.Pusher): # type: ignore
1608
1617
  '''
1609
1618
  Handle when a prop set trigger event fired
1610
1619
  '''
1611
- if self.core.migration:
1620
+ if self.core.migration or self.core.safemode:
1612
1621
  return
1613
1622
 
1614
1623
  await self.triggers.runPropSet(node, prop, oldv)
1615
1624
 
1616
1625
  async def runEdgeAdd(self, n1, edge, n2):
1617
1626
 
1618
- if self.core.migration:
1627
+ if self.core.migration or self.core.safemode:
1619
1628
  return
1620
1629
 
1621
1630
  await self.triggers.runEdgeAdd(n1, edge, n2)
1622
1631
 
1623
1632
  async def runEdgeDel(self, n1, edge, n2):
1624
1633
 
1625
- if self.core.migration:
1634
+ if self.core.migration or self.core.safemode:
1626
1635
  return
1627
1636
 
1628
1637
  await self.triggers.runEdgeDel(n1, edge, n2)
synapse/models/inet.py CHANGED
@@ -1542,7 +1542,7 @@ class InetModule(s_module.CoreModule):
1542
1542
  ('inet:service:app', ('guid', {}), {
1543
1543
  'interfaces': ('inet:service:object',),
1544
1544
  'template': {'service:base': 'application'},
1545
- 'doc': 'A platform specific application.'}),
1545
+ 'doc': 'An application which is part of a service architecture.'}),
1546
1546
 
1547
1547
  ('inet:service:instance', ('guid', {}), {
1548
1548
  'doc': 'An instance of the platform such as Slack or Discord instances.'}),
@@ -3769,6 +3769,12 @@ class InetModule(s_module.CoreModule):
3769
3769
  ('desc', ('str', {}), {
3770
3770
  'disp': {'hint': 'text'},
3771
3771
  'doc': 'A description of the platform specific application.'}),
3772
+
3773
+ ('provider', ('ou:org', {}), {
3774
+ 'doc': 'The organization which provides the application.'}),
3775
+
3776
+ ('provider:name', ('ou:name', {}), {
3777
+ 'doc': 'The name of the organization which provides the application.'}),
3772
3778
  )),
3773
3779
 
3774
3780
  ('inet:service:account', {}, (
@@ -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
 
synapse/models/risk.py CHANGED
@@ -220,6 +220,8 @@ class RiskModule(s_module.CoreModule):
220
220
  'doc': 'The threat cluster targeted the target node.'}),
221
221
  (('risk:threat', 'uses', None), {
222
222
  'doc': 'The threat cluster uses the target node.'}),
223
+ (('risk:threat', 'uses', 'inet:service:app'), {
224
+ 'doc': 'The threat cluster uses the online application.'}),
223
225
  (('risk:attack', 'targets', None), {
224
226
  'doc': 'The attack targeted the target node.'}),
225
227
  (('risk:attack', 'uses', None), {