synapse 2.164.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 (89) hide show
  1. synapse/axon.py +3 -3
  2. synapse/cmds/cortex.py +1 -6
  3. synapse/common.py +7 -1
  4. synapse/cortex.py +145 -192
  5. synapse/datamodel.py +36 -1
  6. synapse/lib/agenda.py +87 -97
  7. synapse/lib/aha.py +51 -0
  8. synapse/lib/ast.py +22 -23
  9. synapse/lib/base.py +0 -6
  10. synapse/lib/boss.py +3 -0
  11. synapse/lib/cell.py +70 -39
  12. synapse/lib/certdir.py +9 -0
  13. synapse/lib/hiveauth.py +65 -12
  14. synapse/lib/httpapi.py +1 -0
  15. synapse/lib/modelrev.py +121 -33
  16. synapse/lib/modules.py +1 -0
  17. synapse/lib/nexus.py +64 -26
  18. synapse/lib/parser.py +2 -0
  19. synapse/lib/schemas.py +14 -0
  20. synapse/lib/snap.py +50 -4
  21. synapse/lib/storm.lark +4 -3
  22. synapse/lib/storm.py +96 -22
  23. synapse/lib/storm_format.py +1 -0
  24. synapse/lib/stormlib/aha.py +7 -1
  25. synapse/lib/stormlib/auth.py +13 -5
  26. synapse/lib/stormlib/cache.py +202 -0
  27. synapse/lib/stormlib/cortex.py +147 -8
  28. synapse/lib/stormlib/gen.py +53 -6
  29. synapse/lib/stormlib/math.py +1 -1
  30. synapse/lib/stormlib/model.py +11 -1
  31. synapse/lib/stormlib/spooled.py +109 -0
  32. synapse/lib/stormlib/vault.py +1 -1
  33. synapse/lib/stormtypes.py +113 -17
  34. synapse/lib/trigger.py +36 -47
  35. synapse/lib/types.py +29 -2
  36. synapse/lib/version.py +2 -2
  37. synapse/lib/view.py +80 -53
  38. synapse/models/economic.py +174 -5
  39. synapse/models/files.py +2 -0
  40. synapse/models/inet.py +77 -2
  41. synapse/models/infotech.py +12 -12
  42. synapse/models/orgs.py +72 -21
  43. synapse/models/person.py +40 -11
  44. synapse/models/risk.py +78 -24
  45. synapse/models/science.py +102 -0
  46. synapse/telepath.py +117 -35
  47. synapse/tests/test_cortex.py +84 -158
  48. synapse/tests/test_datamodel.py +22 -0
  49. synapse/tests/test_lib_agenda.py +52 -96
  50. synapse/tests/test_lib_aha.py +126 -4
  51. synapse/tests/test_lib_ast.py +412 -6
  52. synapse/tests/test_lib_cell.py +24 -8
  53. synapse/tests/test_lib_certdir.py +32 -0
  54. synapse/tests/test_lib_grammar.py +9 -1
  55. synapse/tests/test_lib_httpapi.py +0 -1
  56. synapse/tests/test_lib_jupyter.py +0 -1
  57. synapse/tests/test_lib_modelrev.py +41 -0
  58. synapse/tests/test_lib_nexus.py +38 -0
  59. synapse/tests/test_lib_storm.py +95 -5
  60. synapse/tests/test_lib_stormlib_cache.py +272 -0
  61. synapse/tests/test_lib_stormlib_cortex.py +71 -0
  62. synapse/tests/test_lib_stormlib_gen.py +37 -2
  63. synapse/tests/test_lib_stormlib_model.py +2 -0
  64. synapse/tests/test_lib_stormlib_spooled.py +190 -0
  65. synapse/tests/test_lib_stormlib_vault.py +12 -3
  66. synapse/tests/test_lib_stormsvc.py +0 -10
  67. synapse/tests/test_lib_stormtypes.py +60 -8
  68. synapse/tests/test_lib_trigger.py +20 -2
  69. synapse/tests/test_lib_types.py +17 -1
  70. synapse/tests/test_model_economic.py +114 -0
  71. synapse/tests/test_model_files.py +2 -0
  72. synapse/tests/test_model_inet.py +73 -1
  73. synapse/tests/test_model_infotech.py +2 -2
  74. synapse/tests/test_model_orgs.py +10 -1
  75. synapse/tests/test_model_risk.py +30 -2
  76. synapse/tests/test_model_science.py +59 -0
  77. synapse/tests/test_model_syn.py +0 -1
  78. synapse/tests/test_telepath.py +30 -7
  79. synapse/tests/test_tools_modrole.py +81 -0
  80. synapse/tests/test_tools_moduser.py +105 -0
  81. synapse/tools/modrole.py +59 -7
  82. synapse/tools/moduser.py +78 -10
  83. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
  84. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/RECORD +87 -83
  85. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +1 -1
  86. synapse/lib/provenance.py +0 -111
  87. synapse/tests/test_lib_provenance.py +0 -37
  88. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
  89. {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,102 @@
1
+ import synapse.lib.module as s_module
2
+
3
+ class ScienceModule(s_module.CoreModule):
4
+
5
+ def getModelDefs(self):
6
+ return (('sci', {
7
+ 'types': (
8
+ ('sci:hypothesis:type:taxonomy', ('taxonomy', {}), {
9
+ 'doc': 'A taxonomy of hypothesis types.'}),
10
+ ('sci:hypothesis', ('guid', {}), {
11
+ 'doc': 'A hypothesis or theory.'}),
12
+
13
+ # TODO link experiment to eventual procedure node
14
+ ('sci:experiment:type:taxonomy', ('taxonomy', {}), {
15
+ 'doc': 'A taxonomy of experiment types.'}),
16
+ ('sci:experiment', ('guid', {}), {
17
+ 'doc': 'An instance of running an experiment.'}),
18
+
19
+ ('sci:observation', ('guid', {}), {
20
+ 'doc': 'An observation which may have resulted from an experiment.'}),
21
+
22
+ ('sci:evidence', ('guid', {}), {
23
+ 'doc': 'An assessment of how an observation supports or refutes a hypothesis.'}),
24
+ ),
25
+
26
+ 'edges': (
27
+ (('sci:experiment', 'uses', None), {
28
+ 'doc': 'The experiment used the target nodes when it was run.'}),
29
+ (('sci:observation', 'has', None), {
30
+ 'doc': 'The observations are summarized from the target nodes.'}),
31
+ (('sci:evidence', 'has', None), {
32
+ 'doc': 'The evidence includes observations from the target nodes.'}),
33
+ ),
34
+
35
+ 'forms': (
36
+ # TODO many of these forms need author/contact props
37
+ ('sci:hypothesis:type:taxonomy', {}, {}),
38
+ ('sci:hypothesis', {}, (
39
+
40
+ ('name', ('str', {'lower': True, 'onespace': True}), {
41
+ 'doc': 'The name of the hypothesis.'}),
42
+
43
+ ('type', ('sci:hypothesis:type:taxonomy', {}), {
44
+ 'doc': 'The type of hypothesis as a user defined taxonomy.'}),
45
+
46
+ ('summary', ('str', {}), {
47
+ 'disp': {'hint': 'text'},
48
+ 'doc': 'A summary of the hypothesis.'}),
49
+ )),
50
+
51
+ # TODO eventually link to a procedure form
52
+ ('sci:experiment:type:taxonomy', {}, {}),
53
+ ('sci:experiment', {}, (
54
+
55
+ ('name', ('str', {'lower': True, 'onespace': True}), {
56
+ 'doc': 'The name of the experiment.'}),
57
+
58
+ ('summary', ('str', {}), {
59
+ 'disp': {'hint': 'text'},
60
+ 'doc': 'A summary of the experiment.'}),
61
+
62
+ ('time', ('time', {}), {
63
+ 'doc': 'The time when the experiment was initiated.'}),
64
+
65
+ ('type', ('sci:experiment:type:taxonomy', {}), {
66
+ 'doc': 'The type of experiment as a user defined taxonomy.'}),
67
+
68
+ ('window', ('ival', {}), {
69
+ 'doc': 'The time window where the experiment was run.'}),
70
+
71
+ )),
72
+
73
+ ('sci:observation', {}, (
74
+
75
+ ('experiment', ('sci:experiment', {}), {
76
+ 'doc': 'The experiment which produced the observation.'}),
77
+
78
+ ('summary', ('str', {}), {
79
+ 'disp': {'hint': 'text'},
80
+ 'doc': 'A summary of the observation.'}),
81
+
82
+ ('time', ('time', {}), {
83
+ 'doc': 'The time that the observation occurred.'}),
84
+ )),
85
+
86
+ ('sci:evidence', {}, (
87
+
88
+ ('hypothesis', ('sci:experiment', {}), {
89
+ 'doc': 'The hypothesis which the evidence supports or refutes.'}),
90
+
91
+ ('observation', ('sci:observation', {}), {
92
+ 'doc': 'The observation which supports or refutes the hypothesis.'}),
93
+
94
+ ('summary', ('str', {}), {
95
+ 'disp': {'hint': 'text'},
96
+ 'doc': 'A summary of how the observation supports or refutes the hypothesis.'}),
97
+
98
+ ('refutes', ('bool', {}), {
99
+ 'doc': 'Set to true if the evidence refutes the hypothesis or false if it supports the hypothesis.'}),
100
+ )),
101
+ ),
102
+ }),)
synapse/telepath.py CHANGED
@@ -135,25 +135,24 @@ def mergeAhaInfo(info0, info1):
135
135
 
136
136
  return info0
137
137
 
138
- async def open(url, timeout=None):
138
+ async def open(url, onlink=None):
139
139
  '''
140
- Open a new telepath Client (or AHA Service Pool) based on the given URL.
141
- '''
142
- # backward compatible support for a list of URLs or urlinfo dicts...
143
- if isinstance(url, (tuple, list)): # pragma: no cover
144
- return await Client.anit(url)
145
-
146
- urlinfo = chopurl(url)
140
+ Open a new telepath ClientV2 object based on the given URL.
147
141
 
148
- if urlinfo.get('scheme') == 'aha':
149
-
150
- ahaclient, ahasvc = await _getAhaSvc(urlinfo, timeout=timeout)
142
+ Args:
143
+ url (str): The URL to connect to.
144
+ onlink: An optional async callback function to run when connections are made.
151
145
 
152
- # check if we should return a Pool rather than a Client :)
153
- if ahasvc.get('services'):
154
- return await Pool.anit(ahaclient, ahasvc, urlinfo)
146
+ Notes:
147
+ The onlink callback function has the call signature ``(proxy, urlinfo)``.
148
+ The proxy is the Telepath Proxy object.
149
+ The urlinfo is the parsed URL information used to create the proxy object.
150
+ The urlinfo structure may change between versions of Synapse.
155
151
 
156
- return await Client.anit(urlinfo)
152
+ Returns:
153
+ ClientV2: A ClientV2 object.
154
+ '''
155
+ return await ClientV2.anit(url, onlink=onlink)
157
156
 
158
157
  async def _getAhaSvc(urlinfo, timeout=None):
159
158
 
@@ -832,7 +831,7 @@ class Proxy(s_base.Base):
832
831
 
833
832
  mesg = await link.rx()
834
833
  if mesg is None:
835
- raise s_exc.LinkShutDown(mesg=mesg)
834
+ raise s_exc.LinkShutDown(mesg='Remote peer disconnected')
836
835
 
837
836
  if mesg[0] != 't2:yield': # pragma: no cover
838
837
  info = 'Telepath protocol violation: unexpected message received'
@@ -869,6 +868,8 @@ class Proxy(s_base.Base):
869
868
  if self.sess is not None:
870
869
  return await self.taskv2(todo, name=name)
871
870
 
871
+ s_common.deprecated('Telepath task with no session', curv='2.166.0')
872
+
872
873
  task = Task()
873
874
 
874
875
  mesg = ('task:init', {
@@ -980,21 +981,39 @@ class Proxy(s_base.Base):
980
981
  setattr(self, name, meth)
981
982
  return meth
982
983
 
983
- class Pool(s_base.Base):
984
+ class ClientV2(s_base.Base):
984
985
  '''
985
986
  A telepath client which:
986
987
  * connects to multiple services
987
988
  * distributes API calls across them
988
989
  * receives topology updates from AHA
990
+
991
+ NOTE: This must co-exist with Client until we eliminate uses that
992
+ attempt to call telepath APIs directly from the Client rather
993
+ than awaiting a proxy()
989
994
  '''
990
- async def __anit__(self, aha, ahasvc, urlinfo):
995
+ async def __anit__(self, urlinfo, onlink=None):
996
+
991
997
  await s_base.Base.__anit__(self)
998
+
999
+ # some ugly stuff in order to be backward compatible...
1000
+ if not isinstance(urlinfo, (list, tuple)):
1001
+ urlinfo = (urlinfo,)
1002
+
1003
+ urlinfo = [chopurl(u) for u in urlinfo]
1004
+
1005
+ self.aha = None
1006
+
992
1007
  self.clients = {}
993
1008
  self.proxies = set()
994
1009
 
995
- self.aha = aha
996
- self.ahasvc = ahasvc
997
- self.urlinfo = urlinfo
1010
+ self.poolname = None
1011
+
1012
+ self.onlink = onlink
1013
+
1014
+ self.booturls = urlinfo
1015
+ self.bootdeque = collections.deque()
1016
+ self.bootdeque.extend(self.booturls)
998
1017
 
999
1018
  self.ready = asyncio.Event()
1000
1019
  self.deque = collections.deque()
@@ -1003,7 +1022,6 @@ class Pool(s_base.Base):
1003
1022
  'svc:add': self._onPoolSvcAdd,
1004
1023
  'svc:del': self._onPoolSvcDel,
1005
1024
  }
1006
- self.schedCoro(self._toposync())
1007
1025
 
1008
1026
  async def fini():
1009
1027
  await self._shutDownPool()
@@ -1012,19 +1030,72 @@ class Pool(s_base.Base):
1012
1030
 
1013
1031
  self.onfini(fini)
1014
1032
 
1033
+ self.schedCoro(self._initBootProxy())
1034
+
1035
+ def getNextBootUrl(self):
1036
+ if not self.bootdeque:
1037
+ self.bootdeque.extend(self.booturls)
1038
+ return self.bootdeque.popleft()
1039
+
1040
+ async def _initBootProxy(self):
1041
+
1042
+ lastlog = 0.0
1043
+ while not self.isfini:
1044
+
1045
+ urlinfo = self.getNextBootUrl()
1046
+
1047
+ try:
1048
+
1049
+ if urlinfo.get('scheme') == 'aha':
1050
+
1051
+ self.aha, svcinfo = await _getAhaSvc(urlinfo)
1052
+
1053
+ # if the service is a pool, enter pool mode and fire
1054
+ # the topography sync task to manage pool members.
1055
+ services = svcinfo.get('services')
1056
+ if services is not None:
1057
+ # we are an AHA pool!
1058
+ if self.poolname is None:
1059
+ self.poolname = svcinfo.get('name')
1060
+ self.schedCoro(self._toposync())
1061
+ return
1062
+
1063
+ # regular telepath client behavior
1064
+ proxy = await openinfo(urlinfo)
1065
+ await self._onPoolLink(proxy, urlinfo)
1066
+
1067
+ async def reconnect():
1068
+ if not self.isfini:
1069
+ self.schedCoro(self._initBootProxy())
1070
+
1071
+ proxy.onfini(reconnect)
1072
+ return
1073
+
1074
+ except Exception as e:
1075
+
1076
+ now = time.monotonic()
1077
+ if now > lastlog + 60.0: # don't logspam the disconnect message more than 1/min
1078
+ url = s_urlhelp.sanitizeUrl(zipurl(urlinfo))
1079
+ logger.exception(f'telepath clientv2 ({url}) encountered an error: {e}')
1080
+ lastlog = now
1081
+
1082
+ retrysleep = float(urlinfo.get('retrysleep', 0.2))
1083
+ await self.waitfini(timeout=retrysleep)
1084
+
1085
+ async def waitready(self, timeout=None):
1086
+ await s_common.wait_for(self.ready.wait(), timeout=timeout)
1087
+
1015
1088
  def size(self):
1016
- return len(self.clients)
1089
+ return len(self.proxies)
1017
1090
 
1018
1091
  async def _onPoolSvcAdd(self, mesg):
1019
1092
  svcname = mesg[1].get('name')
1020
- svcinfo = mesg[1].get('svcinfo')
1021
- urlinfo = mergeAhaInfo(self.urlinfo, svcinfo.get('urlinfo', {}))
1022
1093
 
1023
1094
  if (oldc := self.clients.pop(svcname, None)) is not None:
1024
1095
  await oldc.fini()
1025
1096
 
1026
- # one-off default user to root
1027
- self.clients[svcname] = await Client.anit(urlinfo, onlink=self._onPoolLink)
1097
+ urlinfo = {'scheme': 'aha', 'host': svcname, 'path': ''}
1098
+ self.clients[svcname] = await ClientV2.anit(urlinfo, onlink=self._onPoolLink)
1028
1099
  await self.fire('svc:add', **mesg[1])
1029
1100
 
1030
1101
  async def _onPoolSvcDel(self, mesg):
@@ -1035,10 +1106,13 @@ class Pool(s_base.Base):
1035
1106
  self.deque.clear()
1036
1107
  await self.fire('svc:del', **mesg[1])
1037
1108
 
1038
- async def _onPoolLink(self, proxy):
1109
+ async def _onPoolLink(self, proxy, urlinfo):
1039
1110
 
1040
1111
  async def onfini():
1041
- self.proxies.remove(proxy)
1112
+ if proxy in self.proxies:
1113
+ self.proxies.remove(proxy)
1114
+ if proxy in self.deque:
1115
+ self.deque.remove(proxy)
1042
1116
  if not len(self.proxies):
1043
1117
  self.ready.clear()
1044
1118
 
@@ -1046,13 +1120,23 @@ class Pool(s_base.Base):
1046
1120
  self.proxies.add(proxy)
1047
1121
  self.ready.set()
1048
1122
 
1123
+ if self.onlink is not None:
1124
+ try:
1125
+ await self.onlink(proxy, urlinfo)
1126
+ except Exception as e:
1127
+ logger.exception(f'onlink: {self.onlink}')
1128
+
1049
1129
  async def _shutDownPool(self):
1050
1130
  # when we reconnect to our AHA service, we need to dump the current
1051
1131
  # topology state and gather it again.
1052
- for client in self.clients.values():
1132
+ for client in list(self.clients.values()):
1053
1133
  await client.fini()
1054
1134
 
1135
+ for proxy in list(self.proxies):
1136
+ await proxy.fini()
1137
+
1055
1138
  self.deque.clear()
1139
+ self.ready.clear()
1056
1140
  self.clients.clear()
1057
1141
  self.proxies.clear()
1058
1142
 
@@ -1065,16 +1149,14 @@ class Pool(s_base.Base):
1065
1149
 
1066
1150
  while not self.isfini:
1067
1151
 
1068
- poolname = self.ahasvc.get('name')
1069
-
1070
1152
  try:
1071
1153
  ahaproxy = await self.aha.proxy()
1072
1154
 
1073
1155
  await reset()
1074
1156
 
1075
- async for mesg in ahaproxy.iterPoolTopo(poolname):
1157
+ async for mesg in ahaproxy.iterPoolTopo(self.poolname):
1076
1158
  hand = self.mesghands.get(mesg[0])
1077
- if hand is None: # pragma: no cover
1159
+ if hand is None: # pragma: no cover
1078
1160
  logger.warning(f'Unknown AHA pool topography message: {mesg}')
1079
1161
  continue
1080
1162
 
@@ -1092,7 +1174,7 @@ class Pool(s_base.Base):
1092
1174
 
1093
1175
  await self.ready.wait()
1094
1176
 
1095
- if self.isfini: # pragma: no cover
1177
+ if self.isfini: # pragma: no cover
1096
1178
  raise s_exc.IsFini()
1097
1179
 
1098
1180
  if not self.deque: