synapse 2.191.0__py311-none-any.whl → 2.193.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 +54 -23
- synapse/common.py +15 -0
- synapse/cortex.py +18 -20
- synapse/exc.py +6 -1
- synapse/lib/agenda.py +0 -2
- synapse/lib/ast.py +30 -12
- synapse/lib/cell.py +79 -85
- synapse/lib/cli.py +20 -11
- synapse/lib/nexus.py +2 -1
- synapse/lib/parser.py +1 -1
- synapse/lib/snap.py +4 -4
- synapse/lib/storm.py +34 -17
- synapse/lib/stormhttp.py +32 -35
- synapse/lib/stormlib/json.py +5 -2
- synapse/lib/stormtypes.py +121 -20
- synapse/lib/version.py +2 -2
- synapse/models/inet.py +17 -1
- synapse/models/infotech.py +14 -4
- synapse/models/risk.py +16 -2
- synapse/tests/test_axon.py +10 -0
- synapse/tests/test_cortex.py +55 -3
- synapse/tests/test_exc.py +3 -0
- synapse/tests/test_lib_agenda.py +157 -1
- synapse/tests/test_lib_ast.py +49 -1
- synapse/tests/test_lib_cell.py +106 -1
- synapse/tests/test_lib_httpapi.py +9 -2
- synapse/tests/test_lib_storm.py +72 -30
- synapse/tests/test_lib_stormhttp.py +57 -12
- synapse/tests/test_lib_stormlib_json.py +20 -0
- synapse/tests/test_lib_stormlib_scrape.py +2 -2
- synapse/tests/test_model_inet.py +40 -5
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/test_servers_univ.py +0 -12
- synapse/tests/test_tools_apikey.py +227 -0
- synapse/tests/test_tools_storm.py +95 -0
- synapse/tests/test_utils_getrefs.py +1 -1
- synapse/tools/apikey.py +93 -0
- synapse/utils/getrefs.py +14 -3
- synapse/vendor/cpython/lib/http/__init__.py +0 -0
- synapse/vendor/cpython/lib/http/cookies.py +59 -0
- synapse/vendor/cpython/lib/test/test_http_cookies.py +49 -0
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/METADATA +2 -2
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/RECORD +46 -41
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/WHEEL +1 -1
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/LICENSE +0 -0
- {synapse-2.191.0.dist-info → synapse-2.193.0.dist-info}/top_level.txt +0 -0
synapse/axon.py
CHANGED
|
@@ -594,7 +594,7 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
594
594
|
return await self.cell.dels(sha256s)
|
|
595
595
|
|
|
596
596
|
async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
|
|
597
|
-
ssl=True, timeout=None, proxy=
|
|
597
|
+
ssl=True, timeout=None, proxy=True, ssl_opts=None):
|
|
598
598
|
'''
|
|
599
599
|
Stream a file download directly into the Axon.
|
|
600
600
|
|
|
@@ -607,6 +607,7 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
607
607
|
method (str): The HTTP method to use.
|
|
608
608
|
ssl (bool): Perform SSL verification.
|
|
609
609
|
timeout (int): The timeout of the request, in seconds.
|
|
610
|
+
proxy (str|bool): The proxy value.
|
|
610
611
|
ssl_opts (dict): Additional SSL/TLS options.
|
|
611
612
|
|
|
612
613
|
Notes:
|
|
@@ -621,6 +622,13 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
621
622
|
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
622
623
|
}
|
|
623
624
|
|
|
625
|
+
The following proxy arguments are supported::
|
|
626
|
+
|
|
627
|
+
None: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
|
|
628
|
+
True: Use the proxy defined by the http:proxy configuration option if set.
|
|
629
|
+
False: Do not use the proxy defined by the http:proxy configuration option if set.
|
|
630
|
+
<str>: A proxy URL string.
|
|
631
|
+
|
|
624
632
|
The dictionary returned by this may contain the following values::
|
|
625
633
|
|
|
626
634
|
{
|
|
@@ -654,13 +662,13 @@ class AxonApi(s_cell.CellApi, s_share.Share): # type: ignore
|
|
|
654
662
|
ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
|
|
655
663
|
|
|
656
664
|
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
657
|
-
ssl=True, timeout=None, proxy=
|
|
665
|
+
ssl=True, timeout=None, proxy=True, ssl_opts=None):
|
|
658
666
|
await self._reqUserAllowed(('axon', 'wput'))
|
|
659
667
|
return await self.cell.postfiles(fields, url, params=params, headers=headers, method=method,
|
|
660
668
|
ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
|
|
661
669
|
|
|
662
670
|
async def wput(self, sha256, url, params=None, headers=None, method='PUT',
|
|
663
|
-
ssl=True, timeout=None, proxy=
|
|
671
|
+
ssl=True, timeout=None, proxy=True, ssl_opts=None):
|
|
664
672
|
await self._reqUserAllowed(('axon', 'wput'))
|
|
665
673
|
return await self.cell.wput(sha256, url, params=params, headers=headers, method=method,
|
|
666
674
|
ssl=ssl, timeout=timeout, proxy=proxy, ssl_opts=ssl_opts)
|
|
@@ -935,6 +943,24 @@ class Axon(s_cell.Cell):
|
|
|
935
943
|
self.axonhist.add(item, tick=tick)
|
|
936
944
|
self.axonseqn.add(item)
|
|
937
945
|
|
|
946
|
+
async def _resolveProxyUrl(self, valu):
|
|
947
|
+
match valu:
|
|
948
|
+
case None:
|
|
949
|
+
s_common.deprecated('Setting the Axon HTTP proxy argument to None', curv='2.192.0')
|
|
950
|
+
return await self.getConfOpt('http:proxy')
|
|
951
|
+
|
|
952
|
+
case True:
|
|
953
|
+
return await self.getConfOpt('http:proxy')
|
|
954
|
+
|
|
955
|
+
case False:
|
|
956
|
+
return None
|
|
957
|
+
|
|
958
|
+
case str():
|
|
959
|
+
return valu
|
|
960
|
+
|
|
961
|
+
case _:
|
|
962
|
+
raise s_exc.BadArg(mesg='HTTP proxy argument must be a string or bool.')
|
|
963
|
+
|
|
938
964
|
async def _reqHas(self, sha256):
|
|
939
965
|
'''
|
|
940
966
|
Ensure a file exists; and return its size if so.
|
|
@@ -1462,7 +1488,7 @@ class Axon(s_cell.Cell):
|
|
|
1462
1488
|
sha256=sha256) from None
|
|
1463
1489
|
|
|
1464
1490
|
async def postfiles(self, fields, url, params=None, headers=None, method='POST',
|
|
1465
|
-
ssl=True, timeout=None, proxy=
|
|
1491
|
+
ssl=True, timeout=None, proxy=True, ssl_opts=None):
|
|
1466
1492
|
'''
|
|
1467
1493
|
Send files from the axon as fields in a multipart/form-data HTTP request.
|
|
1468
1494
|
|
|
@@ -1474,7 +1500,7 @@ class Axon(s_cell.Cell):
|
|
|
1474
1500
|
method (str): The HTTP method to use.
|
|
1475
1501
|
ssl (bool): Perform SSL verification.
|
|
1476
1502
|
timeout (int): The timeout of the request, in seconds.
|
|
1477
|
-
proxy (
|
|
1503
|
+
proxy (str|bool): The proxy value.
|
|
1478
1504
|
ssl_opts (dict): Additional SSL/TLS options.
|
|
1479
1505
|
|
|
1480
1506
|
Notes:
|
|
@@ -1497,6 +1523,13 @@ class Axon(s_cell.Cell):
|
|
|
1497
1523
|
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
1498
1524
|
}
|
|
1499
1525
|
|
|
1526
|
+
The following proxy arguments are supported::
|
|
1527
|
+
|
|
1528
|
+
None: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
|
|
1529
|
+
True: Use the proxy defined by the http:proxy configuration option if set.
|
|
1530
|
+
False: Do not use the proxy defined by the http:proxy configuration option if set.
|
|
1531
|
+
<str>: A proxy URL string.
|
|
1532
|
+
|
|
1500
1533
|
The dictionary returned by this may contain the following values::
|
|
1501
1534
|
|
|
1502
1535
|
{
|
|
@@ -1512,14 +1545,11 @@ class Axon(s_cell.Cell):
|
|
|
1512
1545
|
Returns:
|
|
1513
1546
|
dict: An information dictionary containing the results of the request.
|
|
1514
1547
|
'''
|
|
1515
|
-
if proxy is None:
|
|
1516
|
-
proxy = self.conf.get('http:proxy')
|
|
1517
|
-
|
|
1518
1548
|
ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
|
|
1519
1549
|
|
|
1520
1550
|
connector = None
|
|
1521
|
-
if proxy:
|
|
1522
|
-
connector = aiohttp_socks.ProxyConnector.from_url(
|
|
1551
|
+
if proxyurl := await self._resolveProxyUrl(proxy):
|
|
1552
|
+
connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
|
|
1523
1553
|
|
|
1524
1554
|
atimeout = aiohttp.ClientTimeout(total=timeout)
|
|
1525
1555
|
|
|
@@ -1583,18 +1613,15 @@ class Axon(s_cell.Cell):
|
|
|
1583
1613
|
}
|
|
1584
1614
|
|
|
1585
1615
|
async def wput(self, sha256, url, params=None, headers=None, method='PUT', ssl=True, timeout=None,
|
|
1586
|
-
filename=None, filemime=None, proxy=
|
|
1616
|
+
filename=None, filemime=None, proxy=True, ssl_opts=None):
|
|
1587
1617
|
'''
|
|
1588
1618
|
Stream a blob from the axon as the body of an HTTP request.
|
|
1589
1619
|
'''
|
|
1590
|
-
if proxy is None:
|
|
1591
|
-
proxy = self.conf.get('http:proxy')
|
|
1592
|
-
|
|
1593
1620
|
ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
|
|
1594
1621
|
|
|
1595
1622
|
connector = None
|
|
1596
|
-
if proxy:
|
|
1597
|
-
connector = aiohttp_socks.ProxyConnector.from_url(
|
|
1623
|
+
if proxyurl := await self._resolveProxyUrl(proxy):
|
|
1624
|
+
connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
|
|
1598
1625
|
|
|
1599
1626
|
atimeout = aiohttp.ClientTimeout(total=timeout)
|
|
1600
1627
|
|
|
@@ -1654,7 +1681,7 @@ class Axon(s_cell.Cell):
|
|
|
1654
1681
|
return info
|
|
1655
1682
|
|
|
1656
1683
|
async def wget(self, url, params=None, headers=None, json=None, body=None, method='GET',
|
|
1657
|
-
ssl=True, timeout=None, proxy=
|
|
1684
|
+
ssl=True, timeout=None, proxy=True, ssl_opts=None):
|
|
1658
1685
|
'''
|
|
1659
1686
|
Stream a file download directly into the Axon.
|
|
1660
1687
|
|
|
@@ -1667,7 +1694,7 @@ class Axon(s_cell.Cell):
|
|
|
1667
1694
|
method (str): The HTTP method to use.
|
|
1668
1695
|
ssl (bool): Perform SSL verification.
|
|
1669
1696
|
timeout (int): The timeout of the request, in seconds.
|
|
1670
|
-
proxy (
|
|
1697
|
+
proxy (str|bool): The proxy value.
|
|
1671
1698
|
ssl_opts (dict): Additional SSL/TLS options.
|
|
1672
1699
|
|
|
1673
1700
|
Notes:
|
|
@@ -1682,6 +1709,13 @@ class Axon(s_cell.Cell):
|
|
|
1682
1709
|
'client_key': <str> - PEM encoded key for use in mTLS. Alternatively, can be included in client_cert.
|
|
1683
1710
|
}
|
|
1684
1711
|
|
|
1712
|
+
The following proxy arguments are supported::
|
|
1713
|
+
|
|
1714
|
+
None: Deprecated - Use the proxy defined by the http:proxy configuration option if set.
|
|
1715
|
+
True: Use the proxy defined by the http:proxy configuration option if set.
|
|
1716
|
+
False: Do not use the proxy defined by the http:proxy configuration option if set.
|
|
1717
|
+
<str>: A proxy URL string.
|
|
1718
|
+
|
|
1685
1719
|
The dictionary returned by this may contain the following values::
|
|
1686
1720
|
|
|
1687
1721
|
{
|
|
@@ -1712,14 +1746,11 @@ class Axon(s_cell.Cell):
|
|
|
1712
1746
|
'''
|
|
1713
1747
|
logger.debug(f'Wget called for [{url}].', extra=await self.getLogExtra(url=s_urlhelp.sanitizeUrl(url)))
|
|
1714
1748
|
|
|
1715
|
-
if proxy is None:
|
|
1716
|
-
proxy = self.conf.get('http:proxy')
|
|
1717
|
-
|
|
1718
1749
|
ssl = self.getCachedSslCtx(opts=ssl_opts, verify=ssl)
|
|
1719
1750
|
|
|
1720
1751
|
connector = None
|
|
1721
|
-
if proxy:
|
|
1722
|
-
connector = aiohttp_socks.ProxyConnector.from_url(
|
|
1752
|
+
if proxyurl := await self._resolveProxyUrl(proxy):
|
|
1753
|
+
connector = aiohttp_socks.ProxyConnector.from_url(proxyurl)
|
|
1723
1754
|
|
|
1724
1755
|
atimeout = aiohttp.ClientTimeout(total=timeout)
|
|
1725
1756
|
|
synapse/common.py
CHANGED
|
@@ -29,6 +29,8 @@ import traceback
|
|
|
29
29
|
import contextlib
|
|
30
30
|
import collections
|
|
31
31
|
|
|
32
|
+
import http.cookies
|
|
33
|
+
|
|
32
34
|
import yaml
|
|
33
35
|
import regex
|
|
34
36
|
|
|
@@ -38,6 +40,8 @@ import synapse.lib.msgpack as s_msgpack
|
|
|
38
40
|
import synapse.lib.structlog as s_structlog
|
|
39
41
|
|
|
40
42
|
import synapse.vendor.cpython.lib.ipaddress as ipaddress
|
|
43
|
+
import synapse.vendor.cpython.lib.http.cookies as v_cookies
|
|
44
|
+
|
|
41
45
|
|
|
42
46
|
try:
|
|
43
47
|
from yaml import CSafeLoader as Loader
|
|
@@ -1218,6 +1222,17 @@ def trimText(text: str, n: int = 256, placeholder: str = '...') -> str:
|
|
|
1218
1222
|
assert n > plen
|
|
1219
1223
|
return f'{text[:mlen]}{placeholder}'
|
|
1220
1224
|
|
|
1225
|
+
def _patch_http_cookies():
|
|
1226
|
+
'''
|
|
1227
|
+
Patch stdlib http.cookies._unquote from the 3.11.10 implementation if
|
|
1228
|
+
the interpreter we are using is not patched for CVE-2024-7592.
|
|
1229
|
+
'''
|
|
1230
|
+
if not hasattr(http.cookies, '_QuotePatt'):
|
|
1231
|
+
return
|
|
1232
|
+
http.cookies._unquote = v_cookies._unquote
|
|
1233
|
+
|
|
1234
|
+
_patch_http_cookies()
|
|
1235
|
+
|
|
1221
1236
|
# TODO: Switch back to using asyncio.wait_for when we are using py 3.12+
|
|
1222
1237
|
# This is a workaround for a race where asyncio.wait_for can end up
|
|
1223
1238
|
# ignoring cancellation https://github.com/python/cpython/issues/86296
|
synapse/cortex.py
CHANGED
|
@@ -1739,7 +1739,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
1739
1739
|
for filt in gdef.get('filters', ()):
|
|
1740
1740
|
await self.getStormQuery(filt)
|
|
1741
1741
|
|
|
1742
|
-
for pivo in gdef.get('
|
|
1742
|
+
for pivo in gdef.get('pivots', ()):
|
|
1743
1743
|
await self.getStormQuery(pivo)
|
|
1744
1744
|
|
|
1745
1745
|
for form, rule in gdef.get('forms', {}).items():
|
|
@@ -1749,7 +1749,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
1749
1749
|
for filt in rule.get('filters', ()):
|
|
1750
1750
|
await self.getStormQuery(filt)
|
|
1751
1751
|
|
|
1752
|
-
for pivo in rule.get('
|
|
1752
|
+
for pivo in rule.get('pivots', ()):
|
|
1753
1753
|
await self.getStormQuery(pivo)
|
|
1754
1754
|
|
|
1755
1755
|
async def addStormGraph(self, gdef, user=None):
|
|
@@ -2240,7 +2240,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2240
2240
|
|
|
2241
2241
|
'''
|
|
2242
2242
|
name = cdef.get('name')
|
|
2243
|
-
|
|
2243
|
+
self._setStormCmd(cdef)
|
|
2244
2244
|
self.cmddefs.set(name, cdef)
|
|
2245
2245
|
|
|
2246
2246
|
async def _reqStormCmd(self, cdef):
|
|
@@ -2483,7 +2483,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2483
2483
|
async for sodes in self._mergeSodes(layers, genrs, cmprkey_indx, filtercmpr, reverse=reverse):
|
|
2484
2484
|
yield sodes
|
|
2485
2485
|
|
|
2486
|
-
|
|
2486
|
+
def _setStormCmd(self, cdef):
|
|
2487
2487
|
'''
|
|
2488
2488
|
Note:
|
|
2489
2489
|
No change control or persistence
|
|
@@ -2543,13 +2543,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2543
2543
|
name = cdef.get('name')
|
|
2544
2544
|
self.stormcmds[name] = ctor
|
|
2545
2545
|
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
async def _popStormCmd(self, name):
|
|
2546
|
+
def _popStormCmd(self, name):
|
|
2549
2547
|
self.stormcmds.pop(name, None)
|
|
2550
2548
|
|
|
2551
|
-
await self.fire('core:cmd:change', cmd=name, act='del')
|
|
2552
|
-
|
|
2553
2549
|
async def delStormCmd(self, name):
|
|
2554
2550
|
'''
|
|
2555
2551
|
Remove a previously set pure storm command.
|
|
@@ -2575,8 +2571,6 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2575
2571
|
self.cmddefs.pop(name)
|
|
2576
2572
|
self.stormcmds.pop(name, None)
|
|
2577
2573
|
|
|
2578
|
-
await self.fire('core:cmd:change', cmd=name, act='del')
|
|
2579
|
-
|
|
2580
2574
|
async def addStormPkg(self, pkgdef, verify=False):
|
|
2581
2575
|
'''
|
|
2582
2576
|
Add the given storm package to the cortex.
|
|
@@ -2630,11 +2624,11 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2630
2624
|
olddef = self.pkgdefs.get(name, None)
|
|
2631
2625
|
if olddef is not None:
|
|
2632
2626
|
if s_hashitem.hashitem(pkgdef) != s_hashitem.hashitem(olddef):
|
|
2633
|
-
|
|
2627
|
+
self._dropStormPkg(olddef)
|
|
2634
2628
|
else:
|
|
2635
2629
|
return
|
|
2636
2630
|
|
|
2637
|
-
|
|
2631
|
+
self.loadStormPkg(pkgdef)
|
|
2638
2632
|
self.pkgdefs.set(name, pkgdef)
|
|
2639
2633
|
|
|
2640
2634
|
self._clearPermDefs()
|
|
@@ -2664,7 +2658,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2664
2658
|
if pkgdef is None:
|
|
2665
2659
|
return
|
|
2666
2660
|
|
|
2667
|
-
|
|
2661
|
+
self._dropStormPkg(pkgdef)
|
|
2668
2662
|
|
|
2669
2663
|
self._clearPermDefs()
|
|
2670
2664
|
|
|
@@ -2713,7 +2707,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2713
2707
|
async def _tryLoadStormPkg(self, pkgdef):
|
|
2714
2708
|
try:
|
|
2715
2709
|
await self._normStormPkg(pkgdef, validstorm=False)
|
|
2716
|
-
|
|
2710
|
+
self.loadStormPkg(pkgdef)
|
|
2717
2711
|
|
|
2718
2712
|
except asyncio.CancelledError: # pragma: no cover TODO: remove once >= py 3.8 only
|
|
2719
2713
|
raise
|
|
@@ -2881,7 +2875,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2881
2875
|
for configvar in pkgdef.get('configvars', ()):
|
|
2882
2876
|
self._reqStormPkgVarType(pkgname, configvar.get('type'))
|
|
2883
2877
|
|
|
2884
|
-
async
|
|
2878
|
+
# N.B. This function is intentionally not async in order to prevent possible user race conditions for code
|
|
2879
|
+
# executing outside of the nexus lock.
|
|
2880
|
+
def loadStormPkg(self, pkgdef):
|
|
2885
2881
|
'''
|
|
2886
2882
|
Load a storm package into the storm library for this cortex.
|
|
2887
2883
|
|
|
@@ -2911,7 +2907,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2911
2907
|
self.stormmods = stormmods
|
|
2912
2908
|
|
|
2913
2909
|
for cdef in cmds:
|
|
2914
|
-
|
|
2910
|
+
self._setStormCmd(cdef)
|
|
2915
2911
|
|
|
2916
2912
|
for gdef in pkgdef.get('graphs', ()):
|
|
2917
2913
|
gdef = copy.deepcopy(gdef)
|
|
@@ -2937,7 +2933,9 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2937
2933
|
await self.fire('core:pkg:onload:complete', pkg=name)
|
|
2938
2934
|
self.schedCoro(_onload())
|
|
2939
2935
|
|
|
2940
|
-
async
|
|
2936
|
+
# N.B. This function is intentionally not async in order to prevent possible user race conditions for code
|
|
2937
|
+
# executing outside of the nexus lock.
|
|
2938
|
+
def _dropStormPkg(self, pkgdef):
|
|
2941
2939
|
'''
|
|
2942
2940
|
Reverse the process of loadStormPkg()
|
|
2943
2941
|
'''
|
|
@@ -2948,7 +2946,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
2948
2946
|
|
|
2949
2947
|
for cdef in pkgdef.get('commands', ()):
|
|
2950
2948
|
name = cdef.get('name')
|
|
2951
|
-
|
|
2949
|
+
self._popStormCmd(name)
|
|
2952
2950
|
|
|
2953
2951
|
pkgname = pkgdef.get('name')
|
|
2954
2952
|
|
|
@@ -4435,7 +4433,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
4435
4433
|
|
|
4436
4434
|
async def _trySetStormCmd(self, name, cdef):
|
|
4437
4435
|
try:
|
|
4438
|
-
|
|
4436
|
+
self._setStormCmd(cdef)
|
|
4439
4437
|
except (asyncio.CancelledError, Exception):
|
|
4440
4438
|
logger.exception(f'Storm command load failed: {name}')
|
|
4441
4439
|
|
synapse/exc.py
CHANGED
|
@@ -56,9 +56,14 @@ class SynErr(Exception):
|
|
|
56
56
|
self.errinfo[name] = valu
|
|
57
57
|
self._setExcMesg()
|
|
58
58
|
|
|
59
|
+
def update(self, items: dict):
|
|
60
|
+
'''Update multiple items in the errinfo dict at once.'''
|
|
61
|
+
self.errinfo.update(**items)
|
|
62
|
+
self._setExcMesg()
|
|
63
|
+
|
|
59
64
|
class StormRaise(SynErr):
|
|
60
65
|
'''
|
|
61
|
-
This represents a user provided exception
|
|
66
|
+
This represents a user provided exception raised in the Storm runtime. It requires a errname key.
|
|
62
67
|
'''
|
|
63
68
|
def __init__(self, *args, **info):
|
|
64
69
|
SynErr.__init__(self, *args, **info)
|
synapse/lib/agenda.py
CHANGED
synapse/lib/ast.py
CHANGED
|
@@ -59,7 +59,8 @@ class AstNode:
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
def addExcInfo(self, exc):
|
|
62
|
-
|
|
62
|
+
if 'highlight' not in exc.errinfo:
|
|
63
|
+
exc.set('highlight', self.getPosInfo())
|
|
63
64
|
return exc
|
|
64
65
|
|
|
65
66
|
def repr(self):
|
|
@@ -3554,7 +3555,10 @@ class VarDeref(Value):
|
|
|
3554
3555
|
|
|
3555
3556
|
valu = s_stormtypes.fromprim(base, path=path)
|
|
3556
3557
|
with s_scope.enter({'runt': runt}):
|
|
3557
|
-
|
|
3558
|
+
try:
|
|
3559
|
+
return await valu.deref(name)
|
|
3560
|
+
except s_exc.SynErr as e:
|
|
3561
|
+
raise self.kids[1].addExcInfo(e)
|
|
3558
3562
|
|
|
3559
3563
|
class FuncCall(Value):
|
|
3560
3564
|
|
|
@@ -3575,10 +3579,23 @@ class FuncCall(Value):
|
|
|
3575
3579
|
kwargs = {k: v for (k, v) in await self.kids[2].compute(runt, path)}
|
|
3576
3580
|
|
|
3577
3581
|
with s_scope.enter({'runt': runt}):
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
+
try:
|
|
3583
|
+
retn = func(*argv, **kwargs)
|
|
3584
|
+
if s_coro.iscoro(retn):
|
|
3585
|
+
return await retn
|
|
3586
|
+
return retn
|
|
3587
|
+
|
|
3588
|
+
except TypeError as e:
|
|
3589
|
+
mesg = str(e)
|
|
3590
|
+
if (funcpath := getattr(func, '_storm_funcpath', None)) is not None:
|
|
3591
|
+
mesg = f"{funcpath}(){mesg.split(')', 1)[1]}"
|
|
3592
|
+
|
|
3593
|
+
raise self.addExcInfo(s_exc.StormRuntimeError(mesg=mesg))
|
|
3594
|
+
|
|
3595
|
+
except s_exc.SynErr as e:
|
|
3596
|
+
if getattr(func, '_storm_runtime_lib_func', None) is not None:
|
|
3597
|
+
e.errinfo.pop('highlight', None)
|
|
3598
|
+
raise self.addExcInfo(e)
|
|
3582
3599
|
|
|
3583
3600
|
class DollarExpr(Value):
|
|
3584
3601
|
'''
|
|
@@ -4887,8 +4904,9 @@ class Function(AstNode):
|
|
|
4887
4904
|
|
|
4888
4905
|
@s_stormtypes.stormfunc(readonly=True)
|
|
4889
4906
|
async def realfunc(*args, **kwargs):
|
|
4890
|
-
return await self.callfunc(runt, argdefs, args, kwargs)
|
|
4907
|
+
return await self.callfunc(runt, argdefs, args, kwargs, realfunc._storm_funcpath)
|
|
4891
4908
|
|
|
4909
|
+
realfunc._storm_funcpath = self.name
|
|
4892
4910
|
await runt.setVar(self.name, realfunc)
|
|
4893
4911
|
|
|
4894
4912
|
count = 0
|
|
@@ -4910,7 +4928,7 @@ class Function(AstNode):
|
|
|
4910
4928
|
# var scope validation occurs in the sub-runtime
|
|
4911
4929
|
pass
|
|
4912
4930
|
|
|
4913
|
-
async def callfunc(self, runt, argdefs, args, kwargs):
|
|
4931
|
+
async def callfunc(self, runt, argdefs, args, kwargs, funcpath):
|
|
4914
4932
|
'''
|
|
4915
4933
|
Execute a function call using the given runtime.
|
|
4916
4934
|
|
|
@@ -4921,7 +4939,7 @@ class Function(AstNode):
|
|
|
4921
4939
|
|
|
4922
4940
|
argcount = len(args) + len(kwargs)
|
|
4923
4941
|
if argcount > len(argdefs):
|
|
4924
|
-
mesg = f'{
|
|
4942
|
+
mesg = f'{funcpath}() takes {len(argdefs)} arguments but {argcount} were provided'
|
|
4925
4943
|
raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg))
|
|
4926
4944
|
|
|
4927
4945
|
# Fill in the positional arguments
|
|
@@ -4935,7 +4953,7 @@ class Function(AstNode):
|
|
|
4935
4953
|
valu = kwargs.pop(name, s_common.novalu)
|
|
4936
4954
|
if valu is s_common.novalu:
|
|
4937
4955
|
if defv is s_common.novalu:
|
|
4938
|
-
mesg = f'{
|
|
4956
|
+
mesg = f'{funcpath}() missing required argument {name}'
|
|
4939
4957
|
raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg))
|
|
4940
4958
|
valu = defv
|
|
4941
4959
|
|
|
@@ -4946,11 +4964,11 @@ class Function(AstNode):
|
|
|
4946
4964
|
# used a kwarg not defined.
|
|
4947
4965
|
kwkeys = list(kwargs.keys())
|
|
4948
4966
|
if kwkeys[0] in posnames:
|
|
4949
|
-
mesg = f'{
|
|
4967
|
+
mesg = f'{funcpath}() got multiple values for parameter {kwkeys[0]}'
|
|
4950
4968
|
raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg))
|
|
4951
4969
|
|
|
4952
4970
|
plural = 's' if len(kwargs) > 1 else ''
|
|
4953
|
-
mesg = f'{
|
|
4971
|
+
mesg = f'{funcpath}() got unexpected keyword argument{plural}: {",".join(kwkeys)}'
|
|
4954
4972
|
raise self.kids[1].addExcInfo(s_exc.StormRuntimeError(mesg=mesg))
|
|
4955
4973
|
|
|
4956
4974
|
assert len(mergargs) == len(argdefs)
|