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.
- synapse/axon.py +3 -3
- synapse/cmds/cortex.py +1 -6
- synapse/common.py +7 -1
- synapse/cortex.py +145 -192
- synapse/datamodel.py +36 -1
- synapse/lib/agenda.py +87 -97
- synapse/lib/aha.py +51 -0
- synapse/lib/ast.py +22 -23
- synapse/lib/base.py +0 -6
- synapse/lib/boss.py +3 -0
- synapse/lib/cell.py +70 -39
- synapse/lib/certdir.py +9 -0
- synapse/lib/hiveauth.py +65 -12
- synapse/lib/httpapi.py +1 -0
- synapse/lib/modelrev.py +121 -33
- synapse/lib/modules.py +1 -0
- synapse/lib/nexus.py +64 -26
- synapse/lib/parser.py +2 -0
- synapse/lib/schemas.py +14 -0
- synapse/lib/snap.py +50 -4
- synapse/lib/storm.lark +4 -3
- synapse/lib/storm.py +96 -22
- synapse/lib/storm_format.py +1 -0
- synapse/lib/stormlib/aha.py +7 -1
- synapse/lib/stormlib/auth.py +13 -5
- synapse/lib/stormlib/cache.py +202 -0
- synapse/lib/stormlib/cortex.py +147 -8
- synapse/lib/stormlib/gen.py +53 -6
- synapse/lib/stormlib/math.py +1 -1
- synapse/lib/stormlib/model.py +11 -1
- synapse/lib/stormlib/spooled.py +109 -0
- synapse/lib/stormlib/vault.py +1 -1
- synapse/lib/stormtypes.py +113 -17
- synapse/lib/trigger.py +36 -47
- synapse/lib/types.py +29 -2
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +80 -53
- synapse/models/economic.py +174 -5
- synapse/models/files.py +2 -0
- synapse/models/inet.py +77 -2
- synapse/models/infotech.py +12 -12
- synapse/models/orgs.py +72 -21
- synapse/models/person.py +40 -11
- synapse/models/risk.py +78 -24
- synapse/models/science.py +102 -0
- synapse/telepath.py +117 -35
- synapse/tests/test_cortex.py +84 -158
- synapse/tests/test_datamodel.py +22 -0
- synapse/tests/test_lib_agenda.py +52 -96
- synapse/tests/test_lib_aha.py +126 -4
- synapse/tests/test_lib_ast.py +412 -6
- synapse/tests/test_lib_cell.py +24 -8
- synapse/tests/test_lib_certdir.py +32 -0
- synapse/tests/test_lib_grammar.py +9 -1
- synapse/tests/test_lib_httpapi.py +0 -1
- synapse/tests/test_lib_jupyter.py +0 -1
- synapse/tests/test_lib_modelrev.py +41 -0
- synapse/tests/test_lib_nexus.py +38 -0
- synapse/tests/test_lib_storm.py +95 -5
- synapse/tests/test_lib_stormlib_cache.py +272 -0
- synapse/tests/test_lib_stormlib_cortex.py +71 -0
- synapse/tests/test_lib_stormlib_gen.py +37 -2
- synapse/tests/test_lib_stormlib_model.py +2 -0
- synapse/tests/test_lib_stormlib_spooled.py +190 -0
- synapse/tests/test_lib_stormlib_vault.py +12 -3
- synapse/tests/test_lib_stormsvc.py +0 -10
- synapse/tests/test_lib_stormtypes.py +60 -8
- synapse/tests/test_lib_trigger.py +20 -2
- synapse/tests/test_lib_types.py +17 -1
- synapse/tests/test_model_economic.py +114 -0
- synapse/tests/test_model_files.py +2 -0
- synapse/tests/test_model_inet.py +73 -1
- synapse/tests/test_model_infotech.py +2 -2
- synapse/tests/test_model_orgs.py +10 -1
- synapse/tests/test_model_risk.py +30 -2
- synapse/tests/test_model_science.py +59 -0
- synapse/tests/test_model_syn.py +0 -1
- synapse/tests/test_telepath.py +30 -7
- synapse/tests/test_tools_modrole.py +81 -0
- synapse/tests/test_tools_moduser.py +105 -0
- synapse/tools/modrole.py +59 -7
- synapse/tools/moduser.py +78 -10
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/METADATA +2 -2
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/RECORD +87 -83
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/WHEEL +1 -1
- synapse/lib/provenance.py +0 -111
- synapse/tests/test_lib_provenance.py +0 -37
- {synapse-2.164.0.dist-info → synapse-2.166.0.dist-info}/LICENSE +0 -0
- {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,
|
|
138
|
+
async def open(url, onlink=None):
|
|
139
139
|
'''
|
|
140
|
-
Open a new telepath
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
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=
|
|
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
|
|
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,
|
|
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.
|
|
996
|
-
|
|
997
|
-
self.
|
|
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.
|
|
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
|
-
|
|
1027
|
-
self.clients[svcname] = await
|
|
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
|
|
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:
|
|
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:
|
|
1177
|
+
if self.isfini: # pragma: no cover
|
|
1096
1178
|
raise s_exc.IsFini()
|
|
1097
1179
|
|
|
1098
1180
|
if not self.deque:
|