synapse 2.208.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/layer.py +23 -1
- synapse/lib/nexus.py +6 -0
- synapse/lib/rstorm.py +3 -1
- synapse/lib/storm.py +10 -2
- synapse/lib/stormlib/auth.py +6 -0
- synapse/lib/stormlib/notifications.py +12 -2
- synapse/lib/stormtypes.py +8 -0
- synapse/lib/version.py +2 -2
- synapse/lib/view.py +19 -6
- 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_lib_rstorm.py +4 -3
- synapse/tests/test_lib_stormtypes.py +135 -3
- synapse/tests/test_lib_view.py +22 -0
- 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.208.0.dist-info → synapse-2.210.0.dist-info}/METADATA +2 -2
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/RECORD +60 -59
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/WHEEL +1 -1
- {synapse-2.208.0.dist-info → synapse-2.210.0.dist-info}/licenses/LICENSE +0 -0
- {synapse-2.208.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/layer.py
CHANGED
|
@@ -1569,7 +1569,10 @@ class Layer(s_nexus.Pusher):
|
|
|
1569
1569
|
await self.initUpstreamSync(uplayr)
|
|
1570
1570
|
|
|
1571
1571
|
async def initLayerPassive(self):
|
|
1572
|
+
await self._stopMirror()
|
|
1573
|
+
self._stopUpstream()
|
|
1572
1574
|
|
|
1575
|
+
async def _stopMirror(self):
|
|
1573
1576
|
if self.leadtask is not None:
|
|
1574
1577
|
self.leadtask.cancel()
|
|
1575
1578
|
self.leadtask = None
|
|
@@ -1578,6 +1581,7 @@ class Layer(s_nexus.Pusher):
|
|
|
1578
1581
|
await self.leader.fini()
|
|
1579
1582
|
self.leader = None
|
|
1580
1583
|
|
|
1584
|
+
def _stopUpstream(self):
|
|
1581
1585
|
[t.cancel() for t in self.activetasks]
|
|
1582
1586
|
self.activetasks.clear()
|
|
1583
1587
|
|
|
@@ -2786,6 +2790,11 @@ class Layer(s_nexus.Pusher):
|
|
|
2786
2790
|
async def setLayerInfo(self, name, valu):
|
|
2787
2791
|
if name != 'readonly':
|
|
2788
2792
|
self._reqNotReadOnly()
|
|
2793
|
+
|
|
2794
|
+
if name in ('mirror', 'upstream') and valu is not None:
|
|
2795
|
+
mesg = 'Layer only supports setting "mirror" and "upstream" to None.'
|
|
2796
|
+
raise s_exc.BadOptValu(mesg=mesg)
|
|
2797
|
+
|
|
2789
2798
|
return await self._push('layer:set', name, valu)
|
|
2790
2799
|
|
|
2791
2800
|
@s_nexus.Pusher.onPush('layer:set')
|
|
@@ -2793,17 +2802,25 @@ class Layer(s_nexus.Pusher):
|
|
|
2793
2802
|
'''
|
|
2794
2803
|
Set a mutable layer property.
|
|
2795
2804
|
'''
|
|
2796
|
-
if name not in ('name', 'desc', 'logedits', 'readonly'):
|
|
2805
|
+
if name not in ('name', 'desc', 'logedits', 'readonly', 'mirror', 'upstream'):
|
|
2797
2806
|
mesg = f'{name} is not a valid layer info key'
|
|
2798
2807
|
raise s_exc.BadOptValu(mesg=mesg)
|
|
2799
2808
|
|
|
2800
2809
|
if name == 'logedits':
|
|
2801
2810
|
valu = bool(valu)
|
|
2802
2811
|
self.logedits = valu
|
|
2812
|
+
|
|
2803
2813
|
elif name == 'readonly':
|
|
2804
2814
|
valu = bool(valu)
|
|
2805
2815
|
self.readonly = valu
|
|
2806
2816
|
|
|
2817
|
+
elif name == 'mirror' and valu is None:
|
|
2818
|
+
await self._stopMirror()
|
|
2819
|
+
self.ismirror = False
|
|
2820
|
+
|
|
2821
|
+
elif name == 'upstream' and valu is None:
|
|
2822
|
+
self._stopUpstream()
|
|
2823
|
+
|
|
2807
2824
|
# TODO when we can set more props, we may need to parse values.
|
|
2808
2825
|
if valu is None:
|
|
2809
2826
|
self.layrinfo.pop(name, None)
|
|
@@ -4382,6 +4399,11 @@ class Layer(s_nexus.Pusher):
|
|
|
4382
4399
|
async for verb, n2iden in self.iterNodeEdgesN1(buid):
|
|
4383
4400
|
edits.append((EDIT_EDGE_ADD, (verb, n2iden), ()))
|
|
4384
4401
|
|
|
4402
|
+
if len(edits) >= 100:
|
|
4403
|
+
yield nodeedit
|
|
4404
|
+
edits = []
|
|
4405
|
+
nodeedit = (buid, form, edits)
|
|
4406
|
+
|
|
4385
4407
|
yield nodeedit
|
|
4386
4408
|
|
|
4387
4409
|
async def initUpstreamSync(self, url):
|
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/rstorm.py
CHANGED
|
@@ -168,7 +168,9 @@ class StormOutput(s_cmds_cortex.StormCmd):
|
|
|
168
168
|
if self.ctx.pop('storm-fail', None):
|
|
169
169
|
s_cmds_cortex.StormCmd._onErr(self, mesg, opts)
|
|
170
170
|
return
|
|
171
|
-
|
|
171
|
+
(errname, errinfo) = mesg[1]
|
|
172
|
+
errinfo.setdefault('_errname', errname)
|
|
173
|
+
raise s_exc.StormRuntimeError(**errinfo)
|
|
172
174
|
|
|
173
175
|
async def runCmdOpts(self, opts):
|
|
174
176
|
|
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/stormtypes.py
CHANGED
|
@@ -7669,10 +7669,18 @@ class Layer(Prim):
|
|
|
7669
7669
|
valu = None
|
|
7670
7670
|
else:
|
|
7671
7671
|
valu = await tostr(await toprim(valu), noneok=True)
|
|
7672
|
+
|
|
7672
7673
|
elif name == 'logedits':
|
|
7673
7674
|
valu = await tobool(valu)
|
|
7675
|
+
|
|
7674
7676
|
elif name == 'readonly':
|
|
7675
7677
|
valu = await tobool(valu)
|
|
7678
|
+
|
|
7679
|
+
elif name in ('mirror', 'upstream'):
|
|
7680
|
+
if (valu := await toprim(valu)) is not None:
|
|
7681
|
+
mesg = 'Layer only supports setting "mirror" and "upstream" to null.'
|
|
7682
|
+
raise s_exc.BadOptValu(mesg=mesg)
|
|
7683
|
+
|
|
7676
7684
|
else:
|
|
7677
7685
|
mesg = f'Layer does not support setting: {name}'
|
|
7678
7686
|
raise s_exc.BadOptValu(mesg=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/lib/view.py
CHANGED
|
@@ -412,7 +412,7 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
412
412
|
|
|
413
413
|
nodeedits.append(nodeedit)
|
|
414
414
|
|
|
415
|
-
if len(nodeedits) ==
|
|
415
|
+
if len(nodeedits) == 5:
|
|
416
416
|
yield nodeedits
|
|
417
417
|
nodeedits.clear()
|
|
418
418
|
|
|
@@ -432,7 +432,7 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
432
432
|
|
|
433
433
|
meta['time'] = s_common.now()
|
|
434
434
|
|
|
435
|
-
await snap.
|
|
435
|
+
await snap._applyNodeEdits(edits, meta)
|
|
436
436
|
await asyncio.sleep(0)
|
|
437
437
|
|
|
438
438
|
count += len(edits)
|
|
@@ -1467,8 +1467,6 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
1467
1467
|
Merge this view into its parent. All changes made to this view will be applied to the parent. Parent's
|
|
1468
1468
|
triggers will be run.
|
|
1469
1469
|
'''
|
|
1470
|
-
fromlayr = self.layers[0]
|
|
1471
|
-
|
|
1472
1470
|
if useriden is None:
|
|
1473
1471
|
user = await self.core.auth.getUserByName('root')
|
|
1474
1472
|
else:
|
|
@@ -1481,10 +1479,25 @@ class View(s_nexus.Pusher): # type: ignore
|
|
|
1481
1479
|
|
|
1482
1480
|
async with await self.parent.snap(user=user) as snap:
|
|
1483
1481
|
|
|
1482
|
+
async def chunked():
|
|
1483
|
+
nodeedits = []
|
|
1484
|
+
|
|
1485
|
+
async for nodeedit in self.layers[0].iterLayerNodeEdits():
|
|
1486
|
+
|
|
1487
|
+
nodeedits.append(nodeedit)
|
|
1488
|
+
|
|
1489
|
+
if len(nodeedits) == 5:
|
|
1490
|
+
yield nodeedits
|
|
1491
|
+
nodeedits.clear()
|
|
1492
|
+
|
|
1493
|
+
if nodeedits:
|
|
1494
|
+
yield nodeedits
|
|
1495
|
+
|
|
1484
1496
|
meta = await snap.getSnapMeta()
|
|
1485
|
-
async for
|
|
1497
|
+
async for edits in chunked():
|
|
1486
1498
|
meta['time'] = s_common.now()
|
|
1487
|
-
await snap.
|
|
1499
|
+
await snap._applyNodeEdits(edits, meta)
|
|
1500
|
+
await asyncio.sleep(0)
|
|
1488
1501
|
|
|
1489
1502
|
async def swapLayer(self):
|
|
1490
1503
|
oldlayr = self.layers[0]
|
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')
|