synapse 2.193.0__py311-none-any.whl → 2.194.0__py311-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of synapse might be problematic. Click here for more details.

Files changed (65) hide show
  1. synapse/cortex.py +3 -7
  2. synapse/datamodel.py +6 -3
  3. synapse/exc.py +1 -1
  4. synapse/lib/agenda.py +17 -4
  5. synapse/lib/ast.py +217 -86
  6. synapse/lib/auth.py +1 -0
  7. synapse/lib/parser.py +4 -0
  8. synapse/lib/snap.py +40 -11
  9. synapse/lib/storm.lark +16 -1
  10. synapse/lib/storm.py +6 -4
  11. synapse/lib/storm_format.py +1 -0
  12. synapse/lib/stormctrl.py +88 -6
  13. synapse/lib/stormlib/cache.py +6 -2
  14. synapse/lib/stormlib/scrape.py +1 -1
  15. synapse/lib/stormlib/stix.py +8 -8
  16. synapse/lib/stormtypes.py +13 -5
  17. synapse/lib/version.py +2 -2
  18. synapse/lib/view.py +20 -3
  19. synapse/models/geopol.py +1 -0
  20. synapse/models/geospace.py +1 -0
  21. synapse/models/inet.py +3 -0
  22. synapse/models/infotech.py +10 -2
  23. synapse/models/orgs.py +7 -2
  24. synapse/models/person.py +15 -4
  25. synapse/models/risk.py +3 -0
  26. synapse/models/telco.py +10 -3
  27. synapse/tests/test_axon.py +6 -6
  28. synapse/tests/test_cortex.py +130 -11
  29. synapse/tests/test_exc.py +1 -0
  30. synapse/tests/test_lib_agenda.py +125 -1
  31. synapse/tests/test_lib_aha.py +13 -6
  32. synapse/tests/test_lib_ast.py +258 -9
  33. synapse/tests/test_lib_auth.py +6 -7
  34. synapse/tests/test_lib_grammar.py +14 -0
  35. synapse/tests/test_lib_layer.py +1 -1
  36. synapse/tests/test_lib_lmdbslab.py +3 -3
  37. synapse/tests/test_lib_storm.py +201 -25
  38. synapse/tests/test_lib_stormctrl.py +65 -0
  39. synapse/tests/test_lib_stormhttp.py +5 -5
  40. synapse/tests/test_lib_stormlib_auth.py +5 -5
  41. synapse/tests/test_lib_stormlib_cache.py +38 -6
  42. synapse/tests/test_lib_stormlib_modelext.py +3 -3
  43. synapse/tests/test_lib_stormlib_scrape.py +4 -4
  44. synapse/tests/test_lib_stormlib_spooled.py +1 -1
  45. synapse/tests/test_lib_stormlib_xml.py +5 -5
  46. synapse/tests/test_lib_stormtypes.py +54 -57
  47. synapse/tests/test_lib_view.py +1 -1
  48. synapse/tests/test_model_base.py +1 -2
  49. synapse/tests/test_model_geopol.py +4 -0
  50. synapse/tests/test_model_geospace.py +6 -0
  51. synapse/tests/test_model_inet.py +3 -0
  52. synapse/tests/test_model_infotech.py +10 -1
  53. synapse/tests/test_model_orgs.py +17 -2
  54. synapse/tests/test_model_person.py +23 -1
  55. synapse/tests/test_model_risk.py +11 -0
  56. synapse/tests/test_tools_healthcheck.py +4 -4
  57. synapse/tests/test_utils.py +17 -18
  58. synapse/tests/utils.py +0 -35
  59. synapse/tools/changelog.py +6 -4
  60. synapse/tools/storm.py +1 -1
  61. {synapse-2.193.0.dist-info → synapse-2.194.0.dist-info}/METADATA +5 -5
  62. {synapse-2.193.0.dist-info → synapse-2.194.0.dist-info}/RECORD +65 -64
  63. {synapse-2.193.0.dist-info → synapse-2.194.0.dist-info}/WHEEL +1 -1
  64. {synapse-2.193.0.dist-info → synapse-2.194.0.dist-info}/LICENSE +0 -0
  65. {synapse-2.193.0.dist-info → synapse-2.194.0.dist-info}/top_level.txt +0 -0
synapse/lib/ast.py CHANGED
@@ -28,6 +28,16 @@ import synapse.lib.stormtypes as s_stormtypes
28
28
 
29
29
  from synapse.lib.stormtypes import tobool, toint, toprim, tostr, tonumber, tocmprvalu, undef
30
30
 
31
+ SET_ALWAYS = 0
32
+ SET_UNSET = 1
33
+ SET_NEVER = 2
34
+
35
+ COND_EDIT_SET = {
36
+ 'always': SET_ALWAYS,
37
+ 'unset': SET_UNSET,
38
+ 'never': SET_NEVER,
39
+ }
40
+
31
41
  logger = logging.getLogger(__name__)
32
42
 
33
43
  def parseNumber(x):
@@ -124,27 +134,27 @@ class AstNode:
124
134
  pass
125
135
 
126
136
  def hasAstClass(self, clss):
127
- hasast = self.hasast.get(clss)
128
- if hasast is not None:
137
+ if (hasast := self.hasast.get(clss)) is not None:
129
138
  return hasast
130
139
 
131
- retn = False
140
+ retn = self._hasAstClass(clss)
141
+ self.hasast[clss] = retn
142
+ return retn
143
+
144
+ def _hasAstClass(self, clss):
132
145
 
133
146
  for kid in self.kids:
134
147
 
135
148
  if isinstance(kid, clss):
136
- retn = True
137
- break
149
+ return True
138
150
 
139
- if isinstance(kid, (EditPropSet, Function, CmdOper)):
151
+ if isinstance(kid, (Edit, Function, CmdOper, SetVarOper, SetItemOper, VarListSetOper, Value, N1Walk, LiftOper)):
140
152
  continue
141
153
 
142
154
  if kid.hasAstClass(clss):
143
- retn = True
144
- break
155
+ return True
145
156
 
146
- self.hasast[clss] = retn
147
- return retn
157
+ return False
148
158
 
149
159
  def optimize(self):
150
160
  [k.optimize() for k in self.kids]
@@ -179,6 +189,12 @@ class AstNode:
179
189
 
180
190
  todo.extend(nkid.kids)
181
191
 
192
+ def reqNotReadOnly(self, runt, mesg=None):
193
+ if runt.readonly:
194
+ if mesg is None:
195
+ mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
196
+ raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
197
+
182
198
  def hasVarName(self, name):
183
199
  return any(k.hasVarName(name) for k in self.kids)
184
200
 
@@ -238,9 +254,8 @@ class Lookup(Query):
238
254
 
239
255
  async def run(self, runt, genr):
240
256
 
241
- if runt.readonly and self.autoadd:
242
- mesg = 'Autoadd may not be executed in readonly Storm runtime.'
243
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
257
+ if self.autoadd:
258
+ self.reqNotReadOnly(runt)
244
259
 
245
260
  async def getnode(form, valu):
246
261
  try:
@@ -915,6 +930,9 @@ class TryCatch(AstNode):
915
930
 
916
931
  class CatchBlock(AstNode):
917
932
 
933
+ def _hasAstClass(self, clss):
934
+ return self.kids[1].hasAstClass(clss)
935
+
918
936
  async def run(self, runt, genr):
919
937
  async for item in self.kids[2].run(runt, genr):
920
938
  yield item
@@ -948,6 +966,9 @@ class CatchBlock(AstNode):
948
966
 
949
967
  class ForLoop(Oper):
950
968
 
969
+ def _hasAstClass(self, clss):
970
+ return self.kids[2].hasAstClass(clss)
971
+
951
972
  def getRuntVars(self, runt):
952
973
 
953
974
  runtsafe = self.kids[1].isRuntSafe(runt)
@@ -983,6 +1004,14 @@ class ForLoop(Oper):
983
1004
  valu = ()
984
1005
 
985
1006
  async with contextlib.aclosing(s_coro.agen(valu)) as agen:
1007
+
1008
+ try:
1009
+ agen, _ = await pullone(agen)
1010
+ except TypeError:
1011
+ styp = await s_stormtypes.totype(valu, basetypes=True)
1012
+ mesg = f"'{styp}' object is not iterable: {s_common.trimText(repr(valu))}"
1013
+ raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg, type=styp)) from None
1014
+
986
1015
  async for item in agen:
987
1016
 
988
1017
  if isinstance(name, (list, tuple)):
@@ -1020,13 +1049,13 @@ class ForLoop(Oper):
1020
1049
  yield item
1021
1050
 
1022
1051
  except s_stormctrl.StormBreak as e:
1023
- if e.item is not None:
1024
- yield e.item
1052
+ if (eitem := e.get('item')) is not None:
1053
+ yield eitem
1025
1054
  break
1026
1055
 
1027
1056
  except s_stormctrl.StormContinue as e:
1028
- if e.item is not None:
1029
- yield e.item
1057
+ if (eitem := e.get('item')) is not None:
1058
+ yield eitem
1030
1059
  continue
1031
1060
 
1032
1061
  finally:
@@ -1049,6 +1078,13 @@ class ForLoop(Oper):
1049
1078
  valu = ()
1050
1079
 
1051
1080
  async with contextlib.aclosing(s_coro.agen(valu)) as agen:
1081
+ try:
1082
+ agen, _ = await pullone(agen)
1083
+ except TypeError:
1084
+ styp = await s_stormtypes.totype(valu, basetypes=True)
1085
+ mesg = f"'{styp}' object is not iterable: {s_common.trimText(repr(valu))}"
1086
+ raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg, type=styp)) from None
1087
+
1052
1088
  async for item in agen:
1053
1089
 
1054
1090
  if isinstance(name, (list, tuple)):
@@ -1079,13 +1115,13 @@ class ForLoop(Oper):
1079
1115
  yield jtem
1080
1116
 
1081
1117
  except s_stormctrl.StormBreak as e:
1082
- if e.item is not None:
1083
- yield e.item
1118
+ if (eitem := e.get('item')) is not None:
1119
+ yield eitem
1084
1120
  break
1085
1121
 
1086
1122
  except s_stormctrl.StormContinue as e:
1087
- if e.item is not None:
1088
- yield e.item
1123
+ if (eitem := e.get('item')) is not None:
1124
+ yield eitem
1089
1125
  continue
1090
1126
 
1091
1127
  finally:
@@ -1094,6 +1130,9 @@ class ForLoop(Oper):
1094
1130
 
1095
1131
  class WhileLoop(Oper):
1096
1132
 
1133
+ def _hasAstClass(self, clss):
1134
+ return self.kids[1].hasAstClass(clss)
1135
+
1097
1136
  async def run(self, runt, genr):
1098
1137
  subq = self.kids[1]
1099
1138
  node = None
@@ -1109,13 +1148,13 @@ class WhileLoop(Oper):
1109
1148
  await asyncio.sleep(0)
1110
1149
 
1111
1150
  except s_stormctrl.StormBreak as e:
1112
- if e.item is not None:
1113
- yield e.item
1151
+ if (eitem := e.get('item')) is not None:
1152
+ yield eitem
1114
1153
  break
1115
1154
 
1116
1155
  except s_stormctrl.StormContinue as e:
1117
- if e.item is not None:
1118
- yield e.item
1156
+ if (eitem := e.get('item')) is not None:
1157
+ yield eitem
1119
1158
  continue
1120
1159
 
1121
1160
  finally:
@@ -1133,13 +1172,13 @@ class WhileLoop(Oper):
1133
1172
  await asyncio.sleep(0)
1134
1173
 
1135
1174
  except s_stormctrl.StormBreak as e:
1136
- if e.item is not None:
1137
- yield e.item
1175
+ if (eitem := e.get('item')) is not None:
1176
+ yield eitem
1138
1177
  break
1139
1178
 
1140
1179
  except s_stormctrl.StormContinue as e:
1141
- if e.item is not None:
1142
- yield e.item
1180
+ if (eitem := e.get('item')) is not None:
1181
+ yield eitem
1143
1182
  continue
1144
1183
 
1145
1184
  finally:
@@ -1147,20 +1186,21 @@ class WhileLoop(Oper):
1147
1186
  await asyncio.sleep(0)
1148
1187
 
1149
1188
  async def pullone(genr):
1150
- gotone = None
1151
- async for gotone in genr:
1152
- break
1189
+ empty = False
1190
+ try:
1191
+ gotone = await genr.__anext__()
1192
+ except StopAsyncIteration:
1193
+ empty = True
1153
1194
 
1154
1195
  async def pullgenr():
1155
-
1156
- if gotone is None:
1196
+ if empty:
1157
1197
  return
1158
1198
 
1159
1199
  yield gotone
1160
1200
  async for item in genr:
1161
1201
  yield item
1162
1202
 
1163
- return pullgenr(), gotone is None
1203
+ return pullgenr(), empty
1164
1204
 
1165
1205
  class CmdOper(Oper):
1166
1206
 
@@ -1269,15 +1309,17 @@ class SetItemOper(Oper):
1269
1309
  item = s_stormtypes.fromprim(await self.kids[0].compute(runt, path), basetypes=False)
1270
1310
 
1271
1311
  if runt.readonly and not getattr(item.setitem, '_storm_readonly', False):
1272
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
1273
- raise self.kids[0].addExcInfo(s_exc.IsReadOnly(mesg=mesg))
1312
+ self.kids[0].reqNotReadOnly(runt)
1274
1313
 
1275
1314
  name = await self.kids[1].compute(runt, path)
1276
1315
  valu = await self.kids[2].compute(runt, path)
1277
1316
 
1278
1317
  # TODO: ditch this when storm goes full heavy object
1279
1318
  with s_scope.enter({'runt': runt}):
1280
- await item.setitem(name, valu)
1319
+ try:
1320
+ await item.setitem(name, valu)
1321
+ except s_exc.SynErr as e:
1322
+ raise self.kids[0].addExcInfo(e)
1281
1323
 
1282
1324
  yield node, path
1283
1325
 
@@ -1289,12 +1331,14 @@ class SetItemOper(Oper):
1289
1331
  valu = await self.kids[2].compute(runt, None)
1290
1332
 
1291
1333
  if runt.readonly and not getattr(item.setitem, '_storm_readonly', False):
1292
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
1293
- raise self.kids[0].addExcInfo(s_exc.IsReadOnly(mesg=mesg))
1334
+ self.kids[0].reqNotReadOnly(runt)
1294
1335
 
1295
1336
  # TODO: ditch this when storm goes full heavy object
1296
1337
  with s_scope.enter({'runt': runt}):
1297
- await item.setitem(name, valu)
1338
+ try:
1339
+ await item.setitem(name, valu)
1340
+ except s_exc.SynErr as e:
1341
+ raise self.kids[0].addExcInfo(e)
1298
1342
 
1299
1343
  class VarListSetOper(Oper):
1300
1344
 
@@ -1366,6 +1410,14 @@ class VarEvalOper(Oper):
1366
1410
 
1367
1411
  class SwitchCase(Oper):
1368
1412
 
1413
+ def _hasAstClass(self, clss):
1414
+
1415
+ for kid in self.kids[1:]:
1416
+ if kid.hasAstClass(clss):
1417
+ return True
1418
+
1419
+ return False
1420
+
1369
1421
  def prepare(self):
1370
1422
  self.cases = {}
1371
1423
  self.defcase = None
@@ -3572,7 +3624,8 @@ class FuncCall(Value):
3572
3624
  raise self.addExcInfo(s_exc.StormRuntimeError(mesg=mesg))
3573
3625
 
3574
3626
  if runt.readonly and not getattr(func, '_storm_readonly', False):
3575
- mesg = f'Function ({func.__name__}) is not marked readonly safe.'
3627
+ funcname = getattr(func, '_storm_funcpath', func.__name__)
3628
+ mesg = f'{funcname}() is not marked readonly safe.'
3576
3629
  raise self.kids[0].addExcInfo(s_exc.IsReadOnly(mesg=mesg))
3577
3630
 
3578
3631
  argv = await self.kids[1].compute(runt, path)
@@ -3998,9 +4051,7 @@ class EditParens(Edit):
3998
4051
 
3999
4052
  async def run(self, runt, genr):
4000
4053
 
4001
- if runt.readonly:
4002
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4003
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4054
+ self.reqNotReadOnly(runt)
4004
4055
 
4005
4056
  nodeadd = self.kids[0]
4006
4057
  assert isinstance(nodeadd, EditNodeAdd)
@@ -4093,9 +4144,7 @@ class EditNodeAdd(Edit):
4093
4144
  # case 2: <query> [ foo:bar=($node, 20) ]
4094
4145
  # case 2: <query> $blah=:baz [ foo:bar=($blah, 20) ]
4095
4146
 
4096
- if runt.readonly:
4097
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4098
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4147
+ self.reqNotReadOnly(runt)
4099
4148
 
4100
4149
  runtsafe = self.isRuntSafe(runt)
4101
4150
 
@@ -4103,7 +4152,6 @@ class EditNodeAdd(Edit):
4103
4152
 
4104
4153
  if not runtsafe:
4105
4154
 
4106
- first = True
4107
4155
  async for node, path in genr:
4108
4156
 
4109
4157
  # must reach back first to trigger sudo / etc
@@ -4161,13 +4209,79 @@ class EditNodeAdd(Edit):
4161
4209
  async for item in agen:
4162
4210
  yield item
4163
4211
 
4212
+ class CondSetOper(Oper):
4213
+ def __init__(self, astinfo, kids, errok=False):
4214
+ Value.__init__(self, astinfo, kids=kids)
4215
+ self.errok = errok
4216
+
4217
+ def prepare(self):
4218
+ self.isconst = False
4219
+ if isinstance(self.kids[0], Const):
4220
+ self.isconst = True
4221
+ self.valu = COND_EDIT_SET.get(self.kids[0].value())
4222
+
4223
+ async def compute(self, runt, path):
4224
+ if self.isconst:
4225
+ return self.valu
4226
+
4227
+ valu = await self.kids[0].compute(runt, path)
4228
+ if (retn := COND_EDIT_SET.get(valu)) is not None:
4229
+ return retn
4230
+
4231
+ mesg = f'Invalid conditional set operator ({valu}).'
4232
+ exc = s_exc.StormRuntimeError(mesg=mesg)
4233
+ raise self.addExcInfo(exc)
4234
+
4235
+ class EditCondPropSet(Edit):
4236
+
4237
+ async def run(self, runt, genr):
4238
+
4239
+ self.reqNotReadOnly(runt)
4240
+
4241
+ excignore = (s_exc.BadTypeValu,) if self.kids[1].errok else ()
4242
+ rval = self.kids[2]
4243
+
4244
+ async for node, path in genr:
4245
+
4246
+ propname = await self.kids[0].compute(runt, path)
4247
+ name = await tostr(propname)
4248
+
4249
+ prop = node.form.reqProp(name, extra=self.kids[0].addExcInfo)
4250
+
4251
+ oper = await self.kids[1].compute(runt, path)
4252
+ if oper == SET_NEVER or (oper == SET_UNSET and (oldv := node.get(name)) is not None):
4253
+ yield node, path
4254
+ await asyncio.sleep(0)
4255
+ continue
4256
+
4257
+ if not node.form.isrunt:
4258
+ # runt node property permissions are enforced by the callback
4259
+ runt.confirmPropSet(prop)
4260
+
4261
+ isndef = isinstance(prop.type, s_types.Ndef)
4262
+
4263
+ try:
4264
+ valu = await rval.compute(runt, path)
4265
+ valu = await s_stormtypes.tostor(valu, isndef=isndef)
4266
+
4267
+ if isinstance(prop.type, s_types.Ival) and oldv is not None:
4268
+ valu, _ = prop.type.norm(valu)
4269
+ valu = prop.type.merge(oldv, valu)
4270
+
4271
+ await node.set(name, valu)
4272
+
4273
+ except excignore:
4274
+ pass
4275
+
4276
+ yield node, path
4277
+
4278
+ await asyncio.sleep(0)
4279
+
4164
4280
  class EditPropSet(Edit):
4165
4281
 
4166
4282
  async def run(self, runt, genr):
4167
4283
 
4168
- if runt.readonly:
4169
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4170
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4284
+ self.reqNotReadOnly(runt)
4171
4285
 
4172
4286
  oper = await self.kids[1].compute(runt, None)
4173
4287
  excignore = (s_exc.BadTypeValu,) if oper in ('?=', '?+=', '?-=') else ()
@@ -4212,7 +4326,7 @@ class EditPropSet(Edit):
4212
4326
 
4213
4327
  if not isarray:
4214
4328
  mesg = f'Property set using ({oper}) is only valid on arrays.'
4215
- exc = s_exc.StormRuntimeError(mesg)
4329
+ exc = s_exc.StormRuntimeError(mesg=mesg)
4216
4330
  raise self.kids[0].addExcInfo(exc)
4217
4331
 
4218
4332
  arry = node.get(name)
@@ -4260,9 +4374,7 @@ class EditPropDel(Edit):
4260
4374
 
4261
4375
  async def run(self, runt, genr):
4262
4376
 
4263
- if runt.readonly:
4264
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4265
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4377
+ self.reqNotReadOnly(runt)
4266
4378
 
4267
4379
  async for node, path in genr:
4268
4380
  propname = await self.kids[0].compute(runt, path)
@@ -4288,9 +4400,7 @@ class EditUnivDel(Edit):
4288
4400
 
4289
4401
  async def run(self, runt, genr):
4290
4402
 
4291
- if runt.readonly:
4292
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4293
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4403
+ self.reqNotReadOnly(runt)
4294
4404
 
4295
4405
  univprop = self.kids[0]
4296
4406
  assert isinstance(univprop, UnivProp)
@@ -4466,9 +4576,7 @@ class EditEdgeAdd(Edit):
4466
4576
 
4467
4577
  async def run(self, runt, genr):
4468
4578
 
4469
- if runt.readonly:
4470
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4471
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4579
+ self.reqNotReadOnly(runt)
4472
4580
 
4473
4581
  # SubQuery -> Query
4474
4582
  query = self.kids[1].kids[0]
@@ -4531,9 +4639,7 @@ class EditEdgeDel(Edit):
4531
4639
 
4532
4640
  async def run(self, runt, genr):
4533
4641
 
4534
- if runt.readonly:
4535
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4536
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4642
+ self.reqNotReadOnly(runt)
4537
4643
 
4538
4644
  query = self.kids[1].kids[0]
4539
4645
 
@@ -4589,9 +4695,7 @@ class EditTagAdd(Edit):
4589
4695
 
4590
4696
  async def run(self, runt, genr):
4591
4697
 
4592
- if runt.readonly:
4593
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4594
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4698
+ self.reqNotReadOnly(runt)
4595
4699
 
4596
4700
  if len(self.kids) > 1 and isinstance(self.kids[0], Const) and (await self.kids[0].compute(runt, None)) == '?':
4597
4701
  oper_offset = 1
@@ -4635,9 +4739,7 @@ class EditTagDel(Edit):
4635
4739
 
4636
4740
  async def run(self, runt, genr):
4637
4741
 
4638
- if runt.readonly:
4639
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4640
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4742
+ self.reqNotReadOnly(runt)
4641
4743
 
4642
4744
  async for node, path in genr:
4643
4745
 
@@ -4661,9 +4763,7 @@ class EditTagPropSet(Edit):
4661
4763
  '''
4662
4764
  async def run(self, runt, genr):
4663
4765
 
4664
- if runt.readonly:
4665
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4666
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4766
+ self.reqNotReadOnly(runt)
4667
4767
 
4668
4768
  oper = await self.kids[1].compute(runt, None)
4669
4769
  excignore = s_exc.BadTypeValu if oper == '?=' else ()
@@ -4697,9 +4797,7 @@ class EditTagPropDel(Edit):
4697
4797
  '''
4698
4798
  async def run(self, runt, genr):
4699
4799
 
4700
- if runt.readonly:
4701
- mesg = 'Storm runtime is in readonly mode, cannot create or edit nodes and other graph data.'
4702
- raise self.addExcInfo(s_exc.IsReadOnly(mesg=mesg))
4800
+ self.reqNotReadOnly(runt)
4703
4801
 
4704
4802
  async for node, path in genr:
4705
4803
 
@@ -4724,9 +4822,9 @@ class BreakOper(AstNode):
4724
4822
  yield _
4725
4823
 
4726
4824
  async for node, path in genr:
4727
- raise s_stormctrl.StormBreak(item=(node, path))
4825
+ raise self.addExcInfo(s_stormctrl.StormBreak(item=(node, path)))
4728
4826
 
4729
- raise s_stormctrl.StormBreak()
4827
+ raise self.addExcInfo(s_stormctrl.StormBreak())
4730
4828
 
4731
4829
  class ContinueOper(AstNode):
4732
4830
 
@@ -4737,15 +4835,31 @@ class ContinueOper(AstNode):
4737
4835
  yield _
4738
4836
 
4739
4837
  async for node, path in genr:
4740
- raise s_stormctrl.StormContinue(item=(node, path))
4838
+ raise self.addExcInfo(s_stormctrl.StormContinue(item=(node, path)))
4741
4839
 
4742
- raise s_stormctrl.StormContinue()
4840
+ raise self.addExcInfo(s_stormctrl.StormContinue())
4743
4841
 
4744
4842
  class IfClause(AstNode):
4745
4843
  pass
4746
4844
 
4747
4845
  class IfStmt(Oper):
4748
4846
 
4847
+ def _hasAstClass(self, clss):
4848
+
4849
+ clauses = self.kids
4850
+
4851
+ if not isinstance(clauses[-1], IfClause):
4852
+ if clauses[-1].hasAstClass(clss):
4853
+ return True
4854
+
4855
+ clauses = clauses[:-1]
4856
+
4857
+ for clause in clauses:
4858
+ if clause.kids[1].hasAstClass(clss):
4859
+ return True
4860
+
4861
+ return False
4862
+
4749
4863
  def prepare(self):
4750
4864
  if isinstance(self.kids[-1], IfClause):
4751
4865
  self.elsequery = None
@@ -4830,20 +4944,26 @@ class Emit(Oper):
4830
4944
  count = 0
4831
4945
  async for node, path in genr:
4832
4946
  count += 1
4833
- await runt.emit(await self.kids[0].compute(runt, path))
4947
+ try:
4948
+ await runt.emit(await self.kids[0].compute(runt, path))
4949
+ except s_exc.StormRuntimeError as e:
4950
+ raise self.addExcInfo(e)
4834
4951
  yield node, path
4835
4952
 
4836
4953
  # no items in pipeline and runtsafe. execute once.
4837
4954
  if count == 0 and self.isRuntSafe(runt):
4838
- await runt.emit(await self.kids[0].compute(runt, None))
4955
+ try:
4956
+ await runt.emit(await self.kids[0].compute(runt, None))
4957
+ except s_exc.StormRuntimeError as e:
4958
+ raise self.addExcInfo(e)
4839
4959
 
4840
4960
  class Stop(Oper):
4841
4961
 
4842
4962
  async def run(self, runt, genr):
4843
4963
  for _ in (): yield _
4844
4964
  async for node, path in genr:
4845
- raise s_stormctrl.StormStop()
4846
- raise s_stormctrl.StormStop()
4965
+ raise self.addExcInfo(s_stormctrl.StormStop())
4966
+ raise self.addExcInfo(s_stormctrl.StormStop())
4847
4967
 
4848
4968
  class FuncArgs(AstNode):
4849
4969
  '''
@@ -4987,9 +5107,16 @@ class Function(AstNode):
4987
5107
  await asyncio.sleep(0)
4988
5108
 
4989
5109
  return None
4990
-
4991
5110
  except s_stormctrl.StormReturn as e:
4992
5111
  return e.item
5112
+ except s_stormctrl.StormLoopCtrl as e:
5113
+ mesg = f'function {self.name} - Loop control statement "{e.statement}" used outside of a loop.'
5114
+ raise self.addExcInfo(s_exc.StormRuntimeError(mesg=mesg, function=self.name,
5115
+ statement=e.statement)) from e
5116
+ except s_stormctrl.StormGenrCtrl as e:
5117
+ mesg = f'function {self.name} - Generator control statement "{e.statement}" used outside of a generator function.'
5118
+ raise self.addExcInfo(s_exc.StormRuntimeError(mesg=mesg, function=self.name,
5119
+ statement=e.statement)) from e
4993
5120
 
4994
5121
  async def genr():
4995
5122
  async with runt.getSubRuntime(self.kids[2], opts=opts) as subr:
@@ -5009,5 +5136,9 @@ class Function(AstNode):
5009
5136
  yield node, path
5010
5137
  except s_stormctrl.StormStop:
5011
5138
  return
5139
+ except s_stormctrl.StormLoopCtrl as e:
5140
+ mesg = f'function {self.name} - Loop control statement "{e.statement}" used outside of a loop.'
5141
+ raise self.addExcInfo(s_exc.StormRuntimeError(mesg=mesg, function=self.name,
5142
+ statement=e.statement)) from e
5012
5143
 
5013
5144
  return genr()
synapse/lib/auth.py CHANGED
@@ -1545,6 +1545,7 @@ class User(Ruler):
1545
1545
  # Prevent empty string or non-string values
1546
1546
  if passwd is None:
1547
1547
  shadow = None
1548
+ enforce_policy = False
1548
1549
  elif passwd and isinstance(passwd, str):
1549
1550
  shadow = await s_passwd.getShadowV2(passwd=passwd)
1550
1551
  else:
synapse/lib/parser.py CHANGED
@@ -95,6 +95,7 @@ terminalEnglishMap = {
95
95
  'TRYSETPLUS': '?+=',
96
96
  'TRYSETMINUS': '?-=',
97
97
  'UNIVNAME': 'universal property',
98
+ 'UNSET': 'unset',
98
99
  'EXPRUNIVNAME': 'universal property',
99
100
  'VARTOKN': 'variable',
100
101
  'EXPRVARTOKN': 'variable',
@@ -642,6 +643,8 @@ ruleClassMap = {
642
643
  'andexpr': s_ast.AndCond,
643
644
  'baresubquery': s_ast.SubQuery,
644
645
  'catchblock': s_ast.CatchBlock,
646
+ 'condsetoper': s_ast.CondSetOper,
647
+ 'condtrysetoper': lambda astinfo, kids: s_ast.CondSetOper(astinfo, kids, errok=True),
645
648
  'condsubq': s_ast.SubqCond,
646
649
  'dollarexpr': s_ast.DollarExpr,
647
650
  'edgeaddn1': s_ast.EditEdgeAdd,
@@ -657,6 +660,7 @@ ruleClassMap = {
657
660
  'formname': s_ast.FormName,
658
661
  'editpropdel': lambda astinfo, kids: s_ast.EditPropDel(astinfo, kids[1:]),
659
662
  'editpropset': s_ast.EditPropSet,
663
+ 'editcondpropset': s_ast.EditCondPropSet,
660
664
  'edittagadd': s_ast.EditTagAdd,
661
665
  'edittagdel': lambda astinfo, kids: s_ast.EditTagDel(astinfo, kids[1:]),
662
666
  'edittagpropset': s_ast.EditTagPropSet,