synapse 2.202.0__py311-none-any.whl → 2.203.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 (100) hide show
  1. synapse/axon.py +4 -4
  2. synapse/cmds/cortex.py +4 -6
  3. synapse/cmds/hive.py +10 -10
  4. synapse/common.py +17 -58
  5. synapse/cortex.py +6 -6
  6. synapse/data/__init__.py +3 -2
  7. synapse/data/iana.uris.mpk +1 -0
  8. synapse/lib/autodoc.py +3 -3
  9. synapse/lib/cli.py +2 -2
  10. synapse/lib/config.py +2 -2
  11. synapse/lib/encoding.py +4 -3
  12. synapse/lib/httpapi.py +7 -11
  13. synapse/lib/json.py +224 -0
  14. synapse/lib/lmdbslab.py +1 -1
  15. synapse/lib/oauth.py +176 -54
  16. synapse/lib/rstorm.py +18 -14
  17. synapse/lib/schemas.py +87 -1
  18. synapse/lib/scrape.py +35 -13
  19. synapse/lib/snap.py +2 -1
  20. synapse/lib/storm.py +2 -2
  21. synapse/lib/stormhttp.py +11 -13
  22. synapse/lib/stormlib/aha.py +4 -4
  23. synapse/lib/stormlib/auth.py +1 -1
  24. synapse/lib/stormlib/cache.py +2 -2
  25. synapse/lib/stormlib/cortex.py +5 -5
  26. synapse/lib/stormlib/graph.py +1 -1
  27. synapse/lib/stormlib/imap.py +1 -1
  28. synapse/lib/stormlib/json.py +8 -11
  29. synapse/lib/stormlib/model.py +1 -1
  30. synapse/lib/stormlib/notifications.py +2 -2
  31. synapse/lib/stormlib/oauth.py +105 -2
  32. synapse/lib/stormlib/stats.py +4 -0
  33. synapse/lib/stormlib/stix.py +3 -4
  34. synapse/lib/stormlib/vault.py +6 -6
  35. synapse/lib/stormlib/xml.py +2 -2
  36. synapse/lib/stormtypes.py +19 -28
  37. synapse/lib/structlog.py +3 -3
  38. synapse/lib/types.py +2 -1
  39. synapse/lib/version.py +2 -2
  40. synapse/lib/view.py +7 -3
  41. synapse/models/base.py +51 -2
  42. synapse/telepath.py +5 -3
  43. synapse/tests/files/__init__.py +0 -1
  44. synapse/tests/test_axon.py +1 -1
  45. synapse/tests/test_cmds_cortex.py +3 -2
  46. synapse/tests/test_cmds_hive.py +4 -4
  47. synapse/tests/test_common.py +29 -19
  48. synapse/tests/test_cortex.py +5 -5
  49. synapse/tests/test_lib_ast.py +3 -3
  50. synapse/tests/test_lib_autodoc.py +5 -5
  51. synapse/tests/test_lib_base.py +1 -1
  52. synapse/tests/test_lib_cell.py +16 -10
  53. synapse/tests/test_lib_config.py +2 -2
  54. synapse/tests/test_lib_encoding.py +2 -2
  55. synapse/tests/test_lib_grammar.py +64 -64
  56. synapse/tests/test_lib_httpapi.py +13 -13
  57. synapse/tests/test_lib_json.py +219 -0
  58. synapse/tests/test_lib_multislabseqn.py +2 -1
  59. synapse/tests/test_lib_node.py +2 -2
  60. synapse/tests/test_lib_scrape.py +50 -0
  61. synapse/tests/test_lib_storm.py +6 -6
  62. synapse/tests/test_lib_stormhttp.py +4 -4
  63. synapse/tests/test_lib_stormlib_auth.py +3 -2
  64. synapse/tests/test_lib_stormlib_cortex.py +10 -12
  65. synapse/tests/test_lib_stormlib_infosec.py +2 -3
  66. synapse/tests/test_lib_stormlib_json.py +18 -21
  67. synapse/tests/test_lib_stormlib_log.py +1 -1
  68. synapse/tests/test_lib_stormlib_oauth.py +603 -1
  69. synapse/tests/test_lib_stormlib_stats.py +13 -3
  70. synapse/tests/test_lib_stormlib_stix.py +5 -5
  71. synapse/tests/test_lib_stormtypes.py +4 -4
  72. synapse/tests/test_lib_structlog.py +5 -6
  73. synapse/tests/test_lib_view.py +8 -0
  74. synapse/tests/test_model_base.py +32 -0
  75. synapse/tests/test_model_infotech.py +2 -2
  76. synapse/tests/test_telepath.py +0 -1
  77. synapse/tests/test_tools_cryo_cat.py +4 -3
  78. synapse/tests/test_tools_docker_validate.py +4 -2
  79. synapse/tests/test_tools_feed.py +30 -2
  80. synapse/tests/test_tools_genpkg.py +1 -1
  81. synapse/tests/test_tools_healthcheck.py +8 -7
  82. synapse/tests/test_utils.py +2 -2
  83. synapse/tests/utils.py +3 -3
  84. synapse/tools/autodoc.py +3 -3
  85. synapse/tools/changelog.py +2 -2
  86. synapse/tools/cryo/cat.py +3 -3
  87. synapse/tools/csvtool.py +2 -3
  88. synapse/tools/docker/validate.py +5 -5
  89. synapse/tools/feed.py +2 -1
  90. synapse/tools/genpkg.py +3 -2
  91. synapse/tools/healthcheck.py +2 -3
  92. synapse/tools/json2mpk.py +2 -2
  93. synapse/utils/getrefs.py +6 -6
  94. synapse/vendor/cpython/lib/json.py +35 -0
  95. synapse/vendor/cpython/lib/test/test_json.py +22 -0
  96. {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/METADATA +2 -1
  97. {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/RECORD +100 -95
  98. {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/WHEEL +1 -1
  99. {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/LICENSE +0 -0
  100. {synapse-2.202.0.dist-info → synapse-2.203.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,3 @@
1
- import json
2
1
  import uuid
3
2
  import asyncio
4
3
  import logging
@@ -589,7 +588,7 @@ def validateStix(bundle, version='2.1'):
589
588
  'mesg': '',
590
589
  'result': {},
591
590
  }
592
- bundle = json.loads(json.dumps(bundle))
591
+ bundle = s_msgpack.deepcopy(bundle, use_list=True)
593
592
  opts = stix2validator.ValidationOptions(strict=True, version=version)
594
593
  try:
595
594
  results = stix2validator.validate_parsed_json(bundle, options=opts)
@@ -1172,7 +1171,7 @@ class LibStixExport(s_stormtypes.Lib):
1172
1171
  @s_stormtypes.stormfunc(readonly=True)
1173
1172
  async def config(self):
1174
1173
  # make a new mutable config
1175
- return json.loads(json.dumps(_DefaultConfig))
1174
+ return s_msgpack.deepcopy(_DefaultConfig, use_list=True)
1176
1175
 
1177
1176
  @s_stormtypes.stormfunc(readonly=True)
1178
1177
  async def bundle(self, config=None):
@@ -1372,7 +1371,7 @@ class StixBundle(s_stormtypes.Prim):
1372
1371
  return stixid
1373
1372
 
1374
1373
  def _initStixItem(self, stixid, stixtype, node):
1375
- ndef = json.loads(json.dumps(node.ndef))
1374
+ ndef = s_msgpack.deepcopy(node.ndef, use_list=True)
1376
1375
  retn = {
1377
1376
  'id': stixid,
1378
1377
  'type': stixtype,
@@ -321,7 +321,7 @@ class LibVault(s_stormtypes.Lib):
321
321
  {'name': 'vtype', 'type': 'str',
322
322
  'desc': 'The type of this vault.'},
323
323
  {'name': 'scope', 'type': 'str',
324
- 'desc': 'Scope for this vault. One of "user", "role", "global", or $lib.null for unscoped vaults.'},
324
+ 'desc': 'Scope for this vault. One of "user", "role", "global", or ``(null)`` for unscoped vaults.'},
325
325
  {'name': 'owner', 'type': 'str',
326
326
  'desc': 'User/role iden for this vault if scope is "user" or "role". None for "global" scope vaults.'},
327
327
  {'name': 'secrets', 'type': 'dict',
@@ -359,9 +359,9 @@ class LibVault(s_stormtypes.Lib):
359
359
  'args': (
360
360
  {'name': 'vtype', 'type': 'str', 'desc': 'The vault type to retrieved.'},
361
361
  {'name': 'scope', 'type': 'str', 'default': None,
362
- 'desc': 'The scope for the specified type. If $lib.null, then getByType will search.'},
362
+ 'desc': 'The scope for the specified type. If ``(null)``, then getByType will search.'},
363
363
  ),
364
- 'returns': {'type': 'vault', 'desc': 'Vault or $lib.null if the vault could not be retrieved.'}}},
364
+ 'returns': {'type': 'vault', 'desc': 'Vault or ``(null)`` if the vault could not be retrieved.'}}},
365
365
  {'name': 'list', 'desc': 'List vaults accessible to the current user.',
366
366
  'type': {'type': 'function', '_funcname': '_listVaults',
367
367
  'args': (),
@@ -649,14 +649,14 @@ class Vault(s_stormtypes.Prim):
649
649
  'type': {'type': 'function', '_funcname': '_methSetPerm',
650
650
  'args': (
651
651
  {'name': 'iden', 'type': 'str', 'desc': 'The user or role to modify.'},
652
- {'name': 'level', 'type': 'str', 'desc': 'The easyperm level for the iden. $lib.null to remove an existing permission.'},
652
+ {'name': 'level', 'type': 'str', 'desc': 'The easyperm level for the iden. ``(null)`` to remove an existing permission.'},
653
653
  ),
654
- 'returns': {'type': 'boolean', 'desc': '$lib.true if the permission was set, $lib.false otherwise.', }}},
654
+ 'returns': {'type': 'boolean', 'desc': '``(true)`` if the permission was set, ``(false)`` otherwise.', }}},
655
655
 
656
656
  {'name': 'delete', 'desc': 'Delete the Vault.',
657
657
  'type': {'type': 'function', '_funcname': '_methDelete',
658
658
  'args': (),
659
- 'returns': {'type': 'boolean', 'desc': '$lib.true if the vault was deleted, $lib.false otherwise.', }}},
659
+ 'returns': {'type': 'boolean', 'desc': '``(true)`` if the vault was deleted, ``(false)`` otherwise.', }}},
660
660
  )
661
661
  _storm_typename = 'vault'
662
662
  _ismutable = False
@@ -21,7 +21,7 @@ class XmlElement(s_stormtypes.Prim):
21
21
  'args': (
22
22
  {'name': 'name', 'type': 'str', 'desc': 'The name of the XML tag.'},
23
23
  {'name': 'nested', 'type': 'bool', 'default': True,
24
- 'desc': 'Set to $lib.false to only find direct children.'},
24
+ 'desc': 'Set to ``(false)`` to only find direct children.'},
25
25
  ),
26
26
  'returns': {'type': 'generator', 'desc': 'A generator which yields xml:elements.'}}},
27
27
 
@@ -30,7 +30,7 @@ class XmlElement(s_stormtypes.Prim):
30
30
  'args': (
31
31
  {'name': 'name', 'type': 'str', 'desc': 'The name of the child XML element tag.'},
32
32
  ),
33
- 'returns': {'type': 'xml:element', 'desc': 'The child XML element or $lib.null'}}},
33
+ 'returns': {'type': 'xml:element', 'desc': 'The child XML element or ``(null)``.'}}},
34
34
  )
35
35
 
36
36
  def __init__(self, runt, elem):
synapse/lib/stormtypes.py CHANGED
@@ -1,7 +1,6 @@
1
1
  import bz2
2
2
  import copy
3
3
  import gzip
4
- import json
5
4
  import time
6
5
 
7
6
  import regex
@@ -25,6 +24,7 @@ import synapse.common as s_common
25
24
  import synapse.telepath as s_telepath
26
25
 
27
26
  import synapse.lib.coro as s_coro
27
+ import synapse.lib.json as s_json
28
28
  import synapse.lib.node as s_node
29
29
  import synapse.lib.time as s_time
30
30
  import synapse.lib.cache as s_cache
@@ -837,14 +837,14 @@ class LibDmon(Lib):
837
837
  {'name': 'iden', 'type': 'str', 'desc': 'The GUID of the Dmon to stop.'},
838
838
  ),
839
839
  'returns': {'type': 'boolean',
840
- 'desc': '$lib.true unless the dmon does not exist or was already stopped.'}}},
840
+ 'desc': '``(true)`` unless the dmon does not exist or was already stopped.'}}},
841
841
  {'name': 'start', 'desc': 'Start a storm dmon.',
842
842
  'type': {'type': 'function', '_funcname': '_libDmonStart',
843
843
  'args': (
844
844
  {'name': 'iden', 'type': 'str', 'desc': 'The GUID of the dmon to start.'},
845
845
  ),
846
846
  'returns': {'type': 'boolean',
847
- 'desc': '$lib.true unless the dmon does not exist or was already started.'}}},
847
+ 'desc': '``(true)`` unless the dmon does not exist or was already started.'}}},
848
848
  )
849
849
  _storm_lib_path = ('dmon',)
850
850
 
@@ -1469,7 +1469,7 @@ class LibBase(Lib):
1469
1469
 
1470
1470
  Update the current runtime to enable debugging::
1471
1471
 
1472
- $lib.debug = $lib.true''',
1472
+ $lib.debug = (true)''',
1473
1473
  'type': {
1474
1474
  'type': ['gtor', 'stor'],
1475
1475
  '_storfunc': '_setRuntDebug',
@@ -1782,7 +1782,7 @@ class LibBase(Lib):
1782
1782
  name = await tostr(name)
1783
1783
  mesg = await tostr(mesg)
1784
1784
  info = await toprim(info)
1785
- s_common.reqjsonsafe(info)
1785
+ s_json.reqjsonsafe(info)
1786
1786
 
1787
1787
  ctor = getattr(s_exc, name, None)
1788
1788
  if ctor is not None:
@@ -1841,7 +1841,7 @@ class LibBase(Lib):
1841
1841
  @stormfunc(readonly=True)
1842
1842
  async def _fire(self, name, **info):
1843
1843
  info = await toprim(info)
1844
- s_common.reqjsonsafe(info)
1844
+ s_json.reqjsonsafe(info)
1845
1845
  await self.runt.snap.fire('storm:fire', type=name, data=info)
1846
1846
 
1847
1847
  @registry.registerLib
@@ -2103,9 +2103,9 @@ class LibAxon(Lib):
2103
2103
 
2104
2104
  For APIs that accept a proxy argument, the following values are supported::
2105
2105
 
2106
- $lib.null: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
2107
- $lib.true: Use the proxy defined by the http:proxy configuration option if set.
2108
- $lib.false: Do not use the proxy defined by the http:proxy configuration option if set.
2106
+ ``(null)``: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
2107
+ ``(true)``: Use the proxy defined by the http:proxy configuration option if set.
2108
+ ``(false)``: Do not use the proxy defined by the http:proxy configuration option if set.
2109
2109
  <str>: A proxy URL string.
2110
2110
  '''
2111
2111
  _storm_locals = (
@@ -3025,7 +3025,7 @@ class LibTime(Lib):
3025
3025
  {'name': 'valu', 'type': 'str', 'desc': 'The timestamp string to parse.', },
3026
3026
  {'name': 'format', 'type': 'str', 'desc': 'The format string to use for parsing.', },
3027
3027
  {'name': 'errok', 'type': 'boolean', 'default': False,
3028
- 'desc': 'If set, parsing errors will return ``$lib.null`` instead of raising an exception.'}
3028
+ 'desc': 'If set, parsing errors will return ``(null)`` instead of raising an exception.'}
3029
3029
  ),
3030
3030
  'returns': {'type': 'int', 'desc': 'The epoch timestamp for the string.', }}},
3031
3031
  {'name': 'format', 'desc': '''
@@ -3365,7 +3365,7 @@ class LibRegx(Lib):
3365
3365
  In order to get the matching groups, patterns must use parentheses
3366
3366
  to indicate the start and stop of the regex to return portions of.
3367
3367
  If groups are not used, a successful match will return a empty list
3368
- and a unsuccessful match will return ``$lib.null``.
3368
+ and a unsuccessful match will return ``(null)``.
3369
3369
 
3370
3370
  Example:
3371
3371
  Extract the matching groups from a piece of text::
@@ -3407,7 +3407,6 @@ class LibRegx(Lib):
3407
3407
  'returns': {'type': 'list', 'desc': 'A list of lists of strings for the matching groups in the pattern.', }}},
3408
3408
  {'name': 'matches', 'desc': '''
3409
3409
  Check if text matches a pattern.
3410
- Returns $lib.true if the text matches the pattern, otherwise $lib.false.
3411
3410
 
3412
3411
  Notes:
3413
3412
  This API requires the pattern to match at the start of the string.
@@ -4797,11 +4796,7 @@ class Str(Prim):
4797
4796
 
4798
4797
  @stormfunc(readonly=True)
4799
4798
  async def _methStrJson(self):
4800
- try:
4801
- return json.loads(self.valu, strict=True)
4802
- except Exception as e:
4803
- mesg = f'Text is not valid JSON: {self.valu}'
4804
- raise s_exc.BadJsonText(mesg=mesg)
4799
+ return s_json.loads(self.valu)
4805
4800
 
4806
4801
  @registry.registerType
4807
4802
  class Bytes(Prim):
@@ -4990,19 +4985,15 @@ class Bytes(Prim):
4990
4985
  errors = await tostr(errors)
4991
4986
 
4992
4987
  if encoding is None:
4993
- encoding = json.detect_encoding(valu)
4988
+ encoding = s_json.detect_encoding(valu)
4994
4989
  else:
4995
4990
  encoding = await tostr(encoding)
4996
4991
 
4997
- return json.loads(valu.decode(encoding, errors))
4992
+ return s_json.loads(valu.decode(encoding, errors))
4998
4993
 
4999
4994
  except UnicodeDecodeError as e:
5000
4995
  raise s_exc.StormRuntimeError(mesg=f'{e}: {s_common.trimText(repr(valu))}') from None
5001
4996
 
5002
- except json.JSONDecodeError as e:
5003
- mesg = f'Unable to decode bytes as json: {e.args[0]}'
5004
- raise s_exc.BadJsonText(mesg=mesg)
5005
-
5006
4997
  @registry.registerType
5007
4998
  class Dict(Prim):
5008
4999
  '''
@@ -6262,7 +6253,7 @@ class NodeData(Prim):
6262
6253
  gateiden = self.valu.snap.wlyr.iden
6263
6254
  confirm(('node', 'data', 'set', name), gateiden=gateiden)
6264
6255
  valu = await toprim(valu)
6265
- s_common.reqjsonsafe(valu)
6256
+ s_json.reqjsonsafe(valu)
6266
6257
  return await self.valu.setData(name, valu)
6267
6258
 
6268
6259
  async def _popNodeData(self, name):
@@ -7790,7 +7781,7 @@ class View(Prim):
7790
7781
  _storm_locals = (
7791
7782
  {'name': 'iden', 'desc': 'The iden of the View.', 'type': 'str', },
7792
7783
  {'name': 'layers', 'desc': 'The ``layer`` objects associated with the ``view``.', 'type': 'list', },
7793
- {'name': 'parent', 'desc': 'The parent View. Will be ``$lib.null`` if the view is not a fork.', 'type': 'str'},
7784
+ {'name': 'parent', 'desc': 'The parent View. Will be ``(null)`` if the view is not a fork.', 'type': 'str'},
7794
7785
  {'name': 'triggers', 'desc': 'The ``trigger`` objects associated with the ``view``.',
7795
7786
  'type': 'list', },
7796
7787
  {'name': 'children', 'desc': 'Yield Views which are children of this View.',
@@ -7815,7 +7806,7 @@ class View(Prim):
7815
7806
  the protected option (below) until this option is removed.
7816
7807
 
7817
7808
  protected (bool)
7818
- Setting to $lib.true will prevent the layer from being merged or deleted.
7809
+ Setting to ``(true)`` will prevent the layer from being merged or deleted.
7819
7810
 
7820
7811
  layers (list(str))
7821
7812
  Set the list of layer idens for a non-forked view. Layers are specified
@@ -8752,7 +8743,7 @@ class LibTrigger(Lib):
8752
8743
  pass
8753
8744
 
8754
8745
  if trigger is None:
8755
- raise s_exc.NoSuchIden('Trigger not found')
8746
+ raise s_exc.NoSuchIden(mesg='Trigger not found', iden=iden)
8756
8747
 
8757
8748
  self.runt.confirm(('trigger', 'get'), gateiden=iden)
8758
8749
 
@@ -8906,7 +8897,7 @@ class LibJsonStor(Lib):
8906
8897
  {'name': 'path', 'type': 'str|list', 'desc': 'A path string or list of path parts.'},
8907
8898
  {'name': 'prop', 'type': 'str|list', 'desc': 'A property name or list of name parts.', 'default': None},
8908
8899
  ),
8909
- 'returns': {'type': 'prim', 'desc': 'The previously stored value or $lib.null'}}},
8900
+ 'returns': {'type': 'prim', 'desc': 'The previously stored value or ``(null)``.'}}},
8910
8901
 
8911
8902
  {'name': 'set', 'desc': 'Set a JSON object or object property.',
8912
8903
  'type': {'type': 'function', '_funcname': 'set',
synapse/lib/structlog.py CHANGED
@@ -1,9 +1,9 @@
1
- import json
2
-
3
1
  import logging
4
2
 
5
3
  import synapse.common as s_common
6
4
 
5
+ import synapse.lib.json as s_json
6
+
7
7
  class JsonFormatter(logging.Formatter):
8
8
  def __init__(self, *args, **kwargs):
9
9
  super().__init__(*args, **kwargs)
@@ -37,4 +37,4 @@ class JsonFormatter(logging.Formatter):
37
37
  if extras:
38
38
  ret.update({k: v for k, v in extras.items() if k not in ret})
39
39
 
40
- return json.dumps(ret, default=str)
40
+ return s_json.dumps(ret, default=str).decode()
synapse/lib/types.py CHANGED
@@ -11,6 +11,7 @@ import synapse.exc as s_exc
11
11
  import synapse.common as s_common
12
12
 
13
13
  import synapse.lib.chop as s_chop
14
+ import synapse.lib.json as s_json
14
15
  import synapse.lib.node as s_node
15
16
  import synapse.lib.time as s_time
16
17
  import synapse.lib.cache as s_cache
@@ -1601,7 +1602,7 @@ class Data(Type):
1601
1602
 
1602
1603
  def norm(self, valu):
1603
1604
  try:
1604
- s_common.reqjsonsafe(valu)
1605
+ s_json.reqjsonsafe(valu)
1605
1606
  if self.validator is not None:
1606
1607
  self.validator(valu)
1607
1608
  except (s_exc.MustBeJsonSafe, s_exc.SchemaViolation) as e:
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, 202, 0)
226
+ version = (2, 203, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = '744d404357c48b663bd03528e35c6f0e186edb0e'
228
+ commit = '809ecdca2e2b05f1cd111bb23c237127b2b9c177'
synapse/lib/view.py CHANGED
@@ -1360,17 +1360,21 @@ class View(s_nexus.Pusher): # type: ignore
1360
1360
  'readonly': False
1361
1361
  }
1362
1362
 
1363
+ if name is None:
1364
+ if (pname := self.parent.info.get('name')) is not None:
1365
+ name = f'inserted fork of {pname}'
1366
+ else:
1367
+ name = f'inserted fork of {self.parent.iden}'
1368
+
1363
1369
  vdef = {
1364
1370
  'iden': s_common.guid(),
1371
+ 'name': name,
1365
1372
  'created': ctime,
1366
1373
  'creator': useriden,
1367
1374
  'parent': self.parent.iden,
1368
1375
  'layers': [layriden] + [lyr.iden for lyr in self.parent.layers]
1369
1376
  }
1370
1377
 
1371
- if name is not None:
1372
- vdef['name'] = name
1373
-
1374
1378
  s_layer.reqValidLdef(ldef)
1375
1379
  s_schemas.reqValidView(vdef)
1376
1380
 
synapse/models/base.py CHANGED
@@ -29,10 +29,18 @@ class BaseModule(s_module.CoreModule):
29
29
 
30
30
  'types': (
31
31
 
32
+ ('meta:feed', ('guid', {}), {
33
+ 'doc': 'A data feed provided by a specific source.'}),
34
+
35
+ ('meta:feed:type:taxonomy', ('taxonomy', {}), {
36
+ 'interfaces': ('meta:taxonomy',),
37
+ 'doc': 'A data feed type taxonomy.'}),
38
+
32
39
  ('meta:source', ('guid', {}), {
33
40
  'doc': 'A data source unique identifier.'}),
34
41
 
35
42
  ('meta:seen', ('comp', {'fields': (('source', 'meta:source'), ('node', 'ndef'))}), {
43
+ 'deprecated': True,
36
44
  'doc': 'Annotates that the data in a node was obtained from or observed by a given source.'}),
37
45
 
38
46
  ('meta:note', ('guid', {}), {
@@ -167,15 +175,22 @@ class BaseModule(s_module.CoreModule):
167
175
  'edges': (
168
176
  ((None, 'refs', None), {
169
177
  'doc': 'The source node contains a reference to the target node.'}),
178
+
170
179
  (('meta:source', 'seen', None), {
171
180
  'doc': 'The meta:source observed the target node.'}),
181
+
182
+ (('meta:feed', 'found', None), {
183
+ 'doc': 'The meta:feed produced the target node.'}),
184
+
172
185
  (('meta:note', 'about', None), {
173
- 'doc': 'The meta:note is about the target node.'
174
- }),
186
+ 'doc': 'The meta:note is about the target node.'}),
187
+
175
188
  (('meta:ruleset', 'has', 'meta:rule'), {
176
189
  'doc': 'The meta:ruleset includes the meta:rule.'}),
190
+
177
191
  (('meta:rule', 'matches', None), {
178
192
  'doc': 'The meta:rule has matched on target node.'}),
193
+
179
194
  (('meta:rule', 'detects', None), {
180
195
  'doc': 'The meta:rule is designed to detect instances of the target node.'}),
181
196
  ),
@@ -213,6 +228,40 @@ class BaseModule(s_module.CoreModule):
213
228
 
214
229
  )),
215
230
 
231
+ ('meta:feed:type:taxonomy', {}, ()),
232
+ ('meta:feed', {}, (
233
+
234
+ ('name', ('str', {'lower': True, 'onespace': True}), {
235
+ 'doc': 'A name for the feed.'}),
236
+
237
+ ('type', ('meta:feed:type:taxonomy', {}), {
238
+ 'doc': 'The type of data feed.'}),
239
+
240
+ ('source', ('meta:source', {}), {
241
+ 'doc': 'The meta:source which provides the feed.'}),
242
+
243
+ ('url', ('inet:url', {}), {
244
+ 'doc': 'The URL of the feed API endpoint.'}),
245
+
246
+ ('query', ('str', {}), {
247
+ 'doc': 'The query logic associated with generating the feed output.'}),
248
+
249
+ ('opts', ('data', {}), {
250
+ 'doc': 'An opaque JSON object containing feed parameters and options.'}),
251
+
252
+ ('period', ('ival', {}), {
253
+ 'doc': 'The time window over which results have been ingested.'}),
254
+
255
+ ('latest', ('time', {}), {
256
+ 'doc': 'The time of the last record consumed from the feed.'}),
257
+
258
+ ('offset', ('int', {}), {
259
+ 'doc': 'The offset of the last record consumed from the feed.'}),
260
+
261
+ ('cursor', ('str', {'strip': True}), {
262
+ 'doc': 'A cursor used to track ingest offset within the feed.'}),
263
+ )),
264
+
216
265
  ('meta:note:type:taxonomy', {}, ()),
217
266
  ('meta:note', {}, (
218
267
 
synapse/telepath.py CHANGED
@@ -394,7 +394,7 @@ class Share(s_base.Base):
394
394
  This should never be used by synapse core code. This is for sync client code convenience only.
395
395
  '''
396
396
  if s_threads.iden() == self.tid:
397
- raise s_exc.SynErr('Use of synchronous context manager in async code')
397
+ raise s_exc.SynErr(mesg='Use of synchronous context manager in async code')
398
398
 
399
399
  self._ctxobj = self.schedCoroSafePend(self.__aenter__())
400
400
  return self
@@ -593,7 +593,7 @@ class Proxy(s_base.Base):
593
593
 
594
594
  '''
595
595
  _link_task = None
596
- _link_event = asyncio.Event()
596
+ _link_event = None
597
597
  _all_proxies = set()
598
598
 
599
599
  async def __anit__(self, link, name):
@@ -650,6 +650,7 @@ class Proxy(s_base.Base):
650
650
  if not Proxy._all_proxies and Proxy._link_task is not None:
651
651
  Proxy._link_task.cancel()
652
652
  Proxy._link_task = None
653
+ Proxy._link_event = None
653
654
 
654
655
  Proxy._all_proxies.add(self)
655
656
 
@@ -657,6 +658,7 @@ class Proxy(s_base.Base):
657
658
  self.link.onfini(self.fini)
658
659
 
659
660
  if Proxy._link_task is None:
661
+ Proxy._link_event = asyncio.Event()
660
662
  Proxy._link_task = s_coro.create_task(Proxy._linkLoopTask())
661
663
 
662
664
  @classmethod
@@ -821,7 +823,7 @@ class Proxy(s_base.Base):
821
823
  This must not be used from async code, and it should never be used in core synapse code.
822
824
  '''
823
825
  if s_threads.iden() == self.tid:
824
- raise s_exc.SynErr('Use of synchronous context manager in async code')
826
+ raise s_exc.SynErr(mesg='Use of synchronous context manager in async code')
825
827
  self._ctxobj = self.schedCoroSafePend(self.__aenter__())
826
828
  return self
827
829
 
@@ -1,7 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Stdlib
3
3
  import os
4
- import json
5
4
  import logging
6
5
 
7
6
  log = logging.getLogger(__name__)
@@ -103,7 +103,7 @@ class HttpPushFile(s_httpapi.StreamHandler):
103
103
  assert item['filename'] == 'bytes'
104
104
 
105
105
  assert args.get('zip_password') == [b'test']
106
- assert args.get('dict') == [b'{"foo": "bar"}']
106
+ assert args.get('dict') == [b'{"foo":"bar"}']
107
107
  self.sendRestRetn(self.gotsize)
108
108
 
109
109
  class AxonTest(s_t_utils.SynTest):
@@ -4,6 +4,7 @@ import asyncio
4
4
  import synapse.common as s_common
5
5
 
6
6
  import synapse.lib.cmdr as s_cmdr
7
+ import synapse.lib.json as s_json
7
8
  import synapse.lib.encoding as s_encoding
8
9
  import synapse.lib.lmdbslab as s_lmdbslab
9
10
 
@@ -352,7 +353,7 @@ class CmdCoreTest(s_t_utils.SynTest):
352
353
  await cmdr.runCmdLine(f'storm --save-nodes {path} test:int')
353
354
  outp.expect('2 nodes')
354
355
 
355
- jsdata = [item for item in s_common.jslines(path)]
356
+ jsdata = [item for item in s_json.jslines(path)]
356
357
  self.len(2, jsdata)
357
358
  self.eq({tuple(n[0]) for n in jsdata},
358
359
  {('test:int', 20), ('test:int', 30)})
@@ -371,7 +372,7 @@ class CmdCoreTest(s_t_utils.SynTest):
371
372
  with s_common.genfile(stormfile) as fd:
372
373
  fd.write(b'[ inet:fqdn=$hehe ]')
373
374
 
374
- s_common.jssave(test_opts, optsfile)
375
+ s_json.jssave(test_opts, optsfile)
375
376
  s_common.yamlsave(test_opts, optsfile_yaml)
376
377
 
377
378
  outp = self.getTestOutp()
@@ -5,10 +5,10 @@ import synapse.lib.cmdr as s_cmdr
5
5
  import synapse.tests.utils as s_t_utils
6
6
 
7
7
  _json_output = '''[
8
- 1,
9
- 2,
10
- 3,
11
- 4
8
+ 1,
9
+ 2,
10
+ 3,
11
+ 4
12
12
  ]'''
13
13
 
14
14
  class CmdHiveTest(s_t_utils.SynTest):
@@ -1,12 +1,17 @@
1
1
  import os
2
+ import http
2
3
  import asyncio
3
4
  import logging
4
5
  import subprocess
5
6
 
6
7
  import yaml
8
+ import aiohttp
7
9
 
8
10
  import synapse.exc as s_exc
9
11
  import synapse.common as s_common
12
+
13
+ import synapse.lib.httpapi as s_httpapi
14
+
10
15
  import synapse.tests.utils as s_t_utils
11
16
 
12
17
  logger = logging.getLogger(__name__)
@@ -426,25 +431,6 @@ class CommonTest(s_t_utils.SynTest):
426
431
  retn = s_common.merggenr2([asyncl(lt) for lt in (l3, l2, l1)], reverse=True)
427
432
  self.eq((9, 8, 7, 6, 5, 4, 3, 2, 1), await alist(retn))
428
433
 
429
- def test_jsonsafe(self):
430
- items = (
431
- (None, None),
432
- (1234, None),
433
- ('1234', None),
434
- ({'asdf': 'haha'}, None),
435
- ({'a': (1,), 'b': [{'': 4}, 56, None, {'t': True, 'f': False}, 'oh my']}, None),
436
- (b'1234', s_exc.BadArg),
437
- ({'a': 'a', 2: 2}, s_exc.BadArg),
438
- ({'a', 'b', 'c'}, s_exc.BadArg),
439
- (s_common.novalu, s_exc.BadArg),
440
- )
441
- for (item, eret) in items:
442
- if eret is None:
443
- self.none(s_common.reqJsonSafeStrict(item))
444
- else:
445
- with self.raises(eret):
446
- s_common.reqJsonSafeStrict(item)
447
-
448
434
  def test_sslctx(self):
449
435
  with self.getTestDir(mirror='certdir') as dirn:
450
436
  cadir = s_common.genpath(dirn, 'cas')
@@ -481,3 +467,27 @@ class CommonTest(s_t_utils.SynTest):
481
467
  v = s_common.trimText(iv, n=n)
482
468
  self.le(len(v), n)
483
469
  self.eq(v, ev)
470
+
471
+ async def test_tornado_monkeypatch(self):
472
+ class JsonHandler(s_httpapi.Handler):
473
+ async def get(self):
474
+ resp = {
475
+ 'foo': 'bar',
476
+ 'html': '<html></html>'
477
+ }
478
+ self.write(resp)
479
+
480
+ async with self.getTestCore() as core:
481
+ core.addHttpApi('/api/v1/test_tornado/', JsonHandler, {'cell': core})
482
+ _, port = await core.addHttpsPort(0)
483
+ url = f'https://127.0.0.1:{port}/api/v1/test_tornado/'
484
+
485
+ async with aiohttp.ClientSession() as session:
486
+ async with session.get(url, ssl=False) as resp:
487
+ self.eq(resp.status, http.HTTPStatus.OK)
488
+
489
+ text = await resp.text()
490
+ self.eq(text, '{"foo":"bar","html":"<html><\\/html>"}')
491
+
492
+ json = await resp.json()
493
+ self.eq(json, {'foo': 'bar', 'html': '<html></html>'})
@@ -1559,8 +1559,8 @@ class CortexTest(s_t_utils.SynTest):
1559
1559
  self.eq(refs.get('fqdn'), ('inet:fqdn', 'woot.com'))
1560
1560
  self.eq(refs.get('ipv4'), ('inet:ipv4', 0x01020304))
1561
1561
 
1562
- self.len(1, await core.nodes('[meta:seen=($sorc, $valu)]',
1563
- opts={'vars': {'sorc': sorc, 'valu': node.ndef}}))
1562
+ self.len(1, await core.nodes('[test:str=testndef :somestr=$somestr :bar=$valu]',
1563
+ opts={'vars': {'somestr': sorc, 'valu': node.ndef}}))
1564
1564
 
1565
1565
  # test un-populated properties
1566
1566
  nodes = await core.nodes('[ps:contact="*"]')
@@ -1592,13 +1592,13 @@ class CortexTest(s_t_utils.SynTest):
1592
1592
  self.eq(ints, (('test:int', 1), ('test:int', 2), ('test:int', 3)))
1593
1593
 
1594
1594
  opts = {'vars': {'sorc': sorc}}
1595
- nodes = await core.nodes('meta:seen:source=$sorc -> *', opts=opts)
1595
+ nodes = await core.nodes('test:str:somestr=$sorc -> *', opts=opts)
1596
1596
 
1597
1597
  self.len(2, nodes)
1598
1598
  self.isin('inet:dns:a', {n.ndef[0] for n in nodes})
1599
1599
 
1600
1600
  opts = {'vars': {'sorc': sorc}}
1601
- nodes = await core.nodes('meta:seen:source=$sorc :node -> *', opts=opts)
1601
+ nodes = await core.nodes('test:str:somestr=$sorc :bar -> *', opts=opts)
1602
1602
 
1603
1603
  self.len(1, nodes)
1604
1604
  self.eq('inet:dns:a', nodes[0].ndef[0])
@@ -3955,7 +3955,7 @@ class CortexBasicTest(s_t_utils.SynTest):
3955
3955
  'refs': True,
3956
3956
  'edges': False,
3957
3957
  'forms': {},
3958
- 'pivots': ['<- meta:seen'],
3958
+ 'pivots': ['<(seen)- meta:source'],
3959
3959
  'degrees': 3,
3960
3960
  'filters': ['+#nope'],
3961
3961
  'filterinput': False,