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/snap.py CHANGED
@@ -362,7 +362,7 @@ class ProtoNode:
362
362
  try:
363
363
  valu, norminfo = prop.type.norm(valu)
364
364
  except s_exc.BadTypeValu as e:
365
- oldm = e.errinfo.get('mesg')
365
+ oldm = e.get('mesg')
366
366
  e.update({'prop': prop.name,
367
367
  'form': prop.form.name,
368
368
  'mesg': f'Bad prop value {prop.full}={valu!r} : {oldm}'})
@@ -1404,25 +1404,54 @@ class Snap(s_base.Base):
1404
1404
 
1405
1405
  trycast = vals.pop('$try', False)
1406
1406
  addprops = vals.pop('$props', None)
1407
- if addprops is not None:
1408
- props.update(addprops)
1409
1407
 
1410
- try:
1411
- for name, valu in list(props.items()):
1408
+ if not vals:
1409
+ mesg = f'No values provided for form {form.full}'
1410
+ raise s_exc.BadTypeValu(mesg=mesg)
1411
+
1412
+ for name, valu in list(props.items()):
1413
+ try:
1412
1414
  props[name] = form.reqProp(name).type.norm(valu)
1415
+ except s_exc.BadTypeValu as e:
1416
+ mesg = e.get('mesg')
1417
+ e.update({
1418
+ 'prop': name,
1419
+ 'form': form.name,
1420
+ 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}',
1421
+ })
1422
+ raise e
1413
1423
 
1414
- for name, valu in vals.items():
1424
+ if addprops is not None:
1425
+ for name, valu in addprops.items():
1426
+ try:
1427
+ props[name] = form.reqProp(name).type.norm(valu)
1428
+ except s_exc.BadTypeValu as e:
1429
+ mesg = e.get("mesg")
1430
+ if not trycast:
1431
+ e.update({
1432
+ 'prop': name,
1433
+ 'form': form.name,
1434
+ 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}'
1435
+ })
1436
+ raise e
1437
+ await self.warn(f'Skipping bad value for prop {form.name}:{name}: {mesg}')
1438
+
1439
+ for name, valu in vals.items():
1415
1440
 
1441
+ try:
1416
1442
  prop = form.reqProp(name)
1417
1443
  norm, norminfo = prop.type.norm(valu)
1418
1444
 
1419
1445
  norms[name] = (prop, norm, norminfo)
1420
1446
  proplist.append((name, norm))
1421
- except s_exc.BadTypeValu as e:
1422
- if not trycast: raise
1423
- mesg = e.errinfo.get('mesg')
1424
- await self.warn(f'Bad value for prop {name}: {mesg}')
1425
- return
1447
+ except s_exc.BadTypeValu as e:
1448
+ mesg = e.get('mesg')
1449
+ e.update({
1450
+ 'prop': name,
1451
+ 'form': form.name,
1452
+ 'mesg': f'Bad value for prop {form.name}:{name}: {mesg}',
1453
+ })
1454
+ raise e
1426
1455
 
1427
1456
  proplist.sort()
1428
1457
 
synapse/lib/storm.lark CHANGED
@@ -39,7 +39,7 @@ _editblock: "[" _editoper* "]"
39
39
 
40
40
  // A single edit operation
41
41
  _editoper: editnodeadd
42
- | editpropset | editunivset | edittagpropset | edittagadd
42
+ | editpropset | editunivset | edittagpropset | edittagadd | editcondpropset
43
43
  | editpropdel | editunivdel | edittagpropdel | edittagdel
44
44
  | editparens | edgeaddn1 | edgedeln1 | edgeaddn2 | edgedeln2
45
45
 
@@ -49,11 +49,13 @@ edittagadd: "+" [SETTAGOPER] tagname [(EQSPACE | EQNOSPACE) _valu]
49
49
  editunivdel: EXPRMINUS univprop
50
50
  edittagdel: EXPRMINUS tagname
51
51
  editpropset: relprop (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYSETPLUS | TRYSETMINUS) _valu
52
+ editcondpropset: relprop condsetoper _valu
52
53
  editpropdel: EXPRMINUS relprop
53
54
  editunivset: univprop (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYSETPLUS | TRYSETMINUS) _valu
54
55
  editnodeadd: formname (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYSETPLUS | TRYSETMINUS) _valu
55
56
  edittagpropset: "+" tagprop (EQSPACE | EQNOSPACE | MODSET | TRYSET | TRYSETPLUS | TRYSETMINUS) _valu
56
57
  edittagpropdel: EXPRMINUS tagprop
58
+
57
59
  EQSPACE: /((?<=\s)=|=(?=\s))/
58
60
  MODSET.4: "+=" | "-="
59
61
  TRYSETPLUS.1: "?+="
@@ -61,6 +63,19 @@ TRYSETMINUS.1: "?-="
61
63
  TRYSET.1: "?="
62
64
  SETTAGOPER: "?"
63
65
 
66
+ condsetoper: ("*" UNSET | _DEREF "$" _condvarvaluatom) "="
67
+ | ("*" UNSET | _DEREF "$" _condvarvaluatom) "?=" -> condtrysetoper
68
+ UNSET: "unset"
69
+ _condvarvaluatom: condvarvalue | condvarderef | condfunccall
70
+ condvarvalue: VARTOKN -> varvalue
71
+
72
+ !condvarderef: _condvarvaluatom "." (VARTOKN | "$" VARTOKN | _condderefexpr) -> varderef
73
+ _condderefexpr: "$"? conddollarexpr
74
+ conddollarexpr: "(" expror ")" -> dollarexpr
75
+
76
+ condfunccall: _condvarvaluatom _condcallargs -> funccall
77
+ _condcallargs: _LPARNOSPACE [(_valu | VARTOKN | (VARTOKN | NONQUOTEWORD) (EQSPACE | EQNOSPACE) _valu) ("," (_valu | VARTOKN | (VARTOKN | NONQUOTEWORD) (EQSPACE | EQNOSPACE) _valu))*] ","? ")"
78
+
64
79
  // The set of non-edit non-commands in storm
65
80
 
66
81
  _oper: stormfunc | initblock | emptyblock | finiblock | trycatch | subquery | _formpivot | formjoin
synapse/lib/storm.py CHANGED
@@ -984,7 +984,9 @@ stormcmds = (
984
984
  $ssl = $lib.true
985
985
  if $cmdopts.ssl_noverify { $ssl = $lib.false }
986
986
 
987
- $resp = $lib.inet.http.get($cmdopts.url, ssl_verify=$ssl)
987
+ $headers = ({'X-Synapse-Version': $lib.str.join('.', $lib.version.synapse())})
988
+
989
+ $resp = $lib.inet.http.get($cmdopts.url, ssl_verify=$ssl, headers=$headers)
988
990
 
989
991
  if ($resp.code != 200) {
990
992
  $lib.warn("pkg.load got HTTP code: {code} for URL: {url}", code=$resp.code, url=$cmdopts.url)
@@ -1603,7 +1605,7 @@ stormcmds = (
1603
1605
  function fetchnodes(url, ssl) {
1604
1606
  $resp = $lib.inet.http.get($url, ssl_verify=$ssl)
1605
1607
  if ($resp.code = 200) {
1606
- $nodes = $lib.list()
1608
+ $nodes = ()
1607
1609
  for $valu in $resp.msgpack() {
1608
1610
  $nodes.append($valu)
1609
1611
  }
@@ -3552,7 +3554,7 @@ class HelpCmd(Cmd):
3552
3554
  await runt.printf(line)
3553
3555
 
3554
3556
  else: # pragma: no cover
3555
- raise s_exc.StormRuntimeError(mesgf=f'Unknown bound method {func}')
3557
+ raise s_exc.StormRuntimeError(mesg=f'Unknown bound method {func}')
3556
3558
 
3557
3559
  async def _handleStormLibMethod(self, func, runt: Runtime, verbose: bool =False):
3558
3560
  # Storm library methods must be derived from a library definition.
@@ -3583,7 +3585,7 @@ class HelpCmd(Cmd):
3583
3585
  await runt.printf(line)
3584
3586
 
3585
3587
  else: # pragma: no cover
3586
- raise s_exc.StormRuntimeError(mesgf=f'Unknown runtime lib method {func} {cls} {fname}')
3588
+ raise s_exc.StormRuntimeError(mesg=f'Unknown runtime lib method {func} {cls} {fname}')
3587
3589
 
3588
3590
  class DiffCmd(Cmd):
3589
3591
  '''
@@ -77,6 +77,7 @@ TerminalPygMap = {
77
77
  'TRYSETMINUS': p_t.Operator,
78
78
  'TRYSETPLUS': p_t.Operator,
79
79
  'UNIVNAME': p_t.Name,
80
+ 'UNSET': p_t.Operator,
80
81
  'EXPRUNIVNAME': p_t.Name,
81
82
  'VARTOKN': p_t.Name.Variable,
82
83
  'EXPRVARTOKN': p_t.Name.Variable,
synapse/lib/stormctrl.py CHANGED
@@ -1,9 +1,91 @@
1
1
  class StormCtrlFlow(Exception):
2
+ '''
3
+ Base class all StormCtrlFlow exceptions derive from.
4
+ '''
5
+ def __init__(self):
6
+ raise NotImplementedError
7
+
8
+ class _SynErrMixin(Exception):
9
+ '''
10
+ An exception mixin to give some control flow classes functionality like SynErr.
11
+ '''
12
+ def __init__(self, *args, **info):
13
+ self.errinfo = info
14
+ Exception.__init__(self, self._getExcMsg())
15
+
16
+ def _getExcMsg(self):
17
+ props = sorted(self.errinfo.items())
18
+ displ = ' '.join(['%s=%r' % (p, v) for (p, v) in props])
19
+ return '%s: %s' % (self.__class__.__name__, displ)
20
+
21
+ def _setExcMesg(self):
22
+ '''Should be called when self.errinfo is modified.'''
23
+ self.args = (self._getExcMsg(),)
24
+
25
+ def __setstate__(self, state):
26
+ '''Pickle support.'''
27
+ super(StormCtrlFlow, self).__setstate__(state)
28
+ self._setExcMesg()
29
+
30
+ def items(self):
31
+ return {k: v for k, v in self.errinfo.items()}
32
+
33
+ def get(self, name, defv=None):
34
+ '''
35
+ Return a value from the errinfo dict.
36
+
37
+ Example:
38
+
39
+ try:
40
+ foothing()
41
+ except SynErr as e:
42
+ blah = e.get('blah')
43
+
44
+ '''
45
+ return self.errinfo.get(name, defv)
46
+
47
+ def set(self, name, valu):
48
+ '''
49
+ Set a value in the errinfo dict.
50
+ '''
51
+ self.errinfo[name] = valu
52
+ self._setExcMesg()
53
+
54
+ def setdefault(self, name, valu):
55
+ '''
56
+ Set a value in errinfo dict if it is not already set.
57
+ '''
58
+ if name in self.errinfo:
59
+ return
60
+ self.errinfo[name] = valu
61
+ self._setExcMesg()
62
+
63
+ def update(self, items: dict):
64
+ '''Update multiple items in the errinfo dict at once.'''
65
+ self.errinfo.update(items)
66
+ self._setExcMesg()
67
+
68
+ class StormLoopCtrl(_SynErrMixin):
69
+ # Control flow statements for WHILE and FOR loop control
70
+ statement = ''
71
+
72
+ class StormGenrCtrl(_SynErrMixin):
73
+ # Control flow statements for GENERATOR control
74
+ statement = ''
75
+
76
+ class StormStop(StormGenrCtrl, StormCtrlFlow):
77
+ statement = 'stop'
78
+
79
+ class StormBreak(StormLoopCtrl, StormCtrlFlow):
80
+ statement = 'break'
81
+
82
+ class StormContinue(StormLoopCtrl, StormCtrlFlow):
83
+ statement = 'continue'
84
+
85
+ class StormExit(_SynErrMixin, StormCtrlFlow): pass
86
+
87
+ # StormReturn is kept thin since it is commonly used and just
88
+ # needs to be the container for moving an item up a frame.
89
+ class StormReturn(StormCtrlFlow):
2
90
  def __init__(self, item=None):
3
91
  self.item = item
4
-
5
- class StormExit(StormCtrlFlow): pass
6
- class StormStop(StormCtrlFlow): pass
7
- class StormBreak(StormCtrlFlow): pass
8
- class StormReturn(StormCtrlFlow): pass
9
- class StormContinue(StormCtrlFlow): pass
@@ -172,8 +172,12 @@ class FixedCache(s_stormtypes.StormType):
172
172
  await asyncio.sleep(0)
173
173
  except s_stormctrl.StormReturn as e:
174
174
  return await s_stormtypes.toprim(e.item)
175
- except s_stormctrl.StormCtrlFlow:
176
- pass
175
+ except s_stormctrl.StormCtrlFlow as e:
176
+ name = e.__class__.__name__
177
+ if hasattr(e, 'statement'):
178
+ name = e.statement
179
+ exc = s_exc.StormRuntimeError(mesg=f'Storm control flow "{name}" not allowed in cache callbacks.')
180
+ raise exc from None
177
181
 
178
182
  async def _reqKey(self, key):
179
183
  if s_stormtypes.ismutable(key):
@@ -71,7 +71,7 @@ class LibScrape(s_stormtypes.Lib):
71
71
  $form="ps:name"
72
72
 
73
73
  function scrape(text, form) {
74
- $ret = $lib.list()
74
+ $ret = ()
75
75
  for ($valu, $info) in $lib.scrape.genMatches($text, $re) {
76
76
  $ret.append(($form, $valu, $info))
77
77
  }
@@ -74,7 +74,7 @@ _DefaultConfig = {
74
74
  'created': 'return($lib.stix.export.timestamp(.created))',
75
75
  'modified': 'return($lib.stix.export.timestamp(.created))',
76
76
  'sectors': '''
77
- init { $list = $lib.list() }
77
+ init { $list = () }
78
78
  -> ou:industry +:name $list.append(:name)
79
79
  fini { if $list { return($list) } }
80
80
  ''',
@@ -88,7 +88,7 @@ _DefaultConfig = {
88
88
  'first_seen': '+.seen $seen=.seen return($lib.stix.export.timestamp($seen.0))',
89
89
  'last_seen': '+.seen $seen=.seen return($lib.stix.export.timestamp($seen.1))',
90
90
  'goals': '''
91
- init { $goals = $lib.list() }
91
+ init { $goals = () }
92
92
  -> ou:campaign:org -> ou:goal | uniq | +:name $goals.append(:name)
93
93
  fini { if $goals { return($goals) } }
94
94
  ''',
@@ -183,7 +183,7 @@ _DefaultConfig = {
183
183
  'props': {
184
184
  'value': 'return($node.repr())',
185
185
  'resolves_to_refs': '''
186
- init { $refs = $lib.list() }
186
+ init { $refs = () }
187
187
  { -> inet:dns:a -> inet:ipv4 $refs.append($bundle.add($node)) }
188
188
  { -> inet:dns:aaaa -> inet:ipv6 $refs.append($bundle.add($node)) }
189
189
  { -> inet:dns:cname:fqdn :cname -> inet:fqdn $refs.append($bundle.add($node)) }
@@ -257,7 +257,7 @@ _DefaultConfig = {
257
257
  ''',
258
258
  'mime_type': '+:mime return(:mime)',
259
259
  'contains_refs': '''
260
- init { $refs = $lib.list() }
260
+ init { $refs = () }
261
261
  -(refs)> *
262
262
  $stixid = $bundle.add($node)
263
263
  if $stixid { $refs.append($stixid) }
@@ -279,7 +279,7 @@ _DefaultConfig = {
279
279
  'is_multipart': 'return($lib.false)',
280
280
  'from_ref': ':from -> inet:email return($bundle.add($node))',
281
281
  'to_refs': '''
282
- init { $refs = $lib.list() }
282
+ init { $refs = () }
283
283
  { :to -> inet:email $refs.append($bundle.add($node)) }
284
284
  fini { if $refs { return($refs) } }
285
285
  ''',
@@ -311,7 +311,7 @@ _DefaultConfig = {
311
311
  'created': 'return($lib.stix.export.timestamp(.created))',
312
312
  'modified': 'return($lib.stix.export.timestamp(.created))',
313
313
  'sample_refs': '''
314
- init { $refs = $lib.list() }
314
+ init { $refs = () }
315
315
  -> file:bytes $refs.append($bundle.add($node))
316
316
  fini { if $refs { return($refs) } }
317
317
  ''',
@@ -393,7 +393,7 @@ _DefaultConfig = {
393
393
  'description': 'if (:desc) { return (:desc) }',
394
394
  'created': 'return($lib.stix.export.timestamp(.created))',
395
395
  'modified': 'return($lib.stix.export.timestamp(.created))',
396
- 'external_references': 'if :cve { $cve=:cve $cve=$cve.upper() $list=$lib.list(({"source_name": "cve", "external_id": $cve})) return($list) }'
396
+ 'external_references': 'if :cve { $cve=:cve $cve=$cve.upper() return(([{"source_name": "cve", "external_id": $cve}])) }'
397
397
  },
398
398
  'rels': (
399
399
 
@@ -439,7 +439,7 @@ _DefaultConfig = {
439
439
  'modified': 'return($lib.stix.export.timestamp(.created))',
440
440
  'published': 'return($lib.stix.export.timestamp(:published))',
441
441
  'object_refs': '''
442
- init { $refs = $lib.list() }
442
+ init { $refs = () }
443
443
  -(refs)> *
444
444
  $stixid = $bundle.add($node)
445
445
  if $stixid { $refs.append($stixid) }
synapse/lib/stormtypes.py CHANGED
@@ -575,7 +575,7 @@ class StormType:
575
575
  raise s_exc.NoSuchName(name=name, mesg=mesg)
576
576
 
577
577
  if s_scope.get('runt').readonly and not getattr(stor, '_storm_readonly', False):
578
- mesg = f'Function ({stor.__name__}) is not marked readonly safe.'
578
+ mesg = f'Setting {name} on {self._storm_typename} is not marked readonly safe.'
579
579
  raise s_exc.IsReadOnly(mesg=mesg, name=name, valu=valu)
580
580
 
581
581
  await s_coro.ornot(stor, valu)
@@ -1247,7 +1247,8 @@ class LibBase(Lib):
1247
1247
  'desc': 'Additional keyword arguments containing data to add to the event.', },
1248
1248
  ),
1249
1249
  'returns': {'type': 'null', }}},
1250
- {'name': 'list', 'desc': 'Get a Storm List object.',
1250
+ {'name': 'list', 'desc': 'Get a Storm List object. This is deprecated, use ([]) to declare a list instead.',
1251
+ 'deprecated': {'eolvers': 'v3.0.0'},
1251
1252
  'type': {'type': 'function', '_funcname': '_list',
1252
1253
  'args': (
1253
1254
  {'name': '*vals', 'type': 'any', 'desc': 'Initial values to place in the list.', },
@@ -1307,7 +1308,8 @@ class LibBase(Lib):
1307
1308
  cli> storm if $lib.false { $lib.print('Is True') } else { $lib.print('Is False') }
1308
1309
  Is False''',
1309
1310
  'type': 'boolean', },
1310
- {'name': 'text', 'desc': 'Get a Storm Text object.',
1311
+ {'name': 'text', 'desc': 'Get a Storm Text object. This is deprecated; please use a list to append strings to, and then use ``$lib.str.join()`` to join them on demand.',
1312
+ 'deprecated': {'eolvers': '3.0.0'},
1311
1313
  'type': {'type': 'function', '_funcname': '_text',
1312
1314
  'args': (
1313
1315
  {'name': '*args', 'type': 'str',
@@ -1663,7 +1665,7 @@ class LibBase(Lib):
1663
1665
  if mesg:
1664
1666
  mesg = await self._get_mesg(mesg, **kwargs)
1665
1667
  await self.runt.warn(mesg, log=False)
1666
- raise s_stormctrl.StormExit(mesg)
1668
+ raise s_stormctrl.StormExit(mesg=mesg)
1667
1669
  raise s_stormctrl.StormExit()
1668
1670
 
1669
1671
  @stormfunc(readonly=True)
@@ -1680,10 +1682,16 @@ class LibBase(Lib):
1680
1682
 
1681
1683
  @stormfunc(readonly=True)
1682
1684
  async def _list(self, *vals):
1685
+ s_common.deprecated('$lib.list()', curv='2.194.0')
1686
+ await self.runt.snap.warnonce('$lib.list() is deprecated. Use ([]) instead.')
1683
1687
  return List(list(vals))
1684
1688
 
1685
1689
  @stormfunc(readonly=True)
1686
1690
  async def _text(self, *args):
1691
+ s_common.deprecated('$lib.text()', curv='2.194.0')
1692
+ runt = s_scope.get('runt')
1693
+ if runt:
1694
+ await runt.snap.warnonce('$lib.text() is deprecated. Please use a list to append strings to, and then use ``$lib.str.join()`` to join them on demand.')
1687
1695
  valu = ''.join(args)
1688
1696
  return Text(valu)
1689
1697
 
@@ -5177,7 +5185,7 @@ class List(Prim):
5177
5185
  Examples:
5178
5186
  Populate a list by extending it with to other lists::
5179
5187
 
5180
- $list = $lib.list()
5188
+ $list = ()
5181
5189
 
5182
5190
  $foo = (f, o, o)
5183
5191
  $bar = (b, a, r)
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, 193, 0)
226
+ version = (2, 194, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = 'ad17bf2e740ba11453b7827ce70c140f969a1430'
228
+ commit = 'fb479d376805f963f11c5029310325c13ef2c883'
synapse/lib/view.py CHANGED
@@ -635,7 +635,6 @@ class View(s_nexus.Pusher): # type: ignore
635
635
  async def _calcForkLayers(self):
636
636
  # recompute the proper set of layers for a forked view
637
637
  # (this may only be called from within a nexus handler)
638
-
639
638
  '''
640
639
  We spent a lot of time thinking/talking about this so some hefty
641
640
  comments are in order:
@@ -953,6 +952,15 @@ class View(s_nexus.Pusher): # type: ignore
953
952
  extra={'synapse': {'text': text, 'username': user.name, 'user': user.iden}})
954
953
  raise
955
954
 
955
+ except (s_stormctrl.StormLoopCtrl, s_stormctrl.StormGenrCtrl) as e:
956
+ if isinstance(e, s_stormctrl.StormLoopCtrl):
957
+ mesg = f'Loop control statement "{e.statement}" used outside of a loop.'
958
+ else:
959
+ mesg = f'Generator control statement "{e.statement}" used outside of a generator function.'
960
+ logmesg = f'Error during storm execution for {{ {text} }} - {mesg}'
961
+ logger.exception(logmesg, extra={'synapse': {'text': text, 'username': user.name, 'user': user.iden}})
962
+ raise s_exc.StormRuntimeError(mesg=mesg, statement=e.statement, highlight=e.get('highlight')) from e
963
+
956
964
  except Exception:
957
965
  logger.exception(f'Error during callStorm execution for {{ {text} }}',
958
966
  extra={'synapse': {'text': text, 'username': user.name, 'user': user.iden}})
@@ -1055,8 +1063,17 @@ class View(s_nexus.Pusher): # type: ignore
1055
1063
  raise
1056
1064
 
1057
1065
  except Exception as e:
1058
- logger.exception(f'Error during storm execution for {{ {text} }}',
1059
- extra={'synapse': {'text': text, 'username': user.name, 'user': user.iden}})
1066
+ mesg = ''
1067
+ if isinstance(e, s_stormctrl.StormLoopCtrl):
1068
+ mesg = f'Loop control statement "{e.statement}" used outside of a loop.'
1069
+ e = s_exc.StormRuntimeError(mesg=mesg, statement=e.statement, highlight=e.get('highlight'))
1070
+ elif isinstance(e, s_stormctrl.StormGenrCtrl):
1071
+ mesg = f'Generator control statement "{e.statement}" used outside of a generator function.'
1072
+ e = s_exc.StormRuntimeError(mesg=mesg, statement=e.statement, highlight=e.get('highlight'))
1073
+ logmesg = f'Error during storm execution for {{ {text} }}'
1074
+ if mesg:
1075
+ logmesg = f'{logmesg} - {mesg}'
1076
+ logger.exception(logmesg, extra={'synapse': {'text': text, 'username': user.name, 'user': user.iden}})
1060
1077
  enfo = s_common.err(e)
1061
1078
  enfo[1].pop('esrc', None)
1062
1079
  enfo[1].pop('ename', None)
synapse/models/geopol.py CHANGED
@@ -69,6 +69,7 @@ class PolModule(s_module.CoreModule):
69
69
  ('tld', ('inet:fqdn', {}), {}),
70
70
 
71
71
  ('name', ('geo:name', {}), {
72
+ 'alts': ('names',),
72
73
  'doc': 'The name of the country.'}),
73
74
 
74
75
  ('names', ('array', {'type': 'geo:name', 'uniq': True, 'sorted': True}), {
@@ -495,6 +495,7 @@ class GeoModule(s_module.CoreModule):
495
495
  ('geo:place', {}, (
496
496
 
497
497
  ('name', ('geo:name', {}), {
498
+ 'alts': ('names',),
498
499
  'doc': 'The name of the place.'}),
499
500
 
500
501
  ('type', ('geo:place:taxonomy', {}), {
synapse/models/inet.py CHANGED
@@ -3785,6 +3785,9 @@ class InetModule(s_module.CoreModule):
3785
3785
  ('replyto', ('inet:service:message', {}), {
3786
3786
  'doc': 'The message that this message was sent in reply to. Used for message threading.'}),
3787
3787
 
3788
+ ('repost', ('inet:service:message', {}), {
3789
+ 'doc': 'The original message reposted by this message.'}),
3790
+
3788
3791
  ('links', ('array', {'type': 'inet:service:message:link', 'uniq': True, 'sorted': True}), {
3789
3792
  'doc': 'An array of links contained within the message.'}),
3790
3793
 
@@ -857,10 +857,12 @@ class ItModule(s_module.CoreModule):
857
857
  }),
858
858
 
859
859
  ('it:os:ios:idfa', ('it:adid', {}), {
860
- 'doc': 'An iOS advertising identification string.'}),
860
+ 'deprecated': True,
861
+ 'doc': 'Deprecated. Please use it:adid.'}),
861
862
 
862
863
  ('it:os:android:aaid', ('it:adid', {}), {
863
- 'doc': 'An android advertising identification string.'}),
864
+ 'deprecated': True,
865
+ 'doc': 'Deprecated. Please use it:adid.'}),
864
866
 
865
867
  ('it:os:android:perm', ('str', {}), {
866
868
  'doc': 'An android permission string.'}),
@@ -2094,7 +2096,12 @@ class ItModule(s_module.CoreModule):
2094
2096
  )),
2095
2097
  ('it:prod:soft:taxonomy', {}, ()),
2096
2098
  ('it:prod:soft', {}, (
2099
+
2100
+ ('id', ('str', {'strip': True}), {
2101
+ 'doc': 'An ID for the software.'}),
2102
+
2097
2103
  ('name', ('it:prod:softname', {}), {
2104
+ 'alts': ('names',),
2098
2105
  'doc': 'Name of the software.',
2099
2106
  }),
2100
2107
  ('type', ('it:prod:soft:taxonomy', {}), {
@@ -2216,6 +2223,7 @@ class ItModule(s_module.CoreModule):
2216
2223
  'doc': 'Deprecated. Please use it:prod:softver:name.',
2217
2224
  }),
2218
2225
  ('name', ('it:prod:softname', {}), {
2226
+ 'alts': ('names',),
2219
2227
  'doc': 'Name of the software version.',
2220
2228
  }),
2221
2229
  ('names', ('array', {'type': 'it:prod:softname', 'uniq': True, 'sorted': True}), {
synapse/models/orgs.py CHANGED
@@ -493,10 +493,10 @@ class OuModule(s_module.CoreModule):
493
493
  ('ou:id:number', {}, (
494
494
 
495
495
  ('type', ('ou:id:type', {}), {
496
- 'doc': 'The type of org id', 'ro': True}),
496
+ 'doc': 'The type of org ID.', 'ro': True}),
497
497
 
498
498
  ('value', ('ou:id:value', {}), {
499
- 'doc': 'The value of org id', 'ro': True}),
499
+ 'doc': 'The value of the org ID.', 'ro': True}),
500
500
 
501
501
  ('status', ('str', {'lower': True, 'strip': True}), {
502
502
  'doc': 'A freeform status such as valid, suspended, expired.'}),
@@ -526,6 +526,7 @@ class OuModule(s_module.CoreModule):
526
526
  ('ou:goal', {}, (
527
527
 
528
528
  ('name', ('ou:goalname', {}), {
529
+ 'alts': ('names',),
529
530
  'doc': 'A terse name for the goal.'}),
530
531
 
531
532
  ('names', ('array', {'type': 'ou:goalname', 'sorted': True, 'uniq': True}), {
@@ -570,6 +571,7 @@ class OuModule(s_module.CoreModule):
570
571
  'doc': 'The FQDN of the org responsible for the campaign. Used for entity resolution.'}),
571
572
 
572
573
  ('goal', ('ou:goal', {}), {
574
+ 'alts': ('goals',),
573
575
  'doc': 'The assessed primary goal of the campaign.'}),
574
576
 
575
577
  ('slogan', ('lang:phrase', {}), {
@@ -585,6 +587,7 @@ class OuModule(s_module.CoreModule):
585
587
  'doc': 'Records the success/failure status of the campaign if known.'}),
586
588
 
587
589
  ('name', ('ou:campname', {}), {
590
+ 'alts': ('names',),
588
591
  'ex': 'operation overlord',
589
592
  'doc': 'A terse name of the campaign.'}),
590
593
 
@@ -924,6 +927,7 @@ class OuModule(s_module.CoreModule):
924
927
  ('ou:industry', {}, (
925
928
 
926
929
  ('name', ('ou:industryname', {}), {
930
+ 'alts': ('names',),
927
931
  'doc': 'The name of the industry.'}),
928
932
 
929
933
  ('type', ('ou:industry:type:taxonomy', {}), {
@@ -1176,6 +1180,7 @@ class OuModule(s_module.CoreModule):
1176
1180
  'doc': 'An array of contacts which sponsored the conference.',
1177
1181
  }),
1178
1182
  ('name', ('entity:name', {}), {
1183
+ 'alts': ('names',),
1179
1184
  'doc': 'The full name of the conference.',
1180
1185
  'ex': 'defcon 2017'}),
1181
1186