synapse 2.197.0__py311-none-any.whl → 2.198.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 -0
- synapse/common.py +3 -0
- synapse/cortex.py +1 -3
- synapse/lib/aha.py +3 -0
- synapse/lib/ast.py +277 -165
- synapse/lib/auth.py +39 -11
- synapse/lib/cell.py +22 -4
- synapse/lib/hive.py +2 -1
- synapse/lib/hiveauth.py +10 -1
- synapse/lib/jsonstor.py +6 -5
- synapse/lib/layer.py +6 -5
- synapse/lib/node.py +10 -4
- synapse/lib/parser.py +46 -21
- synapse/lib/schemas.py +13 -0
- synapse/lib/snap.py +68 -26
- synapse/lib/storm.lark +13 -11
- synapse/lib/storm.py +1 -1
- synapse/lib/storm_format.py +3 -2
- synapse/lib/stormtypes.py +13 -4
- synapse/lib/version.py +2 -2
- synapse/models/infotech.py +18 -0
- synapse/models/risk.py +9 -0
- synapse/models/syn.py +18 -2
- synapse/tests/files/stormpkg/badendpoints.yaml +7 -0
- synapse/tests/files/stormpkg/testpkg.yaml +8 -0
- synapse/tests/test_cortex.py +108 -0
- synapse/tests/test_lib_aha.py +12 -2
- synapse/tests/test_lib_ast.py +57 -0
- synapse/tests/test_lib_auth.py +143 -2
- synapse/tests/test_lib_grammar.py +54 -2
- synapse/tests/test_lib_lmdbslab.py +24 -0
- synapse/tests/test_lib_storm.py +20 -0
- synapse/tests/test_lib_stormlib_macro.py +3 -3
- synapse/tests/test_lib_stormtypes.py +14 -2
- synapse/tests/test_model_infotech.py +13 -0
- synapse/tests/test_model_risk.py +6 -0
- synapse/tests/test_model_syn.py +58 -0
- synapse/tests/test_tools_genpkg.py +10 -0
- synapse/tools/hive/load.py +1 -0
- {synapse-2.197.0.dist-info → synapse-2.198.0.dist-info}/METADATA +1 -1
- {synapse-2.197.0.dist-info → synapse-2.198.0.dist-info}/RECORD +44 -43
- {synapse-2.197.0.dist-info → synapse-2.198.0.dist-info}/LICENSE +0 -0
- {synapse-2.197.0.dist-info → synapse-2.198.0.dist-info}/WHEEL +0 -0
- {synapse-2.197.0.dist-info → synapse-2.198.0.dist-info}/top_level.txt +0 -0
synapse/lib/storm.lark
CHANGED
|
@@ -40,7 +40,7 @@ _editblock: "[" _editoper* "]"
|
|
|
40
40
|
// A single edit operation
|
|
41
41
|
_editoper: editnodeadd
|
|
42
42
|
| editpropset | editunivset | edittagpropset | edittagadd | editcondpropset
|
|
43
|
-
| editpropdel | editunivdel | edittagpropdel | edittagdel
|
|
43
|
+
| editpropsetmulti | editpropdel | editunivdel | edittagpropdel | edittagdel
|
|
44
44
|
| editparens | edgeaddn1 | edgedeln1 | edgeaddn2 | edgedeln2
|
|
45
45
|
|
|
46
46
|
// Parenthesis in an edit block don't have incoming nodes
|
|
@@ -48,18 +48,20 @@ editparens: "(" editnodeadd _editoper* ")"
|
|
|
48
48
|
edittagadd: "+" [SETTAGOPER] tagname [(EQSPACE | EQNOSPACE) _valu]
|
|
49
49
|
editunivdel: EXPRMINUS univprop
|
|
50
50
|
edittagdel: EXPRMINUS tagname
|
|
51
|
-
editpropset: relprop (EQSPACE | EQNOSPACE | MODSET | TRYSET |
|
|
51
|
+
editpropset: relprop (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYMODSET) _valu
|
|
52
52
|
editcondpropset: relprop condsetoper _valu
|
|
53
|
+
editpropsetmulti: relprop (MODSETMULTI | TRYMODSETMULTI) _valu
|
|
53
54
|
editpropdel: EXPRMINUS relprop
|
|
54
|
-
editunivset: univprop (EQSPACE | EQNOSPACE | MODSET | TRYSET |
|
|
55
|
-
editnodeadd: formname (EQSPACE | EQNOSPACE | MODSET | TRYSET |
|
|
56
|
-
edittagpropset: "+" tagprop (EQSPACE | EQNOSPACE | MODSET | TRYSET |
|
|
55
|
+
editunivset: univprop (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYMODSET) _valu
|
|
56
|
+
editnodeadd: formname (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYMODSET) _valu
|
|
57
|
+
edittagpropset: "+" tagprop (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYMODSET) _valu
|
|
57
58
|
edittagpropdel: EXPRMINUS tagprop
|
|
58
59
|
|
|
59
60
|
EQSPACE: /((?<=\s)=|=(?=\s))/
|
|
60
61
|
MODSET.4: "+=" | "-="
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
TRYMODSET.1: "?+=" | "?-="
|
|
63
|
+
MODSETMULTI.4: "++=" | "--="
|
|
64
|
+
TRYMODSETMULTI.1: "?++=" | "?--="
|
|
63
65
|
TRYSET.1: "?="
|
|
64
66
|
SETTAGOPER: "?"
|
|
65
67
|
|
|
@@ -226,10 +228,10 @@ _EDGEN2JOININIT: "<+("
|
|
|
226
228
|
// comparisons to an expression like '<(2)'
|
|
227
229
|
_EDGEN2INIT: /\<\((?=(?>(?<EDGEN2INITRECUR>\(((?>[^()"'`]+|(?&EDGEN2INITRECUR)|`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'''.*?'''|'[^']*'(?!'))*)\))|'''.*?'''|`(?:[^`\\]|\\.)*`|"(?:[^"\\]|\\.)*"|'[^']*'(?!')|[^)])*\)[\-\+])/
|
|
228
230
|
|
|
229
|
-
edgeaddn1: _EDGEADDN1INIT _valu _EDGEN1FINI baresubquery
|
|
230
|
-
edgedeln1: _EDGEN1INIT _valu _EDGEN1FINI baresubquery
|
|
231
|
-
edgeaddn2: _EDGEN2INIT _valu _EDGEADDN2FINI baresubquery
|
|
232
|
-
edgedeln2: _EDGEN2INIT _valu _EDGEN2FINI baresubquery
|
|
231
|
+
edgeaddn1: _EDGEADDN1INIT _valu _EDGEN1FINI (baresubquery | _varvalu)
|
|
232
|
+
edgedeln1: _EDGEN1INIT _valu _EDGEN1FINI (baresubquery | _varvalu)
|
|
233
|
+
edgeaddn2: _EDGEN2INIT _valu _EDGEADDN2FINI (baresubquery | _varvalu)
|
|
234
|
+
edgedeln2: _EDGEN2INIT _valu _EDGEN2FINI (baresubquery | _varvalu)
|
|
233
235
|
|
|
234
236
|
_REVERSE: /reverse(?=[\s\(])/
|
|
235
237
|
liftreverse: _REVERSE "(" (liftformtag | liftpropby | liftprop | liftbyarray | lifttagtag | liftbytag | liftbytagprop | liftbyformtagprop) ")"
|
synapse/lib/storm.py
CHANGED
|
@@ -1299,7 +1299,7 @@ stormcmds = (
|
|
|
1299
1299
|
|
|
1300
1300
|
@s_cache.memoize(size=1024)
|
|
1301
1301
|
def queryhash(text):
|
|
1302
|
-
return
|
|
1302
|
+
return s_common.queryhash(text)
|
|
1303
1303
|
|
|
1304
1304
|
class DmonManager(s_base.Base):
|
|
1305
1305
|
'''
|
synapse/lib/storm_format.py
CHANGED
|
@@ -55,6 +55,7 @@ TerminalPygMap = {
|
|
|
55
55
|
'LSQB': p_t.Punctuation,
|
|
56
56
|
'MCASEBARE': p_t.Literal.String,
|
|
57
57
|
'MODSET': p_t.Operator,
|
|
58
|
+
'MODSETMULTI': p_t.Operator,
|
|
58
59
|
'NONQUOTEWORD': p_t.Literal,
|
|
59
60
|
'NOT': p_t.Keyword,
|
|
60
61
|
'NULL': p_t.Keyword,
|
|
@@ -74,8 +75,8 @@ TerminalPygMap = {
|
|
|
74
75
|
'TAGSEGNOVAR': p_t.Name,
|
|
75
76
|
'TRIPLEQUOTEDSTRING': p_t.Literal.String,
|
|
76
77
|
'TRYSET': p_t.Operator,
|
|
77
|
-
'
|
|
78
|
-
'
|
|
78
|
+
'TRYMODSET': p_t.Operator,
|
|
79
|
+
'TRYMODSETMULTI': p_t.Operator,
|
|
79
80
|
'UNIVNAME': p_t.Name,
|
|
80
81
|
'UNSET': p_t.Operator,
|
|
81
82
|
'EXPRUNIVNAME': p_t.Name,
|
synapse/lib/stormtypes.py
CHANGED
|
@@ -3490,7 +3490,11 @@ class LibRegx(Lib):
|
|
|
3490
3490
|
lkey = (pattern, flags)
|
|
3491
3491
|
regx = self.compiled.get(lkey)
|
|
3492
3492
|
if regx is None:
|
|
3493
|
-
|
|
3493
|
+
try:
|
|
3494
|
+
regx = self.compiled[lkey] = regex.compile(pattern, flags=flags)
|
|
3495
|
+
except (regex.error, ValueError) as e:
|
|
3496
|
+
mesg = f'Error compiling regex pattern: {e}: pattern="{s_common.trimText(pattern)}"'
|
|
3497
|
+
raise s_exc.BadArg(mesg=mesg) from None
|
|
3494
3498
|
return regx
|
|
3495
3499
|
|
|
3496
3500
|
@stormfunc(readonly=True)
|
|
@@ -3500,7 +3504,12 @@ class LibRegx(Lib):
|
|
|
3500
3504
|
pattern = await tostr(pattern)
|
|
3501
3505
|
replace = await tostr(replace)
|
|
3502
3506
|
regx = await self._getRegx(pattern, flags)
|
|
3503
|
-
|
|
3507
|
+
|
|
3508
|
+
try:
|
|
3509
|
+
return regx.sub(replace, text)
|
|
3510
|
+
except (regex.error, IndexError) as e:
|
|
3511
|
+
mesg = f'$lib.regex.replace() error: {e}'
|
|
3512
|
+
raise s_exc.BadArg(mesg=mesg) from None
|
|
3504
3513
|
|
|
3505
3514
|
@stormfunc(readonly=True)
|
|
3506
3515
|
async def matches(self, pattern, text, flags=0):
|
|
@@ -9868,7 +9877,7 @@ async def tostor(valu, isndef=False):
|
|
|
9868
9877
|
retn = []
|
|
9869
9878
|
for v in valu:
|
|
9870
9879
|
try:
|
|
9871
|
-
retn.append(await tostor(v))
|
|
9880
|
+
retn.append(await tostor(v, isndef=isndef))
|
|
9872
9881
|
except s_exc.NoSuchType:
|
|
9873
9882
|
pass
|
|
9874
9883
|
return tuple(retn)
|
|
@@ -9877,7 +9886,7 @@ async def tostor(valu, isndef=False):
|
|
|
9877
9886
|
retn = {}
|
|
9878
9887
|
for k, v in valu.items():
|
|
9879
9888
|
try:
|
|
9880
|
-
retn[k] = await tostor(v)
|
|
9889
|
+
retn[k] = await tostor(v, isndef=isndef)
|
|
9881
9890
|
except s_exc.NoSuchType:
|
|
9882
9891
|
pass
|
|
9883
9892
|
return retn
|
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, 198, 0)
|
|
227
227
|
verstring = '.'.join([str(x) for x in version])
|
|
228
|
-
commit = '
|
|
228
|
+
commit = '047e5e996d0bcaad4ada4ea390a726aca1abba9b'
|
synapse/models/infotech.py
CHANGED
|
@@ -1252,6 +1252,15 @@ class ItModule(s_module.CoreModule):
|
|
|
1252
1252
|
('product', ('it:prod:softver', {}), {
|
|
1253
1253
|
'doc': 'The software which produced the log entry.'}),
|
|
1254
1254
|
|
|
1255
|
+
('service:platform', ('inet:service:platform', {}), {
|
|
1256
|
+
'doc': 'The service platform which generated the log event.'}),
|
|
1257
|
+
|
|
1258
|
+
('service:instance', ('inet:service:instance', {}), {
|
|
1259
|
+
'doc': 'The service instance which generated the log event.'}),
|
|
1260
|
+
|
|
1261
|
+
('service:account', ('inet:service:account', {}), {
|
|
1262
|
+
'doc': 'The service account which generated the log event.'}),
|
|
1263
|
+
|
|
1255
1264
|
)),
|
|
1256
1265
|
('it:domain', {}, (
|
|
1257
1266
|
('name', ('str', {'lower': True, 'onespace': True}), {
|
|
@@ -2587,6 +2596,15 @@ class ItModule(s_module.CoreModule):
|
|
|
2587
2596
|
|
|
2588
2597
|
('synuser', ('syn:user', {}), {
|
|
2589
2598
|
'doc': 'The synapse user who executed the query.'}),
|
|
2599
|
+
|
|
2600
|
+
('service:platform', ('inet:service:platform', {}), {
|
|
2601
|
+
'doc': 'The service platform which was queried.'}),
|
|
2602
|
+
|
|
2603
|
+
('service:instance', ('inet:service:instance', {}), {
|
|
2604
|
+
'doc': 'The service instance which was queried.'}),
|
|
2605
|
+
|
|
2606
|
+
('service:account', ('inet:service:account', {}), {
|
|
2607
|
+
'doc': 'The service account which ran the query.'}),
|
|
2590
2608
|
)),
|
|
2591
2609
|
('it:exec:thread', {}, (
|
|
2592
2610
|
('proc', ('it:exec:proc', {}), {
|
synapse/models/risk.py
CHANGED
|
@@ -810,6 +810,15 @@ class RiskModule(s_module.CoreModule):
|
|
|
810
810
|
|
|
811
811
|
('host', ('it:host', {}), {
|
|
812
812
|
'doc': 'The host which generated the alert.'}),
|
|
813
|
+
|
|
814
|
+
('service:platform', ('inet:service:platform', {}), {
|
|
815
|
+
'doc': 'The service platform which generated the alert.'}),
|
|
816
|
+
|
|
817
|
+
('service:instance', ('inet:service:instance', {}), {
|
|
818
|
+
'doc': 'The service instance which generated the alert.'}),
|
|
819
|
+
|
|
820
|
+
('service:account', ('inet:service:account', {}), {
|
|
821
|
+
'doc': 'The service account which generated the alert.'}),
|
|
813
822
|
)),
|
|
814
823
|
('risk:compromisetype', {}, ()),
|
|
815
824
|
('risk:compromise', {}, (
|
synapse/models/syn.py
CHANGED
|
@@ -23,7 +23,15 @@ class SynUser(s_types.Guid):
|
|
|
23
23
|
if user is not None:
|
|
24
24
|
return user.iden, {}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
if text == '*':
|
|
27
|
+
mesg = f'{self.name} values must be a valid username or a guid.'
|
|
28
|
+
raise s_exc.BadTypeValu(mesg=mesg, name=self.name, valu=text)
|
|
29
|
+
|
|
30
|
+
try:
|
|
31
|
+
return s_types.Guid._normPyStr(self, text)
|
|
32
|
+
except s_exc.BadTypeValu:
|
|
33
|
+
mesg = f'No user named {text} and value is not a guid.'
|
|
34
|
+
raise s_exc.BadTypeValu(mesg=mesg, name=self.name, valu=text) from None
|
|
27
35
|
|
|
28
36
|
def repr(self, iden):
|
|
29
37
|
|
|
@@ -51,7 +59,15 @@ class SynRole(s_types.Guid):
|
|
|
51
59
|
if role is not None:
|
|
52
60
|
return role.iden, {}
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
if text == '*':
|
|
63
|
+
mesg = f'{self.name} values must be a valid rolename or a guid.'
|
|
64
|
+
raise s_exc.BadTypeValu(mesg=mesg, name=self.name, valu=text)
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
return s_types.Guid._normPyStr(self, text)
|
|
68
|
+
except s_exc.BadTypeValu:
|
|
69
|
+
mesg = f'No role named {text} and value is not a guid.'
|
|
70
|
+
raise s_exc.BadTypeValu(mesg=mesg, name=self.name, valu=text) from None
|
|
55
71
|
|
|
56
72
|
def repr(self, iden):
|
|
57
73
|
|
|
@@ -113,6 +113,14 @@ commands:
|
|
|
113
113
|
- help: Help on foo opt
|
|
114
114
|
- - --bar
|
|
115
115
|
- help: Help on bar opt
|
|
116
|
+
storm: |
|
|
117
|
+
test:str
|
|
118
|
+
endpoints:
|
|
119
|
+
- path: /v1/test/one
|
|
120
|
+
- path: /v1/test/two
|
|
121
|
+
host: vertex.link
|
|
122
|
+
- path: /v1/test/three
|
|
123
|
+
desc: endpoint three
|
|
116
124
|
|
|
117
125
|
- name: testpkg.baz
|
|
118
126
|
descr: |
|
synapse/tests/test_cortex.py
CHANGED
|
@@ -1001,6 +1001,114 @@ class CortexTest(s_t_utils.SynTest):
|
|
|
1001
1001
|
self.eq(cm.exception.get('mesg'),
|
|
1002
1002
|
'walk operation expected a string or list. got: 0.')
|
|
1003
1003
|
|
|
1004
|
+
await core.nodes('[media:news=*]')
|
|
1005
|
+
|
|
1006
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ +(refs)> $n ]')
|
|
1007
|
+
self.len(1, nodes)
|
|
1008
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1009
|
+
|
|
1010
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1011
|
+
self.len(1, nodes)
|
|
1012
|
+
|
|
1013
|
+
q = '''
|
|
1014
|
+
function foo() {
|
|
1015
|
+
for $x in $lib.range(5) {
|
|
1016
|
+
[ it:dev:int=$x ]
|
|
1017
|
+
emit $node
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
media:news [ +(refs)> $foo() ]
|
|
1021
|
+
'''
|
|
1022
|
+
nodes = await core.nodes(q)
|
|
1023
|
+
self.len(1, nodes)
|
|
1024
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1025
|
+
|
|
1026
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:int')
|
|
1027
|
+
self.len(5, nodes)
|
|
1028
|
+
|
|
1029
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ -(refs)> $n ]')
|
|
1030
|
+
self.len(1, nodes)
|
|
1031
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1032
|
+
|
|
1033
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1034
|
+
self.len(0, nodes)
|
|
1035
|
+
|
|
1036
|
+
q = '''
|
|
1037
|
+
function foo() {
|
|
1038
|
+
for $x in $lib.range(5) {
|
|
1039
|
+
[ it:dev:int=$x ]
|
|
1040
|
+
emit $node
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
media:news [ -(refs)> $foo() ]
|
|
1044
|
+
'''
|
|
1045
|
+
nodes = await core.nodes(q)
|
|
1046
|
+
self.len(1, nodes)
|
|
1047
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1048
|
+
|
|
1049
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:int')
|
|
1050
|
+
self.len(0, nodes)
|
|
1051
|
+
|
|
1052
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ <(refs)+ $n ]')
|
|
1053
|
+
self.len(1, nodes)
|
|
1054
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1055
|
+
|
|
1056
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:str')
|
|
1057
|
+
self.len(1, nodes)
|
|
1058
|
+
|
|
1059
|
+
q = '''
|
|
1060
|
+
function foo() {
|
|
1061
|
+
for $x in $lib.range(5) {
|
|
1062
|
+
[ it:dev:int=$x ]
|
|
1063
|
+
emit $node
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
media:news [ <(refs)+ $foo() ]
|
|
1067
|
+
'''
|
|
1068
|
+
nodes = await core.nodes(q)
|
|
1069
|
+
self.len(1, nodes)
|
|
1070
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1071
|
+
|
|
1072
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:int')
|
|
1073
|
+
self.len(5, nodes)
|
|
1074
|
+
|
|
1075
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} media:news [ <(refs)- $n ]')
|
|
1076
|
+
self.len(1, nodes)
|
|
1077
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1078
|
+
|
|
1079
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:str')
|
|
1080
|
+
self.len(0, nodes)
|
|
1081
|
+
|
|
1082
|
+
q = '''
|
|
1083
|
+
function foo() {
|
|
1084
|
+
for $x in $lib.range(5) {
|
|
1085
|
+
[ it:dev:int=$x ]
|
|
1086
|
+
emit $node
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
media:news [ <(refs)- $foo() ]
|
|
1090
|
+
'''
|
|
1091
|
+
nodes = await core.nodes(q)
|
|
1092
|
+
self.len(1, nodes)
|
|
1093
|
+
self.eq(nodes[0].ndef[0], 'media:news')
|
|
1094
|
+
|
|
1095
|
+
nodes = await core.nodes('media:news <(refs)- it:dev:int')
|
|
1096
|
+
self.len(0, nodes)
|
|
1097
|
+
|
|
1098
|
+
await core.nodes('[media:news=*]')
|
|
1099
|
+
|
|
1100
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} $edge=refs media:news [ +($edge)> $n ]')
|
|
1101
|
+
self.len(2, nodes)
|
|
1102
|
+
|
|
1103
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1104
|
+
self.len(2, nodes)
|
|
1105
|
+
|
|
1106
|
+
nodes = await core.nodes('$n = {[it:dev:str=foo]} $edge=refs media:news [ -($edge)> $n ]')
|
|
1107
|
+
self.len(2, nodes)
|
|
1108
|
+
|
|
1109
|
+
nodes = await core.nodes('media:news -(refs)> it:dev:str')
|
|
1110
|
+
self.len(0, nodes)
|
|
1111
|
+
|
|
1004
1112
|
async def test_cortex_callstorm(self):
|
|
1005
1113
|
|
|
1006
1114
|
async with self.getTestCore(conf={'auth:passwd': 'root'}) as core:
|
synapse/tests/test_lib_aha.py
CHANGED
|
@@ -133,9 +133,14 @@ class AhaTest(s_test.SynTest):
|
|
|
133
133
|
with self.getTestDir() as dirn:
|
|
134
134
|
cryo0_dirn = s_common.gendir(dirn, 'cryo0')
|
|
135
135
|
async with self.getTestAha(dirn=dirn) as aha:
|
|
136
|
+
|
|
137
|
+
replaymult = 1
|
|
138
|
+
if s_common.envbool('SYNDEV_NEXUS_REPLAY'):
|
|
139
|
+
replaymult = 2
|
|
140
|
+
|
|
136
141
|
purl = await aha.addAhaSvcProv('0.cryo')
|
|
137
142
|
|
|
138
|
-
wait00 = aha.waiter(1, 'aha:svcadd')
|
|
143
|
+
wait00 = aha.waiter(1 * replaymult, 'aha:svcadd')
|
|
139
144
|
|
|
140
145
|
conf = {'aha:provision': purl}
|
|
141
146
|
async with self.getTestCryo(dirn=cryo0_dirn, conf=conf) as cryo:
|
|
@@ -444,8 +449,13 @@ class AhaTest(s_test.SynTest):
|
|
|
444
449
|
|
|
445
450
|
async with self.getTestAha() as aha:
|
|
446
451
|
|
|
452
|
+
replaymult = 1
|
|
453
|
+
if s_common.envbool('SYNDEV_NEXUS_REPLAY'):
|
|
454
|
+
replaymult = 2
|
|
455
|
+
|
|
447
456
|
aha.testerr = True
|
|
448
457
|
wait00 = aha.waiter(1, 'aha:svcadd')
|
|
458
|
+
|
|
449
459
|
conf = {'aha:provision': await aha.addAhaSvcProv('0.cryo')}
|
|
450
460
|
async with self.getTestCryo(conf=conf) as cryo:
|
|
451
461
|
|
|
@@ -454,7 +464,7 @@ class AhaTest(s_test.SynTest):
|
|
|
454
464
|
svc = await aha.getAhaSvc('0.cryo...')
|
|
455
465
|
self.none(svc)
|
|
456
466
|
|
|
457
|
-
wait01 = aha.waiter(1, 'aha:svcadd')
|
|
467
|
+
wait01 = aha.waiter(1 * replaymult, 'aha:svcadd')
|
|
458
468
|
aha.testerr = False
|
|
459
469
|
|
|
460
470
|
self.nn(await wait01.wait(timeout=2))
|
synapse/tests/test_lib_ast.py
CHANGED
|
@@ -492,6 +492,63 @@ class AstTest(s_test.SynTest):
|
|
|
492
492
|
q = '$foo=newp [test:str=foo :hehe*$foo=heval]'
|
|
493
493
|
nodes = await core.nodes(q)
|
|
494
494
|
|
|
495
|
+
async def test_ast_setmultioper(self):
|
|
496
|
+
async with self.getTestCore() as core:
|
|
497
|
+
|
|
498
|
+
nodes = await core.nodes('[ test:arrayprop="*" :ints=(1,) ]')
|
|
499
|
+
self.eq(nodes[0].get('ints'), (1,))
|
|
500
|
+
|
|
501
|
+
nodes = await core.nodes('test:arrayprop [ :ints++=([3, 4]) ]')
|
|
502
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
503
|
+
|
|
504
|
+
nodes = await core.nodes('test:arrayprop [ :ints++=(null) ]')
|
|
505
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
506
|
+
|
|
507
|
+
nodes = await core.nodes('test:arrayprop [ :ints--=(null) ]')
|
|
508
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
509
|
+
|
|
510
|
+
nodes = await core.nodes('test:arrayprop [ :strs++=(foo, bar, baz) ]')
|
|
511
|
+
self.eq(nodes[0].get('strs'), ('foo', 'bar', 'baz'))
|
|
512
|
+
|
|
513
|
+
with self.raises(s_exc.BadTypeValu):
|
|
514
|
+
await core.nodes('test:arrayprop [ :ints++=(["newp", 5, 6]) ]')
|
|
515
|
+
|
|
516
|
+
nodes = await core.nodes('test:arrayprop [ :ints?++=(["newp", 5, 6]) ]')
|
|
517
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4, 5, 6))
|
|
518
|
+
|
|
519
|
+
with self.raises(s_exc.BadTypeValu):
|
|
520
|
+
await core.nodes('test:arrayprop [ :ints--=(["newp", 5, 6]) ]')
|
|
521
|
+
|
|
522
|
+
nodes = await core.nodes('test:arrayprop [ :ints?--=(["newp", 5, 6, 7]) ]')
|
|
523
|
+
self.eq(nodes[0].get('ints'), (1, 3, 4))
|
|
524
|
+
|
|
525
|
+
nodes = await core.nodes('[ test:str=foo :ndefs++={[ test:str=bar ]} ]')
|
|
526
|
+
self.eq(nodes[0].get('ndefs'), (('test:str', 'bar'),))
|
|
527
|
+
|
|
528
|
+
nodes = await core.nodes('test:str=foo [ :ndefs++={[ test:str=baz test:str=faz ]} ]')
|
|
529
|
+
self.eq(nodes[0].get('ndefs'), (('test:str', 'bar'), ('test:str', 'baz'), ('test:str', 'faz')))
|
|
530
|
+
|
|
531
|
+
nodes = await core.nodes('test:str=foo [ :ndefs--={ test:str=baz test:str=faz } ]')
|
|
532
|
+
self.eq(nodes[0].get('ndefs'), (('test:str', 'bar'),))
|
|
533
|
+
|
|
534
|
+
with self.raises(s_exc.NoSuchProp):
|
|
535
|
+
await core.nodes('test:arrayprop [ :newp++=(["newp", 5, 6]) ]')
|
|
536
|
+
|
|
537
|
+
badq = [
|
|
538
|
+
'test:str [ :hehe++=([3, 4]) ]',
|
|
539
|
+
'test:str [ :hehe?++=([3, 4]) ]',
|
|
540
|
+
'test:str [ :hehe--=([3, 4]) ]',
|
|
541
|
+
'test:str [ :hehe?--=([3, 4]) ]',
|
|
542
|
+
'test:arrayprop [ :ints++=(3) ]',
|
|
543
|
+
'test:arrayprop [ :ints?++=(3) ]',
|
|
544
|
+
'test:arrayprop [ :ints--=(3) ]',
|
|
545
|
+
'test:arrayprop [ :ints?--=(3) ]',
|
|
546
|
+
]
|
|
547
|
+
|
|
548
|
+
for q in badq:
|
|
549
|
+
with self.raises(s_exc.StormRuntimeError):
|
|
550
|
+
await core.nodes(q)
|
|
551
|
+
|
|
495
552
|
async def test_ast_editparens(self):
|
|
496
553
|
|
|
497
554
|
async with self.getTestCore() as core:
|
synapse/tests/test_lib_auth.py
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import string
|
|
2
2
|
import pathlib
|
|
3
3
|
|
|
4
|
+
from unittest import mock
|
|
5
|
+
|
|
4
6
|
import synapse.exc as s_exc
|
|
7
|
+
import synapse.common as s_common
|
|
5
8
|
import synapse.telepath as s_telepath
|
|
6
|
-
|
|
9
|
+
|
|
10
|
+
import synapse.lib.auth as s_auth
|
|
11
|
+
import synapse.lib.cell as s_cell
|
|
12
|
+
import synapse.lib.lmdbslab as s_lmdbslab
|
|
7
13
|
|
|
8
14
|
import synapse.tests.utils as s_test
|
|
9
15
|
|
|
@@ -426,6 +432,126 @@ class AuthTest(s_test.SynTest):
|
|
|
426
432
|
with self.raises(s_exc.SchemaViolation):
|
|
427
433
|
await core.auth.allrole.setRules([(True, )])
|
|
428
434
|
|
|
435
|
+
async def test_auth_archived_locked_interaction(self):
|
|
436
|
+
|
|
437
|
+
# Check that we can't unlock an archived user
|
|
438
|
+
async with self.getTestCore() as core:
|
|
439
|
+
lowuser = await core.addUser('lowuser')
|
|
440
|
+
useriden = lowuser.get('iden')
|
|
441
|
+
|
|
442
|
+
await core.setUserArchived(useriden, True)
|
|
443
|
+
|
|
444
|
+
udef = await core.getUserDef(useriden)
|
|
445
|
+
self.true(udef.get('archived'))
|
|
446
|
+
self.true(udef.get('locked'))
|
|
447
|
+
|
|
448
|
+
# Unlocking an archived user is invalid
|
|
449
|
+
with self.raises(s_exc.BadArg) as exc:
|
|
450
|
+
await core.setUserLocked(useriden, False)
|
|
451
|
+
self.eq(exc.exception.get('mesg'), 'Cannot unlock archived user.')
|
|
452
|
+
self.eq(exc.exception.get('user'), useriden)
|
|
453
|
+
self.eq(exc.exception.get('username'), 'lowuser')
|
|
454
|
+
|
|
455
|
+
# Check our cell migration that locks archived users
|
|
456
|
+
async with self.getRegrCore('unlocked-archived-users') as core:
|
|
457
|
+
for ii in range(10):
|
|
458
|
+
user = await core.getUserDefByName(f'lowuser{ii:02d}')
|
|
459
|
+
self.nn(user)
|
|
460
|
+
self.true(user.get('archived'))
|
|
461
|
+
self.true(user.get('locked'))
|
|
462
|
+
|
|
463
|
+
# Check behavior of upgraded mirrors and non-upgraded leader
|
|
464
|
+
async with self.getTestAha() as aha:
|
|
465
|
+
|
|
466
|
+
with self.getTestDir() as dirn:
|
|
467
|
+
path00 = s_common.gendir(dirn, 'cell00')
|
|
468
|
+
path01 = s_common.gendir(dirn, 'cell01')
|
|
469
|
+
|
|
470
|
+
with mock.patch('synapse.lib.cell.NEXUS_VERSION', (2, 177)):
|
|
471
|
+
async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
|
|
472
|
+
lowuser = await cell00.addUser('lowuser')
|
|
473
|
+
useriden = lowuser.get('iden')
|
|
474
|
+
await cell00.setUserArchived(useriden, True)
|
|
475
|
+
|
|
476
|
+
with mock.patch('synapse.lib.cell.NEXUS_VERSION', (2, 198)):
|
|
477
|
+
async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
|
|
478
|
+
await cell01.sync()
|
|
479
|
+
udef = await cell01.getUserDef(useriden)
|
|
480
|
+
self.true(udef.get('locked'))
|
|
481
|
+
self.true(udef.get('archived'))
|
|
482
|
+
|
|
483
|
+
# Simulate a call to cell00.setUserLocked(useriden, False) to bypass
|
|
484
|
+
# the check in cell00.auth.setUserInfo()
|
|
485
|
+
await cell00.auth._push('user:info', useriden, 'locked', False)
|
|
486
|
+
await cell01.sync()
|
|
487
|
+
|
|
488
|
+
udef00 = await cell00.getUserDef(useriden)
|
|
489
|
+
self.true(udef00.get('archived'))
|
|
490
|
+
self.false(udef00.get('locked'))
|
|
491
|
+
|
|
492
|
+
udef01 = await cell01.getUserDef(useriden)
|
|
493
|
+
self.true(udef01.get('archived'))
|
|
494
|
+
self.false(udef01.get('locked'))
|
|
495
|
+
|
|
496
|
+
# Check that we don't blowup/schism if an upgraded mirror is behind a leader with a pending
|
|
497
|
+
# user:info event that unlocks an archived user
|
|
498
|
+
async with self.getTestAha() as aha:
|
|
499
|
+
|
|
500
|
+
with self.getTestDir() as dirn:
|
|
501
|
+
path00 = s_common.gendir(dirn, 'cell00')
|
|
502
|
+
path01 = s_common.gendir(dirn, 'cell01')
|
|
503
|
+
|
|
504
|
+
async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
|
|
505
|
+
lowuser = await cell00.addUser('lowuser')
|
|
506
|
+
useriden = lowuser.get('iden')
|
|
507
|
+
await cell00.setUserLocked(useriden, True)
|
|
508
|
+
|
|
509
|
+
async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
|
|
510
|
+
await cell01.sync()
|
|
511
|
+
udef = await cell01.getUserDef(useriden)
|
|
512
|
+
self.true(udef.get('locked'))
|
|
513
|
+
self.false(udef.get('archived'))
|
|
514
|
+
|
|
515
|
+
# Set user locked while cell01 is offline so it will get the edit when it comes
|
|
516
|
+
# back
|
|
517
|
+
await cell00.setUserLocked(useriden, False)
|
|
518
|
+
await cell00.sync()
|
|
519
|
+
|
|
520
|
+
# Edit the slabs on both cells directly to archive the user
|
|
521
|
+
lmdb00 = s_common.genpath(path00, 'slabs', 'cell.lmdb')
|
|
522
|
+
lmdb01 = s_common.genpath(path01, 'slabs', 'cell.lmdb')
|
|
523
|
+
|
|
524
|
+
slab00 = await s_lmdbslab.Slab.anit(lmdb00, map_size=s_cell.SLAB_MAP_SIZE)
|
|
525
|
+
slab01 = await s_lmdbslab.Slab.anit(lmdb01, map_size=s_cell.SLAB_MAP_SIZE)
|
|
526
|
+
|
|
527
|
+
# Simulate the cell migration which locks archived users
|
|
528
|
+
for slab in (slab00, slab01):
|
|
529
|
+
authkv = slab.getSafeKeyVal('auth')
|
|
530
|
+
userkv = authkv.getSubKeyVal('user:info:')
|
|
531
|
+
|
|
532
|
+
info = userkv.get(useriden)
|
|
533
|
+
info['archived'] = True
|
|
534
|
+
info['locked'] = True
|
|
535
|
+
userkv.set(useriden, info)
|
|
536
|
+
|
|
537
|
+
await slab00.fini()
|
|
538
|
+
await slab01.fini()
|
|
539
|
+
|
|
540
|
+
# Spin the cells back up and wait for the edit to sync to cell01
|
|
541
|
+
async with self.addSvcToAha(aha, '00.cell', s_cell.Cell, dirn=path00) as cell00:
|
|
542
|
+
udef = await cell00.getUserDef(useriden)
|
|
543
|
+
self.true(udef.get('archived'))
|
|
544
|
+
self.true(udef.get('locked'))
|
|
545
|
+
|
|
546
|
+
async with self.addSvcToAha(aha, '01.cell', s_cell.Cell, dirn=path01, provinfo={'mirror': 'cell'}) as cell01:
|
|
547
|
+
await cell01.sync()
|
|
548
|
+
udef = await cell01.getUserDef(useriden)
|
|
549
|
+
self.true(udef.get('archived'))
|
|
550
|
+
self.true(udef.get('locked'))
|
|
551
|
+
|
|
552
|
+
self.ge(cell00.nexsvers, (2, 198))
|
|
553
|
+
self.ge(cell01.nexsvers, (2, 198))
|
|
554
|
+
|
|
429
555
|
async def test_auth_password_policy(self):
|
|
430
556
|
policy = {
|
|
431
557
|
'complexity': {
|
|
@@ -446,6 +572,21 @@ class AuthTest(s_test.SynTest):
|
|
|
446
572
|
pass3 = 'ZXN-pyv7ber-kzq2kgh'
|
|
447
573
|
|
|
448
574
|
conf = {'auth:passwd:policy': policy}
|
|
575
|
+
async with self.getTestCore(conf=conf) as core:
|
|
576
|
+
|
|
577
|
+
user = await core.auth.addUser('blackout@vertex.link')
|
|
578
|
+
|
|
579
|
+
self.none(user.info.get('policy:previous'))
|
|
580
|
+
await user.setPasswd(pass1, nexs=False)
|
|
581
|
+
await user.setPasswd(pass2, nexs=False)
|
|
582
|
+
await user.setPasswd(pass3, nexs=False)
|
|
583
|
+
self.len(2, user.info.get('policy:previous'))
|
|
584
|
+
|
|
585
|
+
await user.tryPasswd('newp')
|
|
586
|
+
self.eq(1, user.info.get('policy:attempts'))
|
|
587
|
+
await user.setLocked(False, logged=False)
|
|
588
|
+
self.eq(0, user.info.get('policy:attempts'))
|
|
589
|
+
|
|
449
590
|
async with self.getTestCore(conf=conf) as core:
|
|
450
591
|
auth = core.auth
|
|
451
592
|
self.nn(auth.policy)
|
|
@@ -708,7 +849,7 @@ class AuthTest(s_test.SynTest):
|
|
|
708
849
|
await core.callStorm('auth.role.addrule ninjas --gate $gate another.rule',
|
|
709
850
|
opts={'vars': {'gate': fork}})
|
|
710
851
|
|
|
711
|
-
user = await core.auth.getUserByName('lowuser') # type:
|
|
852
|
+
user = await core.auth.getUserByName('lowuser') # type: s_auth.User
|
|
712
853
|
self.false(user.allowed(('hehe',)))
|
|
713
854
|
self.false(user.allowed(('hehe',), deepdeny=True))
|
|
714
855
|
self.true(user.allowed(('hehe', 'haha')))
|