synapse 2.183.0__py311-none-any.whl → 2.185.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/cortex.py +1 -1
- synapse/datamodel.py +82 -9
- synapse/lib/ast.py +85 -23
- synapse/lib/auth.py +13 -0
- synapse/lib/autodoc.py +9 -2
- synapse/lib/cell.py +14 -1
- synapse/lib/modules.py +1 -0
- synapse/lib/parser.py +1 -0
- synapse/lib/snap.py +1 -0
- synapse/lib/storm.lark +12 -6
- synapse/lib/storm.py +45 -9
- synapse/lib/storm_format.py +1 -0
- synapse/lib/stormlib/graph.py +17 -0
- synapse/lib/stormlib/stix.py +14 -5
- synapse/lib/stormtypes.py +65 -37
- synapse/lib/stormwhois.py +3 -0
- synapse/lib/version.py +2 -2
- synapse/models/doc.py +93 -0
- synapse/models/infotech.py +5 -1
- synapse/models/media.py +0 -1
- synapse/models/orgs.py +102 -5
- synapse/models/proj.py +56 -36
- synapse/models/risk.py +22 -0
- synapse/models/syn.py +64 -6
- synapse/tests/test_cortex.py +54 -45
- synapse/tests/test_lib_ast.py +58 -0
- synapse/tests/test_lib_autodoc.py +54 -0
- synapse/tests/test_lib_cell.py +44 -1
- synapse/tests/test_lib_grammar.py +2 -0
- synapse/tests/test_lib_storm.py +68 -1
- synapse/tests/test_lib_stormlib_modelext.py +52 -0
- synapse/tests/test_lib_stormlib_stix.py +3 -2
- synapse/tests/test_lib_stormwhois.py +4 -4
- synapse/tests/test_model_doc.py +51 -0
- synapse/tests/test_model_infotech.py +5 -1
- synapse/tests/test_model_orgs.py +78 -0
- synapse/tests/test_model_risk.py +3 -0
- synapse/tests/test_model_syn.py +43 -0
- synapse/tests/test_tools_promote.py +67 -0
- synapse/tests/utils.py +26 -0
- synapse/tools/promote.py +14 -1
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/METADATA +5 -10
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/RECORD +46 -43
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/WHEEL +1 -1
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/LICENSE +0 -0
- {synapse-2.183.0.dist-info → synapse-2.185.0.dist-info}/top_level.txt +0 -0
synapse/cortex.py
CHANGED
|
@@ -946,7 +946,7 @@ class Cortex(s_oauth.OAuthMixin, s_cell.Cell): # type: ignore
|
|
|
946
946
|
self._exthttpapicache = s_cache.FixedCache(self._getHttpExtApiByPath, size=1000)
|
|
947
947
|
self._initCortexExtHttpApi()
|
|
948
948
|
|
|
949
|
-
self.model = s_datamodel.Model()
|
|
949
|
+
self.model = s_datamodel.Model(core=self)
|
|
950
950
|
|
|
951
951
|
await self._bumpCellVers('cortex:extmodel', (
|
|
952
952
|
(1, self._migrateTaxonomyIface),
|
synapse/datamodel.py
CHANGED
|
@@ -482,8 +482,9 @@ class Model:
|
|
|
482
482
|
'''
|
|
483
483
|
The data model used by a Cortex hypergraph.
|
|
484
484
|
'''
|
|
485
|
-
def __init__(self):
|
|
485
|
+
def __init__(self, core=None):
|
|
486
486
|
|
|
487
|
+
self.core = core
|
|
487
488
|
self.types = {} # name: Type()
|
|
488
489
|
self.forms = {} # name: Form()
|
|
489
490
|
self.props = {} # (form,name): Prop() and full: Prop()
|
|
@@ -653,13 +654,16 @@ class Model:
|
|
|
653
654
|
self.formprefixcache[prefix] = forms
|
|
654
655
|
return forms
|
|
655
656
|
|
|
656
|
-
def reqProp(self, name):
|
|
657
|
+
def reqProp(self, name, extra=None):
|
|
657
658
|
prop = self.prop(name)
|
|
658
659
|
if prop is not None:
|
|
659
660
|
return prop
|
|
660
661
|
|
|
661
|
-
|
|
662
|
-
|
|
662
|
+
exc = s_exc.NoSuchProp.init(name)
|
|
663
|
+
if extra is not None:
|
|
664
|
+
exc = extra(exc)
|
|
665
|
+
|
|
666
|
+
raise exc
|
|
663
667
|
|
|
664
668
|
def reqUniv(self, name):
|
|
665
669
|
prop = self.univ(name)
|
|
@@ -987,7 +991,17 @@ class Model:
|
|
|
987
991
|
if form is None:
|
|
988
992
|
return
|
|
989
993
|
|
|
990
|
-
|
|
994
|
+
ifaceprops = set()
|
|
995
|
+
for iface in form.ifaces.values():
|
|
996
|
+
for prop in iface.get('props', ()):
|
|
997
|
+
ifaceprops.add(prop[0])
|
|
998
|
+
|
|
999
|
+
formprops = []
|
|
1000
|
+
for propname, prop in form.props.items():
|
|
1001
|
+
if prop.univ is not None or propname in ifaceprops:
|
|
1002
|
+
continue
|
|
1003
|
+
formprops.append(prop)
|
|
1004
|
+
|
|
991
1005
|
if formprops:
|
|
992
1006
|
propnames = ', '.join(prop.name for prop in formprops)
|
|
993
1007
|
mesg = f'Form has extended properties: {propnames}'
|
|
@@ -996,8 +1010,8 @@ class Model:
|
|
|
996
1010
|
if isinstance(form.type, s_types.Array):
|
|
997
1011
|
self.arraysbytype[form.type.arraytype.name].pop(form.name, None)
|
|
998
1012
|
|
|
999
|
-
for ifname in form.
|
|
1000
|
-
self.
|
|
1013
|
+
for ifname in form.type.info.get('interfaces', ()):
|
|
1014
|
+
self._delFormIface(form, ifname)
|
|
1001
1015
|
|
|
1002
1016
|
self.forms.pop(formname, None)
|
|
1003
1017
|
self.props.pop(formname, None)
|
|
@@ -1072,6 +1086,30 @@ class Model:
|
|
|
1072
1086
|
self.props[prop.full] = prop
|
|
1073
1087
|
return prop
|
|
1074
1088
|
|
|
1089
|
+
def _prepFormIface(self, form, iface):
|
|
1090
|
+
|
|
1091
|
+
template = iface.get('template', {})
|
|
1092
|
+
template.update(form.type.info.get('template', {}))
|
|
1093
|
+
|
|
1094
|
+
def convert(item):
|
|
1095
|
+
|
|
1096
|
+
if isinstance(item, str):
|
|
1097
|
+
|
|
1098
|
+
if item == '$self':
|
|
1099
|
+
return form.name
|
|
1100
|
+
|
|
1101
|
+
return item.format(**template)
|
|
1102
|
+
|
|
1103
|
+
if isinstance(item, dict):
|
|
1104
|
+
return {convert(k): convert(v) for (k, v) in item.items()}
|
|
1105
|
+
|
|
1106
|
+
if isinstance(item, (list, tuple)):
|
|
1107
|
+
return tuple([convert(v) for v in item])
|
|
1108
|
+
|
|
1109
|
+
return item
|
|
1110
|
+
|
|
1111
|
+
return convert(iface)
|
|
1112
|
+
|
|
1075
1113
|
def _addFormIface(self, form, name, subifaces=None):
|
|
1076
1114
|
|
|
1077
1115
|
iface = self.ifaces.get(name)
|
|
@@ -1084,9 +1122,14 @@ class Model:
|
|
|
1084
1122
|
mesg = f'Form {form.name} depends on deprecated interface {name} which will be removed in 3.0.0'
|
|
1085
1123
|
logger.warning(mesg)
|
|
1086
1124
|
|
|
1125
|
+
iface = self._prepFormIface(form, iface)
|
|
1126
|
+
|
|
1087
1127
|
for propname, typedef, propinfo in iface.get('props', ()):
|
|
1088
|
-
|
|
1089
|
-
|
|
1128
|
+
|
|
1129
|
+
# allow form props to take precedence
|
|
1130
|
+
if form.prop(propname) is not None:
|
|
1131
|
+
continue
|
|
1132
|
+
|
|
1090
1133
|
prop = self._addFormProp(form, propname, typedef, propinfo)
|
|
1091
1134
|
self.ifaceprops[f'{name}:{propname}'].append(prop.full)
|
|
1092
1135
|
|
|
@@ -1108,6 +1151,36 @@ class Model:
|
|
|
1108
1151
|
for ifname in ifaces:
|
|
1109
1152
|
self._addFormIface(form, ifname, subifaces=subifaces)
|
|
1110
1153
|
|
|
1154
|
+
def _delFormIface(self, form, name, subifaces=None):
|
|
1155
|
+
|
|
1156
|
+
if (iface := self.ifaces.get(name)) is None:
|
|
1157
|
+
return
|
|
1158
|
+
|
|
1159
|
+
iface = self._prepFormIface(form, iface)
|
|
1160
|
+
|
|
1161
|
+
for propname, typedef, propinfo in iface.get('props', ()):
|
|
1162
|
+
fullprop = f'{form.name}:{propname}'
|
|
1163
|
+
self.delFormProp(form.name, propname)
|
|
1164
|
+
self.ifaceprops[f'{name}:{propname}'].remove(fullprop)
|
|
1165
|
+
|
|
1166
|
+
if subifaces is not None:
|
|
1167
|
+
for subi in subifaces:
|
|
1168
|
+
self.ifaceprops[f'{subi}:{propname}'].remove(fullprop)
|
|
1169
|
+
|
|
1170
|
+
form.ifaces.pop(name, None)
|
|
1171
|
+
self.formsbyiface[name].remove(form.name)
|
|
1172
|
+
|
|
1173
|
+
if (ifaces := iface.get('interfaces')) is not None:
|
|
1174
|
+
if subifaces is None:
|
|
1175
|
+
subifaces = []
|
|
1176
|
+
else:
|
|
1177
|
+
subifaces = list(subifaces)
|
|
1178
|
+
|
|
1179
|
+
subifaces.append(name)
|
|
1180
|
+
|
|
1181
|
+
for ifname in ifaces:
|
|
1182
|
+
self._delFormIface(form, ifname, subifaces=subifaces)
|
|
1183
|
+
|
|
1111
1184
|
def delTagProp(self, name):
|
|
1112
1185
|
return self.tagprops.pop(name)
|
|
1113
1186
|
|
synapse/lib/ast.py
CHANGED
|
@@ -1302,8 +1302,9 @@ class VarListSetOper(Oper):
|
|
|
1302
1302
|
names = self.kids[0].value()
|
|
1303
1303
|
vkid = self.kids[1]
|
|
1304
1304
|
|
|
1305
|
+
anynodes = False
|
|
1305
1306
|
async for node, path in genr:
|
|
1306
|
-
|
|
1307
|
+
anynodes = True
|
|
1307
1308
|
item = await vkid.compute(runt, path)
|
|
1308
1309
|
item = [i async for i in s_stormtypes.toiter(item)]
|
|
1309
1310
|
|
|
@@ -1318,7 +1319,7 @@ class VarListSetOper(Oper):
|
|
|
1318
1319
|
|
|
1319
1320
|
yield node, path
|
|
1320
1321
|
|
|
1321
|
-
if vkid.isRuntSafe(runt):
|
|
1322
|
+
if not anynodes and vkid.isRuntSafe(runt):
|
|
1322
1323
|
|
|
1323
1324
|
item = await vkid.compute(runt, None)
|
|
1324
1325
|
item = [i async for i in s_stormtypes.toiter(item)]
|
|
@@ -1425,6 +1426,32 @@ class LiftOper(Oper):
|
|
|
1425
1426
|
self.astinfo = astinfo
|
|
1426
1427
|
self.reverse = True
|
|
1427
1428
|
|
|
1429
|
+
def getPivNames(self, runt, prop, pivs):
|
|
1430
|
+
pivnames = []
|
|
1431
|
+
typename = prop.type.name
|
|
1432
|
+
for piv in pivs:
|
|
1433
|
+
pivprop = runt.model.reqProp(f'{typename}:{piv}', extra=self.kids[0].addExcInfo)
|
|
1434
|
+
pivnames.append(pivprop.full)
|
|
1435
|
+
typename = pivprop.type.name
|
|
1436
|
+
|
|
1437
|
+
return pivnames
|
|
1438
|
+
|
|
1439
|
+
async def pivlift(self, runt, props, pivnames, genr):
|
|
1440
|
+
|
|
1441
|
+
async def pivvals(prop, pivgenr):
|
|
1442
|
+
async for node in pivgenr:
|
|
1443
|
+
async for pivo in runt.snap.nodesByPropValu(prop, '=', node.ndef[1], reverse=self.reverse):
|
|
1444
|
+
yield pivo
|
|
1445
|
+
|
|
1446
|
+
for pivname in pivnames[-2::-1]:
|
|
1447
|
+
genr = pivvals(pivname, genr)
|
|
1448
|
+
|
|
1449
|
+
async for node in genr:
|
|
1450
|
+
valu = node.ndef[1]
|
|
1451
|
+
for prop in props:
|
|
1452
|
+
async for node in runt.snap.nodesByPropValu(prop.full, '=', valu, reverse=self.reverse):
|
|
1453
|
+
yield node
|
|
1454
|
+
|
|
1428
1455
|
async def run(self, runt, genr):
|
|
1429
1456
|
|
|
1430
1457
|
if self.isRuntSafe(runt):
|
|
@@ -1583,30 +1610,52 @@ class LiftByArray(LiftOper):
|
|
|
1583
1610
|
cmpr = await self.kids[1].compute(runt, path)
|
|
1584
1611
|
valu = await s_stormtypes.tostor(await self.kids[2].compute(runt, path))
|
|
1585
1612
|
|
|
1586
|
-
|
|
1587
|
-
if
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
return
|
|
1613
|
+
pivs = None
|
|
1614
|
+
if name.find('::') != -1:
|
|
1615
|
+
parts = name.split('::')
|
|
1616
|
+
name, pivs = parts[0], parts[1:]
|
|
1591
1617
|
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1618
|
+
if (prop := runt.model.props.get(name)) is not None:
|
|
1619
|
+
props = (prop,)
|
|
1620
|
+
else:
|
|
1621
|
+
proplist = runt.model.ifaceprops.get(name)
|
|
1622
|
+
if proplist is None:
|
|
1623
|
+
raise self.kids[0].addExcInfo(s_exc.NoSuchProp.init(name))
|
|
1595
1624
|
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1625
|
+
props = []
|
|
1626
|
+
for propname in proplist:
|
|
1627
|
+
props.append(runt.model.props.get(propname))
|
|
1599
1628
|
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1629
|
+
try:
|
|
1630
|
+
if pivs is not None:
|
|
1631
|
+
pivnames = self.getPivNames(runt, props[0], pivs)
|
|
1603
1632
|
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1633
|
+
genr = runt.snap.nodesByPropArray(pivnames[-1], cmpr, valu, reverse=self.reverse)
|
|
1634
|
+
async for node in self.pivlift(runt, props, pivnames, genr):
|
|
1635
|
+
yield node
|
|
1636
|
+
return
|
|
1607
1637
|
|
|
1608
|
-
|
|
1609
|
-
|
|
1638
|
+
if len(props) == 1:
|
|
1639
|
+
async for node in runt.snap.nodesByPropArray(name, cmpr, valu, reverse=self.reverse):
|
|
1640
|
+
yield node
|
|
1641
|
+
return
|
|
1642
|
+
|
|
1643
|
+
relname = props[0].name
|
|
1644
|
+
def cmprkey(node):
|
|
1645
|
+
return node.props.get(relname)
|
|
1646
|
+
|
|
1647
|
+
genrs = []
|
|
1648
|
+
for prop in props:
|
|
1649
|
+
genrs.append(runt.snap.nodesByPropArray(prop.full, cmpr, valu, reverse=self.reverse))
|
|
1650
|
+
|
|
1651
|
+
async for node in s_common.merggenr2(genrs, cmprkey, reverse=self.reverse):
|
|
1652
|
+
yield node
|
|
1653
|
+
|
|
1654
|
+
except s_exc.BadTypeValu as e:
|
|
1655
|
+
raise self.kids[2].addExcInfo(e)
|
|
1656
|
+
|
|
1657
|
+
except s_exc.SynErr as e:
|
|
1658
|
+
raise self.addExcInfo(e)
|
|
1610
1659
|
|
|
1611
1660
|
class LiftTagProp(LiftOper):
|
|
1612
1661
|
'''
|
|
@@ -1838,6 +1887,11 @@ class LiftPropBy(LiftOper):
|
|
|
1838
1887
|
if not isinstance(valu, s_node.Node):
|
|
1839
1888
|
valu = await s_stormtypes.tostor(valu)
|
|
1840
1889
|
|
|
1890
|
+
pivs = None
|
|
1891
|
+
if name.find('::') != -1:
|
|
1892
|
+
parts = name.split('::')
|
|
1893
|
+
name, pivs = parts[0], parts[1:]
|
|
1894
|
+
|
|
1841
1895
|
prop = runt.model.props.get(name)
|
|
1842
1896
|
if prop is not None:
|
|
1843
1897
|
props = (prop,)
|
|
@@ -1851,6 +1905,14 @@ class LiftPropBy(LiftOper):
|
|
|
1851
1905
|
props.append(runt.model.props.get(propname))
|
|
1852
1906
|
|
|
1853
1907
|
try:
|
|
1908
|
+
if pivs is not None:
|
|
1909
|
+
pivnames = self.getPivNames(runt, props[0], pivs)
|
|
1910
|
+
|
|
1911
|
+
genr = runt.snap.nodesByPropValu(pivnames[-1], cmpr, valu, reverse=self.reverse)
|
|
1912
|
+
async for node in self.pivlift(runt, props, pivnames, genr):
|
|
1913
|
+
yield node
|
|
1914
|
+
return
|
|
1915
|
+
|
|
1854
1916
|
if len(props) == 1:
|
|
1855
1917
|
prop = props[0]
|
|
1856
1918
|
async for node in runt.snap.nodesByPropValu(prop.full, cmpr, valu, reverse=self.reverse):
|
|
@@ -3793,7 +3855,7 @@ class ExprDict(Value):
|
|
|
3793
3855
|
|
|
3794
3856
|
def prepare(self):
|
|
3795
3857
|
self.const = None
|
|
3796
|
-
if all(isinstance(k, Const) for k in self.kids):
|
|
3858
|
+
if all(isinstance(k, Const) and not isinstance(k, EmbedQuery) for k in self.kids):
|
|
3797
3859
|
valu = {}
|
|
3798
3860
|
for i in range(0, len(self.kids), 2):
|
|
3799
3861
|
valu[self.kids[i].value()] = self.kids[i + 1].value()
|
|
@@ -3823,7 +3885,7 @@ class ExprList(Value):
|
|
|
3823
3885
|
|
|
3824
3886
|
def prepare(self):
|
|
3825
3887
|
self.const = None
|
|
3826
|
-
if all(isinstance(k, Const) for k in self.kids):
|
|
3888
|
+
if all(isinstance(k, Const) and not isinstance(k, EmbedQuery) for k in self.kids):
|
|
3827
3889
|
self.const = s_msgpack.en([k.value() for k in self.kids])
|
|
3828
3890
|
|
|
3829
3891
|
async def compute(self, runt, path):
|
synapse/lib/auth.py
CHANGED
|
@@ -264,6 +264,19 @@ class Auth(s_nexus.Pusher):
|
|
|
264
264
|
def _getRoleIden(self, name):
|
|
265
265
|
return self.roleidenbyname.get(name)
|
|
266
266
|
|
|
267
|
+
# TODO convert getUserByName() and getRoleByName()
|
|
268
|
+
# back from async? These were plumbed to avoid infecting
|
|
269
|
+
# type norm/repr functions with async...
|
|
270
|
+
def _getRoleByName(self, name):
|
|
271
|
+
roleiden = self.roleidenbynamecache.get(name)
|
|
272
|
+
if roleiden is not None:
|
|
273
|
+
return self.role(roleiden)
|
|
274
|
+
|
|
275
|
+
def _getUserByName(self, name):
|
|
276
|
+
useriden = self.useridenbynamecache.get(name)
|
|
277
|
+
if useriden is not None:
|
|
278
|
+
return self.user(useriden)
|
|
279
|
+
|
|
267
280
|
@s_nexus.Pusher.onPushAuto('user:profile:set')
|
|
268
281
|
async def setUserProfileValu(self, iden, name, valu):
|
|
269
282
|
user = await self.reqUser(iden)
|
synapse/lib/autodoc.py
CHANGED
|
@@ -464,6 +464,7 @@ def docStormTypes(page, docinfo, linkprefix, islib=False, lvl=1,
|
|
|
464
464
|
|
|
465
465
|
locls = info.get('locals', ())
|
|
466
466
|
locls = sorted(locls, key=lambda x: x.get('name'))
|
|
467
|
+
libdepr = info.get('deprecated')
|
|
467
468
|
|
|
468
469
|
for locl in locls:
|
|
469
470
|
|
|
@@ -478,6 +479,8 @@ def docStormTypes(page, docinfo, linkprefix, islib=False, lvl=1,
|
|
|
478
479
|
lines = []
|
|
479
480
|
if depr := locl.get('deprecated'):
|
|
480
481
|
lines.extend(genDeprecationWarning(f'${loclname}', depr, True))
|
|
482
|
+
elif libdepr is not None:
|
|
483
|
+
lines.extend(genDeprecationWarning(f'${loclname}', libdepr, True))
|
|
481
484
|
|
|
482
485
|
if isinstance(rtype, dict):
|
|
483
486
|
rname = rtype.get('type')
|
|
@@ -576,6 +579,7 @@ def runtimeDocStormTypes(page, docinfo, islib=False, lvl=1,
|
|
|
576
579
|
|
|
577
580
|
page.addLines(*preamble)
|
|
578
581
|
|
|
582
|
+
libdepr = info.get('deprecated')
|
|
579
583
|
locls = info.get('locals', ())
|
|
580
584
|
locls = sorted(locls, key=lambda x: x.get('name'))
|
|
581
585
|
|
|
@@ -624,8 +628,11 @@ def runtimeDocStormTypes(page, docinfo, islib=False, lvl=1,
|
|
|
624
628
|
assert rtype is not None
|
|
625
629
|
|
|
626
630
|
lines = []
|
|
627
|
-
if
|
|
628
|
-
|
|
631
|
+
if not oneline:
|
|
632
|
+
if (depr := locl.get('deprecated')):
|
|
633
|
+
lines.extend(genDeprecationWarning(f'${loclname}', depr))
|
|
634
|
+
elif libdepr is not None:
|
|
635
|
+
lines.extend(genDeprecationWarning(f'${loclname}', libdepr))
|
|
629
636
|
|
|
630
637
|
if isinstance(rtype, dict):
|
|
631
638
|
rname = rtype.get('type')
|
synapse/lib/cell.py
CHANGED
|
@@ -2118,6 +2118,13 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
2118
2118
|
Hand off leadership to a mirror in a transactional fashion.
|
|
2119
2119
|
'''
|
|
2120
2120
|
_dispname = f' ahaname={self.conf.get("aha:name")}' if self.conf.get('aha:name') else ''
|
|
2121
|
+
|
|
2122
|
+
if not self.isactive:
|
|
2123
|
+
mesg = f'HANDOFF: {_dispname} is not the current leader and cannot handoff leadership to' \
|
|
2124
|
+
f' {s_urlhelp.sanitizeUrl(turl)}.'
|
|
2125
|
+
logger.error(mesg)
|
|
2126
|
+
raise s_exc.BadState(mesg=mesg, turl=turl, cursvc=_dispname)
|
|
2127
|
+
|
|
2121
2128
|
logger.warning(f'HANDOFF: Performing leadership handoff to {s_urlhelp.sanitizeUrl(turl)}{_dispname}.')
|
|
2122
2129
|
async with await s_telepath.openurl(turl) as cell:
|
|
2123
2130
|
|
|
@@ -3560,7 +3567,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
3560
3567
|
item.setdefault('permissions', {})
|
|
3561
3568
|
item['permissions'].setdefault('users', {})
|
|
3562
3569
|
item['permissions'].setdefault('roles', {})
|
|
3563
|
-
item['permissions']
|
|
3570
|
+
item['permissions'].setdefault('default', default)
|
|
3564
3571
|
|
|
3565
3572
|
async def getTeleApi(self, link, mesg, path):
|
|
3566
3573
|
|
|
@@ -4439,6 +4446,11 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4439
4446
|
Returns:
|
|
4440
4447
|
Dict: A Dictionary of metadata.
|
|
4441
4448
|
'''
|
|
4449
|
+
|
|
4450
|
+
mirror = self.conf.get('mirror')
|
|
4451
|
+
if mirror is not None:
|
|
4452
|
+
mirror = s_urlhelp.sanitizeUrl(mirror)
|
|
4453
|
+
|
|
4442
4454
|
ret = {
|
|
4443
4455
|
'synapse': {
|
|
4444
4456
|
'commit': s_version.commit,
|
|
@@ -4458,6 +4470,7 @@ class Cell(s_nexus.Pusher, s_telepath.Aware):
|
|
|
4458
4470
|
'cellvers': dict(self.cellvers.items()),
|
|
4459
4471
|
'nexsindx': await self.getNexsIndx(),
|
|
4460
4472
|
'uplink': self.nexsroot.miruplink.is_set(),
|
|
4473
|
+
'mirror': mirror,
|
|
4461
4474
|
'aha': {
|
|
4462
4475
|
'name': self.conf.get('aha:name'),
|
|
4463
4476
|
'leader': self.conf.get('aha:leader'),
|
synapse/lib/modules.py
CHANGED
synapse/lib/parser.py
CHANGED
synapse/lib/snap.py
CHANGED
|
@@ -1692,6 +1692,7 @@ class Snap(s_base.Base):
|
|
|
1692
1692
|
|
|
1693
1693
|
todo = s_common.todo('runRuntLift', full, valu, cmpr, self.view.iden)
|
|
1694
1694
|
async for sode in self.core.dyniter('cortex', todo):
|
|
1695
|
+
await asyncio.sleep(0)
|
|
1695
1696
|
|
|
1696
1697
|
node = s_node.Node(self, sode)
|
|
1697
1698
|
node.isrunt = True
|
synapse/lib/storm.lark
CHANGED
|
@@ -222,9 +222,9 @@ liftreverse: _REVERSE "(" (liftformtag | liftpropby | liftprop | liftbyarray | l
|
|
|
222
222
|
_DEREF.3: /\*(?=\$)/
|
|
223
223
|
|
|
224
224
|
liftformtag: ((PROPS | UNIVNAME | WILDPROPS) | _DEREF _varvalu) tagname [_cmpr _valu]
|
|
225
|
-
liftpropby: ((PROPS | UNIVNAME) | _DEREF _varvalu) _cmpr _valu
|
|
225
|
+
liftpropby: ((PROPS | EMBEDPROPS | UNIVNAME) | _DEREF _varvalu) _cmpr _valu
|
|
226
226
|
liftprop: ((PROPS | UNIVNAME | WILDPROPS) | _DEREF _varvalu)
|
|
227
|
-
liftbyarray: ((PROPS | UNIVNAME) | _DEREF _varvalu) "*[" _safe_cmpr _valu "]"
|
|
227
|
+
liftbyarray: ((PROPS | EMBEDPROPS | UNIVNAME) | _DEREF _varvalu) "*[" _safe_cmpr _valu "]"
|
|
228
228
|
lifttagtag: (_HASH | _HASHSPACE) tagname [_cmpr _valu]
|
|
229
229
|
liftbytag: (tagname | tagnamewithspace) [_cmpr _valu]
|
|
230
230
|
liftbytagprop: (tagprop | tagpropwithspace) [_cmpr _valu]
|
|
@@ -321,10 +321,10 @@ _valu: _basevalu | NONQUOTEWORD
|
|
|
321
321
|
evalvalu: _valu
|
|
322
322
|
exprdict: "{" ((_exprvalu | VARTOKN) (":" | _EXPRCOLONNOSPACE) (_exprvalu | VARTOKN) ("," (_exprvalu | VARTOKN) (":" | _EXPRCOLONNOSPACE) (_exprvalu | VARTOKN))* ","? )? "}"
|
|
323
323
|
exprlist: "[" ((_exprvalu | VARTOKN) ("," (_exprvalu | VARTOKN))* ","? )? "]"
|
|
324
|
-
// Just like _valu, but doesn't allow valu lists or unquoted strings
|
|
324
|
+
// Just like _valu, but doesn't allow valu lists or unquoted strings
|
|
325
325
|
_exprvalu: NUMBER | HEXNUMBER | OCTNUMBER | BOOL | NULL | exprlist | exprdict | _exprvarvalu | exprrelpropvalu
|
|
326
326
|
| exprunivpropvalu | exprtagvalu | exprtagpropvalu | TRIPLEQUOTEDSTRING | DOUBLEQUOTEDSTRING
|
|
327
|
-
| SINGLEQUOTEDSTRING | formatstring | _innerdollarexprs
|
|
327
|
+
| SINGLEQUOTEDSTRING | formatstring | _innerdollarexprs | embedquery
|
|
328
328
|
|
|
329
329
|
// Expr versions of rules to avoid invalid state merges
|
|
330
330
|
_innerdollarexprs: "$"? innerdollaroper
|
|
@@ -454,8 +454,14 @@ formatstring: "`" (_formatexpr | FORMATTEXT)* "`"
|
|
|
454
454
|
|
|
455
455
|
// Must be kept consistent with same regexes in synapse/lib/grammar.py
|
|
456
456
|
// A full property. Must contain at least 1 colon
|
|
457
|
-
PROPS.
|
|
458
|
-
|
|
457
|
+
PROPS.3: /[a-z_][a-z0-9_]*(:[a-z0-9_]+)+([:.][a-z0-9_]+)*(?![:.a-z0-9_\-])/
|
|
458
|
+
|
|
459
|
+
// A full property containing a wildcard
|
|
460
|
+
WILDPROPS.3: /[a-z_][a-z0-9_]*(:\*|(:[a-z0-9_]+)+([:.][a-z0-9_]+)*:?\*)(?![:.a-z0-9_\-\[])/
|
|
461
|
+
|
|
462
|
+
// A full property with embed properties
|
|
463
|
+
EMBEDPROPS.2: /[a-z_][a-z0-9_]*(:[a-z0-9_]+)+((\:\:|\:|\.)[a-z0-9_]+)*(?![:.a-z0-9_\-])/
|
|
464
|
+
|
|
459
465
|
// A universal property
|
|
460
466
|
UNIVNAME.2: /(?<=^|[\s\|\{\(\[+=-])\.[a-z_][a-z0-9_]*([:.][a-z0-9_]+)*/
|
|
461
467
|
univprop: UNIVNAME | "." _varvalu
|
synapse/lib/storm.py
CHANGED
|
@@ -1778,8 +1778,10 @@ class StormDmon(s_base.Base):
|
|
|
1778
1778
|
|
|
1779
1779
|
text = self.ddef.get('storm')
|
|
1780
1780
|
opts = self.ddef.get('stormopts', {})
|
|
1781
|
-
|
|
1781
|
+
|
|
1782
|
+
vars = await s_stormtypes.toprim(opts.get('vars', {}), use_list=True)
|
|
1782
1783
|
vars.setdefault('auto', {'iden': self.iden, 'type': 'dmon'})
|
|
1784
|
+
opts['vars'] = vars
|
|
1783
1785
|
|
|
1784
1786
|
viewiden = opts.get('view')
|
|
1785
1787
|
|
|
@@ -2732,15 +2734,28 @@ class Parser:
|
|
|
2732
2734
|
self.exited = True
|
|
2733
2735
|
return False
|
|
2734
2736
|
|
|
2737
|
+
def _wrap_text(self, text, width):
|
|
2738
|
+
lines, curline, curlen = [], [], 0
|
|
2739
|
+
for word in text.split():
|
|
2740
|
+
if curlen + len(word) + bool(curline) > width:
|
|
2741
|
+
lines.append(' '.join(curline))
|
|
2742
|
+
curline, curlen = [word], len(word)
|
|
2743
|
+
else:
|
|
2744
|
+
curline.append(word)
|
|
2745
|
+
curlen += len(word) + bool(curline)
|
|
2746
|
+
if curline:
|
|
2747
|
+
lines.append(' '.join(curline))
|
|
2748
|
+
return lines
|
|
2749
|
+
|
|
2735
2750
|
def _print_optarg(self, names, argdef):
|
|
2736
2751
|
|
|
2737
2752
|
dest = self._get_dest_str(argdef)
|
|
2738
2753
|
oact = argdef.get('action', 'store')
|
|
2739
2754
|
|
|
2740
2755
|
if oact in ('store_true', 'store_false'):
|
|
2741
|
-
base = f' {names[0]}'
|
|
2756
|
+
base = f' {names[0]}'
|
|
2742
2757
|
else:
|
|
2743
|
-
base = f' {names[0]} {dest}'
|
|
2758
|
+
base = f' {names[0]} {dest}'
|
|
2744
2759
|
|
|
2745
2760
|
defval = argdef.get('default', s_common.novalu)
|
|
2746
2761
|
choices = argdef.get('choices')
|
|
@@ -2748,12 +2763,14 @@ class Parser:
|
|
|
2748
2763
|
|
|
2749
2764
|
if defval is not s_common.novalu and oact not in ('store_true', 'store_false'):
|
|
2750
2765
|
if isinstance(defval, (tuple, list, dict)):
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
defval = '\n' + defval
|
|
2766
|
+
defval_ls = pprint.pformat(defval, width=120).split('\n')
|
|
2767
|
+
defval = '\n'.join(ln.strip() for ln in defval_ls)
|
|
2754
2768
|
|
|
2755
2769
|
if choices is None:
|
|
2756
|
-
|
|
2770
|
+
if (lambda tst: '\n' in tst if isinstance(tst, str) else False)(defval):
|
|
2771
|
+
helpstr = f'{helpstr} (default: \n{defval})'
|
|
2772
|
+
else:
|
|
2773
|
+
helpstr = f'{helpstr} (default: {defval})'
|
|
2757
2774
|
else:
|
|
2758
2775
|
cstr = ', '.join(str(c) for c in choices)
|
|
2759
2776
|
helpstr = f'{helpstr} (default: {defval}, choices: {cstr})'
|
|
@@ -2762,7 +2779,26 @@ class Parser:
|
|
|
2762
2779
|
cstr = ', '.join(str(c) for c in choices)
|
|
2763
2780
|
helpstr = f'{helpstr} (choices: {cstr})'
|
|
2764
2781
|
|
|
2765
|
-
|
|
2782
|
+
helplst = helpstr.split('\n')
|
|
2783
|
+
if helplst and not helplst[0].strip():
|
|
2784
|
+
helplst = helplst[1:]
|
|
2785
|
+
min_space = min((len(ln) - len(ln.lstrip()) for ln in helplst if ln.strip()), default=0)
|
|
2786
|
+
|
|
2787
|
+
base_w = 32
|
|
2788
|
+
wrap_w = 120 - base_w
|
|
2789
|
+
|
|
2790
|
+
first = helplst[0][min_space:]
|
|
2791
|
+
wrap_first = self._wrap_text(first, wrap_w)
|
|
2792
|
+
self._printf(f'{base:<{base_w-2}}: {wrap_first[0]}')
|
|
2793
|
+
|
|
2794
|
+
for ln in wrap_first[1:]: self._printf(f'{"":<{base_w}}{ln}')
|
|
2795
|
+
for ln in helplst[1:]:
|
|
2796
|
+
lead_s = len(ln) - len(ln.lstrip())
|
|
2797
|
+
rel_ind = lead_s - min_space
|
|
2798
|
+
ind = ' ' * (base_w + rel_ind)
|
|
2799
|
+
wrapped = self._wrap_text(ln.lstrip(), wrap_w - rel_ind)
|
|
2800
|
+
for wl in wrapped:
|
|
2801
|
+
self._printf(f'{ind}{wl}')
|
|
2766
2802
|
|
|
2767
2803
|
def _print_posarg(self, name, argdef):
|
|
2768
2804
|
dest = self._get_dest_str(argdef)
|
|
@@ -5232,7 +5268,7 @@ class BackgroundCmd(Cmd):
|
|
|
5232
5268
|
async for item in genr:
|
|
5233
5269
|
yield item
|
|
5234
5270
|
|
|
5235
|
-
runtprims = await s_stormtypes.toprim(self.runt.getScopeVars())
|
|
5271
|
+
runtprims = await s_stormtypes.toprim(self.runt.getScopeVars(), use_list=True)
|
|
5236
5272
|
runtvars = {k: v for (k, v) in runtprims.items() if s_msgpack.isok(v)}
|
|
5237
5273
|
|
|
5238
5274
|
opts = {
|
synapse/lib/storm_format.py
CHANGED
synapse/lib/stormlib/graph.py
CHANGED
|
@@ -157,6 +157,15 @@ class GraphLib(s_stormtypes.Lib):
|
|
|
157
157
|
),
|
|
158
158
|
'returns': {'type': 'null', }}},
|
|
159
159
|
|
|
160
|
+
{'name': 'revoke', 'desc': 'Revoke permissions granted to users/roles on a graph projection.',
|
|
161
|
+
'type': {'type': 'function', '_funcname': '_methGraphRevoke',
|
|
162
|
+
'args': (
|
|
163
|
+
{'name': 'gden', 'type': 'str', 'desc': 'Iden of the graph projection to modify.'},
|
|
164
|
+
{'name': 'scope', 'type': 'str', 'desc': 'The scope, either "users" or "roles".'},
|
|
165
|
+
{'name': 'iden', 'type': 'str', 'desc': 'The user/role iden depending on scope.'},
|
|
166
|
+
),
|
|
167
|
+
'returns': {'type': 'null'}}},
|
|
168
|
+
|
|
160
169
|
{'name': 'activate', 'desc': 'Set the graph projection to use for the top level Storm Runtime.',
|
|
161
170
|
'type': {'type': 'function', '_funcname': '_methGraphActivate',
|
|
162
171
|
'args': (
|
|
@@ -174,6 +183,7 @@ class GraphLib(s_stormtypes.Lib):
|
|
|
174
183
|
'mod': self._methGraphMod,
|
|
175
184
|
'list': self._methGraphList,
|
|
176
185
|
'grant': self._methGraphGrant,
|
|
186
|
+
'revoke': self._methGraphRevoke,
|
|
177
187
|
'activate': self._methGraphActivate,
|
|
178
188
|
}
|
|
179
189
|
|
|
@@ -219,6 +229,13 @@ class GraphLib(s_stormtypes.Lib):
|
|
|
219
229
|
|
|
220
230
|
await self.runt.snap.core.setStormGraphPerm(gden, scope, iden, level, user=self.runt.user)
|
|
221
231
|
|
|
232
|
+
async def _methGraphRevoke(self, gden, scope, iden):
|
|
233
|
+
gden = await s_stormtypes.tostr(gden)
|
|
234
|
+
scope = await s_stormtypes.tostr(scope)
|
|
235
|
+
iden = await s_stormtypes.tostr(iden)
|
|
236
|
+
|
|
237
|
+
await self.runt.snap.core.setStormGraphPerm(gden, scope, iden, None, user=self.runt.user)
|
|
238
|
+
|
|
222
239
|
async def _methGraphActivate(self, iden):
|
|
223
240
|
gdef = await self._methGraphGet(iden)
|
|
224
241
|
self.runt.setGraph(gdef)
|