synapse 2.209.0__py311-none-any.whl → 2.210.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/lib/cell.py +14 -4
- synapse/lib/coro.py +5 -0
- synapse/lib/json.py +48 -22
- synapse/lib/nexus.py +6 -0
- synapse/lib/storm.py +10 -2
- synapse/lib/stormlib/auth.py +6 -0
- synapse/lib/stormlib/notifications.py +12 -2
- synapse/lib/version.py +2 -2
- synapse/models/entity.py +26 -0
- synapse/models/inet.py +11 -0
- synapse/models/person.py +9 -2
- synapse/tests/test_cortex.py +3 -3
- synapse/tests/test_lib_aha.py +1 -1
- synapse/tests/test_lib_cell.py +28 -8
- synapse/tests/test_lib_coro.py +23 -0
- synapse/tests/test_lib_json.py +41 -16
- synapse/tests/test_model_entity.py +21 -0
- synapse/tests/test_model_gov_intl.py +2 -2
- synapse/tests/test_model_inet.py +15 -0
- synapse/tests/test_model_media.py +1 -0
- synapse/tests/test_model_person.py +12 -0
- synapse/tests/test_telepath.py +52 -41
- synapse/tests/test_tools_aha.py +7 -8
- synapse/tests/utils.py +1 -1
- synapse/tools/aha/clone.py +7 -1
- synapse/tools/aha/easycert.py +37 -42
- synapse/tools/aha/enroll.py +7 -1
- synapse/tools/aha/list.py +60 -65
- synapse/tools/aha/mirror.py +7 -1
- synapse/tools/aha/provision/service.py +7 -1
- synapse/tools/aha/provision/user.py +7 -1
- synapse/tools/apikey.py +8 -1
- synapse/tools/axon2axon.py +7 -1
- synapse/tools/cellauth.py +6 -5
- synapse/tools/cmdr.py +2 -1
- synapse/tools/csvtool.py +7 -2
- synapse/tools/feed.py +8 -2
- synapse/tools/genpkg.py +7 -1
- synapse/tools/healthcheck.py +7 -1
- synapse/tools/livebackup.py +7 -3
- synapse/tools/modrole.py +7 -1
- synapse/tools/moduser.py +7 -2
- synapse/tools/promote.py +7 -3
- synapse/tools/pullfile.py +6 -1
- synapse/tools/pushfile.py +7 -1
- synapse/tools/reload.py +7 -4
- synapse/tools/snapshot.py +7 -1
- synapse/tools/storm.py +7 -1
- {synapse-2.209.0.dist-info → synapse-2.210.0.dist-info}/METADATA +2 -2
- {synapse-2.209.0.dist-info → synapse-2.210.0.dist-info}/RECORD +53 -52
- {synapse-2.209.0.dist-info → synapse-2.210.0.dist-info}/WHEEL +1 -1
- {synapse-2.209.0.dist-info → synapse-2.210.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.209.0.dist-info → synapse-2.210.0.dist-info}/top_level.txt +0 -0
synapse/lib/cell.py
CHANGED
|
@@ -2220,14 +2220,24 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2220
2220
|
|
|
2221
2221
|
logger.debug(f'HANDOFF: Connected to {s_urlhelp.sanitizeUrl(turl)}{_dispname}.')
|
|
2222
2222
|
|
|
2223
|
-
|
|
2223
|
+
cellinfo = await cell.getCellInfo()
|
|
2224
|
+
cnfo = cellinfo.get('cell')
|
|
2225
|
+
if self.iden != cnfo.get('iden'): # pragma: no cover
|
|
2224
2226
|
mesg = 'Mirror handoff remote cell iden does not match!'
|
|
2225
2227
|
raise s_exc.BadArg(mesg=mesg)
|
|
2226
2228
|
|
|
2227
|
-
if self.runid ==
|
|
2229
|
+
if self.runid == cnfo.get('run'): # pragma: no cover
|
|
2228
2230
|
mesg = 'Cannot handoff mirror leadership to myself!'
|
|
2229
2231
|
raise s_exc.BadArg(mesg=mesg)
|
|
2230
2232
|
|
|
2233
|
+
ahalead = cnfo.get('aha', {}).get('leader')
|
|
2234
|
+
mirror_url = turl
|
|
2235
|
+
if turl.startswith('aha://') and ahalead is not None:
|
|
2236
|
+
ahauser = self.conf.get('aha:user')
|
|
2237
|
+
if ahauser is not None:
|
|
2238
|
+
ahauser = f'{ahauser}@'
|
|
2239
|
+
mirror_url = f'aha://{ahauser}{ahalead}...'
|
|
2240
|
+
|
|
2231
2241
|
logger.debug(f'HANDOFF: Obtaining nexus lock{_dispname}.')
|
|
2232
2242
|
|
|
2233
2243
|
async with self.nexslock:
|
|
@@ -2247,8 +2257,8 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2247
2257
|
logger.debug(f'HANDOFF: Setting the service as inactive{_dispname}.')
|
|
2248
2258
|
await self.setCellActive(False)
|
|
2249
2259
|
|
|
2250
|
-
logger.debug(f'HANDOFF: Configuring service to sync from new leader{_dispname}.')
|
|
2251
|
-
self.modCellConf({'mirror':
|
|
2260
|
+
logger.debug(f'HANDOFF: Configuring service to sync from new leader{_dispname} @ {s_urlhelp.sanitizeUrl(mirror_url)}.')
|
|
2261
|
+
self.modCellConf({'mirror': mirror_url})
|
|
2252
2262
|
|
|
2253
2263
|
logger.debug(f'HANDOFF: Restarting the nexus{_dispname}.')
|
|
2254
2264
|
await self.nexsroot.startup()
|
synapse/lib/coro.py
CHANGED
synapse/lib/json.py
CHANGED
|
@@ -7,7 +7,7 @@ from typing import Any, BinaryIO, Callable, Iterator, Optional
|
|
|
7
7
|
|
|
8
8
|
from synapse.vendor.cpython.lib.json import detect_encoding
|
|
9
9
|
|
|
10
|
-
import
|
|
10
|
+
import yyjson
|
|
11
11
|
|
|
12
12
|
import synapse.exc as s_exc
|
|
13
13
|
|
|
@@ -37,8 +37,9 @@ def loads(s: str | bytes) -> Any:
|
|
|
37
37
|
deserializing the provided data.
|
|
38
38
|
'''
|
|
39
39
|
try:
|
|
40
|
-
return
|
|
41
|
-
|
|
40
|
+
return yyjson.Document(s, flags=yyjson.ReaderFlags.BIGNUM_AS_RAW).as_obj
|
|
41
|
+
|
|
42
|
+
except (ValueError, TypeError) as exc:
|
|
42
43
|
extra = {'synapse': {'fn': 'loads', 'reason': str(exc)}}
|
|
43
44
|
logger.warning('Using fallback JSON deserialization. Please report this to Vertex.', extra=extra)
|
|
44
45
|
return _fallback_loads(s)
|
|
@@ -70,6 +71,33 @@ def _fallback_dumps(obj: Any, sort_keys: bool = False, indent: bool = False, def
|
|
|
70
71
|
except TypeError as exc:
|
|
71
72
|
raise s_exc.MustBeJsonSafe(mesg=exc.args[0])
|
|
72
73
|
|
|
74
|
+
def _dumps(obj, sort_keys=False, indent=False, default=None, newline=False):
|
|
75
|
+
rflags = 0
|
|
76
|
+
wflags = 0
|
|
77
|
+
|
|
78
|
+
if sort_keys:
|
|
79
|
+
rflags |= yyjson.ReaderFlags.SORT_KEYS
|
|
80
|
+
|
|
81
|
+
if indent:
|
|
82
|
+
wflags |= yyjson.WriterFlags.PRETTY_TWO_SPACES
|
|
83
|
+
|
|
84
|
+
if newline:
|
|
85
|
+
wflags |= yyjson.WriterFlags.WRITE_NEWLINE_AT_END
|
|
86
|
+
|
|
87
|
+
if isinstance(obj, bytes):
|
|
88
|
+
mesg = 'Object of type bytes is not JSON serializable'
|
|
89
|
+
raise s_exc.MustBeJsonSafe(mesg=mesg)
|
|
90
|
+
|
|
91
|
+
# Raw strings have to be double-quoted. This is because the default behavior for `yyjson.Document`
|
|
92
|
+
# is to attempt to parse the string as a serialized JSON string into objects, so we escape string
|
|
93
|
+
# values so we can get the JSON encoded string as output.
|
|
94
|
+
if isinstance(obj, str) and obj not in ('null', 'true', 'false'):
|
|
95
|
+
# TODO in 3xx convert this into obj = f'''"{obj.replace('"', '\\"')}"'''
|
|
96
|
+
obj = ''.join(('"', obj.replace('"', '\\"'), '"'))
|
|
97
|
+
|
|
98
|
+
doc = yyjson.Document(obj, default=default, flags=rflags)
|
|
99
|
+
return doc.dumps(flags=wflags).encode()
|
|
100
|
+
|
|
73
101
|
def dumps(obj: Any, sort_keys: bool = False, indent: bool = False, default: Optional[Callable] = None, newline: bool = False) -> bytes:
|
|
74
102
|
'''
|
|
75
103
|
Serialize a python object to byte string.
|
|
@@ -89,24 +117,9 @@ def dumps(obj: Any, sort_keys: bool = False, indent: bool = False, default: Opti
|
|
|
89
117
|
Raises:
|
|
90
118
|
synapse.exc.MustBeJsonSafe: This exception is raised when a python object cannot be serialized.
|
|
91
119
|
'''
|
|
92
|
-
opts = 0
|
|
93
|
-
|
|
94
|
-
if indent:
|
|
95
|
-
opts |= orjson.OPT_INDENT_2
|
|
96
|
-
|
|
97
|
-
if sort_keys:
|
|
98
|
-
opts |= orjson.OPT_SORT_KEYS
|
|
99
|
-
|
|
100
|
-
if newline:
|
|
101
|
-
opts |= orjson.OPT_APPEND_NEWLINE
|
|
102
|
-
|
|
103
120
|
try:
|
|
104
|
-
return
|
|
105
|
-
|
|
106
|
-
except orjson.JSONEncodeError as exc:
|
|
107
|
-
if not isinstance(exc.__cause__, UnicodeEncodeError):
|
|
108
|
-
raise s_exc.MustBeJsonSafe(mesg=exc.args[0])
|
|
109
|
-
|
|
121
|
+
return _dumps(obj, sort_keys=sort_keys, indent=indent, default=default, newline=newline)
|
|
122
|
+
except UnicodeEncodeError as exc:
|
|
110
123
|
extra = {'synapse': {'fn': 'dumps', 'reason': str(exc)}}
|
|
111
124
|
logger.warning('Using fallback JSON serialization. Please report this to Vertex.', extra=extra)
|
|
112
125
|
|
|
@@ -117,6 +130,10 @@ def dumps(obj: Any, sort_keys: bool = False, indent: bool = False, default: Opti
|
|
|
117
130
|
|
|
118
131
|
return ret
|
|
119
132
|
|
|
133
|
+
except (TypeError, ValueError) as exc:
|
|
134
|
+
mesg = f'{exc.__class__.__name__}: {exc}'
|
|
135
|
+
raise s_exc.MustBeJsonSafe(mesg=mesg)
|
|
136
|
+
|
|
120
137
|
def dump(obj: Any, fp: BinaryIO, sort_keys: bool = False, indent: bool = False, default: Optional[Callable] = None, newline: bool = False) -> None:
|
|
121
138
|
'''
|
|
122
139
|
Serialize a python object to a file-like object opened in binary mode.
|
|
@@ -217,8 +234,17 @@ def reqjsonsafe(item: Any, strict: bool = False) -> None:
|
|
|
217
234
|
'''
|
|
218
235
|
if strict:
|
|
219
236
|
try:
|
|
220
|
-
|
|
237
|
+
_dumps(item)
|
|
238
|
+
|
|
239
|
+
except s_exc.MustBeJsonSafe:
|
|
240
|
+
raise
|
|
241
|
+
|
|
242
|
+
except UnicodeEncodeError as exc:
|
|
243
|
+
mesg = str(exc)
|
|
244
|
+
raise s_exc.MustBeJsonSafe(mesg=mesg)
|
|
245
|
+
|
|
221
246
|
except Exception as exc:
|
|
222
|
-
|
|
247
|
+
mesg = f'{exc.__class__.__name__}: {exc}'
|
|
248
|
+
raise s_exc.MustBeJsonSafe(mesg=mesg)
|
|
223
249
|
else:
|
|
224
250
|
dumps(item)
|
synapse/lib/nexus.py
CHANGED
|
@@ -506,6 +506,7 @@ class NexsRoot(s_base.Base):
|
|
|
506
506
|
|
|
507
507
|
async def runMirrorLoop(self, proxy):
|
|
508
508
|
|
|
509
|
+
cellinfo = None
|
|
509
510
|
try:
|
|
510
511
|
cellinfo = await proxy.getCellInfo()
|
|
511
512
|
features = cellinfo.get('features', {})
|
|
@@ -536,6 +537,11 @@ class NexsRoot(s_base.Base):
|
|
|
536
537
|
|
|
537
538
|
while not proxy.isfini:
|
|
538
539
|
|
|
540
|
+
if cellinfo:
|
|
541
|
+
ahaname = cellinfo.get('cell').get('aha', {}).get('name')
|
|
542
|
+
if ahaname:
|
|
543
|
+
logger.info(f'Mirror communicating with aha service {ahaname}')
|
|
544
|
+
|
|
539
545
|
try:
|
|
540
546
|
|
|
541
547
|
if self.readonly:
|
synapse/lib/storm.py
CHANGED
|
@@ -174,6 +174,14 @@ Examples:
|
|
|
174
174
|
cron.at --dt 20181231Z2359 {[inet:ipv4=1]}
|
|
175
175
|
'''
|
|
176
176
|
|
|
177
|
+
viewdeldescr = '''
|
|
178
|
+
Delete a view from the cortex.
|
|
179
|
+
|
|
180
|
+
Notes:
|
|
181
|
+
Deleting a view with the `view.del` command does not delete any of the layers in the view.
|
|
182
|
+
To delete layers, you must use the `layer.del` command separately.
|
|
183
|
+
'''
|
|
184
|
+
|
|
177
185
|
wgetdescr = '''Retrieve bytes from a URL and store them in the axon. Yields inet:urlfile nodes.
|
|
178
186
|
|
|
179
187
|
Examples:
|
|
@@ -656,7 +664,7 @@ stormcmds = (
|
|
|
656
664
|
},
|
|
657
665
|
{
|
|
658
666
|
'name': 'view.del',
|
|
659
|
-
'descr':
|
|
667
|
+
'descr': viewdeldescr,
|
|
660
668
|
'cmdargs': (
|
|
661
669
|
('iden', {'help': 'Iden of the view to delete.'}),
|
|
662
670
|
),
|
|
@@ -2056,7 +2064,7 @@ class Runtime(s_base.Base):
|
|
|
2056
2064
|
continue
|
|
2057
2065
|
|
|
2058
2066
|
if len(nodes) == 1:
|
|
2059
|
-
mesg = 'Ambiguous value for single node lookup: {propname}
|
|
2067
|
+
mesg = f'Ambiguous value for single node lookup: {propname}{cmpr}{valu}'
|
|
2060
2068
|
raise s_exc.StormRuntimeError(mesg=mesg)
|
|
2061
2069
|
|
|
2062
2070
|
nodes.append(node)
|
synapse/lib/stormlib/auth.py
CHANGED
|
@@ -901,12 +901,14 @@ class User(s_stormtypes.Prim):
|
|
|
901
901
|
),
|
|
902
902
|
'returns': {'type': 'null', }}},
|
|
903
903
|
{'name': 'tell', 'desc': 'Send a tell notification to a user.',
|
|
904
|
+
'deprecated': {'eolvers': 'v3.0.0'},
|
|
904
905
|
'type': {'type': 'function', '_funcname': '_methUserTell',
|
|
905
906
|
'args': (
|
|
906
907
|
{'name': 'text', 'type': 'str', 'desc': 'The text of the message to send.', },
|
|
907
908
|
),
|
|
908
909
|
'returns': {'type': 'null', }}},
|
|
909
910
|
{'name': 'notify', 'desc': 'Send an arbitrary user notification.',
|
|
911
|
+
'deprecated': {'eolvers': 'v3.0.0'},
|
|
910
912
|
'type': {'type': 'function', '_funcname': '_methUserNotify',
|
|
911
913
|
'args': (
|
|
912
914
|
{'name': 'mesgtype', 'type': 'str', 'desc': 'The notification type.', },
|
|
@@ -1153,6 +1155,8 @@ class User(s_stormtypes.Prim):
|
|
|
1153
1155
|
return await self.value()
|
|
1154
1156
|
|
|
1155
1157
|
async def _methUserTell(self, text):
|
|
1158
|
+
s_common.deprecated('user.tell()', '2.210.0', '3.0.0')
|
|
1159
|
+
await self.runt.snap.warnonce('user.tell() is deprecated.')
|
|
1156
1160
|
self.runt.confirm(('tell', self.valu), default=True)
|
|
1157
1161
|
mesgdata = {
|
|
1158
1162
|
'text': await s_stormtypes.tostr(text),
|
|
@@ -1161,6 +1165,8 @@ class User(s_stormtypes.Prim):
|
|
|
1161
1165
|
return await self.runt.snap.core.addUserNotif(self.valu, 'tell', mesgdata)
|
|
1162
1166
|
|
|
1163
1167
|
async def _methUserNotify(self, mesgtype, mesgdata):
|
|
1168
|
+
s_common.deprecated('user.notify()', '2.210.0', '3.0.0')
|
|
1169
|
+
await self.runt.snap.warnonce('user.notify() is deprecated.')
|
|
1164
1170
|
if not self.runt.isAdmin():
|
|
1165
1171
|
mesg = '$user.notify() method requires admin privs.'
|
|
1166
1172
|
raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import synapse.exc as s_exc
|
|
2
|
+
import synapse.common as s_common
|
|
3
|
+
|
|
2
4
|
import synapse.lib.stormtypes as s_stormtypes
|
|
3
5
|
|
|
4
6
|
@s_stormtypes.registry.registerLib
|
|
@@ -12,6 +14,7 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
12
14
|
Yield (<indx>, <mesg>) tuples for a user's notifications.
|
|
13
15
|
|
|
14
16
|
''',
|
|
17
|
+
'deprecated': {'eolvers': 'v3.0.0'},
|
|
15
18
|
'type': {
|
|
16
19
|
'type': 'function', '_funcname': 'list',
|
|
17
20
|
'args': (
|
|
@@ -28,6 +31,7 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
28
31
|
Delete a previously delivered notification.
|
|
29
32
|
|
|
30
33
|
''',
|
|
34
|
+
'deprecated': {'eolvers': 'v3.0.0'},
|
|
31
35
|
'type': {
|
|
32
36
|
'type': 'function', '_funcname': '_del',
|
|
33
37
|
'args': (
|
|
@@ -44,6 +48,7 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
44
48
|
Return a notification by ID (or ``(null)`` ).
|
|
45
49
|
|
|
46
50
|
''',
|
|
51
|
+
'deprecated': {'eolvers': 'v3.0.0'},
|
|
47
52
|
'type': {
|
|
48
53
|
'type': 'function', '_funcname': 'get',
|
|
49
54
|
'args': (
|
|
@@ -55,20 +60,21 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
55
60
|
},
|
|
56
61
|
},
|
|
57
62
|
)
|
|
63
|
+
_storm_lib_deprecation = {'eolvers': 'v3.0.0'}
|
|
58
64
|
|
|
59
65
|
def getObjLocals(self):
|
|
60
66
|
return {
|
|
61
67
|
'get': self.get,
|
|
62
68
|
'del': self._del,
|
|
63
69
|
'list': self.list,
|
|
64
|
-
# 'bytime':
|
|
65
|
-
# 'bytype':
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
@s_stormtypes.stormfunc(readonly=True)
|
|
69
73
|
async def get(self, indx):
|
|
70
74
|
indx = await s_stormtypes.toint(indx)
|
|
71
75
|
mesg = await self.runt.snap.core.getUserNotif(indx)
|
|
76
|
+
s_common.deprecated('$lib.notifications.get()', '2.210.0', '3.0.0')
|
|
77
|
+
await self.runt.snap.warnonce('$lib.notifications.get() is deprecated.')
|
|
72
78
|
if mesg[0] != self.runt.user.iden and not self.runt.isAdmin():
|
|
73
79
|
mesg = 'You may only get notifications which belong to you.'
|
|
74
80
|
raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
|
|
@@ -77,6 +83,8 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
77
83
|
async def _del(self, indx):
|
|
78
84
|
indx = await s_stormtypes.toint(indx)
|
|
79
85
|
mesg = await self.runt.snap.core.getUserNotif(indx)
|
|
86
|
+
s_common.deprecated('$lib.notifications.del()', '2.210.0', '3.0.0')
|
|
87
|
+
await self.runt.snap.warnonce('$lib.notifications.del() is deprecated.')
|
|
80
88
|
if mesg[0] != self.runt.user.iden and not self.runt.isAdmin():
|
|
81
89
|
mesg = 'You may only delete notifications which belong to you.'
|
|
82
90
|
raise s_exc.AuthDeny(mesg=mesg, user=self.runt.user.iden, username=self.runt.user.name)
|
|
@@ -85,5 +93,7 @@ class NotifyLib(s_stormtypes.Lib):
|
|
|
85
93
|
@s_stormtypes.stormfunc(readonly=True)
|
|
86
94
|
async def list(self, size=None):
|
|
87
95
|
size = await s_stormtypes.toint(size, noneok=True)
|
|
96
|
+
s_common.deprecated('$lib.notifications.list()', '2.210.0', '3.0.0')
|
|
97
|
+
await self.runt.snap.warnonce('$lib.notifications.list() is deprecated.')
|
|
88
98
|
async for mesg in self.runt.snap.core.iterUserNotifs(self.runt.user.iden, size=size):
|
|
89
99
|
yield mesg
|
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,
|
|
226
|
+
version = (2, 210, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = 'e43efa9d9c2257ff05fe47988a323e16896fdf50'
|
synapse/models/entity.py
CHANGED
|
@@ -8,9 +8,35 @@ class EntityModule(s_module.CoreModule):
|
|
|
8
8
|
'types': (
|
|
9
9
|
('entity:name', ('str', {'onespace': True, 'lower': True}), {
|
|
10
10
|
'doc': 'A name used to refer to an entity.'}),
|
|
11
|
+
|
|
12
|
+
('entity:actor', ('ndef', {'forms': ('ou:org', 'ps:person', 'ps:contact', 'risk:threat')}), {
|
|
13
|
+
'doc': 'An entity which has initiative to act.'}),
|
|
14
|
+
|
|
15
|
+
('entity:relationship:type:taxonomy', ('taxonomy', {}), {
|
|
16
|
+
'interfaces': ('meta:taxonomy', ),
|
|
17
|
+
'doc': 'A hierarchical taxonomy of entity relationship types.'}),
|
|
18
|
+
|
|
19
|
+
('entity:relationship', ('guid', {}), {
|
|
20
|
+
'doc': 'A directional relationship between two actor entities.'}),
|
|
11
21
|
),
|
|
12
22
|
|
|
13
23
|
'forms': (
|
|
14
24
|
('entity:name', {}, ()),
|
|
25
|
+
|
|
26
|
+
('entity:relationship:type:taxonomy', {}, ()),
|
|
27
|
+
('entity:relationship', {}, (
|
|
28
|
+
|
|
29
|
+
('type', ('entity:relationship:type:taxonomy', {}), {
|
|
30
|
+
'doc': 'The type of relationship.'}),
|
|
31
|
+
|
|
32
|
+
('period', ('ival', {}), {
|
|
33
|
+
'doc': 'The time period when the relationship existed.'}),
|
|
34
|
+
|
|
35
|
+
('source', ('entity:actor', {}), {
|
|
36
|
+
'doc': 'The source entity in the relationship.'}),
|
|
37
|
+
|
|
38
|
+
('target', ('entity:actor', {}), {
|
|
39
|
+
'doc': 'The target entity in the relationship.'}),
|
|
40
|
+
)),
|
|
15
41
|
),
|
|
16
42
|
}),)
|
synapse/models/inet.py
CHANGED
|
@@ -3802,6 +3802,9 @@ class InetModule(s_module.CoreModule):
|
|
|
3802
3802
|
('attachments', ('array', {'type': 'inet:service:message:attachment', 'uniq': True, 'sorted': True}), {
|
|
3803
3803
|
'doc': 'An array of files attached to the message.'}),
|
|
3804
3804
|
|
|
3805
|
+
('hashtags', ('array', {'type': 'inet:web:hashtag', 'uniq': True, 'sorted': True, 'split': ','}), {
|
|
3806
|
+
'doc': 'An array of hashtags mentioned within the message.'}),
|
|
3807
|
+
|
|
3805
3808
|
('place', ('geo:place', {}), {
|
|
3806
3809
|
'doc': 'The place that the message was sent from.'}),
|
|
3807
3810
|
|
|
@@ -3823,6 +3826,11 @@ class InetModule(s_module.CoreModule):
|
|
|
3823
3826
|
|
|
3824
3827
|
('type', ('inet:service:message:type:taxonomy', {}), {
|
|
3825
3828
|
'doc': 'The type of message.'}),
|
|
3829
|
+
|
|
3830
|
+
('mentions', ('array', {'type': 'ndef',
|
|
3831
|
+
'typeopts': {'forms': ('inet:service:account', 'inet:service:group')},
|
|
3832
|
+
'uniq': True, 'sorted': True}), {
|
|
3833
|
+
'doc': 'Contactable entities mentioned within the message.'}),
|
|
3826
3834
|
)),
|
|
3827
3835
|
|
|
3828
3836
|
('inet:service:message:link', {}, (
|
|
@@ -3863,6 +3871,9 @@ class InetModule(s_module.CoreModule):
|
|
|
3863
3871
|
|
|
3864
3872
|
('period', ('ival', {}), {
|
|
3865
3873
|
'doc': 'The time period where the channel was available.'}),
|
|
3874
|
+
|
|
3875
|
+
('topic', ('media:topic', {}), {
|
|
3876
|
+
'doc': 'The visible topic of the channel.'}),
|
|
3866
3877
|
)),
|
|
3867
3878
|
|
|
3868
3879
|
('inet:service:thread', {}, (
|
synapse/models/person.py
CHANGED
|
@@ -490,13 +490,20 @@ class PsModule(s_module.CoreModule):
|
|
|
490
490
|
('crypto:address', ('crypto:currency:address', {}), {
|
|
491
491
|
'doc': 'A crypto currency address associated with the contact.'
|
|
492
492
|
}),
|
|
493
|
-
|
|
494
493
|
('lang', ('lang:language', {}), {
|
|
495
494
|
'alts': ('langs',),
|
|
496
495
|
'doc': 'The language specified for the contact.'}),
|
|
497
|
-
|
|
498
496
|
('langs', ('array', {'type': 'lang:language'}), {
|
|
499
497
|
'doc': 'An array of alternative languages specified for the contact.'}),
|
|
498
|
+
('banner', ('file:bytes', {}), {
|
|
499
|
+
'doc': 'The file representing the banner for the contact.'}),
|
|
500
|
+
('passwd', ('inet:passwd', {}), {
|
|
501
|
+
'doc': 'The current password for the contact.'}),
|
|
502
|
+
('website', ('inet:url', {}), {
|
|
503
|
+
'doc': 'A related URL specified by the contact (e.g., a personal or company web '
|
|
504
|
+
'page, blog, etc.).'}),
|
|
505
|
+
('websites', ('array', {'type': 'inet:url', 'uniq': True, 'sorted': True}), {
|
|
506
|
+
'doc': 'Alternative related URLs specified by the contact.'}),
|
|
500
507
|
)),
|
|
501
508
|
('ps:vitals', {}, (
|
|
502
509
|
('asof', ('time', {}), {
|
synapse/tests/test_cortex.py
CHANGED
|
@@ -152,12 +152,12 @@ class CortexTest(s_t_utils.SynTest):
|
|
|
152
152
|
self.false((await core01.getCellInfo())['cell']['uplink'])
|
|
153
153
|
# Note: The following mirror may change when SYN-7659 is addressed and greater
|
|
154
154
|
# control over the topology update is available during the promotion process.
|
|
155
|
-
self.eq((await core00.getCellInfo())['cell']['mirror'], 'aha://
|
|
155
|
+
self.eq((await core00.getCellInfo())['cell']['mirror'], 'aha://root@cortex...')
|
|
156
156
|
self.none((await core01.getCellInfo())['cell']['mirror'])
|
|
157
157
|
|
|
158
158
|
mods00 = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
159
159
|
mods01 = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
160
|
-
self.eq(mods00, {'mirror': 'aha://
|
|
160
|
+
self.eq(mods00, {'mirror': 'aha://root@cortex...'})
|
|
161
161
|
self.eq(mods01, {'mirror': None})
|
|
162
162
|
|
|
163
163
|
await core00.nodes('[inet:ipv4=5.5.5.5]')
|
|
@@ -8367,7 +8367,7 @@ class CortexBasicTest(s_t_utils.SynTest):
|
|
|
8367
8367
|
dirn01 = s_common.genpath(dirn, 'cell01')
|
|
8368
8368
|
|
|
8369
8369
|
core00 = await base.enter_context(self.addSvcToAha(aha, '00.core', s_cortex.Cortex, dirn=dirn00))
|
|
8370
|
-
provinfo = {'mirror': '
|
|
8370
|
+
provinfo = {'mirror': 'core'}
|
|
8371
8371
|
core01 = await base.enter_context(self.addSvcToAha(aha, '01.core', s_cortex.Cortex, dirn=dirn01, provinfo=provinfo))
|
|
8372
8372
|
|
|
8373
8373
|
self.len(1, await core00.nodes('[inet:asn=0]'))
|
synapse/tests/test_lib_aha.py
CHANGED
|
@@ -781,7 +781,7 @@ class AhaTest(s_test.SynTest):
|
|
|
781
781
|
self.false(axon3.isactive)
|
|
782
782
|
self.eq('aha://root@axon...', axon03.conf.get('mirror'))
|
|
783
783
|
|
|
784
|
-
retn, outp = await self.execToolMain(s_a_list.
|
|
784
|
+
retn, outp = await self.execToolMain(s_a_list.main, [aha.getLocalUrl()])
|
|
785
785
|
self.eq(retn, 0)
|
|
786
786
|
outp.expect('Service network leader')
|
|
787
787
|
outp.expect('00.axon synapse True')
|
synapse/tests/test_lib_cell.py
CHANGED
|
@@ -2238,7 +2238,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2238
2238
|
self.false(core00.isactive)
|
|
2239
2239
|
|
|
2240
2240
|
modinfo = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
2241
|
-
self.
|
|
2241
|
+
self.eq('aha://root@core...', modinfo.get('mirror', ''))
|
|
2242
2242
|
modinfo = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
2243
2243
|
self.none(modinfo.get('mirror'))
|
|
2244
2244
|
|
|
@@ -2321,7 +2321,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2321
2321
|
self.false(core00.isactive)
|
|
2322
2322
|
|
|
2323
2323
|
modinfo = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
2324
|
-
self.
|
|
2324
|
+
self.eq('aha://root@core...', modinfo.get('mirror', ''))
|
|
2325
2325
|
modinfo = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
2326
2326
|
self.none(modinfo.get('mirror'))
|
|
2327
2327
|
|
|
@@ -2333,7 +2333,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
2333
2333
|
modinfo = s_common.yamlload(core00.dirn, 'cell.mods.yaml')
|
|
2334
2334
|
self.none(modinfo.get('mirror'))
|
|
2335
2335
|
modinfo = s_common.yamlload(core01.dirn, 'cell.mods.yaml')
|
|
2336
|
-
self.
|
|
2336
|
+
self.eq('aha://root@core...', modinfo.get('mirror', ''))
|
|
2337
2337
|
|
|
2338
2338
|
# Backup the mirror (core01) which points to the core00
|
|
2339
2339
|
async with await axon00.upload() as upfd:
|
|
@@ -3285,6 +3285,7 @@ class CellTest(s_t_utils.SynTest):
|
|
|
3285
3285
|
dirn00 = s_common.genpath(dirn, '00.cell')
|
|
3286
3286
|
dirn01 = s_common.genpath(dirn, '01.cell')
|
|
3287
3287
|
dirn02 = s_common.genpath(dirn, '02.cell')
|
|
3288
|
+
dirn0002 = s_common.genpath(dirn, '00.02.cell')
|
|
3288
3289
|
|
|
3289
3290
|
cell00 = await base.enter_context(self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=dirn00))
|
|
3290
3291
|
cell01 = await base.enter_context(self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=dirn01,
|
|
@@ -3301,24 +3302,43 @@ class CellTest(s_t_utils.SynTest):
|
|
|
3301
3302
|
await cell01.handoff('some://url')
|
|
3302
3303
|
self.isin('01.cell is not the current leader', cm.exception.get('mesg'))
|
|
3303
3304
|
|
|
3304
|
-
#
|
|
3305
|
-
# control over the topology update is available during the promotion process.
|
|
3306
|
-
# Promote 02.cell -> Promote 01.cell -> Promote 00.cell -> BadState exception
|
|
3305
|
+
# Promote 02.cell -> Promote 01.cell -> Promote 00.cell, without breaking the configured topology
|
|
3307
3306
|
await cell02.promote(graceful=True)
|
|
3308
3307
|
self.false(cell00.isactive)
|
|
3308
|
+
self.eq(cell00.conf.get('mirror'), 'aha://root@cell...')
|
|
3309
3309
|
self.false(cell01.isactive)
|
|
3310
|
+
self.eq(cell01.conf.get('mirror'), 'aha://root@cell...')
|
|
3310
3311
|
self.true(cell02.isactive)
|
|
3312
|
+
self.none(cell02.conf.get('mirror'))
|
|
3311
3313
|
await cell02.sync()
|
|
3312
3314
|
|
|
3313
3315
|
await cell01.promote(graceful=True)
|
|
3314
3316
|
self.false(cell00.isactive)
|
|
3317
|
+
self.eq(cell00.conf.get('mirror'), 'aha://root@cell...')
|
|
3315
3318
|
self.true(cell01.isactive)
|
|
3319
|
+
self.none(cell01.conf.get('mirror'))
|
|
3316
3320
|
self.false(cell02.isactive)
|
|
3321
|
+
self.eq(cell02.conf.get('mirror'), 'aha://root@cell...')
|
|
3317
3322
|
await cell02.sync()
|
|
3318
3323
|
|
|
3324
|
+
await cell00.promote(graceful=True)
|
|
3325
|
+
self.true(cell00.isactive)
|
|
3326
|
+
self.none(cell00.conf.get('mirror'))
|
|
3327
|
+
self.false(cell01.isactive)
|
|
3328
|
+
self.eq(cell01.conf.get('mirror'), 'aha://root@cell...')
|
|
3329
|
+
self.false(cell02.isactive)
|
|
3330
|
+
self.eq(cell02.conf.get('mirror'), 'aha://root@cell...')
|
|
3331
|
+
await cell02.sync()
|
|
3332
|
+
|
|
3333
|
+
# A follower of a follower cannot be promoted up since its leader is not the active cell.
|
|
3334
|
+
cell0002 = await base.enter_context(self.addSvcToAha(aha, '00.02.cell', s_cell.Cell, dirn=dirn0002,
|
|
3335
|
+
provinfo={'mirror': '02.cell'}))
|
|
3336
|
+
self.false(cell0002.isactive)
|
|
3337
|
+
self.eq(cell0002.conf.get('mirror'), 'aha://root@02.cell...')
|
|
3319
3338
|
with self.raises(s_exc.BadState) as cm:
|
|
3320
|
-
await
|
|
3321
|
-
|
|
3339
|
+
await cell0002.promote(graceful=True)
|
|
3340
|
+
mesg = 'ahaname=02.cell is not the current leader and cannot handoff leadership to aha://00.02.cell.synapse.'
|
|
3341
|
+
self.isin(mesg, cm.exception.get('mesg'))
|
|
3322
3342
|
|
|
3323
3343
|
async def test_cell_get_aha_proxy(self):
|
|
3324
3344
|
|
synapse/tests/test_lib_coro.py
CHANGED
|
@@ -212,3 +212,26 @@ class CoroTest(s_t_utils.SynTest):
|
|
|
212
212
|
|
|
213
213
|
with self.raises(Exception):
|
|
214
214
|
await s_coro._parserforked(newp)
|
|
215
|
+
|
|
216
|
+
async def test_lib_coro_create_task(self):
|
|
217
|
+
|
|
218
|
+
async def sleep(n):
|
|
219
|
+
await asyncio.sleep(n)
|
|
220
|
+
if n == 0:
|
|
221
|
+
return 1 / 0
|
|
222
|
+
return n
|
|
223
|
+
|
|
224
|
+
s_coro.create_task(sleep(0.1))
|
|
225
|
+
s_coro.create_task(sleep(0.15))
|
|
226
|
+
s_coro.create_task(sleep(0.2))
|
|
227
|
+
self.len(3, s_coro.bgtasks)
|
|
228
|
+
results = await s_coro.await_bg_tasks()
|
|
229
|
+
self.eq(set(results), {0.1, 0.15, 0.2})
|
|
230
|
+
self.len(0, s_coro.bgtasks)
|
|
231
|
+
results = await s_coro.await_bg_tasks()
|
|
232
|
+
self.eq(results, [])
|
|
233
|
+
|
|
234
|
+
s_coro.create_task(sleep(0))
|
|
235
|
+
results = await s_coro.await_bg_tasks()
|
|
236
|
+
self.len(1, results)
|
|
237
|
+
self.isinstance(results[0], ZeroDivisionError)
|